From e29d4b448ead38c55ebd913e163f7c41e6125699 Mon Sep 17 00:00:00 2001 From: jboner Date: Sun, 11 Oct 2009 11:21:12 +0200 Subject: [PATCH 01/12] enhanced the RemoteServer API --- akka-actors/src/main/scala/nio/RemoteServer.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/akka-actors/src/main/scala/nio/RemoteServer.scala b/akka-actors/src/main/scala/nio/RemoteServer.scala index ccb7661674..c8a5bbdd9d 100644 --- a/akka-actors/src/main/scala/nio/RemoteServer.scala +++ b/akka-actors/src/main/scala/nio/RemoteServer.scala @@ -49,10 +49,14 @@ object RemoteServer extends Logging { private val bootstrap = new ServerBootstrap(factory) - def start(loader: Option[ClassLoader]) = synchronized { + def start: Unit = start(None) + def start(loader: Option[ClassLoader]): Unit = start(HOSTNAME, PORT) + def start(hostname: String, port: Int): Unit = start(hostname, port, None) + def start(hostname: String, port: Int, loader: Option[ClassLoader]): Unit = synchronized { if (!isRunning) { log.info("Starting remote server at [%s:%s]", HOSTNAME, PORT) bootstrap.setPipelineFactory(new RemoteServerPipelineFactory(name, loader)) + // FIXME make these RemoteServer options configurable bootstrap.setOption("child.tcpNoDelay", true) bootstrap.setOption("child.keepAlive", true) bootstrap.setOption("child.reuseAddress", true) From 0009c1a1125036cc56937e4566b2cee6e3206d8e Mon Sep 17 00:00:00 2001 From: jboner Date: Sun, 11 Oct 2009 11:21:12 +0200 Subject: [PATCH 02/12] enhanced the RemoteServer API --- akka-actors/src/main/scala/nio/RemoteServer.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/akka-actors/src/main/scala/nio/RemoteServer.scala b/akka-actors/src/main/scala/nio/RemoteServer.scala index ccb7661674..c8a5bbdd9d 100644 --- a/akka-actors/src/main/scala/nio/RemoteServer.scala +++ b/akka-actors/src/main/scala/nio/RemoteServer.scala @@ -49,10 +49,14 @@ object RemoteServer extends Logging { private val bootstrap = new ServerBootstrap(factory) - def start(loader: Option[ClassLoader]) = synchronized { + def start: Unit = start(None) + def start(loader: Option[ClassLoader]): Unit = start(HOSTNAME, PORT) + def start(hostname: String, port: Int): Unit = start(hostname, port, None) + def start(hostname: String, port: Int, loader: Option[ClassLoader]): Unit = synchronized { if (!isRunning) { log.info("Starting remote server at [%s:%s]", HOSTNAME, PORT) bootstrap.setPipelineFactory(new RemoteServerPipelineFactory(name, loader)) + // FIXME make these RemoteServer options configurable bootstrap.setOption("child.tcpNoDelay", true) bootstrap.setOption("child.keepAlive", true) bootstrap.setOption("child.reuseAddress", true) From 56dc6ea770c765d2ffd15d024674566f4fe9c539 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Mon, 12 Oct 2009 21:46:13 +0200 Subject: [PATCH 03/12] Refactored Atmosphere support to be container agnostic + fixed a couple of NPEs --- akka-kernel/src/main/scala/AkkaServlet.scala | 23 +++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/akka-kernel/src/main/scala/AkkaServlet.scala b/akka-kernel/src/main/scala/AkkaServlet.scala index 23cda8140d..54bb195613 100755 --- a/akka-kernel/src/main/scala/AkkaServlet.scala +++ b/akka-kernel/src/main/scala/AkkaServlet.scala @@ -42,31 +42,34 @@ class AkkaServlet extends ServletContainer with Logging { } class AkkaCometServlet extends org.atmosphere.cpr.AtmosphereServlet { - override def init(sconf: ServletConfig) = { + + override def loadConfiguration(sc : ServletConfig) : Unit = { val servlet = new AkkaServlet with AtmosphereServletProcessor { //Delegate to implement the behavior for AtmosphereHandler private val handler = new AbstractReflectorAtmosphereHandler { override def onRequest(event: AtmosphereResource[HttpServletRequest, HttpServletResponse]) : Unit = { - event.getRequest.setAttribute(ReflectorServletProcessor.ATMOSPHERE_RESOURCE, event) - event.getRequest.setAttribute(ReflectorServletProcessor.ATMOSPHERE_HANDLER, this) - service(event.getRequest, event.getResponse) + if(event ne null) + { + event.getRequest.setAttribute(ReflectorServletProcessor.ATMOSPHERE_RESOURCE, event) + event.getRequest.setAttribute(ReflectorServletProcessor.ATMOSPHERE_HANDLER, this) + service(event.getRequest, event.getResponse) + } } } override def onStateChange(event : AtmosphereResourceEvent[HttpServletRequest, HttpServletResponse] ) { - handler onStateChange event + if(event ne null) + handler onStateChange event } override def onRequest(resource: AtmosphereResource[HttpServletRequest, HttpServletResponse]) { - handler onRequest resource + if(resource ne null) + handler onRequest resource } } - config = new AtmosphereConfig { ah = servlet } + atmosphereHandlers.put("/*", new AtmosphereHandlerWrapper(servlet, new JerseyBroadcaster)) - setCometSupport(new GrizzlyCometSupport(config)) - getCometSupport.init(sconf) - servlet.init(sconf) } override def loadAtmosphereDotXml(is: InputStream, urlc: URLClassLoader) = () //Hide it From 169ea22560cb8f5fbe17553e46fe337aa21455ed Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Mon, 12 Oct 2009 23:14:56 +0200 Subject: [PATCH 04/12] Fitted the Atmosphere Chat example onto Akka --- akka-kernel/src/main/scala/AkkaServlet.scala | 9 +-- .../src/main/scala/SimpleService.scala | 8 ++- deploy/root/META-INF/atmosphere.xml | 9 --- deploy/root/META-INF/context.xml | 5 -- deploy/root/jquery-1.3.2.min.js | 19 ------ deploy/root/page.html | 64 ------------------- 6 files changed, 10 insertions(+), 104 deletions(-) delete mode 100755 deploy/root/META-INF/atmosphere.xml delete mode 100755 deploy/root/META-INF/context.xml delete mode 100644 deploy/root/jquery-1.3.2.min.js delete mode 100644 deploy/root/page.html diff --git a/akka-kernel/src/main/scala/AkkaServlet.scala b/akka-kernel/src/main/scala/AkkaServlet.scala index 54bb195613..855c22694f 100755 --- a/akka-kernel/src/main/scala/AkkaServlet.scala +++ b/akka-kernel/src/main/scala/AkkaServlet.scala @@ -43,12 +43,11 @@ class AkkaServlet extends ServletContainer with Logging { class AkkaCometServlet extends org.atmosphere.cpr.AtmosphereServlet { - override def loadConfiguration(sc : ServletConfig) : Unit = { - val servlet = new AkkaServlet with AtmosphereServletProcessor { + val servlet = new AkkaServlet with AtmosphereServletProcessor { //Delegate to implement the behavior for AtmosphereHandler private val handler = new AbstractReflectorAtmosphereHandler { - override def onRequest(event: AtmosphereResource[HttpServletRequest, HttpServletResponse]) : Unit = { + override def onRequest(event: AtmosphereResource[HttpServletRequest, HttpServletResponse]) { if(event ne null) { event.getRequest.setAttribute(ReflectorServletProcessor.ATMOSPHERE_RESOURCE, event) @@ -64,13 +63,11 @@ class AkkaCometServlet extends org.atmosphere.cpr.AtmosphereServlet { } override def onRequest(resource: AtmosphereResource[HttpServletRequest, HttpServletResponse]) { - if(resource ne null) handler onRequest resource } } + override def loadConfiguration(sc : ServletConfig) { atmosphereHandlers.put("/*", new AtmosphereHandlerWrapper(servlet, new JerseyBroadcaster)) } - - override def loadAtmosphereDotXml(is: InputStream, urlc: URLClassLoader) = () //Hide it } diff --git a/akka-samples-scala/src/main/scala/SimpleService.scala b/akka-samples-scala/src/main/scala/SimpleService.scala index 0f595d2cf5..d343f9cd5d 100644 --- a/akka-samples-scala/src/main/scala/SimpleService.scala +++ b/akka-samples-scala/src/main/scala/SimpleService.scala @@ -112,7 +112,13 @@ class Chat extends Actor with Logging { @Suspend @GET @Produces(Array("text/html")) - def suspend = + def suspend = { + val s = new StringBuilder + s append "" + s toString + } override def receive: PartialFunction[Any, Unit] = { case Chat(who, what, msg) => { diff --git a/deploy/root/META-INF/atmosphere.xml b/deploy/root/META-INF/atmosphere.xml deleted file mode 100755 index fa009de51b..0000000000 --- a/deploy/root/META-INF/atmosphere.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/deploy/root/META-INF/context.xml b/deploy/root/META-INF/context.xml deleted file mode 100755 index 71838e0728..0000000000 --- a/deploy/root/META-INF/context.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/deploy/root/jquery-1.3.2.min.js b/deploy/root/jquery-1.3.2.min.js deleted file mode 100644 index b1ae21d8b2..0000000000 --- a/deploy/root/jquery-1.3.2.min.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * jQuery JavaScript Library v1.3.2 - * http://jquery.com/ - * - * Copyright (c) 2009 John Resig - * Dual licensed under the MIT and GPL licenses. - * http://docs.jquery.com/License - * - * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009) - * Revision: 6246 - */ -(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!O.indexOf("",""]||(!O.indexOf("",""]||!O.indexOf("",""]||!o.support.htmlSerialize&&[1,"div
","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}}); -/* - * Sizzle CSS Selector Engine - v0.9.3 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return UT[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="

";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="
";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("
").append(M.responseText.replace(//g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='
';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})(); \ No newline at end of file diff --git a/deploy/root/page.html b/deploy/root/page.html deleted file mode 100644 index b6d3f5f2d5..0000000000 --- a/deploy/root/page.html +++ /dev/null @@ -1,64 +0,0 @@ - - - Push Services Demo - - - - -
-
-
-
-
- - - - -
-
-
- - - \ No newline at end of file From b9262d548c04f93abf90c15b78ebe6b967d5f1c0 Mon Sep 17 00:00:00 2001 From: jboner Date: Tue, 13 Oct 2009 07:46:09 +0200 Subject: [PATCH 05/12] fixed remote server bug --- akka-actors/src/main/scala/nio/RemoteServer.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/akka-actors/src/main/scala/nio/RemoteServer.scala b/akka-actors/src/main/scala/nio/RemoteServer.scala index c8a5bbdd9d..fed2021fa0 100644 --- a/akka-actors/src/main/scala/nio/RemoteServer.scala +++ b/akka-actors/src/main/scala/nio/RemoteServer.scala @@ -50,18 +50,17 @@ object RemoteServer extends Logging { private val bootstrap = new ServerBootstrap(factory) def start: Unit = start(None) - def start(loader: Option[ClassLoader]): Unit = start(HOSTNAME, PORT) def start(hostname: String, port: Int): Unit = start(hostname, port, None) def start(hostname: String, port: Int, loader: Option[ClassLoader]): Unit = synchronized { if (!isRunning) { - log.info("Starting remote server at [%s:%s]", HOSTNAME, PORT) + log.info("Starting remote server at [%s:%s]", hostname, port) bootstrap.setPipelineFactory(new RemoteServerPipelineFactory(name, loader)) // FIXME make these RemoteServer options configurable bootstrap.setOption("child.tcpNoDelay", true) bootstrap.setOption("child.keepAlive", true) bootstrap.setOption("child.reuseAddress", true) bootstrap.setOption("child.connectTimeoutMillis", CONNECTION_TIMEOUT_MILLIS) - bootstrap.bind(new InetSocketAddress(HOSTNAME, PORT)) + bootstrap.bind(new InetSocketAddress(hostname, port)) isRunning = true } } From 617d1a9c2f1bc61bbf27598a6a2677a9ab7e8667 Mon Sep 17 00:00:00 2001 From: jboner Date: Tue, 13 Oct 2009 11:18:21 +0200 Subject: [PATCH 06/12] fixed broken remote server api --- akka-actors/src/main/scala/actor/Actor.scala | 12 +++++------ .../src/main/scala/nio/RemoteServer.scala | 21 ++++++++++++------- .../src/test/scala/RemoteActorSpec.scala | 3 +-- .../src/test/scala/RemoteSupervisorSpec.scala | 3 +-- akka-kernel/src/main/scala/Kernel.scala | 1 - 5 files changed, 22 insertions(+), 18 deletions(-) diff --git a/akka-actors/src/main/scala/actor/Actor.scala b/akka-actors/src/main/scala/actor/Actor.scala index 5e0191483a..d18092dd83 100644 --- a/akka-actors/src/main/scala/actor/Actor.scala +++ b/akka-actors/src/main/scala/actor/Actor.scala @@ -348,8 +348,8 @@ trait Actor extends Logging with TransactionManagement { *

* To be invoked from within the actor itself. */ - protected[this] def startLinkRemote(actor: Actor) = { - actor.makeRemote(RemoteServer.HOSTNAME, RemoteServer.PORT) + protected[this] def startLinkRemote(actor: Actor, hostname: String, port: Int) = { + actor.makeRemote(hostname, port) actor.start link(actor) } @@ -372,9 +372,9 @@ trait Actor extends Logging with TransactionManagement { *

* To be invoked from within the actor itself. */ - protected[this] def spawnRemote[T <: Actor](actorClass: Class[T]): T = { + protected[this] def spawnRemote[T <: Actor](actorClass: Class[T], hostname: String, port: Int): T = { val actor = actorClass.newInstance.asInstanceOf[T] - actor.makeRemote(RemoteServer.HOSTNAME, RemoteServer.PORT) + actor.makeRemote(hostname, port) actor.dispatcher = dispatcher actor.mailbox = mailbox actor.start @@ -397,9 +397,9 @@ trait Actor extends Logging with TransactionManagement { *

* To be invoked from within the actor itself. */ - protected[this] def spawnLinkRemote[T <: Actor](actorClass: Class[T]): T = { + protected[this] def spawnLinkRemote[T <: Actor](actorClass: Class[T], hostname: String, port: Int): T = { val actor = spawn[T](actorClass) - actor.makeRemote(RemoteServer.HOSTNAME, RemoteServer.PORT) + actor.makeRemote(hostname, port) link(actor) actor } diff --git a/akka-actors/src/main/scala/nio/RemoteServer.scala b/akka-actors/src/main/scala/nio/RemoteServer.scala index fed2021fa0..99429fdbb9 100644 --- a/akka-actors/src/main/scala/nio/RemoteServer.scala +++ b/akka-actors/src/main/scala/nio/RemoteServer.scala @@ -23,21 +23,20 @@ import org.jboss.netty.handler.codec.protobuf.{ProtobufDecoder, ProtobufEncoder} /** * @author Jonas Bonér */ -class RemoteServer extends Logging { - def start = RemoteServer.start(None) -} +object RemoteServer extends RemoteServer /** * @author Jonas Bonér */ -object RemoteServer extends Logging { +class RemoteServer extends Logging { import Config.config val HOSTNAME = config.getString("akka.remote.hostname", "localhost") val PORT = config.getInt("akka.remote.port", 9999) val CONNECTION_TIMEOUT_MILLIS = config.getInt("akka.remote.connection-timeout", 1000) - val name = "RemoteServer@" + HOSTNAME - + private var hostname = HOSTNAME + private var port = PORT + @volatile private var isRunning = false @volatile private var isConfigured = false @@ -49,10 +48,18 @@ object RemoteServer extends Logging { private val bootstrap = new ServerBootstrap(factory) + def name = "RemoteServer@" + hostname + ":" + port + def start: Unit = start(None) + + def start(loader: Option[ClassLoader]): Unit = start(HOSTNAME, PORT, loader) + def start(hostname: String, port: Int): Unit = start(hostname, port, None) - def start(hostname: String, port: Int, loader: Option[ClassLoader]): Unit = synchronized { + + def start(_hostname: String, _port: Int, loader: Option[ClassLoader]): Unit = synchronized { if (!isRunning) { + hostname = _hostname + port = _port log.info("Starting remote server at [%s:%s]", hostname, port) bootstrap.setPipelineFactory(new RemoteServerPipelineFactory(name, loader)) // FIXME make these RemoteServer options configurable diff --git a/akka-actors/src/test/scala/RemoteActorSpec.scala b/akka-actors/src/test/scala/RemoteActorSpec.scala index f492189fe2..43f4d7573c 100644 --- a/akka-actors/src/test/scala/RemoteActorSpec.scala +++ b/akka-actors/src/test/scala/RemoteActorSpec.scala @@ -30,8 +30,7 @@ class RemoteActorSpec extends TestCase { akka.Config.config new Thread(new Runnable() { def run = { - val server = new RemoteServer - server.start + RemoteServer.start } }).start Thread.sleep(1000) diff --git a/akka-actors/src/test/scala/RemoteSupervisorSpec.scala b/akka-actors/src/test/scala/RemoteSupervisorSpec.scala index e7425aedc2..dfc97959c9 100644 --- a/akka-actors/src/test/scala/RemoteSupervisorSpec.scala +++ b/akka-actors/src/test/scala/RemoteSupervisorSpec.scala @@ -25,8 +25,7 @@ class RemoteSupervisorSpec extends junit.framework.TestCase with Suite { akka.Config.config new Thread(new Runnable() { def run = { - val server = new RemoteServer - server.start + RemoteServer.start } }).start Thread.sleep(1000) diff --git a/akka-kernel/src/main/scala/Kernel.scala b/akka-kernel/src/main/scala/Kernel.scala index 5dd8bcf190..e9ec2a8275 100644 --- a/akka-kernel/src/main/scala/Kernel.scala +++ b/akka-kernel/src/main/scala/Kernel.scala @@ -33,7 +33,6 @@ object Kernel extends Logging { // FIXME add API to shut server down gracefully @volatile private var hasBooted = false - private var remoteServer: RemoteServer = _ private var jerseySelectorThread: SelectorThread = _ private val startTime = System.currentTimeMillis private var applicationLoader: Option[ClassLoader] = None From 0f6823215a2fa671ee90033602fccf0f4f31ad81 Mon Sep 17 00:00:00 2001 From: jboner Date: Tue, 13 Oct 2009 11:38:05 +0200 Subject: [PATCH 07/12] changed persistent structures names --- .../akka/api/PersistentClasher.java | 3 +- .../src/main/scala/PersistentState.scala | 36 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentClasher.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentClasher.java index 1787548806..f7715d1a82 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentClasher.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentClasher.java @@ -1,10 +1,9 @@ package se.scalablesolutions.akka.api; import se.scalablesolutions.akka.state.TransactionalMap; -import se.scalablesolutions.akka.state.CassandraPersistentTransactionalMap; public class PersistentClasher { - private TransactionalMap state = new CassandraPersistentTransactionalMap(); + private TransactionalMap state = new se.scalablesolutions.akka.state.CassandraPersistentMap(); public String getState(String key) { return (String)state.get(key).get(); diff --git a/akka-persistence/src/main/scala/PersistentState.scala b/akka-persistence/src/main/scala/PersistentState.scala index 75460cc47b..0b8bfb8fd1 100644 --- a/akka-persistence/src/main/scala/PersistentState.scala +++ b/akka-persistence/src/main/scala/PersistentState.scala @@ -39,22 +39,22 @@ object PersistentState extends PersistentState */ class PersistentState { def newMap(config: PersistentStorageConfig): TransactionalMap[AnyRef, AnyRef] = config match { - case CassandraStorageConfig() => new CassandraPersistentTransactionalMap - case MongoStorageConfig() => new MongoPersistentTransactionalMap + case CassandraStorageConfig() => new CassandraPersistentMap + case MongoStorageConfig() => new MongoPersistentMap case TerracottaStorageConfig() => throw new UnsupportedOperationException case TokyoCabinetStorageConfig() => throw new UnsupportedOperationException } def newVector(config: PersistentStorageConfig): TransactionalVector[AnyRef] = config match { - case CassandraStorageConfig() => new CassandraPersistentTransactionalVector - case MongoStorageConfig() => new MongoPersistentTransactionalVector + case CassandraStorageConfig() => new CassandraPersistentVector + case MongoStorageConfig() => new MongoPersistentVector case TerracottaStorageConfig() => throw new UnsupportedOperationException case TokyoCabinetStorageConfig() => throw new UnsupportedOperationException } def newRef(config: PersistentStorageConfig): TransactionalRef[AnyRef] = config match { - case CassandraStorageConfig() => new CassandraPersistentTransactionalRef - case MongoStorageConfig() => new MongoPersistentTransactionalRef + case CassandraStorageConfig() => new CassandraPersistentRef + case MongoStorageConfig() => new MongoPersistentRef case TerracottaStorageConfig() => throw new UnsupportedOperationException case TokyoCabinetStorageConfig() => throw new UnsupportedOperationException } @@ -68,7 +68,7 @@ class PersistentState { * * @author Jonas Bonér */ -abstract class PersistentTransactionalMap[K, V] extends TransactionalMap[K, V] { +abstract class PersistentMap[K, V] extends TransactionalMap[K, V] { // FIXME: need to handle remove in another changeSet protected[akka] val changeSet = new HashMap[K, V] @@ -93,7 +93,7 @@ abstract class PersistentTransactionalMap[K, V] extends TransactionalMap[K, V] { } /** - * Implementation of PersistentTransactionalMap for every concrete + * Implementation of PersistentMap for every concrete * storage will have the same workflow. This abstracts the workflow. * * Subclasses just need to provide the actual concrete instance for the @@ -101,7 +101,7 @@ abstract class PersistentTransactionalMap[K, V] extends TransactionalMap[K, V] { * * @author Jonas Bonér */ -abstract class TemplatePersistentTransactionalMap extends PersistentTransactionalMap[AnyRef, AnyRef] { +abstract class TemplatePersistentMap extends PersistentMap[AnyRef, AnyRef] { // to be concretized in subclasses val storage: MapStorage @@ -191,7 +191,7 @@ abstract class TemplatePersistentTransactionalMap extends PersistentTransactiona * * @author Debasish Ghosh */ -class CassandraPersistentTransactionalMap extends TemplatePersistentTransactionalMap { +class CassandraPersistentMap extends TemplatePersistentMap { val storage = CassandraStorage } @@ -200,7 +200,7 @@ class CassandraPersistentTransactionalMap extends TemplatePersistentTransactiona * * @author Debasish Ghosh */ -class MongoPersistentTransactionalMap extends TemplatePersistentTransactionalMap { +class MongoPersistentMap extends TemplatePersistentMap { val storage = MongoStorage } @@ -212,7 +212,7 @@ class MongoPersistentTransactionalMap extends TemplatePersistentTransactionalMap * * @author Jonas Bonér */ -abstract class PersistentTransactionalVector[T] extends TransactionalVector[T] { +abstract class PersistentVector[T] extends TransactionalVector[T] { // FIXME: need to handle remove in another changeSet protected[akka] val changeSet = new ArrayBuffer[T] @@ -234,7 +234,7 @@ abstract class PersistentTransactionalVector[T] extends TransactionalVector[T] { * * @author Debasish Ghosh */ -abstract class TemplatePersistentTransactionalVector extends PersistentTransactionalVector[AnyRef] { +abstract class TemplatePersistentVector extends PersistentVector[AnyRef] { val storage: VectorStorage @@ -282,7 +282,7 @@ abstract class TemplatePersistentTransactionalVector extends PersistentTransacti * * @author Debaissh Ghosh */ -class CassandraPersistentTransactionalVector extends TemplatePersistentTransactionalVector { +class CassandraPersistentVector extends TemplatePersistentVector { val storage = CassandraStorage } @@ -291,11 +291,11 @@ class CassandraPersistentTransactionalVector extends TemplatePersistentTransacti * * @author Debaissh Ghosh */ -class MongoPersistentTransactionalVector extends TemplatePersistentTransactionalVector { +class MongoPersistentVector extends TemplatePersistentVector { val storage = MongoStorage } -abstract class TemplatePersistentTransactionalRef extends TransactionalRef[AnyRef] { +abstract class TemplatePersistentRef extends TransactionalRef[AnyRef] { val storage: RefStorage override def commit = if (ref.isDefined) { @@ -319,10 +319,10 @@ abstract class TemplatePersistentTransactionalRef extends TransactionalRef[AnyRe } } -class CassandraPersistentTransactionalRef extends TemplatePersistentTransactionalRef { +class CassandraPersistentRef extends TemplatePersistentRef { val storage = CassandraStorage } -class MongoPersistentTransactionalRef extends TemplatePersistentTransactionalRef { +class MongoPersistentRef extends TemplatePersistentRef { val storage = MongoStorage } From 9caf635dfc82ce4ef10f482a8208ccd4a7d39374 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 13 Oct 2009 22:22:38 +0200 Subject: [PATCH 08/12] Added webroot --- config/jndi.properties | 1 + deploy/root/images/body-background.png | Bin 0 -> 2381 bytes deploy/root/images/header-background.png | Bin 0 -> 20847 bytes deploy/root/images/main-background.png | Bin 0 -> 8026 bytes deploy/root/index.html | 45 + deploy/root/javascripts/application.js | 90 ++ deploy/root/javascripts/behaviour.js | 254 +++ deploy/root/javascripts/moo.fx.js | 136 ++ deploy/root/javascripts/moo.fx.pack.js | 83 + deploy/root/javascripts/prototype.js | 1781 ++++++++++++++++++++++ deploy/root/stylesheets/default.css | 54 + 11 files changed, 2444 insertions(+) create mode 100644 config/jndi.properties create mode 100644 deploy/root/images/body-background.png create mode 100644 deploy/root/images/header-background.png create mode 100644 deploy/root/images/main-background.png create mode 100644 deploy/root/index.html create mode 100644 deploy/root/javascripts/application.js create mode 100644 deploy/root/javascripts/behaviour.js create mode 100644 deploy/root/javascripts/moo.fx.js create mode 100644 deploy/root/javascripts/moo.fx.pack.js create mode 100644 deploy/root/javascripts/prototype.js create mode 100644 deploy/root/stylesheets/default.css diff --git a/config/jndi.properties b/config/jndi.properties new file mode 100644 index 0000000000..c4151420d6 --- /dev/null +++ b/config/jndi.properties @@ -0,0 +1 @@ +java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory \ No newline at end of file diff --git a/deploy/root/images/body-background.png b/deploy/root/images/body-background.png new file mode 100644 index 0000000000000000000000000000000000000000..ece11eb20ac9dea8dbda6dfebbc134c78fd3b096 GIT binary patch literal 2381 zcmeAS@N?(olHy`uVBq!ia0y~yVBlh4U{>H@VqjpH+MlA%z`(#+;1OBOz`!jG!i)^F z=14FwaQydlaSW-r^)~wUrpFc>E+YT`AD=ysJ+foZ#@b<6FXn9iab`g;Wx{8u+fS4vxC8XzVC{AoxYd|Uc4~zW%JGN9p}}*9o~}v zY0gB0aEtKRah$i;&%D#*t(4KKlilHdLAw7{^!e_|JSXwA11cVclfs2Ct{re z|Bw9i{$nKJ{%(k$N zy!#^F8&sXlOR-%Labf3^Y)5JLW4BZ@j{ki#=^xj-Z^yq#Iqq+Mv?jG<(x+=xZQ9~@ z{MCCWCs|K!N}E^r^1-E_l?5rRhL&#_1(w`xSW>+vTAw-Qo^po71)UffHc{mh@Bhc# zFa4V?t@UYYzcMq2;!%h5yOeet%YQqN?)XV$fw7Es9@7NNXAcXDj~F~xK6=k3(Mirf z_WjP;Zzb>CIJfZEgg8ZoGYXmEQP)El7B%vEuz0iGsM=u~QN*xlVgmnx30qFRduUwn z^3r9VkfUms7Jf)u-xMU;9eDEhkMf0<-R1j|&awq_`gT2E zp(fk)T(T>E!=9yGE*uXQa?3citIW6-Ei8ECv&~YQ^B=e`Y?0d#7qDIsIQ~$3M->e@@)lIb}~ny5{_?GT*rL z9#4+G;Jjwii+}$bcoW2ShkRN0RQCz%lPN1Z{xKfZxtx>!Y;g`>{&N}Ab!Rt-JPLMX zTkWab*YQ|zO7g5{ldUWbo*WGhRx)#P3%w9{xi<@bnAp$u6MyjOy_;KSIWJ^0FuJnh>y zbn0Qf17SX!+V(jb3oow8H_3W)E5YK?taZC&dzSpRvRpI8#Yg0f(S*tO`5Zq<-a4Ic zqdR@CkIqe>3syGnO+CxzBz0#WlZHlRt4sX=d0}Mc2%(?hpKRqiXiHgHd4$nkgoarb{SxvQ-{z>!{dwamyj2 zzsuJoOidH5T{KPllO*dp%jaPVO;ct0Z(ED9F$qreOD^N74$w95=)8LGys$!IphM>B zaP7W@&aY=wgzTH9ZhY<8ri6uCcRuJ)v^b$yp*;B@!~G(S>CmG5#w%Hmv$QY3H=3^>-Yv9bYihGmd9t z*9At~qpNzOEN(LWv=HM968UmhLdN_-!M#({rqBLazpuqO;-+zEUcxDk{A;tF4bSyO zzji78e#&6Svl8J@#l_0)v48YuaqS6sR9U=N{no5R_KDup@`|2%Y&hHeQsIro z6JO2t7ak3m7g>yk5=jsefnx zrfJfr7T;+-9&b8v%7$G}X9&r~^>f{Q;Snw5$jWnhzOCR^(b=JHPJzj%&NS~jCll4n zve4j_gYn(#-b%~1i6(Q-itV{@{HlR(Z|_3~lVx@@xu=OYJ3QDda)kHUL67>U*%3)W zUy4i`wXX7>I&sfSDeaqgr}UMpI!P1G_-p4s9FpZCO<*tnBWB`LxYWtUEtt)<&lERj1NruXg*gE_MF%bWZe7i}h=sL>-(y^XPIH6A}Ga@4}v+ zNG;#4CVnTVoTVtBv}s@Tdl`whjO{}1783%l@}JJH%n~@?lQcxBaoYdduo3EV-(`aL3)$B9kP`CoZjVsPIV?OxA@oZlW3ubNyqX*xfO z{r#=W{IN=&U&`x7b-a`ofY8oWZH z#xm!moO;HWYm2;9xH&HAJm0YS8r$k9!O&fGS^2+zNA7->y^nPCZ{|<_<()3l>{EAp RGB7YOc)I$ztaD0e0sw=8iI@NY literal 0 HcmV?d00001 diff --git a/deploy/root/images/header-background.png b/deploy/root/images/header-background.png new file mode 100644 index 0000000000000000000000000000000000000000..93e4a49c3795da40ddee63af280a4a0fadffbb45 GIT binary patch literal 20847 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 Q0|Nttr>mdKI;Vst0K + + + + + Atmosphere Scala REST Chat + + + + + + + + +

+
+ +
+
+
+
+
Please input your name:
+
+ +
+ +
+ +
+
+
+
+ + + diff --git a/deploy/root/javascripts/application.js b/deploy/root/javascripts/application.js new file mode 100644 index 0000000000..f8361babea --- /dev/null +++ b/deploy/root/javascripts/application.js @@ -0,0 +1,90 @@ +var count = 0; +var app = { + url: '/chat', + initialize: function() { + $('login-name').focus(); + app.listen(); + }, + listen: function() { + $('comet-frame').src = app.url + '?' + count; + count ++; + }, + login: function() { + var name = $F('login-name'); + if(! name.length > 0) { + $('system-message').style.color = 'red'; + $('login-name').focus(); + return; + } + $('system-message').style.color = '#2d2b3d'; + $('system-message').innerHTML = name + ':'; + + $('login-button').disabled = true; + $('login-form').style.display = 'none'; + $('message-form').style.display = ''; + + var query = + 'action=login' + + '&name=' + encodeURI($F('login-name')); + new Ajax.Request(app.url, { + postBody: query, + onSuccess: function() { + $('message').focus(); + } + }); + }, + post: function() { + var message = $F('message'); + if(!message > 0) { + return; + } + $('message').disabled = true; + $('post-button').disabled = true; + + var query = + 'action=post' + + '&name=' + encodeURI($F('login-name')) + + '&message=' + encodeURI(message); + new Ajax.Request(app.url, { + postBody: query, + onComplete: function() { + $('message').disabled = false; + $('post-button').disabled = false; + $('message').focus(); + $('message').value = ''; + } + }); + }, + update: function(data) { + var p = document.createElement('p'); + p.innerHTML = data.name + ':
' + data.message; + + $('display').appendChild(p); + + new Fx.Scroll('display').down(); + } +}; +var rules = { + '#login-name': function(elem) { + Event.observe(elem, 'keydown', function(e) { + if(e.keyCode == 13) { + $('login-button').focus(); + } + }); + }, + '#login-button': function(elem) { + elem.onclick = app.login; + }, + '#message': function(elem) { + Event.observe(elem, 'keydown', function(e) { + if(e.shiftKey && e.keyCode == 13) { + $('post-button').focus(); + } + }); + }, + '#post-button': function(elem) { + elem.onclick = app.post; + } +}; +Behaviour.addLoadEvent(app.initialize); +Behaviour.register(rules); diff --git a/deploy/root/javascripts/behaviour.js b/deploy/root/javascripts/behaviour.js new file mode 100644 index 0000000000..fdde861bba --- /dev/null +++ b/deploy/root/javascripts/behaviour.js @@ -0,0 +1,254 @@ +/* + Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work + of Simon Willison (see comments by Simon below). + + Description: + + Uses css selectors to apply javascript behaviours to enable + unobtrusive javascript in html documents. + + Usage: + + var myrules = { + 'b.someclass' : function(element){ + element.onclick = function(){ + alert(this.innerHTML); + } + }, + '#someid u' : function(element){ + element.onmouseover = function(){ + this.innerHTML = "BLAH!"; + } + } + }; + + Behaviour.register(myrules); + + // Call Behaviour.apply() to re-apply the rules (if you + // update the dom, etc). + + License: + + This file is entirely BSD licensed. + + More information: + + http://ripcord.co.nz/behaviour/ + +*/ + +var Behaviour = { + list : new Array, + + register : function(sheet){ + Behaviour.list.push(sheet); + }, + + start : function(){ + Behaviour.addLoadEvent(function(){ + Behaviour.apply(); + }); + }, + + apply : function(){ + for (h=0;sheet=Behaviour.list[h];h++){ + for (selector in sheet){ + list = document.getElementsBySelector(selector); + + if (!list){ + continue; + } + + for (i=0;element=list[i];i++){ + sheet[selector](element); + } + } + } + }, + + addLoadEvent : function(func){ + var oldonload = window.onload; + + if (typeof window.onload != 'function') { + window.onload = func; + } else { + window.onload = function() { + oldonload(); + func(); + } + } + } +} + +Behaviour.start(); + +/* + The following code is Copyright (C) Simon Willison 2004. + + document.getElementsBySelector(selector) + - returns an array of element objects from the current document + matching the CSS selector. Selectors can contain element names, + class names and ids and can be nested. For example: + + elements = document.getElementsBySelect('div#main p a.external') + + Will return an array of all 'a' elements with 'external' in their + class attribute that are contained inside 'p' elements that are + contained inside the 'div' element which has id="main" + + New in version 0.4: Support for CSS2 and CSS3 attribute selectors: + See http://www.w3.org/TR/css3-selectors/#attribute-selectors + + Version 0.4 - Simon Willison, March 25th 2003 + -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows + -- Opera 7 fails +*/ + +function getAllChildren(e) { + // Returns all children of element. Workaround required for IE5/Windows. Ugh. + return e.all ? e.all : e.getElementsByTagName('*'); +} + +document.getElementsBySelector = function(selector) { + // Attempt to fail gracefully in lesser browsers + if (!document.getElementsByTagName) { + return new Array(); + } + // Split selector in to tokens + var tokens = selector.split(' '); + var currentContext = new Array(document); + for (var i = 0; i < tokens.length; i++) { + token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');; + if (token.indexOf('#') > -1) { + // Token is an ID selector + var bits = token.split('#'); + var tagName = bits[0]; + var id = bits[1]; + var element = document.getElementById(id); + if (tagName && element.nodeName.toLowerCase() != tagName) { + // tag with that ID not found, return false + return new Array(); + } + // Set currentContext to contain just this element + currentContext = new Array(element); + continue; // Skip to next token + } + if (token.indexOf('.') > -1) { + // Token contains a class selector + var bits = token.split('.'); + var tagName = bits[0]; + var className = bits[1]; + if (!tagName) { + tagName = '*'; + } + // Get elements matching tag, filter them for class selector + var found = new Array; + var foundCount = 0; + for (var h = 0; h < currentContext.length; h++) { + var elements; + if (tagName == '*') { + elements = getAllChildren(currentContext[h]); + } else { + elements = currentContext[h].getElementsByTagName(tagName); + } + for (var j = 0; j < elements.length; j++) { + found[foundCount++] = elements[j]; + } + } + currentContext = new Array; + var currentContextIndex = 0; + for (var k = 0; k < found.length; k++) { + if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) { + currentContext[currentContextIndex++] = found[k]; + } + } + continue; // Skip to next token + } + // Code to deal with attribute selectors + if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) { + var tagName = RegExp.$1; + var attrName = RegExp.$2; + var attrOperator = RegExp.$3; + var attrValue = RegExp.$4; + if (!tagName) { + tagName = '*'; + } + // Grab all of the tagName elements within current context + var found = new Array; + var foundCount = 0; + for (var h = 0; h < currentContext.length; h++) { + var elements; + if (tagName == '*') { + elements = getAllChildren(currentContext[h]); + } else { + elements = currentContext[h].getElementsByTagName(tagName); + } + for (var j = 0; j < elements.length; j++) { + found[foundCount++] = elements[j]; + } + } + currentContext = new Array; + var currentContextIndex = 0; + var checkFunction; // This function will be used to filter the elements + switch (attrOperator) { + case '=': // Equality + checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); }; + break; + case '~': // Match one of space seperated words + checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); }; + break; + case '|': // Match start with value followed by optional hyphen + checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); }; + break; + case '^': // Match starts with value + checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); }; + break; + case '$': // Match ends with value - fails with "Warning" in Opera 7 + checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); }; + break; + case '*': // Match ends with value + checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); }; + break; + default : + // Just test for existence of attribute + checkFunction = function(e) { return e.getAttribute(attrName); }; + } + currentContext = new Array; + var currentContextIndex = 0; + for (var k = 0; k < found.length; k++) { + if (checkFunction(found[k])) { + currentContext[currentContextIndex++] = found[k]; + } + } + // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue); + continue; // Skip to next token + } + + if (!currentContext[0]){ + return; + } + + // If we get here, token is JUST an element (not a class or ID selector) + tagName = token; + var found = new Array; + var foundCount = 0; + for (var h = 0; h < currentContext.length; h++) { + var elements = currentContext[h].getElementsByTagName(tagName); + for (var j = 0; j < elements.length; j++) { + found[foundCount++] = elements[j]; + } + } + currentContext = found; + } + return currentContext; +} + +/* That revolting regular expression explained +/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/ + \---/ \---/\-------------/ \-------/ + | | | | + | | | The value + | | ~,|,^,$,* or = + | Attribute + Tag +*/ diff --git a/deploy/root/javascripts/moo.fx.js b/deploy/root/javascripts/moo.fx.js new file mode 100644 index 0000000000..95c01f819a --- /dev/null +++ b/deploy/root/javascripts/moo.fx.js @@ -0,0 +1,136 @@ +//(c) 2006 Valerio Proietti (http://mad4milk.net). MIT-style license. +//moo.fx.js - depends on prototype.js OR prototype.lite.js +//version 2.0 + +var Fx = fx = {}; + +Fx.Base = function(){}; +Fx.Base.prototype = { + + setOptions: function(options){ + this.options = Object.extend({ + onStart: function(){}, + onComplete: function(){}, + transition: Fx.Transitions.sineInOut, + duration: 500, + unit: 'px', + wait: true, + fps: 50 + }, options || {}); + }, + + step: function(){ + var time = new Date().getTime(); + if (time < this.time + this.options.duration){ + this.cTime = time - this.time; + this.setNow(); + } else { + setTimeout(this.options.onComplete.bind(this, this.element), 10); + this.clearTimer(); + this.now = this.to; + } + this.increase(); + }, + + setNow: function(){ + this.now = this.compute(this.from, this.to); + }, + + compute: function(from, to){ + var change = to - from; + return this.options.transition(this.cTime, from, change, this.options.duration); + }, + + clearTimer: function(){ + clearInterval(this.timer); + this.timer = null; + return this; + }, + + _start: function(from, to){ + if (!this.options.wait) this.clearTimer(); + if (this.timer) return; + setTimeout(this.options.onStart.bind(this, this.element), 10); + this.from = from; + this.to = to; + this.time = new Date().getTime(); + this.timer = setInterval(this.step.bind(this), Math.round(1000/this.options.fps)); + return this; + }, + + custom: function(from, to){ + return this._start(from, to); + }, + + set: function(to){ + this.now = to; + this.increase(); + return this; + }, + + hide: function(){ + return this.set(0); + }, + + setStyle: function(e, p, v){ + if (p == 'opacity'){ + if (v == 0 && e.style.visibility != "hidden") e.style.visibility = "hidden"; + else if (e.style.visibility != "visible") e.style.visibility = "visible"; + if (window.ActiveXObject) e.style.filter = "alpha(opacity=" + v*100 + ")"; + e.style.opacity = v; + } else e.style[p] = v+this.options.unit; + } + +}; + +Fx.Style = Class.create(); +Fx.Style.prototype = Object.extend(new Fx.Base(), { + + initialize: function(el, property, options){ + this.element = $(el); + this.setOptions(options); + this.property = property.camelize(); + }, + + increase: function(){ + this.setStyle(this.element, this.property, this.now); + } + +}); + +Fx.Styles = Class.create(); +Fx.Styles.prototype = Object.extend(new Fx.Base(), { + + initialize: function(el, options){ + this.element = $(el); + this.setOptions(options); + this.now = {}; + }, + + setNow: function(){ + for (p in this.from) this.now[p] = this.compute(this.from[p], this.to[p]); + }, + + custom: function(obj){ + if (this.timer && this.options.wait) return; + var from = {}; + var to = {}; + for (p in obj){ + from[p] = obj[p][0]; + to[p] = obj[p][1]; + } + return this._start(from, to); + }, + + increase: function(){ + for (var p in this.now) this.setStyle(this.element, p, this.now[p]); + } + +}); + +//Transitions (c) 2003 Robert Penner (http://www.robertpenner.com/easing/), BSD License. + +Fx.Transitions = { + linear: function(t, b, c, d) { return c*t/d + b; }, + sineInOut: function(t, b, c, d) { return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; } +}; \ No newline at end of file diff --git a/deploy/root/javascripts/moo.fx.pack.js b/deploy/root/javascripts/moo.fx.pack.js new file mode 100644 index 0000000000..a06656fb44 --- /dev/null +++ b/deploy/root/javascripts/moo.fx.pack.js @@ -0,0 +1,83 @@ +//by Valerio Proietti (http://mad4milk.net). MIT-style license. +//moo.fx.pack.js - depends on prototype.js or prototype.lite.js + moo.fx.js +//version 2.0 + +Fx.Scroll = Class.create(); +Fx.Scroll.prototype = Object.extend(new Fx.Base(), { + + initialize: function(el, options) { + this.element = $(el); + this.setOptions(options); + this.element.style.overflow = 'hidden'; + }, + + down: function(){ + return this.custom(this.element.scrollTop, this.element.scrollHeight-this.element.offsetHeight); + }, + + up: function(){ + return this.custom(this.element.scrollTop, 0); + }, + + increase: function(){ + this.element.scrollTop = this.now; + } + +}); + +//fx.Color, originally by Tom Jensen (http://neuemusic.com) MIT-style LICENSE. + +Fx.Color = Class.create(); +Fx.Color.prototype = Object.extend(new Fx.Base(), { + + initialize: function(el, property, options){ + this.element = $(el); + this.setOptions(options); + this.property = property.camelize(); + this.now = []; + }, + + custom: function(from, to){ + return this._start(from.hexToRgb(true), to.hexToRgb(true)); + }, + + setNow: function(){ + [0,1,2].each(function(i){ + this.now[i] = Math.round(this.compute(this.from[i], this.to[i])); + }.bind(this)); + }, + + increase: function(){ + this.element.style[this.property] = "rgb("+this.now[0]+","+this.now[1]+","+this.now[2]+")"; + } + +}); + +Object.extend(String.prototype, { + + rgbToHex: function(array){ + var rgb = this.match(new RegExp('([\\d]{1,3})', 'g')); + if (rgb[3] == 0) return 'transparent'; + var hex = []; + for (var i = 0; i < 3; i++){ + var bit = (rgb[i]-0).toString(16); + hex.push(bit.length == 1 ? '0'+bit : bit); + } + var hexText = '#'+hex.join(''); + if (array) return hex; + else return hexText; + }, + + hexToRgb: function(array){ + var hex = this.match(new RegExp('^[#]{0,1}([\\w]{1,2})([\\w]{1,2})([\\w]{1,2})$')); + var rgb = []; + for (var i = 1; i < hex.length; i++){ + if (hex[i].length == 1) hex[i] += hex[i]; + rgb.push(parseInt(hex[i], 16)); + } + var rgbText = 'rgb('+rgb.join(',')+')'; + if (array) return rgb; + else return rgbText; + } + +}); \ No newline at end of file diff --git a/deploy/root/javascripts/prototype.js b/deploy/root/javascripts/prototype.js new file mode 100644 index 0000000000..0e85338bab --- /dev/null +++ b/deploy/root/javascripts/prototype.js @@ -0,0 +1,1781 @@ +/* Prototype JavaScript framework, version 1.4.0 + * (c) 2005 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://prototype.conio.net/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.4.0', + ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', + + emptyFunction: function() {}, + K: function(x) {return x} +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.inspect = function(object) { + try { + if (object == undefined) return 'undefined'; + if (object == null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } +} + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this; + return function(event) { + return __method.call(object, event || window.event); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); + +var Try = { + these: function() { + var returnValue; + + for (var i = 0; i < arguments.length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(); + } finally { + this.currentlyExecuting = false; + } + } + } +} + +/*--------------------------------------------------------------------------*/ + +function $() { + var elements = new Array(); + + for (var i = 0; i < arguments.length; i++) { + var element = arguments[i]; + if (typeof element == 'string') + element = document.getElementById(element); + + if (arguments.length == 1) + return element; + + elements.push(element); + } + + return elements; +} +Object.extend(String.prototype, { + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(eval); + }, + + escapeHTML: function() { + var div = document.createElement('div'); + var text = document.createTextNode(this); + div.appendChild(text); + return div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; + }, + + toQueryParams: function() { + var pairs = this.match(/^\??(.*)$/)[1].split('&'); + return pairs.inject({}, function(params, pairString) { + var pair = pairString.split('='); + params[pair[0]] = pair[1]; + return params; + }); + }, + + toArray: function() { + return this.split(''); + }, + + camelize: function() { + var oStringList = this.split('-'); + if (oStringList.length == 1) return oStringList[0]; + + var camelizedString = this.indexOf('-') == 0 + ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) + : oStringList[0]; + + for (var i = 1, len = oStringList.length; i < len; i++) { + var s = oStringList[i]; + camelizedString += s.charAt(0).toUpperCase() + s.substring(1); + } + + return camelizedString; + }, + + inspect: function() { + return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'"; + } +}); + +String.prototype.parseQuery = String.prototype.toQueryParams; + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = true; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function (iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.collect(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (value >= (result || value)) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (value <= (result || value)) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.collect(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.collect(Prototype.K); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + iterator(value = collections.pluck(index)); + return value; + }); + }, + + inspect: function() { + return '#'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray +}); +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0; i < iterable.length; i++) + results.push(iterable[i]); + return results; + } +} + +Object.extend(Array.prototype, Enumerable); + +Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0; i < this.length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != undefined || value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0; i < this.length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + shift: function() { + var result = this[0]; + for (var i = 0; i < this.length - 1; i++) + this[i] = this[i + 1]; + this.length--; + return result; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); +var Hash = { + _each: function(iterator) { + for (key in this) { + var value = this[key]; + if (typeof value == 'function') continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject($H(this), function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + return pair.map(encodeURIComponent).join('='); + }).join('&'); + }, + + inspect: function() { + return '#'; + } +} + +function $H(object) { + var hash = Object.extend({}, object || {}); + Object.extend(hash, Enumerable); + Object.extend(hash, Hash); + return hash; +} +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + do { + iterator(value); + value = value.succ(); + } while (this.include(value)); + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')}, + function() {return new XMLHttpRequest()} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responderToAdd) { + if (!this.include(responderToAdd)) + this.responders.push(responderToAdd); + }, + + unregister: function(responderToRemove) { + this.responders = this.responders.without(responderToRemove); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (responder[callback] && typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + parameters: '' + } + Object.extend(this.options, options || {}); + }, + + responseIsSuccess: function() { + return this.transport.status == undefined + || this.transport.status == 0 + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + responseIsFailure: function() { + return !this.responseIsSuccess(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + var parameters = this.options.parameters || ''; + if (parameters.length > 0) parameters += '&_='; + + try { + this.url = url; + if (this.options.method == 'get' && parameters.length > 0) + this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; + + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.options.method, this.url, + this.options.asynchronous); + + if (this.options.asynchronous) { + this.transport.onreadystatechange = this.onStateChange.bind(this); + setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); + } + + this.setRequestHeaders(); + + var body = this.options.postBody ? this.options.postBody : parameters; + this.transport.send(this.options.method == 'post' ? body : null); + + } catch (e) { + this.dispatchException(e); + } + }, + + setRequestHeaders: function() { + var requestHeaders = + ['X-Requested-With', 'XMLHttpRequest', + 'X-Prototype-Version', Prototype.Version]; + + if (this.options.method == 'post') { + requestHeaders.push('Content-type', + 'application/x-www-form-urlencoded'); + + /* Force "Connection: close" for Mozilla browsers to work around + * a bug where XMLHttpReqeuest sends an incorrect Content-length + * header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType) + requestHeaders.push('Connection', 'close'); + } + + if (this.options.requestHeaders) + requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); + + for (var i = 0; i < requestHeaders.length; i += 2) + this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState != 1) + this.respondToReadyState(this.transport.readyState); + }, + + header: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) {} + }, + + evalJSON: function() { + try { + return eval(this.header('X-JSON')); + } catch (e) {} + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + respondToReadyState: function(readyState) { + var event = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (event == 'Complete') { + try { + (this.options['on' + this.transport.status] + || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + if ((this.header('Content-type') || '').match(/^text\/javascript/i)) + this.evalResponse(); + } + + try { + (this.options['on' + event] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + event, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ + if (event == 'Complete') + this.transport.onreadystatechange = Prototype.emptyFunction; + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.containers = { + success: container.success ? $(container.success) : $(container), + failure: container.failure ? $(container.failure) : + (container.success ? null : $(container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, object) { + this.updateContent(); + onComplete(transport, object); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.responseIsSuccess() ? + this.containers.success : this.containers.failure; + var response = this.transport.responseText; + + if (!this.options.evalScripts) + response = response.stripScripts(); + + if (receiver) { + if (this.options.insertion) { + new this.options.insertion(receiver, response); + } else { + Element.update(receiver, response); + } + } + + if (this.responseIsSuccess()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + return $A(children).inject([], function(elements, child) { + if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + elements.push(child); + return elements; + }); +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) { + var Element = new Object(); +} + +Object.extend(Element, { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + Element[Element.visible(element) ? 'hide' : 'show'](element); + } + }, + + hide: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = 'none'; + } + }, + + show: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = ''; + } + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + }, + + update: function(element, html) { + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + }, + + getHeight: function(element) { + element = $(element); + return element.offsetHeight; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).include(className); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).add(className); + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).remove(className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + for (var i = 0; i < element.childNodes.length; i++) { + var node = element.childNodes[i]; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + Element.remove(node); + } + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + scrollTo: function(element) { + element = $(element); + var x = element.x ? element.x : element.offsetLeft, + y = element.y ? element.y : element.offsetTop; + window.scrollTo(x, y); + }, + + getStyle: function(element, style) { + element = $(element); + var value = element.style[style.camelize()]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css.getPropertyValue(style) : null; + } else if (element.currentStyle) { + value = element.currentStyle[style.camelize()]; + } + } + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (name in style) + element.style[name.camelize()] = style[name]; + }, + + getDimensions: function(element) { + element = $(element); + if (Element.getStyle(element, 'display') != 'none') + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = ''; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = 'none'; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return; + element._overflow = element.style.overflow; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + }, + + undoClipping: function(element) { + element = $(element); + if (element._overflow) return; + element.style.overflow = element._overflow; + element._overflow = undefined; + } +}); + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content.stripScripts(); + + if (this.adjacency && this.element.insertAdjacentHTML) { + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + if (this.element.tagName.toLowerCase() == 'tbody') { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.insertContent([this.range.createContextualFragment(this.content)]); + } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '' + this.content + '
'; + return $A(div.childNodes[0].childNodes[0].childNodes); + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); + } +}); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set(this.toArray().concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set(this.select(function(className) { + return className != classNameToRemove; + }).join(' ')); + }, + + toString: function() { + return this.toArray().join(' '); + } +} + +Object.extend(Element.ClassNames.prototype, Enumerable); +var Field = { + clear: function() { + for (var i = 0; i < arguments.length; i++) + $(arguments[i]).value = ''; + }, + + focus: function(element) { + $(element).focus(); + }, + + present: function() { + for (var i = 0; i < arguments.length; i++) + if ($(arguments[i]).value == '') return false; + return true; + }, + + select: function(element) { + $(element).select(); + }, + + activate: function(element) { + element = $(element); + element.focus(); + if (element.select) + element.select(); + } +} + +/*--------------------------------------------------------------------------*/ + +var Form = { + serialize: function(form) { + var elements = Form.getElements($(form)); + var queryComponents = new Array(); + + for (var i = 0; i < elements.length; i++) { + var queryComponent = Form.Element.serialize(elements[i]); + if (queryComponent) + queryComponents.push(queryComponent); + } + + return queryComponents.join('&'); + }, + + getElements: function(form) { + form = $(form); + var elements = new Array(); + + for (tagName in Form.Element.Serializers) { + var tagElements = form.getElementsByTagName(tagName); + for (var j = 0; j < tagElements.length; j++) + elements.push(tagElements[j]); + } + return elements; + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) + return inputs; + + var matchingInputs = new Array(); + for (var i = 0; i < inputs.length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || + (name && input.name != name)) + continue; + matchingInputs.push(input); + } + + return matchingInputs; + }, + + disable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.blur(); + element.disabled = 'true'; + } + }, + + enable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.disabled = ''; + } + }, + + findFirstElement: function(form) { + return Form.getElements(form).find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + Field.activate(Form.findFirstElement(form)); + }, + + reset: function(form) { + $(form).reset(); + } +} + +Form.Element = { + serialize: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) { + var key = encodeURIComponent(parameter[0]); + if (key.length == 0) return; + + if (parameter[1].constructor != Array) + parameter[1] = [parameter[1]]; + + return parameter[1].map(function(value) { + return key + '=' + encodeURIComponent(value); + }).join('&'); + } + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) + return parameter[1]; + } +} + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'submit': + case 'hidden': + case 'password': + case 'text': + return Form.Element.Serializers.textarea(element); + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + } + return false; + }, + + inputSelector: function(element) { + if (element.checked) + return [element.name, element.value]; + }, + + textarea: function(element) { + return [element.name, element.value]; + }, + + select: function(element) { + return Form.Element.Serializers[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var value = '', opt, index = element.selectedIndex; + if (index >= 0) { + opt = element.options[index]; + value = opt.value; + if (!value && !('value' in opt)) + value = opt.text; + } + return [element.name, value]; + }, + + selectMany: function(element) { + var value = new Array(); + for (var i = 0; i < element.length; i++) { + var opt = element.options[i]; + if (opt.selected) { + var optValue = opt.value; + if (!optValue && !('value' in opt)) + optValue = opt.text; + value.push(optValue); + } + } + return [element.name, value]; + } +} + +/*--------------------------------------------------------------------------*/ + +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + var elements = Form.getElements(this.element); + for (var i = 0; i < elements.length; i++) + this.registerCallback(elements[i]); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + case 'password': + case 'text': + case 'textarea': + case 'select-one': + case 'select-multiple': + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + + element: function(event) { + return event.target || event.srcElement; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0; i < Event.observers.length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) + name = 'keydown'; + + this._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.detachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + element.detachEvent('on' + name, observer); + } + } +}); + +/* prevent memory leaks in IE */ +Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + clone: function(source, target) { + source = $(source); + target = $(target); + target.style.position = 'absolute'; + var offsets = this.cumulativeOffset(source); + target.style.top = offsets[1] + 'px'; + target.style.left = offsets[0] + 'px'; + target.style.width = source.offsetWidth + 'px'; + target.style.height = source.offsetHeight + 'px'; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px';; + element.style.left = left + 'px';; + element.style.width = width + 'px';; + element.style.height = height + 'px';; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} \ No newline at end of file diff --git a/deploy/root/stylesheets/default.css b/deploy/root/stylesheets/default.css new file mode 100644 index 0000000000..716fc7ab59 --- /dev/null +++ b/deploy/root/stylesheets/default.css @@ -0,0 +1,54 @@ +body { + background-image: url(../images/body-background.png); + background-repeat: repeat-x; + background-color: #5c8098; +} +html, body, h1, h2 { + margin: 0px; + padding: 0px; +} +body, textarea, input { + font-size: 12px; + font-family: Verdana, Helvetica, Arial, sans-serif; + color: #2d2b3d; +} +#container { + text-align:center; +} +#container-inner { + margin-left: auto; + margin-right: auto; + text-align: justify; + width: 820px; +} +#header { + width: 820px; + height: 100px; + background-image: url(../images/header-background.png); + background-repeat: no-repeat; +} +#header h1 { + display: none; +} +#main { + height: 610px; + background-image: url(../images/main-background.png); + background-repeat: no-repeat; + text-align: left; + width: 740px; + padding: 30px 40px 20px 40px; +} +#display { + border: 1px solid #5c8098; + width: 740px; + height: 400px; + margin-bottom: 10px; + overflow-y: scroll; +} +#login-name { + width: 200px; +} +#message { + width: 740px; + height: 50px; +} From 9df03500658b08812c74253df403cdbfd37a44c1 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Wed, 14 Oct 2009 10:41:53 +0200 Subject: [PATCH 09/12] Changed to only exclude jars --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5b3ae3f4ba..daf0f3aa93 100755 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ reports dist build target -deploy +deploy/*.jar data out logs From bcbfa84e8d278f5f67085f3f06b6e4ef9e97a656 Mon Sep 17 00:00:00 2001 From: jboner Date: Wed, 14 Oct 2009 12:59:05 +0200 Subject: [PATCH 10/12] fixed bug with using ThreadBasedDispatcher + added tests for dispatchers --- .../src/main/scala/actor/ActiveObject.scala | 32 ++++---- akka-actors/src/main/scala/actor/Actor.scala | 46 +++++------ .../src/main/scala/reactor/Dispatchers.scala | 2 +- .../scala/reactor/ThreadBasedDispatcher.scala | 6 +- .../main/scala/stm/TransactionalState.scala | 2 +- akka-actors/src/test/scala/AllTest.scala | 6 +- .../EventBasedSingleThreadActorSpec.scala | 69 +++++++++++++++++ ...EventBasedSingleThreadDispatcherTest.scala | 4 +- ...la => EventBasedThreadPoolActorSpec.scala} | 6 +- .../EventBasedThreadPoolDispatcherTest.scala | 4 +- akka-actors/src/test/scala/Messages.scala | 2 +- .../src/test/scala/ThreadBasedActorSpec.scala | 69 +++++++++++++++++ .../scala/ThreadBasedDispatcherTest.scala | 2 +- .../akka/api/PersistentStateful.java | 8 +- .../akka/api/PersistentStatefulNested.java | 8 +- .../src/main/scala/PersistentState.scala | 51 ++++++------ .../sample/java/PersistentSimpleService.java | 7 +- .../src/main/scala/akka/SimpleService.scala | 1 + .../src/main/scala/SimpleService.scala | 1 + .../src/main/scala/SimpleService.scala | 1 + config/akka.conf | 77 +++++++++++++++++-- 21 files changed, 303 insertions(+), 101 deletions(-) create mode 100644 akka-actors/src/test/scala/EventBasedSingleThreadActorSpec.scala rename akka-actors/src/test/scala/{ActorSpec.scala => EventBasedThreadPoolActorSpec.scala} (93%) create mode 100644 akka-actors/src/test/scala/ThreadBasedActorSpec.scala diff --git a/akka-actors/src/main/scala/actor/ActiveObject.scala b/akka-actors/src/main/scala/actor/ActiveObject.scala index 7f2d2f8fa3..abefe853ce 100644 --- a/akka-actors/src/main/scala/actor/ActiveObject.scala +++ b/akka-actors/src/main/scala/actor/ActiveObject.scala @@ -67,49 +67,49 @@ class ActiveObjectFactory { def newInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher): T = { val actor = new Dispatcher(None) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher ActiveObject.newInstance(target, actor, None, timeout) } def newInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = { val actor = new Dispatcher(restartCallbacks) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher ActiveObject.newInstance(target, actor, None, timeout) } def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher): T = { val actor = new Dispatcher(None) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher ActiveObject.newInstance(intf, target, actor, None, timeout) } def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = { val actor = new Dispatcher(restartCallbacks) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher ActiveObject.newInstance(intf, target, actor, None, timeout) } def newRemoteInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int): T = { val actor = new Dispatcher(None) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher ActiveObject.newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout) } def newRemoteInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = { val actor = new Dispatcher(restartCallbacks) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher ActiveObject.newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout) } def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int): T = { val actor = new Dispatcher(None) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher ActiveObject.newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout) } def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = { val actor = new Dispatcher(restartCallbacks) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher ActiveObject.newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout) } @@ -173,49 +173,49 @@ object ActiveObject { def newInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher): T = { val actor = new Dispatcher(None) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher newInstance(target, actor, None, timeout) } def newInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = { val actor = new Dispatcher(restartCallbacks) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher newInstance(target, actor, None, timeout) } def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher): T = { val actor = new Dispatcher(None) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher newInstance(intf, target, actor, None, timeout) } def newInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher, restartCallbacks: Option[RestartCallbacks]): T = { val actor = new Dispatcher(restartCallbacks) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher newInstance(intf, target, actor, None, timeout) } def newRemoteInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int): T = { val actor = new Dispatcher(None) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout) } def newRemoteInstance[T](target: Class[T], timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = { val actor = new Dispatcher(restartCallbacks) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher newInstance(target, actor, Some(new InetSocketAddress(hostname, port)), timeout) } def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int): T = { val actor = new Dispatcher(None) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout) } def newRemoteInstance[T](intf: Class[T], target: AnyRef, timeout: Long, dispatcher: MessageDispatcher, hostname: String, port: Int, restartCallbacks: Option[RestartCallbacks]): T = { val actor = new Dispatcher(restartCallbacks) - actor.dispatcher = dispatcher + actor.messageDispatcher = dispatcher newInstance(intf, target, actor, Some(new InetSocketAddress(hostname, port)), timeout) } diff --git a/akka-actors/src/main/scala/actor/Actor.scala b/akka-actors/src/main/scala/actor/Actor.scala index d18092dd83..bd5276bc01 100644 --- a/akka-actors/src/main/scala/actor/Actor.scala +++ b/akka-actors/src/main/scala/actor/Actor.scala @@ -7,15 +7,16 @@ package se.scalablesolutions.akka.actor import com.google.protobuf.ByteString import java.net.InetSocketAddress import java.util.concurrent.CopyOnWriteArraySet - -import reactor._ -import config.ScalaConfig._ -import stm.TransactionManagement -import util.Helpers.ReadWriteLock -import nio.protobuf.RemoteProtocol.RemoteRequest -import util.Logging -import serialization.{Serializer, Serializable, SerializationProtocol} -import nio.{RemoteProtocolBuilder, RemoteClient, RemoteServer, RemoteRequestIdFactory} + +import se.scalablesolutions.akka.reactor._ +import se.scalablesolutions.akka.config.ScalaConfig._ +import se.scalablesolutions.akka.stm.TransactionManagement +import se.scalablesolutions.akka.util.Helpers.ReadWriteLock +import se.scalablesolutions.akka.util.Logging +import se.scalablesolutions.akka.nio.protobuf.RemoteProtocol.RemoteRequest +import se.scalablesolutions.akka.nio.{RemoteProtocolBuilder, RemoteClient, RemoteRequestIdFactory} +import se.scalablesolutions.akka.serialization.Serializer +import se.scalablesolutions.akka.Config._ sealed abstract class LifecycleMessage case class Init(config: AnyRef) extends LifecycleMessage @@ -42,7 +43,6 @@ class ActorMessageInvoker(val actor: Actor) extends MessageInvoker { * @author Jonas Bonér */ object Actor { - import Config._ val TIMEOUT = config.getInt("akka.actor.timeout", 5000) val SERIALIZE_MESSAGES = config.getBool("akka.actor.serialize-messages", false) } @@ -100,7 +100,7 @@ trait Actor extends Logging with TransactionManagement { * .buildThreadPool * */ - protected[akka] var dispatcher: MessageDispatcher = { + protected[akka] var messageDispatcher: MessageDispatcher = { val dispatcher = Dispatchers.newEventBasedThreadPoolDispatcher(getClass.getName) mailbox = dispatcher.messageQueue dispatcher.registerHandler(this, new ActorMessageInvoker(this)) @@ -198,7 +198,7 @@ trait Actor extends Logging with TransactionManagement { */ def start = synchronized { if (!isRunning) { - dispatcher.start + messageDispatcher.start isRunning = true } } @@ -208,7 +208,7 @@ trait Actor extends Logging with TransactionManagement { */ def stop = synchronized { if (isRunning) { - dispatcher.unregisterHandler(this) + messageDispatcher.unregisterHandler(this) isRunning = false shutdown } else throw new IllegalStateException("Actor has not been started, you need to invoke 'actor.start' before using it") @@ -265,14 +265,16 @@ trait Actor extends Logging with TransactionManagement { case Some(future) => future.completeWithResult(message) } + def dispatcher = messageDispatcher + /** * Sets the dispatcher for this actor. Needs to be invoked before the actor is started. */ - def setDispatcher(disp: MessageDispatcher) = synchronized { + def dispatcher_=(dispatcher: MessageDispatcher): Unit = synchronized { if (!isRunning) { - dispatcher = disp - mailbox = dispatcher.messageQueue - dispatcher.registerHandler(this, new ActorMessageInvoker(this)) + messageDispatcher = dispatcher + mailbox = messageDispatcher.messageQueue + messageDispatcher.registerHandler(this, new ActorMessageInvoker(this)) } else throw new IllegalArgumentException("Can not swap dispatcher for " + toString + " after it has been started") } @@ -361,7 +363,7 @@ trait Actor extends Logging with TransactionManagement { */ protected[this] def spawn[T <: Actor](actorClass: Class[T]): T = { val actor = actorClass.newInstance.asInstanceOf[T] - actor.dispatcher = dispatcher + actor.messageDispatcher = messageDispatcher actor.mailbox = mailbox actor.start actor @@ -375,7 +377,7 @@ trait Actor extends Logging with TransactionManagement { protected[this] def spawnRemote[T <: Actor](actorClass: Class[T], hostname: String, port: Int): T = { val actor = actorClass.newInstance.asInstanceOf[T] actor.makeRemote(hostname, port) - actor.dispatcher = dispatcher + actor.messageDispatcher = messageDispatcher actor.mailbox = mailbox actor.start actor @@ -587,9 +589,9 @@ trait Actor extends Logging with TransactionManagement { private[akka] def swapDispatcher(disp: MessageDispatcher) = synchronized { - dispatcher = disp - mailbox = dispatcher.messageQueue - dispatcher.registerHandler(this, new ActorMessageInvoker(this)) + messageDispatcher = disp + mailbox = messageDispatcher.messageQueue + messageDispatcher.registerHandler(this, new ActorMessageInvoker(this)) } private def serializeMessage(message: AnyRef): AnyRef = if (Actor.SERIALIZE_MESSAGES) { diff --git a/akka-actors/src/main/scala/reactor/Dispatchers.scala b/akka-actors/src/main/scala/reactor/Dispatchers.scala index 30846752b6..ad6c94139b 100644 --- a/akka-actors/src/main/scala/reactor/Dispatchers.scala +++ b/akka-actors/src/main/scala/reactor/Dispatchers.scala @@ -4,7 +4,7 @@ package se.scalablesolutions.akka.reactor -import actor.Actor +import se.scalablesolutions.akka.actor.Actor /** * Scala API. Dispatcher factory. diff --git a/akka-actors/src/main/scala/reactor/ThreadBasedDispatcher.scala b/akka-actors/src/main/scala/reactor/ThreadBasedDispatcher.scala index aa04414169..8c70446dba 100644 --- a/akka-actors/src/main/scala/reactor/ThreadBasedDispatcher.scala +++ b/akka-actors/src/main/scala/reactor/ThreadBasedDispatcher.scala @@ -7,7 +7,7 @@ package se.scalablesolutions.akka.reactor import java.util.concurrent.LinkedBlockingQueue import java.util.Queue -import actor.{Actor, ActorMessageInvoker} +import se.scalablesolutions.akka.actor.{Actor, ActorMessageInvoker} /** * Dedicates a unique thread for each actor passed in as reference. Served through its messageQueue. @@ -41,8 +41,8 @@ class ThreadBasedDispatcher private[akka] (val name: String, val messageHandler: selectorThread.interrupt } - def registerHandler(key: AnyRef, handler: MessageInvoker) = throw new UnsupportedOperationException - def unregisterHandler(key: AnyRef) = throw new UnsupportedOperationException + def registerHandler(key: AnyRef, handler: MessageInvoker) = {} + def unregisterHandler(key: AnyRef) = {} } class BlockingMessageQueue(name: String) extends MessageQueue { diff --git a/akka-actors/src/main/scala/stm/TransactionalState.scala b/akka-actors/src/main/scala/stm/TransactionalState.scala index ddc18a61ef..b328684edf 100644 --- a/akka-actors/src/main/scala/stm/TransactionalState.scala +++ b/akka-actors/src/main/scala/stm/TransactionalState.scala @@ -42,7 +42,7 @@ class TransactionalState { @serializable trait Transactional { // FIXME: won't work across the cluster - val uuid = Uuid.newUuid.toString + var uuid = Uuid.newUuid.toString private[akka] def begin private[akka] def commit diff --git a/akka-actors/src/test/scala/AllTest.scala b/akka-actors/src/test/scala/AllTest.scala index 6e782232e7..60f18d7d39 100644 --- a/akka-actors/src/test/scala/AllTest.scala +++ b/akka-actors/src/test/scala/AllTest.scala @@ -4,7 +4,7 @@ import junit.framework.Test import junit.framework.TestCase import junit.framework.TestSuite -import actor.{ActorSpec, RemoteActorSpec, InMemoryActorSpec, SupervisorSpec, RemoteSupervisorSpec,SchedulerSpec} +import actor.{ThreadBasedActorSpec, RemoteActorSpec, InMemoryActorSpec, SupervisorSpec, RemoteSupervisorSpec,SchedulerSpec} import reactor.{EventBasedSingleThreadDispatcherTest, EventBasedThreadPoolDispatcherTest} object AllTest extends TestCase { @@ -14,7 +14,9 @@ object AllTest extends TestCase { suite.addTestSuite(classOf[RemoteSupervisorSpec]) suite.addTestSuite(classOf[EventBasedSingleThreadDispatcherTest]) suite.addTestSuite(classOf[EventBasedThreadPoolDispatcherTest]) - suite.addTestSuite(classOf[ActorSpec]) + suite.addTestSuite(classOf[ThreadBasedActorSpec]) + suite.addTestSuite(classOf[EventBasedSingleThreadDispatcherTest]) + suite.addTestSuite(classOf[EventBasedThreadPoolDispatcherTest]) suite.addTestSuite(classOf[RemoteActorSpec]) suite.addTestSuite(classOf[InMemoryActorSpec]) suite.addTestSuite(classOf[SchedulerSpec]) diff --git a/akka-actors/src/test/scala/EventBasedSingleThreadActorSpec.scala b/akka-actors/src/test/scala/EventBasedSingleThreadActorSpec.scala new file mode 100644 index 0000000000..97da0d6a58 --- /dev/null +++ b/akka-actors/src/test/scala/EventBasedSingleThreadActorSpec.scala @@ -0,0 +1,69 @@ +package se.scalablesolutions.akka.actor + +import java.util.concurrent.TimeUnit + +import junit.framework.Assert._ + +import se.scalablesolutions.akka.reactor.Dispatchers + +class EventBasedSingleThreadActorSpec extends junit.framework.TestCase { + private val unit = TimeUnit.MILLISECONDS + + class TestActor extends Actor { + dispatcher = Dispatchers.newEventBasedSingleThreadDispatcher(name) + + def receive: PartialFunction[Any, Unit] = { + case "Hello" => + reply("World") + case "Failure" => + throw new RuntimeException("expected") + } + } + + def testSendOneWay = { + implicit val timeout = 5000L + var oneWay = "nada" + val actor = new Actor { + def receive: PartialFunction[Any, Unit] = { + case "OneWay" => oneWay = "received" + } + } + actor.start + val result = actor ! "OneWay" + Thread.sleep(100) + assertEquals("received", oneWay) + actor.stop + } + + def testSendReplySync = { + implicit val timeout = 5000L + val actor = new TestActor + actor.start + val result: String = actor !? "Hello" + assertEquals("World", result) + actor.stop + } + + def testSendReplyAsync = { + implicit val timeout = 5000L + val actor = new TestActor + actor.start + val result = actor !! "Hello" + assertEquals("World", result.get.asInstanceOf[String]) + actor.stop + } + + def testSendReceiveException = { + implicit val timeout = 5000L + val actor = new TestActor + actor.start + try { + actor !! "Failure" + fail("Should have thrown an exception") + } catch { + case e => + assertEquals("expected", e.getMessage()) + } + actor.stop + } +} diff --git a/akka-actors/src/test/scala/EventBasedSingleThreadDispatcherTest.scala b/akka-actors/src/test/scala/EventBasedSingleThreadDispatcherTest.scala index 758f9d6cd0..489b20b737 100644 --- a/akka-actors/src/test/scala/EventBasedSingleThreadDispatcherTest.scala +++ b/akka-actors/src/test/scala/EventBasedSingleThreadDispatcherTest.scala @@ -108,8 +108,8 @@ class EventBasedSingleThreadDispatcherTest extends TestCase { }) dispatcher.start for (i <- 0 until 100) { - dispatcher.messageQueue.append(new MessageInvocation(key1, new Integer(i), None, None)) - dispatcher.messageQueue.append(new MessageInvocation(key2, new Integer(i), None, None)) + dispatcher.messageQueue.append(new MessageInvocation(key1, new java.lang.Integer(i), None, None)) + dispatcher.messageQueue.append(new MessageInvocation(key2, new java.lang.Integer(i), None, None)) } assertTrue(handleLatch.await(5, TimeUnit.SECONDS)) assertFalse(threadingIssueDetected.get) diff --git a/akka-actors/src/test/scala/ActorSpec.scala b/akka-actors/src/test/scala/EventBasedThreadPoolActorSpec.scala similarity index 93% rename from akka-actors/src/test/scala/ActorSpec.scala rename to akka-actors/src/test/scala/EventBasedThreadPoolActorSpec.scala index 74ebd13f25..767f30574d 100644 --- a/akka-actors/src/test/scala/ActorSpec.scala +++ b/akka-actors/src/test/scala/EventBasedThreadPoolActorSpec.scala @@ -2,9 +2,9 @@ package se.scalablesolutions.akka.actor import java.util.concurrent.TimeUnit -import org.junit.Assert._ +import junit.framework.Assert._ -class ActorSpec extends junit.framework.TestCase { +class EventBasedThreadPoolActorSpec extends junit.framework.TestCase { private val unit = TimeUnit.MILLISECONDS class TestActor extends Actor { @@ -15,7 +15,7 @@ class ActorSpec extends junit.framework.TestCase { throw new RuntimeException("expected") } } - + def testSendOneWay = { implicit val timeout = 5000L var oneWay = "nada" diff --git a/akka-actors/src/test/scala/EventBasedThreadPoolDispatcherTest.scala b/akka-actors/src/test/scala/EventBasedThreadPoolDispatcherTest.scala index a57ad0b825..9e5db36751 100644 --- a/akka-actors/src/test/scala/EventBasedThreadPoolDispatcherTest.scala +++ b/akka-actors/src/test/scala/EventBasedThreadPoolDispatcherTest.scala @@ -152,8 +152,8 @@ class EventBasedThreadPoolDispatcherTest extends TestCase { }) dispatcher.start for (i <- 0 until 100) { - dispatcher.messageQueue.append(new MessageInvocation(key1, new Integer(i), None, None)) - dispatcher.messageQueue.append(new MessageInvocation(key2, new Integer(i), None, None)) + dispatcher.messageQueue.append(new MessageInvocation(key1, new java.lang.Integer(i), None, None)) + dispatcher.messageQueue.append(new MessageInvocation(key2, new java.lang.Integer(i), None, None)) } assertTrue(handleLatch.await(5, TimeUnit.SECONDS)) assertFalse(threadingIssueDetected.get) diff --git a/akka-actors/src/test/scala/Messages.scala b/akka-actors/src/test/scala/Messages.scala index 7e4d5ca66f..59e884121e 100644 --- a/akka-actors/src/test/scala/Messages.scala +++ b/akka-actors/src/test/scala/Messages.scala @@ -34,7 +34,7 @@ case class User(val usernamePassword: Tuple2[String, String], def toBytes: Array[Byte] = toByteArray(this) } -case class RemotePing extends TestMessage +case object RemotePing extends TestMessage case object RemotePong extends TestMessage case object RemoteOneWay extends TestMessage case object RemoteDie extends TestMessage diff --git a/akka-actors/src/test/scala/ThreadBasedActorSpec.scala b/akka-actors/src/test/scala/ThreadBasedActorSpec.scala new file mode 100644 index 0000000000..412e0cfae5 --- /dev/null +++ b/akka-actors/src/test/scala/ThreadBasedActorSpec.scala @@ -0,0 +1,69 @@ +package se.scalablesolutions.akka.actor + +import java.util.concurrent.TimeUnit + +import junit.framework.Assert._ + +import se.scalablesolutions.akka.reactor.Dispatchers + +class ThreadBasedActorSpec extends junit.framework.TestCase { + private val unit = TimeUnit.MILLISECONDS + + class TestActor extends Actor { + dispatcher = Dispatchers.newThreadBasedDispatcher(this) + + def receive: PartialFunction[Any, Unit] = { + case "Hello" => + reply("World") + case "Failure" => + throw new RuntimeException("expected") + } + } + + def testSendOneWay = { + implicit val timeout = 5000L + var oneWay = "nada" + val actor = new Actor { + def receive: PartialFunction[Any, Unit] = { + case "OneWay" => oneWay = "received" + } + } + actor.start + val result = actor ! "OneWay" + Thread.sleep(100) + assertEquals("received", oneWay) + actor.stop + } + + def testSendReplySync = { + implicit val timeout = 5000L + val actor = new TestActor + actor.start + val result: String = actor !? "Hello" + assertEquals("World", result) + actor.stop + } + + def testSendReplyAsync = { + implicit val timeout = 5000L + val actor = new TestActor + actor.start + val result = actor !! "Hello" + assertEquals("World", result.get.asInstanceOf[String]) + actor.stop + } + + def testSendReceiveException = { + implicit val timeout = 5000L + val actor = new TestActor + actor.start + try { + actor !! "Failure" + fail("Should have thrown an exception") + } catch { + case e => + assertEquals("expected", e.getMessage()) + } + actor.stop + } +} diff --git a/akka-actors/src/test/scala/ThreadBasedDispatcherTest.scala b/akka-actors/src/test/scala/ThreadBasedDispatcherTest.scala index a76d02815d..308191412b 100644 --- a/akka-actors/src/test/scala/ThreadBasedDispatcherTest.scala +++ b/akka-actors/src/test/scala/ThreadBasedDispatcherTest.scala @@ -73,7 +73,7 @@ class ThreadBasedDispatcherTest extends TestCase { }) dispatcher.start for (i <- 0 until 100) { - dispatcher.messageQueue.append(new MessageInvocation("id", new Integer(i), None, None)) + dispatcher.messageQueue.append(new MessageInvocation("id", new java.lang.Integer(i), None, None)) } assertTrue(handleLatch.await(5, TimeUnit.SECONDS)) assertFalse(threadingIssueDetected.get) diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStateful.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStateful.java index 3acf773644..2c166cfcdd 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStateful.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStateful.java @@ -5,11 +5,9 @@ import se.scalablesolutions.akka.state.*; @transactionrequired public class PersistentStateful { - private PersistentState factory = new PersistentState(); - private TransactionalMap mapState = factory.newMap(new CassandraStorageConfig()); - private TransactionalVector vectorState = factory.newVector(new CassandraStorageConfig());; - private TransactionalRef refState = factory.newRef(new CassandraStorageConfig()); - + private PersistentMap mapState = PersistentState.newMap(new CassandraStorageConfig()); + private PersistentVector vectorState = PersistentState.newVector(new CassandraStorageConfig());; + private PersistentRef refState = PersistentState.newRef(new CassandraStorageConfig()); public String getMapState(String key) { return (String) mapState.get(key).get(); diff --git a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStatefulNested.java b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStatefulNested.java index 6f26427118..ced4bc1ac1 100644 --- a/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStatefulNested.java +++ b/akka-fun-test-java/src/test/java/se/scalablesolutions/akka/api/PersistentStatefulNested.java @@ -5,11 +5,9 @@ import se.scalablesolutions.akka.state.*; @transactionrequired public class PersistentStatefulNested { - private PersistentState factory = new PersistentState(); - private TransactionalMap mapState = factory.newMap(new CassandraStorageConfig()); - private TransactionalVector vectorState = factory.newVector(new CassandraStorageConfig());; - private TransactionalRef refState = factory.newRef(new CassandraStorageConfig()); - + private PersistentMap mapState = PersistentState.newMap(new CassandraStorageConfig()); + private PersistentVector vectorState = PersistentState.newVector(new CassandraStorageConfig()); + private PersistentRef refState = PersistentState.newRef(new CassandraStorageConfig()); public String getMapState(String key) { return (String) mapState.get(key).get(); diff --git a/akka-persistence/src/main/scala/PersistentState.scala b/akka-persistence/src/main/scala/PersistentState.scala index 0b8bfb8fd1..c4d45ebd89 100644 --- a/akka-persistence/src/main/scala/PersistentState.scala +++ b/akka-persistence/src/main/scala/PersistentState.scala @@ -13,10 +13,10 @@ import scala.collection.mutable.{ArrayBuffer, HashMap} sealed abstract class PersistentStateConfig abstract class PersistentStorageConfig extends PersistentStateConfig -case class CassandraStorageConfig extends PersistentStorageConfig -case class TerracottaStorageConfig extends PersistentStorageConfig -case class TokyoCabinetStorageConfig extends PersistentStorageConfig -case class MongoStorageConfig extends PersistentStorageConfig +case class CassandraStorageConfig() extends PersistentStorageConfig +case class TerracottaStorageConfig() extends PersistentStorageConfig +case class TokyoCabinetStorageConfig() extends PersistentStorageConfig +case class MongoStorageConfig() extends PersistentStorageConfig /** * Scala API. @@ -25,34 +25,29 @@ case class MongoStorageConfig extends PersistentStorageConfig *
  * val myMap = PersistentState.newMap(CassandraStorageConfig)
  * 
- */ -object PersistentState extends PersistentState - -/** * Java API. *

* Example Java usage: *

- * PersistentState state = new PersistentState();
- * TransactionalMap myMap = state.newMap(new CassandraStorageConfig());
+ * TransactionalMap myMap = PersistentState.newMap(new CassandraStorageConfig());
  * 
*/ -class PersistentState { - def newMap(config: PersistentStorageConfig): TransactionalMap[AnyRef, AnyRef] = config match { +object PersistentState { + def newMap(config: PersistentStorageConfig): PersistentMap = config match { case CassandraStorageConfig() => new CassandraPersistentMap case MongoStorageConfig() => new MongoPersistentMap case TerracottaStorageConfig() => throw new UnsupportedOperationException case TokyoCabinetStorageConfig() => throw new UnsupportedOperationException } - def newVector(config: PersistentStorageConfig): TransactionalVector[AnyRef] = config match { + def newVector(config: PersistentStorageConfig): PersistentVector = config match { case CassandraStorageConfig() => new CassandraPersistentVector case MongoStorageConfig() => new MongoPersistentVector case TerracottaStorageConfig() => throw new UnsupportedOperationException case TokyoCabinetStorageConfig() => throw new UnsupportedOperationException } - def newRef(config: PersistentStorageConfig): TransactionalRef[AnyRef] = config match { + def newRef(config: PersistentStorageConfig): PersistentRef = config match { case CassandraStorageConfig() => new CassandraPersistentRef case MongoStorageConfig() => new MongoPersistentRef case TerracottaStorageConfig() => throw new UnsupportedOperationException @@ -68,10 +63,10 @@ class PersistentState { * * @author Jonas Bonér */ -abstract class PersistentMap[K, V] extends TransactionalMap[K, V] { +abstract class PersistentMap extends TransactionalMap[AnyRef, AnyRef] { // FIXME: need to handle remove in another changeSet - protected[akka] val changeSet = new HashMap[K, V] + protected[akka] val changeSet = new HashMap[AnyRef, AnyRef] def getRange(start: Option[AnyRef], count: Int) @@ -81,15 +76,15 @@ abstract class PersistentMap[K, V] extends TransactionalMap[K, V] { override def rollback = changeSet.clear // ---- For scala.collection.mutable.Map ---- - override def put(key: K, value: V): Option[V] = { + override def put(key: AnyRef, value: AnyRef): Option[AnyRef] = { verifyTransaction changeSet += key -> value None // always return None to speed up writes (else need to go to DB to get } - override def -=(key: K) = remove(key) + override def -=(key: AnyRef) = remove(key) - override def update(key: K, value: V) = put(key, value) + override def update(key: AnyRef, value: AnyRef) = put(key, value) } /** @@ -101,7 +96,7 @@ abstract class PersistentMap[K, V] extends TransactionalMap[K, V] { * * @author Jonas Bonér */ -abstract class TemplatePersistentMap extends PersistentMap[AnyRef, AnyRef] { +abstract class TemplatePersistentMap extends PersistentMap { // to be concretized in subclasses val storage: MapStorage @@ -212,10 +207,10 @@ class MongoPersistentMap extends TemplatePersistentMap { * * @author Jonas Bonér */ -abstract class PersistentVector[T] extends TransactionalVector[T] { +abstract class PersistentVector extends TransactionalVector[AnyRef] { // FIXME: need to handle remove in another changeSet - protected[akka] val changeSet = new ArrayBuffer[T] + protected[akka] val changeSet = new ArrayBuffer[AnyRef] // ---- For Transactional ---- override def begin = {} @@ -223,7 +218,7 @@ abstract class PersistentVector[T] extends TransactionalVector[T] { override def rollback = changeSet.clear // ---- For TransactionalVector ---- - override def add(value: T) = { + override def add(value: AnyRef) = { verifyTransaction changeSet += value } @@ -234,7 +229,7 @@ abstract class PersistentVector[T] extends TransactionalVector[T] { * * @author Debasish Ghosh */ -abstract class TemplatePersistentVector extends PersistentVector[AnyRef] { +abstract class TemplatePersistentVector extends PersistentVector { val storage: VectorStorage @@ -286,7 +281,7 @@ class CassandraPersistentVector extends TemplatePersistentVector { val storage = CassandraStorage } -/** +/** * Implements a persistent transactional vector based on the MongoDB distributed P2P key-value storage. * * @author Debaissh Ghosh @@ -295,7 +290,7 @@ class MongoPersistentVector extends TemplatePersistentVector { val storage = MongoStorage } -abstract class TemplatePersistentRef extends TransactionalRef[AnyRef] { +abstract class PersistentRef extends TransactionalRef[AnyRef] { val storage: RefStorage override def commit = if (ref.isDefined) { @@ -319,10 +314,10 @@ abstract class TemplatePersistentRef extends TransactionalRef[AnyRef] { } } -class CassandraPersistentRef extends TemplatePersistentRef { +class CassandraPersistentRef extends PersistentRef { val storage = CassandraStorage } -class MongoPersistentRef extends TemplatePersistentRef { +class MongoPersistentRef extends PersistentRef { val storage = MongoStorage } diff --git a/akka-samples-java/src/main/java/sample/java/PersistentSimpleService.java b/akka-samples-java/src/main/java/sample/java/PersistentSimpleService.java index 947a0f8b3f..b995972188 100644 --- a/akka-samples-java/src/main/java/sample/java/PersistentSimpleService.java +++ b/akka-samples-java/src/main/java/sample/java/PersistentSimpleService.java @@ -13,7 +13,7 @@ import se.scalablesolutions.akka.annotation.prerestart; import se.scalablesolutions.akka.annotation.postrestart; import se.scalablesolutions.akka.state.TransactionalState; import se.scalablesolutions.akka.state.PersistentState; -import se.scalablesolutions.akka.state.TransactionalMap; +import se.scalablesolutions.akka.state.PersistentMap; import se.scalablesolutions.akka.state.CassandraStorageConfig; /** @@ -26,11 +26,10 @@ import se.scalablesolutions.akka.state.CassandraStorageConfig; @Path("/persistentjavacount") @transactionrequired public class PersistentSimpleService { - private String KEY = "COUNTER"; + private Object KEY = "COUNTER"; private boolean hasStartedTicking = false; - private PersistentState factory = new PersistentState(); - private TransactionalMap storage = factory.newMap(new CassandraStorageConfig()); + private PersistentMap storage = PersistentState.newMap(new CassandraStorageConfig()); @GET @Produces({"application/html"}) diff --git a/akka-samples-lift/src/main/scala/akka/SimpleService.scala b/akka-samples-lift/src/main/scala/akka/SimpleService.scala index a371281b8e..af8e313e31 100644 --- a/akka-samples-lift/src/main/scala/akka/SimpleService.scala +++ b/akka-samples-lift/src/main/scala/akka/SimpleService.scala @@ -5,6 +5,7 @@ import se.scalablesolutions.akka.actor.{SupervisorFactory, Actor} import se.scalablesolutions.akka.config.ScalaConfig._ import se.scalablesolutions.akka.util.Logging +import java.lang.Integer import javax.ws.rs.core.MultivaluedMap import javax.ws.rs.{GET, POST, Path, Produces, WebApplicationException, Consumes} diff --git a/akka-samples-scala/src/main/scala/SimpleService.scala b/akka-samples-scala/src/main/scala/SimpleService.scala index d343f9cd5d..5f3593fea4 100644 --- a/akka-samples-scala/src/main/scala/SimpleService.scala +++ b/akka-samples-scala/src/main/scala/SimpleService.scala @@ -9,6 +9,7 @@ import se.scalablesolutions.akka.actor.{SupervisorFactory, Actor} import se.scalablesolutions.akka.config.ScalaConfig._ import se.scalablesolutions.akka.util.Logging +import java.lang.Integer import javax.ws.rs.core.MultivaluedMap import javax.ws.rs.{GET, POST, Path, QueryParam, Produces, WebApplicationException, Consumes} diff --git a/akka-samples-security/src/main/scala/SimpleService.scala b/akka-samples-security/src/main/scala/SimpleService.scala index a3627586e6..fe43b87952 100644 --- a/akka-samples-security/src/main/scala/SimpleService.scala +++ b/akka-samples-security/src/main/scala/SimpleService.scala @@ -11,6 +11,7 @@ import _root_.se.scalablesolutions.akka.util.Logging import _root_.se.scalablesolutions.akka.security.{DigestAuthenticationActor, UserInfo} import _root_.javax.annotation.security.{DenyAll,PermitAll,RolesAllowed} import javax.ws.rs.{GET, POST, Path, Produces, Consumes} +import java.lang.Integer class Boot { object factory extends SupervisorFactory { diff --git a/config/akka.conf b/config/akka.conf index 049e60d6d6..6a07601c16 100644 --- a/config/akka.conf +++ b/config/akka.conf @@ -1,5 +1,72 @@ -include "akka-reference.conf" - -# This config import the Akka reference configuration. -# In this file you can override any option defined in the 'akka-reference.conf' file. - +#################### +# Akka Config File # +#################### + +# This file has all the default settings, so all these could be remove with no visible effect. +# Modify as needed. + + + filename = "./logs/akka.log" + roll = "daily" # Options: never, hourly, daily, sunday/monday/... + level = "debug" # Options: fatal, critical, error, warning, info, debug, trace + console = on + # syslog_host = "" + # syslog_server_name = "" + + + + version = "0.6" + + # FQN to the class doing initial active object/actor + # supervisor bootstrap, should be defined in default constructor + boot = ["training.ships.akka_rest.Boot", "training.ships.akka_persistence.Boot"] + + + timeout = 5000 # default timeout for future based invocations + serialize-messages = off # does a deep clone of (non-primitive) messages to ensure immutability + + + + service = on + restart-on-collision = off # (not implemented yet) if 'on' then it reschedules the transaction, + # if 'off' then throws an exception or rollback for user to handle + wait-for-completion = 100 # how long time in millis a transaction should be given time to complete when a collision is detected + wait-nr-of-times = 3 # the number of times it should check for completion of a pending transaction upon collision + distributed = off # not implemented yet + + + + service = on + hostname = "localhost" + port = 9999 + connection-timeout = 1000 # in millis + + + + service = on + hostname = "localhost" + port = 9998 + filters = "se.scalablesolutions.akka.security.AkkaSecurityFilterFactory;org.atmosphere.core.AtmosphereFilter" + authenticator = "sample.secure.SimpleAuthenticationService" + + + + system = "mongodb" # Options: cassandra, mongodb + + + service = on + hostname = "127.0.0.1" # IP address or hostname of one of the Cassandra cluster's seeds + port = 9160 + storage-format = "java" # Options: java, scala-json, java-json, protobuf + consistency-level = 1 + + + + service = on + hostname = "127.0.0.1" # IP address or hostname of the MongoDB DB instance + port = 27017 + dbname = "mydb" + storage-format = "scala-json" # Options: java, scala-json, java-json, protobuf + + + From 3da2d6178723d300d809ad2fab1f091908e577aa Mon Sep 17 00:00:00 2001 From: jboner Date: Wed, 14 Oct 2009 22:18:41 +0200 Subject: [PATCH 11/12] added NOOP serializer + fixed wrong servlet name in web.xml --- akka-actors/src/main/scala/serialization/Serializer.scala | 6 ++++++ akka-persistence/src/main/scala/CassandraStorage.scala | 3 ++- akka-samples-lift/src/main/webapp/WEB-INF/web.xml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/akka-actors/src/main/scala/serialization/Serializer.scala b/akka-actors/src/main/scala/serialization/Serializer.scala index 2d2917e0b5..441a8c0aa3 100644 --- a/akka-actors/src/main/scala/serialization/Serializer.scala +++ b/akka-actors/src/main/scala/serialization/Serializer.scala @@ -37,6 +37,12 @@ object Serializer { val EMPTY_CLASS_ARRAY = Array[Class[_]]() val EMPTY_ANY_REF_ARRAY = Array[AnyRef]() + object NOOP extends Serializer { + def deepClone(obj: AnyRef): AnyRef = obj + def out(obj: AnyRef): Array[Byte] = obj.asInstanceOf[Array[Byte]] + def in(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = bytes + } + /** * @author Jonas Bonér */ diff --git a/akka-persistence/src/main/scala/CassandraStorage.scala b/akka-persistence/src/main/scala/CassandraStorage.scala index 02f5f5dbec..ccf5d25b3a 100644 --- a/akka-persistence/src/main/scala/CassandraStorage.scala +++ b/akka-persistence/src/main/scala/CassandraStorage.scala @@ -46,11 +46,12 @@ object CassandraStorage extends MapStorage */ private[this] val serializer: Serializer = { - config.getString("akka.storage.cassandra.storage-format", "java") match { + config.getString("akka.storage.cassandra.storage-format", "manual") match { case "scala-json" => Serializer.ScalaJSON case "java-json" => Serializer.JavaJSON case "protobuf" => Serializer.Protobuf case "java" => Serializer.Java + case "manual" => Serializer.NOOP case "sbinary" => throw new UnsupportedOperationException("SBinary serialization protocol is not yet supported for storage") case "avro" => throw new UnsupportedOperationException("Avro serialization protocol is not yet supported for storage") case unknown => throw new UnsupportedOperationException("Unknown storage serialization protocol [" + unknown + "]") diff --git a/akka-samples-lift/src/main/webapp/WEB-INF/web.xml b/akka-samples-lift/src/main/webapp/WEB-INF/web.xml index d474da1ca1..23348604bb 100755 --- a/akka-samples-lift/src/main/webapp/WEB-INF/web.xml +++ b/akka-samples-lift/src/main/webapp/WEB-INF/web.xml @@ -13,7 +13,7 @@ AkkaServlet - se.scalablesolutions.akka.kernel.rest.AkkaServlet + se.scalablesolutions.akka.rest.AkkaServlet AkkaServlet From 858b219cf6aa1ae2e17a26cf5e5505ebe09c4992 Mon Sep 17 00:00:00 2001 From: jboner Date: Fri, 16 Oct 2009 10:36:17 +0200 Subject: [PATCH 12/12] added wrong config by mistake --- config/akka.conf | 73 ++---------------------------------------------- 1 file changed, 3 insertions(+), 70 deletions(-) diff --git a/config/akka.conf b/config/akka.conf index 6a07601c16..c674817033 100644 --- a/config/akka.conf +++ b/config/akka.conf @@ -1,72 +1,5 @@ -#################### -# Akka Config File # -#################### - -# This file has all the default settings, so all these could be remove with no visible effect. -# Modify as needed. - - - filename = "./logs/akka.log" - roll = "daily" # Options: never, hourly, daily, sunday/monday/... - level = "debug" # Options: fatal, critical, error, warning, info, debug, trace - console = on - # syslog_host = "" - # syslog_server_name = "" - - - - version = "0.6" - - # FQN to the class doing initial active object/actor - # supervisor bootstrap, should be defined in default constructor - boot = ["training.ships.akka_rest.Boot", "training.ships.akka_persistence.Boot"] +include "akka-reference.conf" - - timeout = 5000 # default timeout for future based invocations - serialize-messages = off # does a deep clone of (non-primitive) messages to ensure immutability - +# This config import the Akka reference configuration. +# In this file you can override any option defined in the 'akka-reference.conf' file. - - service = on - restart-on-collision = off # (not implemented yet) if 'on' then it reschedules the transaction, - # if 'off' then throws an exception or rollback for user to handle - wait-for-completion = 100 # how long time in millis a transaction should be given time to complete when a collision is detected - wait-nr-of-times = 3 # the number of times it should check for completion of a pending transaction upon collision - distributed = off # not implemented yet - - - - service = on - hostname = "localhost" - port = 9999 - connection-timeout = 1000 # in millis - - - - service = on - hostname = "localhost" - port = 9998 - filters = "se.scalablesolutions.akka.security.AkkaSecurityFilterFactory;org.atmosphere.core.AtmosphereFilter" - authenticator = "sample.secure.SimpleAuthenticationService" - - - - system = "mongodb" # Options: cassandra, mongodb - - - service = on - hostname = "127.0.0.1" # IP address or hostname of one of the Cassandra cluster's seeds - port = 9160 - storage-format = "java" # Options: java, scala-json, java-json, protobuf - consistency-level = 1 - - - - service = on - hostname = "127.0.0.1" # IP address or hostname of the MongoDB DB instance - port = 27017 - dbname = "mydb" - storage-format = "scala-json" # Options: java, scala-json, java-json, protobuf - - -