You are viewing a plain text version of this content. The canonical link for it is here.
Posted to wadi-commits@incubator.apache.org by bd...@apache.org on 2005/12/14 23:36:16 UTC
svn commit: r356933 [12/35] - in /incubator/wadi/trunk: ./ etc/ modules/
modules/assembly/ modules/assembly/src/ modules/assembly/src/bin/
modules/assembly/src/conf/ modules/assembly/src/main/
modules/assembly/src/main/assembly/ modules/core/ modules/c...
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/JkRouter.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/JkRouter.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/JkRouter.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/JkRouter.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,150 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.Router;
+import org.codehaus.wadi.RouterConfig;
+
+public class JkRouter implements Router {
+
+ protected final Log _log=LogFactory.getLog(getClass());
+ protected final String _info;
+ protected final String _suffix;
+
+ public JkRouter(String info) {
+ _info=info;
+ _suffix="."+_info;
+ }
+
+ protected RouterConfig _config;
+
+ public void init(RouterConfig config) {
+ _config=config;
+ }
+
+ public void destroy() {
+ _config=null;
+ }
+
+ public String strip(String session) {
+ int i=session.lastIndexOf(".");
+ if (i<0)
+ return session;
+ else
+ return session.substring(0, i);
+ }
+
+ public String augment(String id) {
+ return augment(id, _suffix);
+ }
+
+ public String augment(String id, String target) {
+ assert id!=null;
+ assert target.startsWith(".");
+
+ int i=id.lastIndexOf(".");
+ if (i<0) // id has no routing info
+ return id+target;
+ else // routing info already present
+ if (id.endsWith(target))
+ return id; // it's our routing info - leave it
+ else
+ return id.substring(0, i)+target; // it's someone else's - replace it
+
+ }
+
+ public String getInfo() {
+ return _info;
+ }
+
+ public boolean canReroute() {
+ return true;
+ }
+
+ public boolean reroute(InvocationContext invocationContext) {
+ WebInvocationContext context = (WebInvocationContext) invocationContext;
+ HttpServletRequest req = context.getHreq();
+ HttpServletResponse res = context.getHres();
+ String id=req.getRequestedSessionId();
+
+ if (id.endsWith(_suffix))
+ return false;
+
+ if (req.isRequestedSessionIdFromCookie())
+ return rerouteCookie(req, res, id);
+ else
+ return false;
+ }
+
+ public boolean rerouteCookie(HttpServletRequest req, HttpServletResponse res, String id) {
+ return rerouteCookie(req, res, id, _suffix);
+ }
+
+ public boolean rerouteCookie(HttpServletRequest req, HttpServletResponse res, String id, String target) {
+ assert target.startsWith(".");
+
+ String oldId=id;
+ String newId=augment(id);
+
+ if (_log.isInfoEnabled()) _log.info("rerouting cookie: " + oldId + " -> " + newId);
+
+ Cookie[] cookies=req.getCookies();
+
+ // TODO - what about case sensitivity on value ?
+ for (int i=0;i<cookies.length;i++)
+ {
+ Cookie cookie=cookies[i];
+ if (cookie.getName().equalsIgnoreCase(_config.getSessionCookieName()) && cookie.getValue().equals(oldId))
+ {
+ // name, path and domain must match those on client side,
+ // for cookie to be updated in browser...
+
+ String cookiePath=_config.getSessionCookiePath(req);
+ if (cookiePath!=null)
+ cookie.setPath(cookiePath);
+
+ String cookieDomain=_config.getSessionCookieDomain();
+ if (cookieDomain!=null)
+ cookie.setDomain(cookieDomain);
+
+ cookie.setValue(newId); // the session id with redirected routing info
+
+ res.addCookie(cookie);
+ }
+ }
+
+ return false;
+ }
+
+ public boolean rerouteURL() {
+ return rerouteURL(_suffix);
+ }
+
+ public boolean rerouteURL(String target) {
+ assert target.startsWith(".");
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyAttributes.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyAttributes.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyAttributes.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyAttributes.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,122 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.AttributesConfig;
+
+public class LazyAttributes extends DistributableAttributes {
+
+ public LazyAttributes(AttributesConfig config, Map map) {
+ super(config, map);
+ // TODO Auto-generated constructor stub
+ }
+ protected static final Log _log = LogFactory.getLog(LazyAttributes.class);
+
+ protected transient byte[] _bytes;
+
+ protected void deserialise() {
+ try {
+ // deserialise content at last minute ...
+ ByteArrayInputStream bais=new ByteArrayInputStream(_bytes);
+ ObjectInputStream ois=new ObjectInputStream(bais);
+ super.readContent(ois);
+ ois.close();
+ } catch (Exception e) {
+ _log.error("unexpected problem lazily deserialising session attribute value - data lost", e);
+ } finally {
+ _bytes=null;
+ }
+ }
+
+ protected void serialise() throws IOException {
+ ByteArrayOutputStream baos=new ByteArrayOutputStream(); // TODO - pool these objects...
+ ObjectOutputStream oos=new ObjectOutputStream(baos);
+ super.writeContent(oos);
+ oos.close();
+ _bytes=baos.toByteArray();
+ }
+
+ public synchronized Object get(Object key) {
+ if (_bytes!=null)
+ deserialise();
+
+ return super.get(key);
+ }
+
+ public Object remove(Object key) {
+ if (_bytes!=null)
+ deserialise();
+ return super.remove(key);
+ }
+
+ public Object put(Object key, Object newValue) {
+ if (_bytes!=null)
+ deserialise();
+ return super.put(key, newValue);
+ }
+
+ public int size() {
+ if (_bytes!=null)
+ deserialise();
+ return super.size(); // TODO - this should not need deserialisation...
+ }
+
+ public Set keySet(){
+ if (_bytes!=null)
+ deserialise();
+ return super.keySet();
+ }
+
+ public void clear(){
+ _bytes=null;
+ }
+
+ public Set getListenerNames() {
+ if (_bytes!=null)
+ deserialise();
+ return _listenerNames;
+ }
+
+ public synchronized void writeContent(ObjectOutput oo) throws IOException {
+ if (_bytes==null)
+ serialise(); // rebuild cache
+
+ oo.writeInt(_bytes.length);
+ oo.write(_bytes);
+ }
+
+ public synchronized void readContent(ObjectInput oi) throws IOException, ClassNotFoundException {
+ int length=oi.readInt();
+ _bytes=new byte[length];
+ if (oi.read(_bytes)!=length)
+ throw new IOException("data truncated whilst reading Session Attributes- data lost");
+ _map.clear();
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyAttributesFactory.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyAttributesFactory.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyAttributesFactory.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyAttributesFactory.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,31 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.util.HashMap;
+
+import org.codehaus.wadi.Attributes;
+import org.codehaus.wadi.AttributesConfig;
+import org.codehaus.wadi.AttributesFactory;
+
+public class LazyAttributesFactory implements AttributesFactory {
+
+ public Attributes create(AttributesConfig config) {
+ return new LazyAttributes(config, new HashMap());
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyHttpSessionBindingEvent.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyHttpSessionBindingEvent.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyHttpSessionBindingEvent.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyHttpSessionBindingEvent.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,56 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionBindingEvent;
+
+// IDEA - implement later
+
+// With an event like this, even if an HttpSessionAttributeListener is registered with the Context
+// we should be able to avoid deserialisation of a LazyValue, even on session invalidation, unless
+// the LazyValue's value is actually referenced through the event. This would be a substantial saving.
+
+// The same should be possible for LazyAttributes - the first direct reference through the event would
+// deserialise all attribute Values. This will involve changing the way that lazyAttribute serialises.
+// it should probably write out numAttributes, then foreach attribute: listener? and key then foreach
+// attribute: value... etc..
+
+// Ultimately, if session metadata encodes whether a session is carrying binding or activation listeners
+// it should be possible to e.g. expire sessions without listeners directly on disc without reloading (unless
+// listeners are registered with the Context). This would also be a big win.
+
+// I think we will have to change the Value.setValue() sig to include the attribute Name, so that events can be
+// raised from this point. We will also probably have to collapse the BindingNotification aspect into the Value class
+// so that we can keep taks on which attributes are listeners and which are not.
+
+public class LazyHttpSessionBindingEvent extends HttpSessionBindingEvent {
+
+ public LazyHttpSessionBindingEvent(HttpSession session, String name) {
+ super(session, name);
+ }
+
+ public LazyHttpSessionBindingEvent(HttpSession session, String name, Object value) {
+ super(session, name, value);
+ }
+
+ public Object getValue() {
+ LazyValue value=(LazyValue)super.getValue();
+ return value==null?null:value.getValue();
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyValue.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyValue.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyValue.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyValue.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,106 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionBindingListener;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.DistributableValueConfig;
+
+public class LazyValue extends DistributableValue {
+ protected static final Log _log = LogFactory.getLog(LazyValue.class);
+
+ protected transient boolean _listener;
+ protected transient byte[] _bytes;
+
+ public LazyValue(DistributableValueConfig config) {
+ super(config);
+ }
+
+ protected void deserialise() {
+ try {
+ // deserialise content at last minute ...
+ ByteArrayInputStream bais=new ByteArrayInputStream(_bytes);
+ ObjectInputStream ois=new ObjectInputStream(bais);
+ super.readContent(ois);
+ ois.close();
+ } catch (Exception e) {
+ _log.error("unexpected problem lazily deserialising session attribute value - data lost", e);
+ } finally {
+ _bytes=null;
+ }
+ }
+
+ protected void serialise() throws IOException {
+ ByteArrayOutputStream baos=new ByteArrayOutputStream(); // TODO - pool these objects...
+ ObjectOutputStream oos=new ObjectOutputStream(baos);
+ super.writeContent(oos);
+ oos.close();
+ _bytes=baos.toByteArray();
+ }
+
+ public synchronized Object getValue() {
+ if (_bytes!=null)
+ deserialise();
+
+ return super.getValue();
+ }
+
+ public synchronized Object setValue(Object newValue) {
+ if (_bytes!=null) {
+ if (_listener || ((DistributableValueConfig)_config).getHttpSessionAttributeListenersRegistered())
+ deserialise(); // oldValue needs deserialising before it is chucked...
+ }
+
+ Object tmp=super.setValue(newValue);
+ _listener=(_value instanceof HttpSessionActivationListener) || (_value instanceof HttpSessionBindingListener); // doubles up on test in super...
+ return tmp;
+ }
+
+ public synchronized void writeContent(ObjectOutput oo) throws IOException {
+ if (_bytes==null)
+ serialise(); // rebuild cache
+
+ oo.writeBoolean(_listener);
+ oo.writeInt(_bytes.length);
+ oo.write(_bytes);
+ }
+
+ public synchronized void readContent(ObjectInput oi) throws IOException, ClassNotFoundException {
+ _listener=oi.readBoolean();
+ int length=oi.readInt();
+ _bytes=new byte[length];
+ if (oi.read(_bytes)!=length)
+ throw new IOException("data truncated whilst reading Session attribute value - data lost");
+ _value=null;
+ }
+
+ public boolean isListener(){return _listener;}
+
+ // should we register Listeners with our Attributes ?
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyValueFactory.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyValueFactory.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyValueFactory.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/LazyValueFactory.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,34 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import org.codehaus.wadi.DistributableValueConfig;
+import org.codehaus.wadi.Value;
+import org.codehaus.wadi.ValueConfig;
+import org.codehaus.wadi.ValueFactory;
+
+public class LazyValueFactory implements ValueFactory {
+
+ public LazyValueFactory() {
+ super();
+ }
+
+ public Value create(ValueConfig config) {
+ return new LazyValue((DistributableValueConfig)config);
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ListenerSupport.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ListenerSupport.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ListenerSupport.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ListenerSupport.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,82 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.util.ArrayList;
+import java.util.EventListener;
+import java.util.List;
+
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class ListenerSupport {
+
+ protected final Log _log = LogFactory.getLog(getClass());
+ protected final List _sessionListeners = new ArrayList();
+ protected final List _attributeListeners = new ArrayList();
+
+ public synchronized void addEventListener(EventListener listener) throws IllegalArgumentException, IllegalStateException {
+// if (isStarted())
+// throw new IllegalStateException("EventListeners must be added before a Session Manager starts");
+
+ boolean known=false;
+ if (listener instanceof HttpSessionAttributeListener)
+ {
+ if (_log.isDebugEnabled()) _log.debug("adding HttpSessionAttributeListener: "+listener);
+ _attributeListeners.add(listener);
+ known=true;
+ }
+ if (listener instanceof HttpSessionListener)
+ {
+ if (_log.isDebugEnabled()) _log.debug("adding HttpSessionListener: "+listener);
+ _sessionListeners.add(listener);
+ known=true;
+ }
+
+ if (!known)
+ throw new IllegalArgumentException("Unknown EventListener type "+listener);
+ }
+
+ public synchronized void removeEventListener(EventListener listener) throws IllegalStateException {
+// if (isStarted())
+// throw new IllegalStateException("EventListeners may not be removed while a Session Manager is running");
+
+ boolean known=false;
+ if (listener instanceof HttpSessionAttributeListener)
+ {
+ if (_log.isDebugEnabled()) _log.debug("removing HttpSessionAttributeListener: "+listener);
+ known|=_attributeListeners.remove(listener);
+ }
+ if (listener instanceof HttpSessionListener)
+ {
+ if (_log.isDebugEnabled()) _log.debug("removing HttpSessionListener: "+listener);
+ known|=_sessionListeners.remove(listener);
+ }
+
+ if (!known)
+ if (_log.isWarnEnabled()) _log.warn("EventListener not registered: "+listener);
+ }
+
+ public void installListeners(StandardManager manager) {
+ manager.setSessionListeners((HttpSessionListener[])_sessionListeners.toArray(new HttpSessionListener[_sessionListeners.size()]));
+ manager.setAttributelisteners((HttpSessionAttributeListener[])_attributeListeners.toArray(new HttpSessionAttributeListener[_attributeListeners.size()]));
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MBeanServerFactoryBean.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MBeanServerFactoryBean.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MBeanServerFactoryBean.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MBeanServerFactoryBean.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,57 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.util.ArrayList;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+
+// only create a new MBeanServer if one does not already exist...
+
+public class MBeanServerFactoryBean extends org.springframework.jmx.support.MBeanServerFactoryBean {
+
+ protected MBeanServer _server;
+
+ public void afterPropertiesSet() {
+ String agentId=null; // TODO - parameterise
+ ArrayList servers=MBeanServerFactory.findMBeanServer(agentId);
+ if (servers!=null && servers.size()>0)
+ _server=(MBeanServer)servers.get(0);
+ else
+ super.afterPropertiesSet();
+ }
+
+ public Object getObject() {
+ if (_server!=null)
+ return _server;
+ else
+ return super.getObject();
+ }
+
+ public Class getObjectType() {
+ if (_server!=null)
+ return _server.getClass();
+ else
+ return super.getObjectType();
+ }
+
+ public void destroy() {
+ if (_server==null)
+ super.destroy();
+ }
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryContextualiser.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryContextualiser.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryContextualiser.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryContextualiser.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,201 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.Context;
+import org.codehaus.wadi.ContextPool;
+import org.codehaus.wadi.Contextualiser;
+import org.codehaus.wadi.Emoter;
+import org.codehaus.wadi.Evictable;
+import org.codehaus.wadi.Evicter;
+import org.codehaus.wadi.Immoter;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.InvocationException;
+import org.codehaus.wadi.Motable;
+import org.codehaus.wadi.PoolableInvocationWrapper;
+import org.codehaus.wadi.PoolableInvocationWrapperPool;
+import org.codehaus.wadi.Streamer;
+
+import EDU.oswego.cs.dl.util.concurrent.Sync;
+import EDU.oswego.cs.dl.util.concurrent.TimeoutException;
+
+/**
+ * A Contextualiser that stores its state in Memory as Java Objects
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.9 $
+ */
+public class MemoryContextualiser extends AbstractExclusiveContextualiser {
+ protected final ContextPool _pool;
+ protected final Streamer _streamer;
+ protected final Immoter _immoter;
+ protected final Emoter _emoter;
+ protected final Emoter _evictionEmoter;
+ protected final PoolableInvocationWrapperPool _requestPool;
+ protected final Log _lockLog=LogFactory.getLog("org.codehaus.wadi.LOCKS");
+
+ public MemoryContextualiser(Contextualiser next, Evicter evicter, Map map, Streamer streamer, ContextPool pool, PoolableInvocationWrapperPool requestPool) {
+ super(next, new RWLocker(), false, evicter, map);
+ _pool=pool;
+
+ // TODO - streamer should be used inside Motables get/setBytes() methods but that means a ref in every session :-(
+ _streamer=streamer;
+
+ _immoter=new MemoryImmoter(_map);
+ _emoter=new MemoryEmoter(_map);
+ _evictionEmoter=new AbstractMappedEmoter(_map){public String getInfo(){return "memory";}};
+
+ _requestPool=requestPool;
+ }
+
+ public boolean isExclusive(){return true;}
+
+ // TODO - sometime figure out how to make this a wrapper around AbstractMappedContextualiser.handle() instead of a replacement...
+ public boolean handle(InvocationContext invocationContext, String id, Immoter immoter, Sync motionLock) throws InvocationException {
+ Motable emotable=get(id);
+ if (emotable==null)
+ return false; // we cannot proceed without the session...
+
+ if (immoter!=null) {
+ return promote(invocationContext, id, immoter, motionLock, emotable); // motionLock will be released here...
+ } else {
+ return contextualiseLocally(invocationContext, id, motionLock, emotable);
+ }
+ }
+
+ public boolean contextualiseLocally(InvocationContext invocationContext, String id, Sync invocationLock, Motable motable) throws InvocationException {
+ Sync stateLock=((Context)motable).getSharedLock();
+ boolean stateLockAcquired=false;
+ try {
+ try {
+ Utils.acquireUninterrupted("State (shared)", id, stateLock);
+ stateLockAcquired=true;
+ } catch (TimeoutException e) {
+ if (_log.isErrorEnabled()) _log.error("unexpected timeout - continuing without lock: "+id+" : "+stateLock, e);
+ // give this some more thought - TODO
+ }
+
+ if (motable.getName()==null) {
+ if (_log.isTraceEnabled()) _log.trace("context disappeared whilst we were waiting for lock: "+id+" : "+stateLock);
+ return false; // retain the InvocationLock, release the StateLock
+ }
+
+ if (invocationLock!=null) {
+ Utils.release("Invocation", id, invocationLock);
+ }
+
+
+ motable.setLastAccessedTime(System.currentTimeMillis());
+ if (false == invocationContext.isProxiedInvocation()) {
+ // part of the proxying proedure runs a null req...
+ // restick clients whose session is here, but whose routing info points elsewhere...
+ _config.getRouter().reroute(invocationContext); // TODO - hmm... still thinking
+ // take wrapper from pool...
+ PoolableInvocationWrapper wrapper = _requestPool.take();
+ wrapper.init(invocationContext, (Context)motable);
+ invocationContext.invoke(wrapper);
+ wrapper.destroy();
+ _requestPool.put(wrapper);
+ } else {
+ invocationContext.invoke();
+ }
+ return true;
+ } finally {
+ if (stateLockAcquired) {
+ Utils.release("State (shared)", id, stateLock);
+ }
+ }
+ }
+
+ class MemoryEmoter extends AbstractMappedEmoter {
+
+ public MemoryEmoter(Map map) {
+ super(map);
+ }
+
+ public boolean prepare(String name, Motable emotable, Motable immotable) {
+ Sync stateLock=((Context)emotable).getExclusiveLock();
+ try {
+ Utils.acquireUninterrupted("State (excl.)", name, stateLock); // released in commit/rollback
+ } catch (TimeoutException e) {
+ _log.error("unexpected timeout", e);
+ return false;
+ }
+
+ if (emotable.getName()==null)
+ return false; // we lost race to motable and it has gone...
+
+ // copies emotable content into immotable
+ return super.prepare(name, emotable, immotable);
+ }
+
+ public void commit(String name, Motable emotable) {
+ // removes emotable from map
+ // destroys emotable
+ super.commit(name, emotable);
+ Sync stateLock=((Context)emotable).getExclusiveLock();
+ Utils.release("State (excl.)", name, stateLock);
+ }
+
+ public void rollback(String name, Motable emotable) {
+ // noop
+ super.rollback(name, emotable);
+ Sync stateLock=((Context)emotable).getExclusiveLock();
+ Utils.release("State (excl.)", name, stateLock);
+ }
+
+ public String getInfo() {
+ return "memory";
+ }
+ }
+
+ class MemoryImmoter extends AbstractMappedImmoter {
+
+ public MemoryImmoter(Map map) {
+ super(map);
+ }
+
+ public Motable nextMotable(String id, Motable emotable) {
+ return _pool.take();
+ }
+
+ public boolean contextualise(InvocationContext invocationContext, String id, Motable immotable, Sync motionLock) throws InvocationException {
+ return contextualiseLocally(invocationContext, id, motionLock, immotable);
+ }
+
+ public String getInfo() {
+ return "memory";
+ }
+ }
+
+ public Immoter getImmoter(){return _immoter;}
+ public Emoter getEmoter(){return _emoter;}
+ public Immoter getPromoter(Immoter immoter) {return immoter==null?_immoter:immoter;}
+
+ public Sync getEvictionLock(String id, Motable motable){return ((Context)motable).getExclusiveLock();}
+ public Emoter getEvictionEmoter(){return _evictionEmoter;} // leave lock-taking to evict()...
+
+ public void setLastAccessTime(Evictable evictable, long oldTime, long newTime) {_evicter.setLastAccessedTime(evictable, oldTime, newTime);}
+ public void setMaxInactiveInterval(Evictable evictable, int oldInterval, int newInterval) {_evicter.setMaxInactiveInterval(evictable, oldInterval, newInterval);}
+
+ public void expire(Motable motable) {_config.expire(motable);}
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryReplicater.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryReplicater.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryReplicater.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryReplicater.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,83 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.util.Map;
+
+import org.activecluster.Node;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.Replicater;
+
+import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
+
+public class MemoryReplicater implements Replicater {
+
+ protected final Log _log = LogFactory.getLog(getClass());
+
+ protected int numReplicants;
+
+ public MemoryReplicater(int numReplicants) {
+ }
+
+ // client part
+
+ public void create(Object tmp) {
+ if (_log.isTraceEnabled()) _log.trace("create: " + tmp);
+ // decide on replication partners (not ourselves)
+ // sned messages (sync) to insert replicants on these partners
+ }
+
+ public void update(Object tmp) {
+ if (_log.isTraceEnabled()) _log.trace("update: " + tmp);
+ // send messages (sync) to replicate to our partners
+ }
+
+ public void destroy(Object tmp) {
+ if (_log.isTraceEnabled()) _log.trace("destroy: " + tmp);
+ // send messages (sync) to remove replicants on partners
+ }
+
+ public boolean getReusingStore() {
+ return false;
+ }
+
+ // server part
+ protected Map _replicants=new ConcurrentHashMap();
+
+ public void insert(String key, Object tmp) {
+ if (_log.isTraceEnabled()) _log.trace("insert: " + key);
+ _replicants.put(key, tmp);
+ }
+
+ public void replicate(String key, Object value) {
+ if (_log.isTraceEnabled()) _log.trace("replicate: " + key);
+ }
+
+ public void remove(String key) {
+ if (_log.isTraceEnabled()) _log.trace("remove: " + key);
+ }
+
+ // restore
+
+ public void nodeDied(Node node) {
+ // the partitions owned by this node will be reconstructed and repopulated with session-key:location pairs
+ // we need to know which sessions this node was owner of when it died - partition owners will know
+ // these sessions may then be promoted to memory in our node and the partition owners will need to be updated as to their new location.
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryReplicaterFactory.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryReplicaterFactory.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryReplicaterFactory.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/MemoryReplicaterFactory.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,41 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import org.codehaus.wadi.Replicater;
+import org.codehaus.wadi.ReplicaterFactory;
+
+/**
+ * MemoryReplicaters hold per Session state (the location of their replication partners), so we need to create a new
+ * MemoryReplicater for each session.
+ *
+ * @author jules
+ *
+ */
+public class MemoryReplicaterFactory implements ReplicaterFactory {
+
+ protected int _numReplicants;
+
+ public MemoryReplicaterFactory(int numReplicants) {
+ _numReplicants=numReplicants;
+ }
+
+ public Replicater create() {
+ return new MemoryReplicater(_numReplicants);
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/NeverEvicter.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/NeverEvicter.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/NeverEvicter.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/NeverEvicter.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,35 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import org.codehaus.wadi.Evictable;
+
+/**
+ * An Evicter which never evicts (except explicitly invalidated sessions).
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.1 $
+ */
+public class NeverEvicter extends AbstractBestEffortEvicter {
+
+ public NeverEvicter(int sweepInterval, boolean strictOrdering) {
+ super(sweepInterval, strictOrdering);
+ }
+
+ public boolean test(Evictable evictable, long time, long ttl) {return false;}
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ObjectInputStream.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ObjectInputStream.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ObjectInputStream.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ObjectInputStream.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,108 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ *
+ */
+package org.codehaus.wadi.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+
+public class ObjectInputStream extends java.io.ObjectInputStream {
+
+ protected final ClassLoader _classLoader;
+
+ public ObjectInputStream(InputStream is, ClassLoader classLoader) throws IOException {
+ super(is);
+ _classLoader=classLoader;
+ }
+
+ // copied from super as this seems to be the only way to parameterise the ClassLoader... - TODO
+
+ /*
+ * @(#)ObjectInputStream.java 1.146 04/01/13
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+ private static final HashMap primClasses = new HashMap(8, 1.0F);
+ static {
+ primClasses.put("boolean", boolean.class);
+ primClasses.put("byte", byte.class);
+ primClasses.put("char", char.class);
+ primClasses.put("short", short.class);
+ primClasses.put("int", int.class);
+ primClasses.put("long", long.class);
+ primClasses.put("float", float.class);
+ primClasses.put("double", double.class);
+ primClasses.put("void", void.class);
+ }
+
+ protected Class resolveClass(ObjectStreamClass desc)
+ throws IOException, ClassNotFoundException
+ {
+ String name = desc.getName();
+ try {
+ return Class.forName(name, false, _classLoader);
+ } catch (ClassNotFoundException ex) {
+ Class cl = (Class) primClasses.get(name);
+ if (cl != null) {
+ return cl;
+ } else {
+ throw ex;
+ }
+ }
+ }
+
+ protected Class resolveProxyClass(String[] interfaces)
+ throws IOException, ClassNotFoundException
+ {
+ ClassLoader latestLoader = _classLoader;
+ ClassLoader nonPublicLoader = null;
+ boolean hasNonPublicInterface = false;
+
+ // define proxy in class loader of non-public interface(s), if any
+ Class[] classObjs = new Class[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++) {
+ Class cl = Class.forName(interfaces[i], false, latestLoader);
+ if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
+ if (hasNonPublicInterface) {
+ if (nonPublicLoader != cl.getClassLoader()) {
+ throw new IllegalAccessError(
+ "conflicting non-public interface class loaders");
+ }
+ } else {
+ nonPublicLoader = cl.getClassLoader();
+ hasNonPublicInterface = true;
+ }
+ }
+ classObjs[i] = cl;
+ }
+ try {
+ return Proxy.getProxyClass(
+ hasNonPublicInterface ? nonPublicLoader : latestLoader,
+ classObjs);
+ } catch (IllegalArgumentException e) {
+ throw new ClassNotFoundException(null, e);
+ }
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/PartiallyReplicableSession.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/PartiallyReplicableSession.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/PartiallyReplicableSession.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/PartiallyReplicableSession.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,36 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import org.codehaus.wadi.ReplicableSessionConfig;
+
+// A Session from which we can generate replication deltas, instead of complete backup copies...
+
+// I think this approach is only possible under the assumption of ByValue Semantics.
+
+public class PartiallyReplicableSession extends AbstractReplicableSession {
+
+ public PartiallyReplicableSession(ReplicableSessionConfig config) {
+ super(config);
+ // NYI
+ }
+
+ public void readEnded() {
+ throw new UnsupportedOperationException("NYI");
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/Quipu.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/Quipu.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/Quipu.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/Quipu.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,65 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import EDU.oswego.cs.dl.util.concurrent.WaitableInt;
+
+/**
+ * You have a flock of n Llamas, you [un]tie a knot in your Quipu as each one leaves/enters your pen.
+ * When all are in/out, you are free to continue. If the Llamas take too long, you can leave anyway !
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.2 $
+ */
+public class Quipu extends WaitableInt {
+
+ protected final static Log _log = LogFactory.getLog(Quipu.class);
+
+ public Quipu(int numLlammas) {
+ super(numLlammas);
+ // TODO Auto-generated constructor stub
+ }
+
+ public boolean waitFor(long timeout) throws InterruptedException {
+ long end=System.currentTimeMillis()+timeout;
+ long now=0;
+ synchronized(lock_) {
+ while (!(value_==0) && (now=System.currentTimeMillis())<end) lock_.wait(end-now);
+ }
+ return value_==0;
+ }
+
+ // TODO - consider synchronisation...
+ protected final Collection _results=Collections.synchronizedCollection(new ArrayList());
+
+ public void putResult(Object result) {
+ _results.add(result);
+ if (_log.isTraceEnabled()) _log.trace("result arrived: "+result);
+ decrement();
+ }
+
+ public Collection getResults() {
+ return _results;
+ }
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RWLock.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RWLock.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RWLock.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RWLock.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,493 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ File: WriterPreferenceReadWriteLock.java
+
+ Originally written by Doug Lea and released into the public domain.
+ This may be used for any purposes whatsoever without acknowledgment.
+ Thanks for the assistance and support of Sun Microsystems Labs,
+ and everyone contributing, testing, and using this code.
+
+ History:
+ Date Who What
+ 11Jun1998 dl Create public version
+ 5Aug1998 dl replaced int counters with longs
+ 25aug1998 dl record writer thread
+ 3May1999 dl add notifications on interrupt/timeout
+
+*/
+
+package org.codehaus.wadi.impl;
+
+// This started off life as a straight copy of Doug Lea's
+// WriterPreferenceReadWriteLock in
+// EDU.oswego.cs.dl.util.concurrent... I will be refactoring it to add
+// priority ordering of writers and lock overlapping...
+
+// Doug's code is under whatever license he chose, mine is under ASF2
+
+import EDU.oswego.cs.dl.util.concurrent.*;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.RWLockListener;
+
+/**
+ * A read-write lock. Writers are preferred. Writers are ordered
+ * according to 'priority'. A Reader may overlap release of its read
+ * lock with its application for a write lock. A Writer may downgrade,
+ * becoming a Reader.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.5 $
+ */
+public class RWLock implements ReadWriteLock {
+ protected static final Log _log=LogFactory.getLog(RWLock.class);
+
+ protected int _maxPriority=Thread.MAX_PRIORITY;
+ protected static ThreadLocal _priority=new ThreadLocal(){protected synchronized Object initialValue() {return new Integer(0);}};
+ protected class Lock {int _count=0;}
+
+ protected long activeReaders_ = 0;
+ protected Thread activeWriter_ = null;
+ protected long waitingReaders_ = 0;
+ protected long waitingWriters_ = 0;
+
+ public RWLock(int maxPriority){_maxPriority=maxPriority;}
+
+ public static void setPriority(int priority){_priority.set(new Integer(priority));}
+
+ public static int getPriority() {
+ int tmp=((Integer)_priority.get()).intValue();
+ if (0==tmp && _log.isWarnEnabled())
+ _log.warn("no thread priority specified", new Exception());
+ return tmp;
+ }
+
+ protected RWLockListener _listener; // cheaper than an array of Listeners and we only need 0-1 (currently)
+
+ public void setListener(RWLockListener listener) {
+ _listener=listener;
+ }
+
+ protected final ReaderLock readerLock_ = new ReaderLock();
+ protected final WriterLock writerLock_ = new WriterLock();
+
+ public Sync writeLock() { return writerLock_; }
+ public Sync readLock() { return readerLock_; }
+
+ /*
+ A bunch of small synchronized methods are needed
+ to allow communication from the Lock objects
+ back to this object, that serves as controller
+ */
+
+
+ protected synchronized void cancelledWaitingReader() { --waitingReaders_; assert waitingReaders_>-1;}
+ protected synchronized void cancelledWaitingWriter(Lock l) { --waitingWriters_; l._count--; assert waitingWriters_>-1;}
+
+
+ protected boolean allowReader() {
+ return activeWriter_ == null;
+ }
+
+
+ protected synchronized boolean startRead() {
+ boolean allowRead = allowReader();
+ if (allowRead) ++activeReaders_;
+ return allowRead;
+ }
+
+ protected synchronized boolean startWrite() {
+
+ // The allowWrite expression cannot be modified without
+ // also changing startWrite, so is hard-wired
+
+ boolean allowWrite = (activeWriter_ == null && activeReaders_ == 0);
+ if (allowWrite) activeWriter_ = Thread.currentThread();
+ return allowWrite;
+ }
+
+
+ /*
+ Each of these variants is needed to maintain atomicity
+ of wait counts during wait loops. They could be
+ made faster by manually inlining each other. We hope that
+ compilers do this for us though.
+ */
+
+ protected synchronized boolean startReadFromNewReader() {
+ boolean pass = startRead();
+ if (!pass) ++waitingReaders_;
+ return pass;
+ }
+
+ protected synchronized boolean startWriteFromNewWriter(Lock l) {
+ boolean pass = startWrite();
+ if (!pass)
+ {
+ ++waitingWriters_;
+ l._count++;
+ }
+ return pass;
+ }
+
+ protected synchronized boolean startReadFromWaitingReader() {
+ boolean pass = startRead();
+ if (pass)
+ {
+ --waitingReaders_;
+ assert waitingReaders_>-1;
+ }
+
+ return pass;
+ }
+
+ protected synchronized boolean startWriteFromWaitingWriter(Lock l) {
+ boolean pass = startWrite();
+ if (pass)
+ {
+ --waitingWriters_;
+ assert waitingWriters_>-1;
+ l._count--;
+ }
+ return pass;
+ }
+
+ protected boolean notifyReadEnded() {
+ if (_listener!=null)
+ _listener.readEnded();
+
+ return true;
+ }
+
+ /**
+ * Called upon termination of a read.
+ * Returns the object to signal to wake up a waiter, or null if no such
+ **/
+ protected synchronized Signaller endRead() {
+ if ((--activeReaders_==0 && notifyReadEnded()) && waitingWriters_ > 0)
+ return writerLock_;
+ else
+ {
+ if (_log.isTraceEnabled())
+ _log.trace("activeReaders_="+activeReaders_);
+ assert activeReaders_>-1;
+ return null;
+ }
+ }
+
+
+ /**
+ * Called upon termination of a write.
+ * Returns the object to signal to wake up a waiter, or null if no such
+ **/
+ protected synchronized Signaller endWrite() {
+ activeWriter_ = null;
+ if (waitingReaders_ > 0 && allowReader())
+ return readerLock_;
+ else if (waitingWriters_ > 0)
+ return writerLock_;
+ else
+ return null;
+ }
+
+
+ /**
+ * Reader and Writer requests are maintained in two different
+ * wait sets, by two different objects. These objects do not
+ * know whether the wait sets need notification since they
+ * don't know preference rules. So, each supports a
+ * method that can be selected by main controlling object
+ * to perform the notifications. This base class simplifies mechanics.
+ **/
+
+ protected abstract class Signaller { // base for ReaderLock and WriterLock
+ abstract void signalWaiters();
+ }
+
+ protected class ReaderLock extends Signaller implements Sync {
+
+ public String
+ toString()
+ {
+ return "<RWLock.ReaderLock:"+ReaderLock.this.hashCode()+":"+Thread.currentThread()+":activeReaders:"+activeReaders_+", waitingReaders:"+waitingReaders_+">";
+ }
+
+ public void acquire() throws InterruptedException {
+ if (_log.isTraceEnabled())
+ _log.trace(Thread.currentThread().toString()+" acquiring R-lock "+RWLock.this.hashCode());//, new Exception());
+ if (Thread.interrupted()) throw new InterruptedException();
+ InterruptedException ie = null;
+ synchronized(this) {
+ if (!startReadFromNewReader()) {
+ for (;;) {
+ try {
+ ReaderLock.this.wait();
+ if (startReadFromWaitingReader())
+ return;
+ }
+ catch(InterruptedException ex){
+ cancelledWaitingReader();
+ ie = ex;
+ break;
+ }
+ }
+ }
+ }
+ if (ie != null) {
+ // fall through outside synch on interrupt.
+ // This notification is not really needed here,
+ // but may be in plausible subclasses
+ writerLock_.signalWaiters();
+ throw ie;
+ }
+ }
+
+
+ public void release() {
+ if (_log.isTraceEnabled())
+ _log.trace(Thread.currentThread().toString()+" releasing R-lock "+RWLock.this.hashCode());//, new Exception());
+ Signaller s = endRead();
+ if (s != null) s.signalWaiters();
+ }
+
+
+ synchronized void signalWaiters() { ReaderLock.this.notifyAll(); }
+
+ public boolean attempt(long msecs) throws InterruptedException {
+ if (_log.isTraceEnabled())
+ _log.trace(Thread.currentThread().toString()+" attempting R-lock "+RWLock.this.hashCode());//, new Exception());
+ if (Thread.interrupted()) throw new InterruptedException();
+ InterruptedException ie = null;
+ synchronized(this) {
+ if (msecs <= 0)
+ return startRead();
+ else if (startReadFromNewReader())
+ return true;
+ else {
+ long waitTime = msecs;
+ long start = System.currentTimeMillis();
+ for (;;) {
+ try { ReaderLock.this.wait(waitTime); }
+ catch(InterruptedException ex){
+ cancelledWaitingReader();
+ ie = ex;
+ break;
+ }
+ if (startReadFromWaitingReader())
+ return true;
+ else {
+ waitTime = msecs - (System.currentTimeMillis() - start);
+ if (waitTime <= 0) {
+ cancelledWaitingReader();
+ break;
+ }
+ }
+ }
+ }
+ }
+ // safeguard on interrupt or timeout:
+ writerLock_.signalWaiters();
+ if (ie != null) throw ie;
+ else return false; // timed out
+ }
+
+ }
+
+ protected class WriterLock extends Signaller implements Sync {
+
+ public String
+ toString()
+ {
+ return "<RWLock.WriterLock:"+WriterLock.this.hashCode()+":"+Thread.currentThread()+":"+" activeWriter:"+(activeWriter_!=null)+", waitingWriters:"+waitingWriters_+">";
+ }
+
+ Lock[] _locks=new Lock[_maxPriority+1];
+
+ WriterLock()
+ {
+ for (int i=0;i<=_maxPriority;i++)
+ _locks[i]=new Lock();
+ }
+
+ public void acquire() throws InterruptedException {
+ if (_log.isTraceEnabled())
+ _log.trace(Thread.currentThread().toString()+" acquiring W-lock "+RWLock.this.hashCode());//, new Exception());
+ if (Thread.interrupted()) throw new InterruptedException();
+ InterruptedException ie = null;
+ int p=getPriority();
+ Lock l=_locks[p];
+ synchronized(l) {
+ if (!startWriteFromNewWriter(l)) {
+ for (;;) {
+ try {
+ l.wait();
+ if (startWriteFromWaitingWriter(l))
+ return;
+ }
+ catch(InterruptedException ex){
+ cancelledWaitingWriter(l);
+ l.notify();
+ ie = ex;
+ break;
+ }
+ }
+ }
+ }
+ if (ie != null) {
+ // Fall through outside synch on interrupt.
+ // On exception, we may need to signal readers.
+ // It is not worth checking here whether it is strictly necessary.
+ readerLock_.signalWaiters();
+ throw ie;
+ }
+ }
+
+ public void release(){
+ if (_log.isTraceEnabled())
+ _log.trace(Thread.currentThread().toString()+" releasing W-lock "+RWLock.this.hashCode());//, new Exception());
+ Signaller s = endWrite();
+ if (s != null) s.signalWaiters();
+ }
+
+ synchronized void
+ signalWaiters()
+ {
+ // walk down from top priority looking for a thread to notify...
+ for (int i=_maxPriority;i>=0;i--)
+ {
+ Lock l=_locks[i];
+ synchronized (l)
+ {
+ if (l._count>0)
+ {
+ l.notify();
+ return;
+ }
+ }
+ }
+ }
+
+ public boolean attempt(long msecs) throws InterruptedException {
+ if (_log.isTraceEnabled())
+ _log.trace(Thread.currentThread().toString()+" attempting W-lock "+RWLock.this.hashCode());//, new Exception());
+ if (Thread.interrupted()) throw new InterruptedException();
+ InterruptedException ie = null;
+ int p=getPriority();
+ Lock l=_locks[p];
+ synchronized(l) {
+ if (msecs <= 0)
+ return startWrite();
+ else if (startWriteFromNewWriter(l))
+ return true;
+ else {
+ long waitTime = msecs;
+ long start = System.currentTimeMillis();
+ for (;;) {
+ try { l.wait(waitTime); }
+ catch(InterruptedException ex){
+ cancelledWaitingWriter(l);
+ l.notify();
+ ie = ex;
+ break;
+ }
+ if (startWriteFromWaitingWriter(l))
+ return true;
+ else {
+ waitTime = msecs - (System.currentTimeMillis() - start);
+ if (waitTime <= 0) {
+ cancelledWaitingWriter(l);
+ l.notify();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ readerLock_.signalWaiters();
+ if (ie != null) throw ie;
+ else return false; // timed out
+ }
+
+ }
+
+
+ // Not well tested - I'm concerned about the synchronisation...
+ public void
+ overlap()
+ throws InterruptedException
+ {
+ if (_log.isTraceEnabled())
+ _log.trace(Thread.currentThread().toString()+" overlapping W-lock "+writerLock_.hashCode());
+ synchronized (RWLock.this)
+ {
+ Signaller s=endRead();
+
+ if (s==null)
+ {
+ // there are still extant readers - this call to acquire will
+ // just queue a write lock - it could be optimised but...
+ writeLock().acquire();
+ }
+ else
+ {
+ // readers are exhausted, we don't want to let this writer
+ // jump straight into the gap as it may not be of a higher
+ // priority than the other waiting writers...
+
+ // WARNING - TODO - However, at the moment we KNOW that the
+ // only thread using the overlap method will be the
+ // invalidation request thread so we can live with this -
+ // revisit if we ever need this lock to be used in a different
+ // manner...
+ writeLock().acquire();
+ }
+ }
+ }
+
+ // we are a writer and we want to become a reader (i.e. allow other
+ // readers) without another writer jumping in during the
+ // change-over. Writer preference breaks down here, but this is a
+ // useful ability....
+ public synchronized void
+ downgrade()
+ throws IllegalStateException
+ {
+ // test that we are indeed the current writer....
+ if (activeWriter_!=Thread.currentThread())
+ throw new IllegalStateException("downgrading thread is not current writer");
+ else
+ {
+ // cease being the active writer
+ activeWriter_=null;
+ // become an active reader
+ assert activeReaders_==0; // we were writing so there should be no active readers...
+ activeReaders_++;
+ // wake waiting readers
+ if (waitingReaders_>0)
+ readerLock_.signalWaiters();
+ }
+ }
+
+ public String
+ toString()
+ {
+ return "<RWLock:"+this.hashCode()+":"+readerLock_+", "+writerLock_+">";
+ }
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RWLocker.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RWLocker.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RWLocker.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RWLocker.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,35 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import org.codehaus.wadi.Context;
+import org.codehaus.wadi.Locker;
+import org.codehaus.wadi.Motable;
+
+import EDU.oswego.cs.dl.util.concurrent.Sync;
+
+public class RWLocker implements Locker {
+
+ public RWLocker() {
+ super();
+ }
+
+ public Sync getLock(String id, Motable motable) {
+ return ((Context)motable).getExclusiveLock();
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RankedRWLock.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RankedRWLock.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RankedRWLock.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RankedRWLock.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,44 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+// maybe collapse with superclass when sandbox is merged into mainline.
+
+/**
+ * A ReadWriteLock with prioritisable writer threads. The set of priority ranks is tailored
+ * to WADI.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.1 $
+ */
+
+public class RankedRWLock extends org.codehaus.wadi.impl.RWLock {
+
+ public final static int INVALIDATION_PRIORITY=5; // explicit invalidation by user
+ public final static int EMIGRATION_PRIORITY=4; // session is required on another node
+ public final static int EVICTION_PRIORITY=3; // session is being evicted (implicit timeout)
+ public final static int IMMIGRATION_PRIORITY=2; // TODO - do we need this ?
+ public final static int CREATION_PRIORITY=1; // TODO - do we need this ?
+ public final static int NO_PRIORITY=0; // used to remove any of the above from a thread...
+
+ protected final static int MAX_PRIORITY=INVALIDATION_PRIORITY;
+
+ public RankedRWLock() {
+ super(MAX_PRIORITY);
+ }
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RedirectingRelocater.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RedirectingRelocater.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RedirectingRelocater.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/RedirectingRelocater.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,45 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import org.codehaus.wadi.Contextualiser;
+import org.codehaus.wadi.Immoter;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.InvocationException;
+import org.codehaus.wadi.RequestRelocater;
+
+import EDU.oswego.cs.dl.util.concurrent.Sync;
+
+/**
+ * Relocate the request to its state, by redirecting it to another node.
+ * This is only possible if, for example, the load balancer is using routing information
+ * to decide which node to dispatch stateful requests to. If this is the case, we may be
+ * able rewrite this to achieve our desired effect.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.2 $
+ */
+public class RedirectingRelocater extends AbstractRelocater implements RequestRelocater {
+
+ public boolean relocate(InvocationContext invocationContext, String name, Immoter immoter, Sync motionLock) throws InvocationException {
+ return false;
+ }
+
+ public void setTop(Contextualiser top){/* NYI */}
+ public Contextualiser getTop(){return null;}
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SerialContextualiser.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SerialContextualiser.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SerialContextualiser.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SerialContextualiser.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,101 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.Collapser;
+import org.codehaus.wadi.Context;
+import org.codehaus.wadi.Contextualiser;
+import org.codehaus.wadi.Immoter;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.InvocationException;
+
+import EDU.oswego.cs.dl.util.concurrent.NullSync;
+import EDU.oswego.cs.dl.util.concurrent.Sync;
+import EDU.oswego.cs.dl.util.concurrent.TimeoutException;
+
+/**
+ * Ensure that any Contextualisations that pass through are serialised according to the strategy imposed by our Collapser.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.9 $
+ */
+public class SerialContextualiser extends AbstractDelegatingContextualiser {
+
+ protected final Collapser _collapser;
+ protected final Sync _dummyLock=new NullSync();
+ protected final Map _map;
+ protected final Log _lockLog=LogFactory.getLog("org.codehaus.wadi.LOCKS");
+
+ public SerialContextualiser(Contextualiser next, Collapser collapser, Map map) {
+ super(next);
+ _collapser=collapser;
+ _map=map;
+ }
+
+ public boolean contextualise(InvocationContext invocationContext, String id, Immoter immoter, Sync invocationLock, boolean exclusiveOnly) throws InvocationException {
+ if (invocationLock!=null) {
+ // someone is already doing a promotion from further up the
+ // stack - do nothing other than delegate...
+ return _next.contextualise(invocationContext, id, immoter, invocationLock, exclusiveOnly);
+ } else {
+ // the promotion begins here...
+ // allocate a lock and continue...
+ invocationLock=_collapser.getLock(id);
+ boolean invocationLockAcquired=false;
+ try {
+ Utils.acquireUninterrupted("Invocation", id, invocationLock);
+ invocationLockAcquired=true;
+ } catch (TimeoutException e) {
+ _log.error("unexpected timeout - proceding without lock", e);
+ }
+
+ try {
+ // whilst we were waiting for the motionLock, the session in question may have been moved back into memory somehow.
+ // before we proceed, confirm that this has not happened.
+ Context context=(Context)_map.get(id);
+ boolean found=false;
+ if (null!=context) {
+ // oops - it HAS happened...
+ if (_log.isWarnEnabled()) _log.warn("session has reappeared in memory whilst we were waiting to immote it...: "+id+ " ["+Thread.currentThread().getName()+"]"); // TODO - downgrade..
+ // overlap two locking systems until we have secured the session in memory, then run the request
+ // and release the lock.
+ // TODO - we really need to take a read lock before we release the motionLock...
+ found=immoter.contextualise(invocationContext, id, context, invocationLock);
+ // although we did find the context it may have left this contextualiser before we finally acquire its lock.
+ // be prepared to continue dowm the stack looking for it.
+ }
+
+ if (!found) {
+ // session was not promoted whilst we were waiting for motionLock. Continue down Contextualiser stack
+ // it may be below us...
+ // lock is to be released as soon as context is available to subsequent contextualisations...
+ found=_next.contextualise(invocationContext, id, immoter, invocationLock, exclusiveOnly);
+ }
+ invocationLockAcquired=!found;
+ return found;
+ } finally {
+ if (invocationLockAcquired) {
+ Utils.release("Invocation", id, invocationLock);
+ }
+ }
+ }
+ }
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SessionToContextPoolAdapter.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SessionToContextPoolAdapter.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SessionToContextPoolAdapter.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SessionToContextPoolAdapter.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,54 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import org.codehaus.wadi.Context;
+import org.codehaus.wadi.ContextPool;
+import org.codehaus.wadi.Session;
+import org.codehaus.wadi.SessionConfig;
+import org.codehaus.wadi.SessionPool;
+
+
+/**
+ * Hack - plasters over a difference in the API between the Manager and Contextualiser
+ * stacks. Sessions appear in both stacks, and must be pooled by the same object, but with
+ * different APIs. To be resolved ASAP.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.1 $
+ */
+public class SessionToContextPoolAdapter implements ContextPool {
+
+ protected final SessionPool _pool;
+
+ public SessionToContextPoolAdapter(SessionPool pool) {
+ super();
+ _pool=pool;
+ }
+
+ public void init(SessionConfig config) {
+ _pool.init(config);
+ }
+
+ public void put(Context context) {
+ _pool.put((Session)context);
+ }
+
+ public Context take() {
+ return _pool.take();
+ }
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SessionWrapper.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SessionWrapper.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SessionWrapper.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SessionWrapper.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,80 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import java.util.Collections;
+import java.util.Enumeration;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+import org.codehaus.wadi.Session;
+
+/**
+ * Wraps a Session instance, presenting ONLY an HttpSession facade to the application.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.1 $
+ */
+
+public class SessionWrapper implements HttpSession {
+
+ protected final Session _session;
+
+ public SessionWrapper(Session session) {
+ _session=session;
+ }
+
+ // delegate to Session
+ public long getCreationTime() {return _session.getCreationTime();}
+ public long getLastAccessedTime() {return _session.getLastAccessedTime();}
+ public void setMaxInactiveInterval(int interval) {_session.setMaxInactiveInterval(interval);}
+ public int getMaxInactiveInterval() {return _session.getMaxInactiveInterval();}
+ public boolean isNew() {return _session.isNew();}
+ public String getId() {return _session.getId();}
+
+ public void setAttribute(String name, Object value) {
+ if (null==value)
+ _session.removeAttribute(name);
+ else
+ _session.setAttribute(name, value);
+ }
+
+ public Object getAttribute(String name) {return _session.getAttribute(name);}
+ public void removeAttribute(String name) {_session.removeAttribute(name);}
+ public Enumeration getAttributeNames() {return _session.getAttributeNameEnumeration();}
+ public String[] getValueNames() {return _session.getAttributeNameStringArray();}
+
+ // delegate to Wrapper
+ public Object getValue(String name) {return getAttribute(name);}
+ public void putValue(String name, Object value) {setAttribute(name, value);}
+ public void removeValue(String name) {removeAttribute(name);}
+
+ // delegate to Manager
+ public ServletContext getServletContext() {return _session.getConfig().getServletContext();}
+ public void invalidate() {_session.getConfig().destroy(_session);}
+
+ // handle ourselves...
+ protected static final HttpSessionContext _httpSessionContext=new HttpSessionContext() {
+ protected final Enumeration _emptyEnumeration=Collections.enumeration(Collections.EMPTY_LIST);
+ public HttpSession getSession(String sessionId) {return null;}
+ public Enumeration getIds() {return _emptyEnumeration;}
+ };
+ public HttpSessionContext getSessionContext(){return _httpSessionContext;}
+
+}
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SharedStoreContextualiser.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SharedStoreContextualiser.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SharedStoreContextualiser.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/SharedStoreContextualiser.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,134 @@
+/**
+ *
+ * Copyright 2003-2005 Core Developers Network Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.wadi.impl;
+
+import org.codehaus.wadi.Collapser;
+import org.codehaus.wadi.Contextualiser;
+import org.codehaus.wadi.ContextualiserConfig;
+import org.codehaus.wadi.DistributableContextualiserConfig;
+import org.codehaus.wadi.Emoter;
+import org.codehaus.wadi.Immoter;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.InvocationException;
+import org.codehaus.wadi.Motable;
+import org.codehaus.wadi.Store;
+import org.codehaus.wadi.StoreMotable;
+
+import EDU.oswego.cs.dl.util.concurrent.Sync;
+
+/**
+ * A Contextualiser which stores its Contexts in a shared database via JDBC.
+ * On shutdown of the cluster's last node, all extant sessions will be demoted to here.
+ * On startup of the cluster's first node, all sessions stored here will be promoted upwards.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.6 $
+ */
+
+public class SharedStoreContextualiser extends AbstractSharedContextualiser {
+
+ protected final DatabaseStore _store;
+ protected final Immoter _immoter;
+ protected final Emoter _emoter;
+
+ public SharedStoreContextualiser(Contextualiser next, Collapser collapser, boolean clean, DatabaseStore store) {
+ super(next, new CollapsingLocker(collapser), clean);
+ _store=store;
+ _immoter=new SharedJDBCImmoter();
+ _emoter=new SharedJDBCEmoter();
+ }
+
+ public String getStartInfo() {
+ return "["+_store.getLabel()+"/"+_store.getTable()+"]";
+ }
+
+
+ public void init(ContextualiserConfig config) {
+ super.init(config);
+ if (_clean)
+ _store.clean();
+ }
+
+ public Immoter getImmoter(){return _immoter;}
+ public Emoter getEmoter(){return _emoter;}
+
+ public Immoter getDemoter(String name, Motable motable) {
+ // TODO - should check _next... - just remove when we have an evicter sorted
+ return new SharedJDBCImmoter();
+ }
+
+ public Motable get(String id) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * An Emoter that deals in terms of SharedJDBCMotables
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.6 $
+ */
+ public class SharedJDBCImmoter extends AbstractImmoter {
+
+ public Motable nextMotable(String name, Motable emotable) {
+ StoreMotable motable=_store.create();
+ motable.init(_store);
+ return motable; // TODO - Pool, maybe as ThreadLocal
+ }
+
+ public String getInfo() {
+ return _store.getDescription();
+ }
+ }
+
+ public class SharedJDBCEmoter extends AbstractChainedEmoter {
+
+ public String getInfo() {
+ return _store.getDescription();
+ }
+ }
+
+ class SharedPutter implements Store.Putter {
+
+ protected final Emoter _emoter;
+ protected final Immoter _immoter;
+
+ public SharedPutter(Emoter emoter, Immoter immoter) {
+ _emoter=emoter;
+ _immoter=immoter;
+ }
+
+ public void put(String name, Motable motable) {
+ Utils.mote(_emoter, _immoter, motable, name);
+ }
+ }
+
+ public void load(Emoter emoter, Immoter immoter) {
+ // this should only happen when we are the first node in the cluster...
+ _store.load(new SharedPutter(emoter, immoter), ((DistributableContextualiserConfig)_config).getAccessOnLoad());
+ }
+
+ public Emoter getEvictionEmoter() {throw new UnsupportedOperationException();} // FIXME
+ public void expire(Motable motable) {throw new UnsupportedOperationException();} // FIXME
+
+ /**
+ * Shared Contextualisers do nothing at runtime. They exist only to load data at startup and store it at shutdown.
+ */
+ public boolean contextualise(InvocationContext invocationContext, String id, Immoter immoter, Sync motionLock, boolean exclusiveOnly) throws InvocationException {
+ return false;
+ }
+
+}