incubator-wadi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bdud...@apache.org
Subject svn commit: r356933 [11/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...
Date Wed, 14 Dec 2005 23:36:16 GMT
Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableManager.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableManager.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableManager.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableManager.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,133 @@
+/**
+ *
+ * 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.List;
+import java.util.Map;
+
+import org.codehaus.wadi.AttributesFactory;
+import org.codehaus.wadi.Contextualiser;
+import org.codehaus.wadi.DistributableContextualiserConfig;
+import org.codehaus.wadi.ManagerConfig;
+import org.codehaus.wadi.ReplicableSessionConfig;
+import org.codehaus.wadi.Replicater;
+import org.codehaus.wadi.ReplicaterFactory;
+import org.codehaus.wadi.Router;
+import org.codehaus.wadi.SessionIdFactory;
+import org.codehaus.wadi.SessionPool;
+import org.codehaus.wadi.SessionWrapperFactory;
+import org.codehaus.wadi.Streamer;
+import org.codehaus.wadi.StreamerConfig;
+import org.codehaus.wadi.ValueHelper;
+import org.codehaus.wadi.ValuePool;
+import org.codehaus.wadi.impl.ClusteredManager.HelperPair;
+
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
+
+/**
+ * @author jules
+ * A StandardManager that knows how to Serialise HttpSessions.
+ */
+public class DistributableManager extends StandardManager implements ReplicableSessionConfig, DistributableContextualiserConfig, StreamerConfig {
+	
+	protected final List _helpers = new ArrayList();
+	protected final SynchronizedBoolean _shuttingDown = new SynchronizedBoolean(false);
+	protected final Streamer _streamer;
+	protected final boolean _accessOnLoad;
+	protected final ReplicaterFactory _replicaterFactory;
+	
+	public DistributableManager(SessionPool sessionPool, AttributesFactory attributesFactory, ValuePool valuePool, SessionWrapperFactory sessionWrapperFactory, SessionIdFactory sessionIdFactory, Contextualiser contextualiser, Map map, Router router, boolean errorIfSessionNotAcquired, Streamer streamer, boolean accessOnLoad, ReplicaterFactory replicaterFactory) {
+		super(sessionPool, attributesFactory, valuePool, sessionWrapperFactory, sessionIdFactory, contextualiser, map, router, errorIfSessionNotAcquired);
+		(_streamer=streamer).init(this);
+		_accessOnLoad=accessOnLoad;
+		_replicaterFactory=replicaterFactory;
+	}
+	
+	protected ClassLoader _classLoader;
+	
+	public void init(ManagerConfig config) {
+		_classLoader= Thread.currentThread().getContextClassLoader();
+		super.init(config);
+	}
+	
+	public ClassLoader getClassLoader() {
+		return _classLoader;
+	}	
+	
+	/**
+	 * Register a ValueHelper for a particular type. During [de]serialisation
+	 * Objects flowing in/out of the persistance medium will be passed through this
+	 * Helper, which will have the opportunity to convert them between Serializable
+	 * and non-Serializable representations. Helpers will be returned in their registration
+	 * order, so this is significant (as an Object may implement more than one interface
+	 * or registered type).
+	 *
+	 * @param type
+	 * @param helper
+	 */
+	public void registerHelper(Class type, ValueHelper helper) {
+		_helpers.add(new HelperPair(type, helper));
+	}
+	
+	public boolean deregisterHelper(Class type) {
+		int l=_helpers.size();
+		for (int i=0; i<l; i++)
+			if (type.equals(((HelperPair)_helpers.get(i))._type)) {
+				_helpers.remove(i);
+				return true;
+			}
+		return false;
+	}
+	
+	public ValueHelper findHelper(Class type) {
+		int l=_helpers.size();
+		for (int i=0; i<l; i++) {
+			HelperPair p=(HelperPair)_helpers.get(i);
+			if (p._type.isAssignableFrom(type))
+				return p._helper;
+		}
+		return null;
+	}
+	
+	public boolean getHttpSessionAttributeListenersRegistered() {
+		return _attributeListeners.length>0;
+	}
+	
+	public boolean getDistributable() {
+		return true;
+	}
+	
+	public boolean getAccessOnLoad() {
+		return _accessOnLoad;
+	}
+	
+	public SynchronizedBoolean getShuttingDown() {
+		return _shuttingDown;
+	}
+	
+	public Streamer getStreamer() {
+		return _streamer;
+	}
+	
+	// ReplicableSessionConfig
+	
+	public Replicater getReplicater() {
+		return _replicaterFactory.create();
+	}
+	
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableSession.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableSession.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableSession.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableSession.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,69 @@
+/**
+ *
+ * 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.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Set;
+
+import org.codehaus.wadi.DistributableAttributesConfig;
+import org.codehaus.wadi.DistributableSessionConfig;
+import org.codehaus.wadi.Streamer;
+import org.codehaus.wadi.ValueHelper;
+
+/**
+ * A Standard Session enhanced with functionality associated with [de]serialisation - necessary to allow the movement of the session from jvm to jvm/storage.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.4 $
+ */
+
+public class DistributableSession extends StandardSession implements DistributableAttributesConfig {
+
+    public DistributableSession(DistributableSessionConfig config) {
+    	super(config);
+    }
+
+    public Streamer getStreamer() {
+    	return ((DistributableSessionConfig)_config).getStreamer();
+    }
+    
+    public void readContent(ObjectInput oi) throws IOException, ClassNotFoundException {
+        super.readContent(oi);
+        ((DistributableAttributes)_attributes).readContent(oi);
+    }
+    
+    public void writeContent(ObjectOutput oo) throws IOException {
+        super.writeContent(oo);
+        ((DistributableAttributes)_attributes).writeContent(oo);
+    }
+    
+    public byte[] getBodyAsByteArray() throws Exception {
+    	return Utils.getContent(this, getStreamer());
+    }
+    
+    public void setBodyAsByteArray(byte[] bytes) throws IOException, ClassNotFoundException {
+    	Utils.setContent(this, bytes, getStreamer());
+    }
+    
+    public ValueHelper findHelper(Class type){return ((DistributableSessionConfig)_config).findHelper(type);}
+    public Set getListenerNames(){return ((DistributableAttributes)_attributes).getListenerNames();}
+    
+    // Lazy
+    public boolean getHttpSessionAttributeListenersRegistered(){return ((DistributableSessionConfig)_config).getHttpSessionAttributeListenersRegistered();}
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableSessionFactory.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableSessionFactory.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableSessionFactory.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableSessionFactory.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,29 @@
+/**
+ *
+ * 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.DistributableSessionConfig;
+import org.codehaus.wadi.Session;
+import org.codehaus.wadi.SessionConfig;
+import org.codehaus.wadi.SessionFactory;
+
+public class DistributableSessionFactory implements SessionFactory {
+
+    public Session create(SessionConfig config) {
+        return new DistributableSession((DistributableSessionConfig)config);
+    }
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableValue.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableValue.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableValue.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableValue.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.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+
+import javax.servlet.http.HttpSessionActivationListener;
+
+import org.codehaus.wadi.DistributableValueConfig;
+import org.codehaus.wadi.SerializableContent;
+import org.codehaus.wadi.ValueHelper;
+
+/**
+ * An attribute Value that supports the notification of HttpSessionActivationListeners at the correct
+ * times as well as the substition of non-Serializable content with the results of pluggable Helpers.
+ * This allows us to deal with the special cases mentioned in J2EE.6.4 in a non
+ * app-server specific manner. In other words, we can deal with attributes that
+ * are non-serialisable, provided that the application writer provides a mechanism
+ * for their persistance. Types such as EJBHome, EJBObject etc. are likely to be placed
+ * into distributable Sessions.
+ * It does not expect to be accessed after serialisation, until a fresh deserialisation has occurred.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.2 $
+ */
+
+public class DistributableValue extends StandardValue implements SerializableContent  {
+    
+    public DistributableValue(DistributableValueConfig config) {super(config);}
+    
+    protected ValueHelper _helper;
+    
+    public synchronized Object setValue(Object newValue) {
+    	// set up helper if needed or warn if needed but not available...
+        if (newValue!=null && !(newValue instanceof Serializable) && (_helper=((DistributableValueConfig)_config).findHelper(newValue.getClass()))==null)
+            throw new IllegalArgumentException("Distributable HttpSession attribute values must be Serializable or of other designated type (see SRV.7.7.2)");
+
+        return super.setValue(newValue);
+    }
+     
+    public synchronized void writeContent(ObjectOutput oo) throws IOException {
+    	// make necessary notification
+        if (_value!=null && _value instanceof HttpSessionActivationListener) {
+            ((HttpSessionActivationListener)_value).sessionWillPassivate(_config==null?null:((DistributableValueConfig)_config).getHttpSessionEvent());
+        }
+
+        // use helper, if present, to serialise
+        Object value=(_helper==null?_value:_helper.replace(_value));
+        
+        oo.writeObject(value);
+    }
+    
+    public synchronized void readContent(ObjectInput oi) throws IOException, ClassNotFoundException {
+    	_value=oi.readObject();
+    	
+        // reinstate helper, if one was used.
+        if (_value!=null && !(_value instanceof Serializable))
+            _helper=((DistributableValueConfig)_config).findHelper(_value.getClass());
+
+    	// make necessary notification
+        if (_value!=null && _value instanceof HttpSessionActivationListener) {
+            ((HttpSessionActivationListener)_value).sessionDidActivate(_config==null?null:((DistributableValueConfig)_config).getHttpSessionEvent());
+        }
+    }
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableValueFactory.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableValueFactory.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableValueFactory.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DistributableValueFactory.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.DistributableValueConfig;
+import org.codehaus.wadi.Value;
+import org.codehaus.wadi.ValueConfig;
+import org.codehaus.wadi.ValueFactory;
+
+/**
+ * TODO - JavaDoc this type
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.1 $
+ */
+
+public class DistributableValueFactory implements ValueFactory {
+
+    public DistributableValueFactory() {
+        super();
+    }
+
+    public Value create(ValueConfig config) {
+        return new DistributableValue((DistributableValueConfig)config);
+    }
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyContextualiser.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyContextualiser.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyContextualiser.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyContextualiser.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,87 @@
+/**
+ *
+ * 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.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 EDU.oswego.cs.dl.util.concurrent.Sync;
+
+/**
+ * A Contextualiser that does no contextualising
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.2 $
+ */
+public class DummyContextualiser extends AbstractContextualiser {
+	
+	public DummyContextualiser() {
+		super();
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.codehaus.wadi.sandbox.context.Contextualiser#contextualise(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain, java.lang.String, org.codehaus.wadi.sandbox.context.Contextualiser)
+	 */
+	public boolean contextualise(InvocationContext invocationContext, String id, Immoter immoter, Sync motionLock, boolean exclusiveOnly) throws InvocationException {
+		return false;
+	}
+	
+	protected final Evicter _evicter=new DummyEvicter();
+	public Evicter getEvicter(){return _evicter;}
+	
+	public boolean isExclusive(){return false;}
+	
+	public class DummyImmoter implements Immoter {
+		public Motable nextMotable(String id, Motable emotable){return null;}
+		public String getInfo(){return "dummy";}
+		
+		public boolean prepare(String name, Motable emotable, Motable immotable) {return true;}
+		
+		public void commit(String name, Motable immotable) {
+			// throw away incoming state...
+		}
+		
+		public void rollback(String name, Motable immotable) {
+			// nothing to do...
+		}
+		
+		public boolean contextualise(InvocationContext invocationContext, String id, Motable immotable, Sync motionLock) throws InvocationException {
+			return false;
+		}
+	}
+	
+	protected final Immoter _immoter=new DummyImmoter();
+	public Immoter getDemoter(String name, Motable motable) {return _immoter;}
+	public Immoter getSharedDemoter(){return _immoter;}
+	
+	public void promoteToExclusive(Immoter immoter){/* empty */}
+	public void load(Emoter emoter, Immoter immoter) {/* empty */}
+	
+	public void setLastAccessedTime(Evictable evictable, long oldTime, long newTime) {/* do nothing */}
+	public void setMaxInactiveInterval(Evictable evictable, int oldInterval, int newInterval) {/* do nothing */}
+	
+	
+	public int getLocalSessionCount() {
+		return 0;
+	}
+	
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyContextualiserConfig.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyContextualiserConfig.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyContextualiserConfig.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyContextualiserConfig.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,73 @@
+/**
+ *
+ * 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.Timer;
+
+import org.codehaus.wadi.ContextualiserConfig;
+import org.codehaus.wadi.Immoter;
+import org.codehaus.wadi.Motable;
+import org.codehaus.wadi.Router;
+import org.codehaus.wadi.SessionPool;
+
+public class DummyContextualiserConfig implements ContextualiserConfig {
+
+    public DummyContextualiserConfig() {
+        super();
+        // TODO Auto-generated constructor stub
+    }
+
+    public int getMaxInactiveInterval() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public void expire(Motable motable) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public Immoter getEvictionImmoter() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Timer getTimer() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public SessionPool getSessionPool() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Router getRouter() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    
+    public void notifySessionInsertion(String name) {
+    }
+    
+    public void notifySessionDeletion(String name) {
+    }
+
+    public void notifySessionRelocation(String name) {
+    }
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyDistributableContextualiserConfig.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyDistributableContextualiserConfig.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyDistributableContextualiserConfig.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyDistributableContextualiserConfig.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,110 @@
+/**
+ *
+ * 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.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.codehaus.wadi.Contextualiser;
+import org.codehaus.wadi.DistributableContextualiserConfig;
+import org.codehaus.wadi.dindex.impl.DIndex;
+import org.codehaus.wadi.gridstate.Dispatcher;
+import org.codehaus.wadi.gridstate.ExtendedCluster;
+
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
+
+public class DummyDistributableContextualiserConfig extends DummyContextualiserConfig implements DistributableContextualiserConfig {
+	
+	protected final ExtendedCluster _cluster;
+	
+	public DummyDistributableContextualiserConfig(ExtendedCluster cluster) {
+		super();
+		_cluster=cluster;
+	}
+	
+	public ClassLoader getClassLoader() {
+		return getClass().getClassLoader();
+	}
+	
+	public ExtendedCluster getCluster() {
+		return _cluster;
+	}
+	
+	public String getNodeName() {
+		return "dummy";
+	}
+	
+	public InetSocketAddress getHttpAddress() {
+		return null;
+	}
+	
+	protected Map _state=new HashMap();
+	
+	public Object getDistributedState(Object key) {
+		return _state.get(key);
+	}
+	
+	public Object putDistributedState(Object key, Object newValue) {
+		return _state.put(key, newValue);
+	}
+	
+	public Object removeDistributedState(Object key) {
+		return _state.remove(key);
+	}
+	
+	public void distributeState() {
+	}
+	
+	public boolean getAccessOnLoad() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+	
+	public SynchronizedBoolean getShuttingDown() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+	
+	public Map getDistributedState() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+	
+	public long getInactiveTime() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+	
+	public int getNumPartitions() {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+	
+	public Dispatcher getDispatcher() {
+		return null;
+	}
+	
+	public DIndex getDIndex() {
+		return null;
+	}
+	
+	public Contextualiser getContextualiser() {
+		return null;
+	}
+	
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyEvicter.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyEvicter.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyEvicter.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyEvicter.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 org.codehaus.wadi.Evictable;
+
+public class DummyEvicter extends AbstractEvicter {
+
+    public void evict() {/* do nothing */}
+    public boolean test(Evictable evictable, long time, long ttl) {return false;}
+    
+    public void setLastAccessedTime(Evictable evictable, long oldTime, long newTime) {/* do nothing */}
+    public void setMaxInactiveInterval(Evictable evictable, int oldInterval,int newInterval) {/* do nothing */}
+    public void insert(Evictable evictable) {/* do nothing */}
+    public void remove(Evictable evictable) {/* do nothing */}
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyHttpServletRequest.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyHttpServletRequest.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyHttpServletRequest.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyHttpServletRequest.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,96 @@
+/**
+ *
+ * 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.BufferedReader;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Since HttpServletRequestWrapper insists on having a valid delegate at
+ * all times, we need a dummy to use in our cached ThreadLocal whilst it is
+ * not being used - yeugh !
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.1 $
+ */
+
+public class DummyHttpServletRequest implements HttpServletRequest {
+
+	public String getAuthType(){throw new UnsupportedOperationException();}
+	public Cookie[] getCookies(){throw new UnsupportedOperationException();}
+	public long getDateHeader(String name){throw new UnsupportedOperationException();}
+	public String getHeader(String name){throw new UnsupportedOperationException();}
+	public Enumeration getHeaders(String name){throw new UnsupportedOperationException();}
+	public Enumeration getHeaderNames(){throw new UnsupportedOperationException();}
+	public int getIntHeader(String name){throw new UnsupportedOperationException();}
+	public String getMethod(){throw new UnsupportedOperationException();}
+	public String getPathInfo(){throw new UnsupportedOperationException();}
+	public String getPathTranslated(){throw new UnsupportedOperationException();}
+	public String getContextPath(){throw new UnsupportedOperationException();}
+	public String getQueryString(){throw new UnsupportedOperationException();}
+	public String getRemoteUser(){throw new UnsupportedOperationException();}
+	public boolean isUserInRole(String role){throw new UnsupportedOperationException();}
+	public Principal getUserPrincipal(){throw new UnsupportedOperationException();}
+	public String getRequestedSessionId(){throw new UnsupportedOperationException();}
+	public String getRequestURI(){throw new UnsupportedOperationException();}
+	public StringBuffer getRequestURL(){throw new UnsupportedOperationException();}
+	public String getServletPath(){throw new UnsupportedOperationException();}
+	public HttpSession getSession(boolean create){throw new UnsupportedOperationException();}
+	public HttpSession getSession(){throw new UnsupportedOperationException();}
+	public boolean isRequestedSessionIdValid(){throw new UnsupportedOperationException();}
+	public boolean isRequestedSessionIdFromCookie(){throw new UnsupportedOperationException();}
+	public boolean isRequestedSessionIdFromURL(){throw new UnsupportedOperationException();}
+	public boolean isRequestedSessionIdFromUrl(){throw new UnsupportedOperationException();}
+	public Object getAttribute(String name){throw new UnsupportedOperationException();}
+	public Enumeration getAttributeNames(){throw new UnsupportedOperationException();}
+	public String getCharacterEncoding(){throw new UnsupportedOperationException();}
+	public void setCharacterEncoding(String en){throw new UnsupportedOperationException();}
+	public int getContentLength(){throw new UnsupportedOperationException();}
+	public String getContentType(){throw new UnsupportedOperationException();}
+	public ServletInputStream getInputStream(){throw new UnsupportedOperationException();}
+	public String getParameter(String name){throw new UnsupportedOperationException();}
+	public Enumeration getParameterNames(){throw new UnsupportedOperationException();}
+	public String[] getParameterValues(String name){throw new UnsupportedOperationException();}
+	public Map getParameterMap(){throw new UnsupportedOperationException();}
+	public String getProtocol(){throw new UnsupportedOperationException();}
+	public String getScheme(){throw new UnsupportedOperationException();}
+	public String getServerName(){throw new UnsupportedOperationException();}
+	public int getServerPort(){throw new UnsupportedOperationException();}
+	public BufferedReader getReader(){throw new UnsupportedOperationException();}
+	public String getRemoteAddr(){throw new UnsupportedOperationException();}
+	public String getRemoteHost(){throw new UnsupportedOperationException();}
+	public void setAttribute(String name, Object o){throw new UnsupportedOperationException();}
+	public void removeAttribute(String name){throw new UnsupportedOperationException();}
+	public Locale getLocale(){throw new UnsupportedOperationException();}
+	public Enumeration getLocales(){throw new UnsupportedOperationException();}
+	public boolean isSecure(){throw new UnsupportedOperationException();}
+	public RequestDispatcher getRequestDispatcher(String path){throw new UnsupportedOperationException();}
+	public String getRealPath(String path){throw new UnsupportedOperationException();}
+	public int getRemotePort(){throw new UnsupportedOperationException();}
+	public String getLocalName(){throw new UnsupportedOperationException();}
+	public String getLocalAddr(){throw new UnsupportedOperationException();}
+	public int getLocalPort(){throw new UnsupportedOperationException();}
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyRelocater.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyRelocater.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyRelocater.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyRelocater.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.Immoter;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.InvocationException;
+import org.codehaus.wadi.Relocater;
+import org.codehaus.wadi.RelocaterConfig;
+
+import EDU.oswego.cs.dl.util.concurrent.Sync;
+
+public class DummyRelocater implements Relocater {
+	
+	public void init(RelocaterConfig config) {
+		// empty
+	}
+	
+	public void destroy() {
+		// empty
+	}
+	
+	public boolean relocate(InvocationContext invocationContext, String name, Immoter immoter, Sync motionLock) throws InvocationException {
+		return true;
+	}
+	
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyReplicater.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyReplicater.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyReplicater.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyReplicater.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,40 @@
+/**
+ *
+ * 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;
+
+public class DummyReplicater implements Replicater {
+
+	public boolean getReusingStore() {
+		return false;
+	}
+	
+	public void create(Object tmp) {
+    	// empty
+    }
+    
+    public void update(Object tmp) { //TODO
+    	// empty
+	}
+
+    public void destroy(Object tmp) { //TODO
+    	// empty
+	}
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyReplicaterFactory.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyReplicaterFactory.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyReplicaterFactory.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyReplicaterFactory.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,25 @@
+/**
+ *
+ * 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;
+
+public class DummyReplicaterFactory extends StatelessReplicaterFactory {
+
+	public DummyReplicaterFactory() {
+		super(new DummyReplicater());
+	}
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyRouter.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyRouter.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyRouter.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyRouter.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,74 @@
+/**
+ *
+ * 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.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.Router;
+import org.codehaus.wadi.RouterConfig;
+
+public class DummyRouter implements Router {
+	
+	protected RouterConfig _config;
+	
+	public void init(RouterConfig config) {
+		_config=config;
+	}
+	
+	public void destroy() {
+		_config=null;
+	}
+	
+	public String strip(String session) {
+		return session;
+	}
+	
+	public String augment(String session) {
+		return session;
+	}
+	
+	public String getInfo() {
+		return "";
+	}
+	
+	public boolean canReroute() {
+		return false;
+	}
+	
+	public boolean reroute(InvocationContext invocationContext) {
+		return false;
+	}
+	
+	public boolean rerouteCookie(HttpServletRequest req, HttpServletResponse res, String id) {
+		return false;
+	}
+	
+	public boolean rerouteCookie(HttpServletRequest req, HttpServletResponse res, String id, String route) {
+		return false;
+	}
+	
+	public boolean rerouteURL() {
+		return false;
+	}
+	
+	public boolean rerouteURL(String target) {
+		return false;
+	}
+	
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummySessionWrapperFactory.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummySessionWrapperFactory.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummySessionWrapperFactory.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummySessionWrapperFactory.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,28 @@
+/**
+ *
+ * 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 org.codehaus.wadi.Session;
+import org.codehaus.wadi.SessionWrapperFactory;
+
+public class DummySessionWrapperFactory implements SessionWrapperFactory {
+
+    public HttpSession create(Session session) {return new SessionWrapper(session);}
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyStatefulHttpServletRequestWrapperPool.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyStatefulHttpServletRequestWrapperPool.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyStatefulHttpServletRequestWrapperPool.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/DummyStatefulHttpServletRequestWrapperPool.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,32 @@
+/**
+ *
+ * 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.PoolableInvocationWrapper;
+import org.codehaus.wadi.PoolableInvocationWrapperPool;
+
+public class DummyStatefulHttpServletRequestWrapperPool implements PoolableInvocationWrapperPool {
+	
+	public PoolableInvocationWrapper take() {
+		return new StatefulHttpServletRequestWrapper();
+	}
+	
+	public void put(PoolableInvocationWrapper wrapper) {
+		// just drop it...
+	}
+	
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ExclusiveStoreContextualiser.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ExclusiveStoreContextualiser.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ExclusiveStoreContextualiser.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/ExclusiveStoreContextualiser.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,141 @@
+/**
+ *
+ * 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.File;
+import java.util.Map;
+
+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.Evicter;
+import org.codehaus.wadi.Immoter;
+import org.codehaus.wadi.Motable;
+import org.codehaus.wadi.Store;
+import org.codehaus.wadi.StoreMotable;
+import org.codehaus.wadi.Streamer;
+
+// TODO - a JDBC-based equivalent
+
+/**
+ * Maps id:File where file contains Context content...
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.5 $
+ */
+public class ExclusiveStoreContextualiser extends AbstractExclusiveContextualiser {
+
+    protected final Store _store;
+    protected final Immoter _immoter;
+	protected final Emoter _emoter;
+
+	public ExclusiveStoreContextualiser(Contextualiser next, Collapser collapser, boolean clean, Evicter evicter, Map map, Streamer streamer, File dir) throws Exception {
+	    super(next, new CollapsingLocker(collapser), clean, evicter, map);
+        _store=new DiscStore(streamer, dir, true, false);
+	    _immoter=new ExclusiveStoreImmoter(_map);
+	    _emoter=new ExclusiveStoreEmoter(_map);
+	}
+
+    public void init(ContextualiserConfig config) {
+        super.init(config);
+        // perhaps this should be done in start() ?
+        if (_clean)
+            _store.clean();
+    }
+
+    public String getStartInfo() {
+        return "["+_store.getStartInfo()+"]";
+    }
+
+	public boolean isExclusive(){return true;}
+
+	public Immoter getImmoter(){return _immoter;}
+	public Emoter getEmoter(){return _emoter;}
+
+	/**
+	 * An Immoter that deals in terms of StoreMotables
+	 *
+	 * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+	 * @version $Revision: 1.5 $
+	 */
+	public class ExclusiveStoreImmoter extends AbstractMappedImmoter {
+
+	    public ExclusiveStoreImmoter(Map map) {
+	        super(map);
+	    }
+
+		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();
+		}
+	}
+
+	/**
+	 * An Emmoter that deals in terms of StoreMotables
+	 *
+	 * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+	 * @version $Revision: 1.5 $
+	 */
+	class ExclusiveStoreEmoter extends AbstractMappedEmoter {
+
+		public ExclusiveStoreEmoter(Map map) {super(map);}
+
+		public String getInfo(){return _store.getDescription();}
+	}
+
+    public void start() throws Exception {
+        Store.Putter putter=new Store.Putter() {
+            public void put(String name, Motable motable) {
+                _map.put(name, motable);
+            }
+        };
+        _store.load(putter, ((DistributableContextualiserConfig)_config).getAccessOnLoad());
+        super.start(); // continue down chain...
+    }
+
+    // this should move up.....
+    public void expire(Motable motable) {
+        // decide whether session needs promotion
+        boolean needsLoading=true; // FIXME
+        // if so promote to top and expire there
+        String id=motable.getName();
+        if (_log.isTraceEnabled()) _log.trace("expiring from disc: "+id);
+        if (needsLoading) {
+            _map.remove(id);
+            Motable loaded=_config.getSessionPool().take();
+            try {
+                loaded.copy(motable);
+                motable=null;
+                _config.expire(loaded);
+            } catch (Exception e) {
+	      _log.error("unexpected problem expiring from disc", e);
+            }
+            loaded=null;
+        } else {
+            // else, just drop it off the disc here...
+            throw new UnsupportedOperationException(); // FIXME
+        }
+    }
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/Filter.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/Filter.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/Filter.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/Filter.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,140 @@
+/**
+ *
+ * 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 javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+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.Contextualiser;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.InvocationException;
+import org.codehaus.wadi.PoolableInvocationWrapper;
+import org.codehaus.wadi.PoolableInvocationWrapperPool;
+import org.codehaus.wadi.Router;
+
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
+
+public class Filter implements javax.servlet.Filter {
+	
+	protected final Log _log = LogFactory.getLog(getClass());
+	
+	protected StandardManager _manager;
+	protected boolean _distributable;
+	protected Contextualiser _contextualiser;
+	protected Router _router;
+	protected PoolableInvocationWrapperPool _pool=new DummyStatefulHttpServletRequestWrapperPool(); // TODO - init from _manager
+	protected boolean _errorIfSessionNotAcquired;
+	protected SynchronizedBoolean _acceptingSessions;
+	
+	// Filter Lifecycle
+	
+	public void
+	init(FilterConfig filterConfig) throws ServletException
+	{
+		_manager=(StandardManager)filterConfig.getServletContext().getAttribute(StandardManager.class.getName());
+		if (_manager==null)
+			_log.fatal("Manager not found");
+		else
+			if (_log.isInfoEnabled())_log.info("Manager found: "+_manager);
+		
+		_manager.setFilter(this);
+		_distributable=_manager.getDistributable();
+		_contextualiser=_manager.getContextualiser();
+		_router=_manager.getRouter();
+		_errorIfSessionNotAcquired=_manager.getErrorIfSessionNotAcquired();
+		_acceptingSessions=_manager.getAcceptingSessions();
+	}
+	
+	public void setManager(StandardManager manager) {
+		_manager=manager;
+	}
+	
+	public void
+	destroy()
+	{
+		_pool=null;
+		_contextualiser=null;
+		_distributable=false;
+		_manager=null;
+	}
+	
+	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+		if (request instanceof HttpServletRequest)
+			doFilter((HttpServletRequest)request, (HttpServletResponse)response, chain);
+		else // this one is not HTTP - therefore it is and will remain, stateless - not for us...
+			chain.doFilter(request, response);
+	}
+	
+	public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
+		String sessionId=request.getRequestedSessionId();
+		if (_log.isTraceEnabled()) _log.trace("potentially stateful request: "+sessionId);
+		
+		InvocationContext invocationContext = new WebInvocationContext(request, response, chain);
+		
+		try {
+			if (sessionId==null) {
+				processSessionlessRequest(invocationContext);
+			} else {
+				// already associated with a session...
+				String name=_router.strip(sessionId); // strip off any routing info...
+				if (!_contextualiser.contextualise(invocationContext, name, null, null, false)) {
+					if (_log.isErrorEnabled()) _log.error("could not acquire session: " + name);
+					if (_errorIfSessionNotAcquired) // send the client a 503...
+						response.sendError(503, "session "+name+" is not known"); // TODO - should we allow custom error page ?
+					else // process request without session - it may create a new one...
+						processSessionlessRequest(invocationContext);
+				}
+			}
+		} catch (InvocationException e) {
+			Throwable throwable = e.getCause();
+			if (throwable instanceof IOException) {
+				throw (IOException) throwable;
+			} else if (throwable instanceof ServletException) {
+				throw (ServletException) throwable;
+			} else {
+				throw new ServletException(e);
+			}
+		}
+	}
+	
+	public void processSessionlessRequest(InvocationContext invocationContext) throws InvocationException {
+		// are we accepting sessions ? - otherwise proxy to another node...
+		// sync point - expensive, but will only hit sessionless requests...
+		if (!_acceptingSessions.get()) {
+			// think about what to do here... proxy or error page ?
+			_log.warn("sessionless request has arived during shutdown - permitting");
+			// TODO
+		}
+		
+		// no session yet - but may initiate one...
+		PoolableInvocationWrapper wrapper=_pool.take();
+		wrapper.init(invocationContext, null);
+		invocationContext.invoke(wrapper);
+		wrapper.destroy();
+		_pool.put(wrapper);
+	}
+	
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/FixedWidthSessionIdFactory.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/FixedWidthSessionIdFactory.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/FixedWidthSessionIdFactory.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/FixedWidthSessionIdFactory.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,171 @@
+/**
+ *
+ * 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.Random;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.SessionIdFactory;
+import org.codehaus.wadi.gridstate.PartitionMapper;
+
+public class FixedWidthSessionIdFactory implements SessionIdFactory, PartitionMapper {
+
+    protected final Log _log=LogFactory.getLog(getClass().getName());
+    
+	public String create() {
+		int width=_keyLength;
+		char[] buffer=new char[width];
+
+		int offset=width-1;
+		while ((offset=encode(Math.abs(_random.nextLong()), _sectLength, buffer, offset))>=0);
+
+		return new String(buffer);
+	}
+
+	public int getSessionIdLength() {
+		return _keyLength+_divider.length+_partitionLength;
+	}
+
+	public void setSessionIdLength(int l) {
+		//_width=l-_divider.length-_partitionSize;
+	}
+
+  //protected final static char[] _defaultChars="0123456789".toCharArray();
+  protected final static char[] _defaultChars="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
+
+  protected final char[] _divider="-".toCharArray();
+  //protected final char[] _divider="".toCharArray();
+  protected Random _random=new Random();
+  protected final int[] _lookup=new int[Character.MAX_VALUE];
+
+  protected final int _keyLength;
+  protected final char[] _chars;
+  protected final int _base;
+  protected final int _sectLength;
+  protected final int _numPartitions;
+  protected final int _partitionLength;
+
+  public FixedWidthSessionIdFactory(int width, int numPartitions) {
+    this(width, _defaultChars, numPartitions);
+  }
+
+  public FixedWidthSessionIdFactory(int width, char[] chars, int numPartitions) {
+    _keyLength=width;
+    _chars=chars;
+    _base=_chars.length;
+    _numPartitions=numPartitions;
+    _partitionLength=size(_numPartitions);
+
+    //    System.out.println("radix="+_radix);
+    // initialise reverse lookup table...
+    for (int i=0; i<_base; i++)
+      _lookup[_chars[i]]=i;
+
+    // calculate how many digits max-long would render in the given
+    // base...
+    //    System.out.println("max="+Long.MAX_VALUE);
+    _sectLength=size(Long.MAX_VALUE);
+    //    System.out.println("iters="+_iters);
+  }
+
+  public String create(int partition) {
+    int width=_keyLength+_divider.length+_partitionLength;
+    char[] buffer=new char[width];
+
+    int offset=width-1;
+    offset=encode(partition, _partitionLength, buffer, offset);
+
+    for (int i=_divider.length-1; i>=0; i--)
+      buffer[offset--]=_divider[i];
+
+    while ((offset=encode(Math.abs(_random.nextLong()), _sectLength, buffer, offset))>=0);
+
+    return new String(buffer);
+  }
+
+  protected int encode(long sect, int iters, char[] buffer, int offset) {
+    for (int i=0; i<iters && offset>=0; i++) {
+      //      System.out.println(""+i+" - "+source);
+      buffer[offset--]=_chars[(int)(sect%_base)];
+      sect/=_base;
+    }
+    return offset;
+  }
+
+  public int getPartition(String key) {
+    return decode(key.toCharArray(), key.length()-_partitionLength, _partitionLength);
+  }
+
+  protected int decode(char[] buffer, int from, int length) {
+    int result=0;
+    int multiplier=1;
+    for (int i=from+length-1; i>=from; i--) {
+      //      System.out.println(""+buffer[i]+" - "+_lookup[buffer[i]]);
+      result+=_lookup[buffer[i]]*multiplier;
+      multiplier*=_base;
+    }
+    return result;
+  }
+
+  protected int size(long l) {
+    int i=0;
+    while (l!=0) {
+      l/=_base;
+      i++;
+    }
+    return i;
+  }
+
+  protected int size(int n) {
+    int i=0;
+    while (n!=0) {
+      n/=_base;
+      i++;
+    }
+    return i;
+  }
+
+  public static void main(String[] args) {
+    int numPartitions=1024;
+    FixedWidthSessionIdFactory factory=new FixedWidthSessionIdFactory(32, numPartitions);
+    Random r=new Random();
+    for (int i=0; i<numPartitions; i++) {
+      int partition=Math.abs(r.nextInt())%numPartitions;
+      String key=factory.create(partition);
+      System.out.println(key+" - "+partition);
+      assert partition==factory.getPartition(key);
+    }
+  }
+
+  // PartitionMapper API
+
+  public int map(Object key) {
+	  int index=getPartition((String)key);
+	  _log.info("mapped "+key+" -> "+index);
+	  return index;
+  }
+
+  // should we shuffle the _chars used for the key ?
+  // cannot shuffle _chars for partition - since must be the same on every node
+  // rename name->key where dealing with sessions...
+
+  // when we allocate a session, we need to decide which partition to put it in
+  // allocation and entry into partition must be atomic - I guess the entry could chase the partition...
+
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/GZIPStreamer.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/GZIPStreamer.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/GZIPStreamer.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/GZIPStreamer.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,64 @@
+/**
+ *
+ * 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.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import org.codehaus.wadi.Streamer;
+import org.codehaus.wadi.StreamerConfig;
+
+/**
+ * Pluggable support for [un]GZIP-ing sessions as they are exchanged with
+ * peers or long-term storage mechanisms.
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.2 $
+ */
+public class GZIPStreamer implements Streamer {
+	
+	protected StreamerConfig _config;
+	
+	public void init(StreamerConfig config) {
+		_config=config;
+	}
+	
+	public ObjectInput getInputStream(InputStream is) throws IOException {
+		return new ObjectInputStream(new GZIPInputStream(is), _config.getClassLoader());
+	}
+	
+	public ObjectOutput getOutputStream(OutputStream os) throws IOException {
+		return new ObjectOutputStream(new GZIPOutputStream(os));
+	}
+	
+	public String getSuffix() {
+		return "gz";
+	}
+	
+	public String getSuffixWithDot() {
+		return ".gz";
+	}
+	
+}
+

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/GiannisContextualiser.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/GiannisContextualiser.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/GiannisContextualiser.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/GiannisContextualiser.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,163 @@
+/**
+ *
+ * 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.sql.Connection;
+import java.sql.SQLException;
+import java.util.Map;
+
+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.Evicter;
+import org.codehaus.wadi.Immoter;
+import org.codehaus.wadi.Motable;
+import org.codehaus.wadi.Store;
+import org.codehaus.wadi.StoreMotable;
+
+/**
+ * Maps id:File where file contains Context content...
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.8 $
+ */
+public class GiannisContextualiser extends AbstractExclusiveContextualiser {
+
+    protected final Immoter _immoter;
+	protected final Emoter _emoter;
+	protected final DatabaseStore _store;
+
+	public GiannisContextualiser(Contextualiser next, Collapser collapser, boolean clean, Evicter evicter, Map map, DatabaseStore dbstore) throws Exception {
+	    super(next, new CollapsingLocker(collapser), clean, evicter, map);
+	    _immoter=new GiannisImmoter(_map);
+	    _emoter=new GiannisEmoter(_map);
+	    _store=dbstore;
+	}
+
+    public void init(ContextualiserConfig config) {
+        super.init(config);
+        // perhaps this should be done in start() ?
+        if (_clean)
+            _store.clean();
+    }
+
+    public String getStartInfo() {
+        return "["+_store.getLabel()+"/"+_store.getTable()+"] : "+_map.size()+" sessions loaded";
+    }
+
+	public boolean isExclusive(){
+		return true;
+	}
+
+	public Immoter getImmoter() {
+		return _immoter;
+	}
+
+	public Emoter getEmoter(){
+		return _emoter;
+	}
+
+	class GiannisImmoter extends AbstractMappedImmoter {
+
+	    public GiannisImmoter(Map map) {
+	        super(map);
+	    }
+
+		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();
+		}
+	}
+
+	class GiannisEmoter extends AbstractMappedEmoter {
+
+		public GiannisEmoter(Map map) {super(map);}
+
+		public String getInfo() {
+			return _store.getDescription();
+		}
+	}
+
+    public void start() throws Exception {
+    	// TODO - consider moving into load...
+    	Store.Putter putter=new Store.Putter() {
+    		public void put(String name, Motable motable) {
+    			_map.put(name, motable);
+    		}
+        };
+        _store.load(putter, ((DistributableContextualiserConfig)_config).getAccessOnLoad());
+
+        super.start(); // continue down chain...
+    }
+
+    // this should move up.....
+    public void expire(Motable motable) {
+        // decide whether session needs promotion
+        boolean needsLoading=true; // FIXME
+        // if so promote to top and expire there
+        String id=motable.getName();
+        if (_log.isTraceEnabled()) _log.trace("expiring from store: "+id);
+        if (needsLoading) {
+            _map.remove(id);
+            Motable loaded=_config.getSessionPool().take();
+            Connection connection=null;
+            DatabaseMotable dbm=(DatabaseMotable)motable;
+            try {
+            	connection=_store.getDataSource().getConnection();
+            	dbm.setConnection(connection);
+                loaded.copy(dbm);
+                dbm.setConnection(null);
+                _config.expire(loaded);
+            } catch (Exception e) {
+	      _log.error("unexpected problem expiring from store", e);
+            } finally {
+            	if (connection!=null) {
+            		try {
+            		connection.close();
+            		} catch (SQLException e) {
+			  _log.warn("unexpected problem closing connection", e);
+            		}
+            	}
+            }
+            loaded=null;
+        } else {
+            // else, just drop it off the disc here...
+            throw new UnsupportedOperationException(); // FIXME
+        }
+    }
+
+    public void load(Emoter emoter, Immoter immoter) { // - TODO - is this where we should do our own load ?
+        // MappedContextualisers are all Exclusive
+    }
+
+    protected void unload() {
+        if (_log.isInfoEnabled()) _log.info("unloaded sessions: " + _map.size());
+    	_map.clear();
+	}
+
+    public Immoter getSharedDemoter() {
+    	return getImmoter();
+    }
+
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HashingCollapser.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HashingCollapser.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HashingCollapser.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HashingCollapser.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,59 @@
+/**
+ *
+ * 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.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.Collapser;
+
+import EDU.oswego.cs.dl.util.concurrent.Mutex;
+import EDU.oswego.cs.dl.util.concurrent.Sync;
+import EDU.oswego.cs.dl.util.concurrent.TimeoutSync;
+
+/**
+ * A lock Collapser that collapses according to hash code
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.1 $
+ */
+public class HashingCollapser implements Collapser {
+	protected final Log    _log = LogFactory.getLog(getClass());
+	protected final int    _numSyncs;
+	protected final Sync[] _syncs;
+	protected final long   _timeout;
+
+	/**
+	 *
+	 */
+	public HashingCollapser(int numSyncs, long timeout) {
+		super();
+		_numSyncs=numSyncs;
+		_timeout=timeout;
+		_syncs=new Sync[_numSyncs];
+		for (int i=0; i<_numSyncs; i++)
+			_syncs[i]=new TimeoutSync(new Mutex(), _timeout);
+	}
+
+	/* (non-Javadoc)
+	 * @see org.codehaus.wadi.sandbox.context.Collapser#getLock(java.lang.String)
+	 */
+	public Sync getLock(String id) {
+		int index=Math.abs(id.hashCode()%_numSyncs); // Jetty seems to generate negative session id hashcodes...
+		if (_log.isTraceEnabled()) _log.trace("collapsed "+id+" to index: "+index);
+		return _syncs[index];
+	}
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HttpProxyLocation.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HttpProxyLocation.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HttpProxyLocation.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HttpProxyLocation.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,64 @@
+/**
+ *
+ * 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.jms.Destination;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.InvocationProxy;
+import org.codehaus.wadi.Location;
+import org.codehaus.wadi.ProxiedLocation;
+import org.codehaus.wadi.ProxyingException;
+
+/**
+ * A Location that includes a hostname/ip-address and HTTP port
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.2 $
+ */
+
+public class HttpProxyLocation extends SimpleEvictable implements Location {
+	
+	protected final static Log _log = LogFactory.getLog(HttpProxyLocation.class);
+	
+	protected ProxiedLocation _location;
+	protected InvocationProxy _proxy;
+	
+	public HttpProxyLocation(Destination destination, ProxiedLocation location, InvocationProxy proxy) {
+		super();
+		_destination=destination;
+		_location=location;
+		_proxy=proxy;
+	}
+	
+	public void proxy(InvocationContext invocationContext) throws ProxyingException {
+		_proxy.proxy(_location, invocationContext);
+	}
+	
+	public String toString() {
+		return "<HttpProxyLocation:"+_location+">"; // we could include proxy strategy here...
+	}
+	
+	protected final Destination _destination;
+	
+	public Destination getDestination() {
+		return _destination;
+	}
+	
+}

Added: incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HybridRelocater.java
URL: http://svn.apache.org/viewcvs/incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HybridRelocater.java?rev=356933&view=auto
==============================================================================
--- incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HybridRelocater.java (added)
+++ incubator/wadi/trunk/modules/core/src/main/java/org/codehaus/wadi/impl/HybridRelocater.java Wed Dec 14 15:32:56 2005
@@ -0,0 +1,375 @@
+/**
+ *
+ * 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.nio.ByteBuffer;
+
+import javax.jms.JMSException;
+import javax.jms.ObjectMessage;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.codehaus.wadi.Contextualiser;
+import org.codehaus.wadi.Emoter;
+import org.codehaus.wadi.Immoter;
+import org.codehaus.wadi.InvocationContext;
+import org.codehaus.wadi.InvocationException;
+import org.codehaus.wadi.InvocationProxy;
+import org.codehaus.wadi.Motable;
+import org.codehaus.wadi.ProxiedLocation;
+import org.codehaus.wadi.RelocaterConfig;
+import org.codehaus.wadi.dindex.messages.RelocationAcknowledgement;
+import org.codehaus.wadi.dindex.messages.RelocationRequest;
+import org.codehaus.wadi.dindex.messages.RelocationResponse;
+import org.codehaus.wadi.gridstate.Dispatcher;
+
+import EDU.oswego.cs.dl.util.concurrent.Sync;
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
+import EDU.oswego.cs.dl.util.concurrent.TimeoutException;
+
+/**
+ * Combine various RelocationStrategies to produce a cleverer one
+ *
+ * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+ * @version $Revision: 1.23 $
+ */
+public class HybridRelocater extends AbstractRelocater {
+
+	protected final Log _log=LogFactory.getLog(getClass());
+	protected final long _requestHandOverTimeout=2000;// TODO - parameterise
+	protected final long _resTimeout;
+	protected final long _ackTimeout;
+	protected final boolean _sessionOrRequestPreferred; // true if relocation of session is preferred to relocation of request
+	protected final Log _lockLog=LogFactory.getLog("org.codehaus.wadi.LOCKS");
+
+	public HybridRelocater(long resTimeout, long ackTimeout, boolean sessionOrRequestPreferred) {
+		_resTimeout=resTimeout;
+		_ackTimeout=ackTimeout;
+		_sessionOrRequestPreferred=sessionOrRequestPreferred;
+	}
+
+	protected SynchronizedBoolean _shuttingDown;
+	protected Dispatcher _dispatcher;
+	protected String _nodeName;
+	protected Contextualiser _contextualiser;
+	protected InvocationProxy _proxy;
+
+	public void init(RelocaterConfig config) {
+		super.init(config);
+		_shuttingDown=_config.getShuttingDown();
+		_dispatcher=_config.getDispatcher();
+		_nodeName=_config.getNodeName();
+		_contextualiser=_config.getContextualiser();
+		_proxy=_config.getInvocationProxy();
+		_dispatcher.register(this, "onMessage", RelocationRequest.class);
+		_dispatcher.register(RelocationResponse.class, _resTimeout);
+		_dispatcher.register(RelocationAcknowledgement.class, _ackTimeout);
+	}
+
+	public boolean relocate(InvocationContext invocationContext, String name, Immoter immoter, Sync motionLock) throws InvocationException {
+		String sessionName=name;
+		String nodeName=_config.getNodeName();
+		boolean shuttingDown=_shuttingDown.get();
+		int concurrentRequestThreads=1;
+		RelocationResponse response=null;
+		ObjectMessage message2=null;
+
+		boolean useGridState=false;
+
+		if (useGridState) {
+			Motable immotable=null;
+			try {
+				immotable=_config.getDIndex().relocate2(sessionName, nodeName, concurrentRequestThreads, shuttingDown, _resTimeout);
+			} catch (Exception e) {
+				_log.error("unexpected error", e);
+			}
+
+			if (null==immotable) {
+				return false;
+			} else {
+				boolean answer=immoter.contextualise(invocationContext, name, immotable, motionLock);
+				return answer;
+			}
+		} else {
+
+			try {
+				message2=_config.getDIndex().relocate(sessionName, nodeName, concurrentRequestThreads, shuttingDown, _resTimeout);
+				if (message2==null || (response=(RelocationResponse)message2.getObject())==null)
+					return false;
+			} catch (Exception e) {
+				_log.warn("problem arranging relocation", e);
+			}
+
+			Motable emotable=response.getMotable();
+			if (emotable!=null) {
+				// relocate session...
+				if (!emotable.checkTimeframe(System.currentTimeMillis()))
+					if (_log.isWarnEnabled()) _log.warn("immigrating session has come from the future!: "+emotable.getName());
+
+				Emoter emoter=new RelocationEmoter(response.getNodeName(), message2);
+				Motable immotable=Utils.mote(emoter, immoter, emotable, name);
+				if (null==immotable)
+					return false;
+				else {
+					boolean answer=immoter.contextualise(invocationContext, name, immotable, motionLock);
+					return answer;
+				}
+
+			}
+
+			ProxiedLocation location = response.getProxiedLocation();
+			if (location!=null) {
+				// relocate request...
+				try {
+					//FIXME - API should not be in terms of HttpProxy but in terms of RequestRelocater...
+
+					_proxy.proxy(location, invocationContext);
+					_log.trace("PROXY WAS SUCCESSFUL");
+					motionLock.release();
+					return true;
+				} catch (Exception e) {
+					_log.error("problem proxying request", e);
+					return false;
+				}
+			}
+
+			// if we are still here - session could not be found
+			if (_log.isWarnEnabled()) _log.warn("session not found: " + sessionName);
+			return false;
+		}
+	}
+
+	/* We send a RelocationRequest out to fetch a Session. We receive a RelocationResponse containing the Session. We pass a RelocationEmoter
+	 * down the Contextualiser stack. It passes the incoming Session out to the relevant Contextualiser and sends a RelocationAcknowledgment
+	 * back to the src of the RelocationResponse. (could be done in a Motable like Immoter?)
+	 */
+
+	class RelocationEmoter extends AbstractChainedEmoter {
+		protected final Log _log=LogFactory.getLog(getClass());
+
+		protected final String _nodeName;
+		protected final ObjectMessage _message;
+
+		public RelocationEmoter(String nodeName, ObjectMessage message) {
+			_nodeName=nodeName;
+			_message=message;
+		}
+
+		public boolean prepare(String name, Motable emotable, Motable immotable) {
+			try {
+				immotable.copy(emotable);
+			} catch (Exception e) {
+				_log.warn(e);
+				return false;
+			}
+			_config.notifySessionRelocation(name);
+
+			// TODO - move some of this to prepare()...
+			if (_log.isTraceEnabled()) _log.trace("sending RelocationAcknowledgement");
+			RelocationAcknowledgement ack=new RelocationAcknowledgement();//(name, _config.getLocation());
+			if (!_config.getDispatcher().reply(_message, ack)) {
+				if (_log.isErrorEnabled()) _log.error("could not send RelocationAcknowledgement: "+name);
+				return false;
+			}
+
+			return true;
+		}
+
+		public void commit(String name, Motable emotable) {
+			try {
+				emotable.destroy(); // remove copy in store
+			} catch (Exception e) {
+				throw new UnsupportedOperationException("NYI"); // NYI
+			}
+		}
+
+		public void rollback(String name, Motable motable) {
+			throw new RuntimeException("NYI");
+		}
+
+		public String getInfo() {
+			return "immigration:"+_nodeName;
+		}
+	}
+
+	boolean getSessionOrRequestPreferred() {
+		return _sessionOrRequestPreferred;
+		// check out LB's capabilities during init()....
+	}
+
+	// the request arrives ...
+
+	public void onMessage(ObjectMessage om, RelocationRequest request) {
+		if (_log.isTraceEnabled()) _log.trace("RelocationRequest received from " + request.getNodeName() + " for " + request.getSessionName() + " on " + _nodeName);
+		// both of these may be out of date immediately... :-(
+		boolean theyAreShuttingDown=request.getShuttingDown();
+		boolean weAreShuttingDown=_shuttingDown.get();
+		boolean sessionOrRequestPreferred=_sessionOrRequestPreferred;
+
+		if (!theyAreShuttingDown && (weAreShuttingDown || sessionOrRequestPreferred)) {
+			relocateSessionToThem(om, request.getSessionName(), request.getNodeName());
+			return;
+		}
+
+		if (!weAreShuttingDown && (theyAreShuttingDown || !sessionOrRequestPreferred)) {
+			relocateRequestToUs(om, request.getSessionName());
+			return;
+		}
+
+		if (weAreShuttingDown && theyAreShuttingDown) {
+			// yikes !
+			// we need to relocate both session and request to a third, safe node
+			// think about it....
+			throw new UnsupportedOperationException("both source and target node are shutting down");
+		}
+	}
+
+	// response is to relocate session back to sender...
+
+	protected void relocateSessionToThem(ObjectMessage om, String sessionName, String nodeName) {
+		if (_log.isTraceEnabled()) _log.trace("relocating "+sessionName+" from "+_nodeName+" to "+nodeName);
+
+		Sync invocationLock=_config.getCollapser().getLock(sessionName);
+		boolean invocationLockAcquired=false;
+		try {
+			Utils.acquireUninterrupted("Invocation", sessionName, invocationLock);
+			invocationLockAcquired=true;
+		} catch (TimeoutException e) {
+			if (_log.isErrorEnabled()) _log.error("exclusive access could not be guaranteed within timeframe: "+sessionName, e);
+			return;
+		}
+
+		try {
+			// reverse direction...
+			Immoter promoter=new RelocationImmoter(nodeName, om);
+			RankedRWLock.setPriority(RankedRWLock.EMIGRATION_PRIORITY);
+			boolean found=_contextualiser.contextualise(null,sessionName, promoter, invocationLock, true); // if we own session, this will send the correct response...
+			if (found)
+				invocationLockAcquired=false; // someone else has released the promotion lock...
+		} catch (Exception e) {
+			if (_log.isWarnEnabled()) _log.warn("problem handling relocation request: "+sessionName, e);
+		} finally {
+			RankedRWLock.setPriority(RankedRWLock.NO_PRIORITY);
+			if (invocationLockAcquired) {
+				Utils.release("Invocation", sessionName, invocationLock);
+			}
+		}
+		// N.B. - I don't think it is necessary to acquire the motionLock - consider...
+		// TODO - if we see a LocationRequest for a session that we know is Dead - we should respond immediately.
+	}
+
+	class ClusterEmotable extends AbstractMotable {
+
+		protected final String _name;
+		protected final String _tgtNodeName;
+		protected ObjectMessage _message;
+
+		public ClusterEmotable(String name, String nodeName, ObjectMessage message) {
+			_name=name;
+			_tgtNodeName=nodeName;
+			_message=message;
+		}
+		public byte[] getBodyAsByteArray() throws Exception {
+			throw new UnsupportedOperationException();
+		}
+
+		public void setBodyAsByteArray(byte[] bytes) throws Exception {
+			// send the message
+			if (_log.isTraceEnabled()) _log.trace("sending RelocationResponse");
+			Motable immotable=new SimpleMotable();
+			immotable.setBodyAsByteArray(bytes);
+			RelocationResponse response=new RelocationResponse(_name, _nodeName, immotable);
+			ObjectMessage message=_dispatcher.exchangeReply(_message, response, _ackTimeout);
+			RelocationAcknowledgement ack=null;
+			ack=message==null?null:(RelocationAcknowledgement)message.getObject();
+
+			if (ack==null) {
+				if (_log.isWarnEnabled()) _log.warn("no ack received for session RelocationResponse"); // TODO - increment a counter somewhere...
+				// TODO - who owns the session now - consider a syn link to old owner to negotiate this..
+				throw new Exception("no ack received for session RelocationResponse");
+			}
+			if (_log.isTraceEnabled()) _log.trace("received relocation ack");
+		}
+
+		public ByteBuffer getBodyAsByteBuffer() throws Exception {
+			throw new UnsupportedOperationException();
+		}
+
+		public void setBodyAsByteBuffer(ByteBuffer body) throws Exception {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+
+	/**
+	 * We receive a RelocationRequest and pass a RelocationImmoter down the Contextualiser stack. The Session is passed to us
+	 * through the Immoter and we pass it back to the Request-ing node...
+	 *
+	 * @author <a href="mailto:jules@coredevelopers.net">Jules Gosnell</a>
+	 * @version $Revision: 1.23 $
+	 */
+	class RelocationImmoter implements Immoter {
+		protected final Log _log=LogFactory.getLog(getClass());
+
+		protected final String _tgtNodeName;
+		protected ObjectMessage _message;
+
+		public RelocationImmoter(String nodeName, ObjectMessage message) {
+			_tgtNodeName=nodeName;
+			_message=message;
+		}
+
+		public Motable nextMotable(String name, Motable emotable) {
+			return new ClusterEmotable(name, _tgtNodeName, _message);
+		}
+
+		public boolean prepare(String name, Motable emotable, Motable immotable) {
+			// work is done in ClusterEmotable...
+			return true;
+		}
+
+		public void commit(String name, Motable immotable) {
+			// do nothing
+		}
+
+		public void rollback(String name, Motable immotable) {
+			// this probably has to by NYI... - nasty...
+		}
+
+		public boolean contextualise(InvocationContext invocationContext, String id, Motable immotable, Sync motionLock) throws InvocationException {
+			return false;
+		}
+
+		public String getInfo() {
+			return "emigration:"+_tgtNodeName;
+		}
+	}
+
+	// response is to relocate http request from sender to us...
+
+	protected void relocateRequestToUs(ObjectMessage om, String sessionName) {
+		try {
+			String src=_config.getDIndex().getNodeName(om.getJMSReplyTo());
+			if (_log.isTraceEnabled()) _log.trace("arranging for request to be relocated - sending response to: " + src);
+			RelocationResponse response=new RelocationResponse(sessionName, _nodeName, _config.getProxiedLocation());
+			_config.getDispatcher().reply(om, response);
+		} catch (JMSException e) {
+			if (_log.isErrorEnabled()) _log.error("could not send RelocationResponse: "+sessionName, e);
+		}
+	}
+
+}



Mime
View raw message