001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.clustering.wadi;
018
019 import java.util.Collections;
020 import java.util.HashMap;
021 import java.util.Iterator;
022 import java.util.Map;
023 import java.util.regex.Pattern;
024
025 import javax.servlet.ServletContext;
026
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029 import org.apache.geronimo.clustering.Node;
030 import org.apache.geronimo.clustering.Session;
031 import org.apache.geronimo.clustering.SessionAlreadyExistException;
032 import org.apache.geronimo.clustering.SessionListener;
033 import org.apache.geronimo.clustering.SessionManager;
034 import org.apache.geronimo.gbean.GBeanInfo;
035 import org.apache.geronimo.gbean.GBeanInfoBuilder;
036 import org.apache.geronimo.gbean.GBeanLifecycle;
037 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
038 import org.codehaus.wadi.Collapser;
039 import org.codehaus.wadi.Contextualiser;
040 import org.codehaus.wadi.Emoter;
041 import org.codehaus.wadi.Evicter;
042 import org.codehaus.wadi.Immoter;
043 import org.codehaus.wadi.Invocation;
044 import org.codehaus.wadi.InvocationException;
045 import org.codehaus.wadi.Manager;
046 import org.codehaus.wadi.ManagerConfig;
047 import org.codehaus.wadi.Motable;
048 import org.codehaus.wadi.PoolableInvocationWrapperPool;
049 import org.codehaus.wadi.SessionPool;
050 import org.codehaus.wadi.Streamer;
051 import org.codehaus.wadi.group.Dispatcher;
052 import org.codehaus.wadi.impl.AbsoluteEvicter;
053 import org.codehaus.wadi.impl.ClusterContextualiser;
054 import org.codehaus.wadi.impl.ClusteredManager;
055 import org.codehaus.wadi.impl.DummyContextualiser;
056 import org.codehaus.wadi.impl.HashingCollapser;
057 import org.codehaus.wadi.impl.HybridRelocater;
058 import org.codehaus.wadi.impl.MemoryContextualiser;
059 import org.codehaus.wadi.impl.SerialContextualiserFrontingMemory;
060 import org.codehaus.wadi.impl.SimpleSessionPool;
061 import org.codehaus.wadi.impl.SimpleStreamer;
062 import org.codehaus.wadi.impl.SimpleValuePool;
063 import org.codehaus.wadi.impl.StatelessContextualiser;
064 import org.codehaus.wadi.replication.contextualizer.ReplicaAwareContextualiser;
065 import org.codehaus.wadi.replication.manager.ReplicaterAdapterFactory;
066 import org.codehaus.wadi.replication.manager.ReplicationManager;
067 import org.codehaus.wadi.replication.manager.ReplicationManagerFactory;
068 import org.codehaus.wadi.replication.manager.basic.SessionReplicationManager;
069 import org.codehaus.wadi.replication.storage.ReplicaStorage;
070 import org.codehaus.wadi.replication.storage.ReplicaStorageFactory;
071 import org.codehaus.wadi.replication.strategy.BackingStrategyFactory;
072 import org.codehaus.wadi.servicespace.ServiceRegistry;
073 import org.codehaus.wadi.servicespace.ServiceSpaceName;
074 import org.codehaus.wadi.servicespace.basic.BasicServiceSpace;
075 import org.codehaus.wadi.web.WebSession;
076 import org.codehaus.wadi.web.WebSessionPool;
077 import org.codehaus.wadi.web.impl.AtomicallyReplicableSessionFactory;
078 import org.codehaus.wadi.web.impl.DistributableAttributesFactory;
079 import org.codehaus.wadi.web.impl.DistributableValueFactory;
080 import org.codehaus.wadi.web.impl.DummyRouter;
081 import org.codehaus.wadi.web.impl.DummyStatefulHttpServletRequestWrapperPool;
082 import org.codehaus.wadi.web.impl.StandardHttpProxy;
083 import org.codehaus.wadi.web.impl.StandardSessionWrapperFactory;
084 import org.codehaus.wadi.web.impl.WebSessionToSessionPoolAdapter;
085
086 import EDU.oswego.cs.dl.util.concurrent.Sync;
087 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
088
089 /**
090 *
091 * @version $Rev$ $Date$
092 */
093 public class BasicWADISessionManager implements GBeanLifecycle, SessionManager, WADISessionManager {
094 private static final Log log = LogFactory.getLog(BasicWADISessionManager.class);
095
096 private final WADISessionManagerConfigInfo configInfo;
097 private final ReplicationManagerFactory repManagerFactory;
098 private final ReplicaStorageFactory repStorageFactory;
099 private final BackingStrategyFactory backingStrategyFactory;
100 private final DispatcherHolder dispatcherHolder;
101 private final CopyOnWriteArrayList listeners;
102
103 private ClusteredManager manager;
104 private BasicServiceSpace serviceSpace;
105
106 public BasicWADISessionManager(WADISessionManagerConfigInfo configInfo,
107 ReplicationManagerFactory repManagerFactory,
108 ReplicaStorageFactory repStorageFactory,
109 BackingStrategyFactory backingStrategyFactory,
110 DispatcherHolder dispatcherHolder) {
111 this.configInfo = configInfo;
112 this.dispatcherHolder = dispatcherHolder;
113 this.repManagerFactory = repManagerFactory;
114 this.repStorageFactory = repStorageFactory;
115 this.backingStrategyFactory = backingStrategyFactory;
116
117 listeners = new CopyOnWriteArrayList();
118 }
119
120 public void doStart() throws Exception {
121 Dispatcher underlyingDisp = dispatcherHolder.getDispatcher();
122
123 serviceSpace = new BasicServiceSpace(new ServiceSpaceName(configInfo.getServiceSpaceURI()), underlyingDisp);
124
125 boolean strictOrdering = true;
126 Streamer streamer = new SimpleStreamer();
127 Collapser collapser = new HashingCollapser(1024, 10000);
128 Map mmap = Collections.synchronizedMap(new HashMap());
129 WebSessionPool sessionPool = new SimpleSessionPool(new AtomicallyReplicableSessionFactory());
130
131 // end of contextualiser stack
132 Contextualiser contextualiser = new DummyContextualiser();
133
134 // replica aware contextualiser
135 ReplicationManager replicationManager = repManagerFactory.factory(serviceSpace, backingStrategyFactory);
136 ReplicationManager sessionRepManager = new SessionReplicationManager(replicationManager, sessionPool);
137 contextualiser = new ReplicaAwareContextualiser(contextualiser, sessionRepManager);
138
139 // cluster aware contextualiser
140 contextualiser = new ClusterContextualiser(contextualiser, collapser, new HybridRelocater(5000, 5000, true));
141
142 contextualiser = new StatelessContextualiser(contextualiser, Pattern.compile("GET|POST", 2), true,
143 Pattern.compile(".*\\.(JPG|JPEG|GIF|PNG|ICO|HTML|HTM)", 2), false);
144
145 // in-memory contextualiser
146 Evicter mevicter = new AbsoluteEvicter(configInfo.getSweepInterval(), strictOrdering,
147 configInfo.getSessionTimeoutSeconds());
148 SessionPool contextPool = new WebSessionToSessionPoolAdapter(sessionPool);
149 PoolableInvocationWrapperPool requestPool = new DummyStatefulHttpServletRequestWrapperPool();
150 contextualiser = new MotionTracker(contextualiser, mevicter, mmap, streamer, contextPool, requestPool);
151
152 contextualiser = new SerialContextualiserFrontingMemory(contextualiser, collapser);
153
154 // Manager
155 manager = new ClusteredManager(sessionPool,
156 new DistributableAttributesFactory(),
157 new SimpleValuePool(new DistributableValueFactory()),
158 new StandardSessionWrapperFactory(),
159 null,
160 contextualiser,
161 mmap,
162 new DummyRouter(),
163 false,
164 streamer,
165 true,
166 new ReplicaterAdapterFactory(replicationManager, sessionPool),
167 new StandardHttpProxy("jsessionid"),
168 serviceSpace,
169 configInfo.getNumPartitions(),
170 collapser);
171
172 manager.init(new ManagerConfig() {
173 public void callback(Manager manager) {
174 }
175
176 public ServletContext getServletContext() {
177 return null;
178 }
179 });
180
181 ServiceRegistry serviceRegistry = serviceSpace.getServiceRegistry();
182 serviceRegistry.register(ReplicaStorage.NAME, repStorageFactory.factory(serviceSpace));
183 serviceRegistry.register(ReplicationManager.NAME, replicationManager);
184 serviceRegistry.register(ClusteredManager.NAME, manager);
185
186 serviceSpace.start();
187 }
188
189 public void doStop() throws Exception {
190 serviceSpace.stop();
191 }
192
193 public void doFail() {
194 try {
195 serviceSpace.stop();
196 } catch (Exception e) {
197 log.error(e);
198 }
199 }
200
201 public Session createSession(String sessionId) throws SessionAlreadyExistException {
202 WebSession session;
203 try {
204 session = manager.createWithName(sessionId);
205 } catch (org.codehaus.wadi.SessionAlreadyExistException e) {
206 throw new SessionAlreadyExistException(sessionId);
207 }
208 return new WADISessionAdaptor(session);
209 }
210
211 public ClusteredManager getManager() {
212 return manager;
213 }
214
215 public Node getNode() {
216 return dispatcherHolder.getNode();
217 }
218
219 public void registerListener(SessionListener listener) {
220 listeners.add(listener);
221 }
222
223 public void unregisterListener(SessionListener listener) {
224 listeners.remove(listener);
225 }
226
227 private void notifyInboundSessionMigration(WebSession webSession) {
228 for (Iterator iter = listeners.iterator(); iter.hasNext();) {
229 SessionListener listener = (SessionListener) iter.next();
230 listener.notifyInboundSessionMigration(new WADISessionAdaptor(webSession));
231 }
232 }
233
234 private WebSession notifyOutboundSessionMigration(WebSession webSession) {
235 for (Iterator iter = listeners.iterator(); iter.hasNext();) {
236 SessionListener listener = (SessionListener) iter.next();
237 listener.notifyOutboundSessionMigration(new WADISessionAdaptor(webSession));
238 }
239 return webSession;
240 }
241
242 private class MotionTracker extends MemoryContextualiser {
243 private final Immoter immoter;
244
245 private final Emoter emoter;
246
247 public MotionTracker(Contextualiser next, Evicter evicter, Map map, Streamer streamer, SessionPool pool,
248 PoolableInvocationWrapperPool requestPool) {
249 super(next, evicter, map, streamer, pool, requestPool);
250
251 Immoter immoterDelegate = super.getImmoter();
252 immoter = new InboundSessionTracker(immoterDelegate);
253
254 Emoter emoterDelegate = super.getEmoter();
255 emoter = new OutboundSessionTracker(emoterDelegate);
256 }
257
258 public Immoter getPromoter(Immoter immoter) {
259 Immoter delegate = super.getPromoter(immoter);
260 if (null == immoter) {
261 return new InboundSessionTracker(delegate);
262 } else {
263 return delegate;
264 }
265 }
266
267 public Immoter getImmoter() {
268 return immoter;
269 }
270
271 public Emoter getEmoter() {
272 return emoter;
273 }
274 }
275
276 private class OutboundSessionTracker implements Emoter {
277 private final Emoter delegate;
278
279 public OutboundSessionTracker(Emoter delegate) {
280 this.delegate = delegate;
281 }
282
283 public void commit(String arg0, Motable arg1) {
284 notifyOutboundSessionMigration((WebSession) arg1);
285 delegate.commit(arg0, arg1);
286 }
287
288 public String getInfo() {
289 return delegate.getInfo();
290 }
291
292 public boolean prepare(String arg0, Motable arg1, Motable arg2) {
293 return delegate.prepare(arg0, arg1, arg2);
294 }
295
296 public void rollback(String arg0, Motable arg1) {
297 delegate.rollback(arg0, arg1);
298 }
299 }
300
301 private class InboundSessionTracker implements Immoter {
302 private final Immoter delegate;
303
304 public InboundSessionTracker(Immoter delegate) {
305 this.delegate = delegate;
306 }
307
308 public void commit(String arg0, Motable arg1) {
309 notifyInboundSessionMigration((WebSession) arg1);
310 delegate.commit(arg0, arg1);
311 }
312
313 public boolean contextualise(Invocation arg0, String arg1, Motable arg2, Sync arg3) throws InvocationException {
314 return delegate.contextualise(arg0, arg1, arg2, arg3);
315 }
316
317 public String getInfo() {
318 return delegate.getInfo();
319 }
320
321 public Motable nextMotable(String arg0, Motable arg1) {
322 return delegate.nextMotable(arg0, arg1);
323 }
324
325 public boolean prepare(String arg0, Motable arg1, Motable arg2) {
326 return delegate.prepare(arg0, arg1, arg2);
327 }
328
329 public void rollback(String arg0, Motable arg1) {
330 delegate.rollback(arg0, arg1);
331 }
332 }
333
334 public static final GBeanInfo GBEAN_INFO;
335
336 public static final String GBEAN_ATTR_WADI_CONFIG_INFO = "wadiConfigInfo";
337
338 public static final String GBEAN_REF_REPLICATION_MANAGER_FACTORY = "ReplicationManagerFactory";
339 public static final String GBEAN_REF_REPLICA_STORAGE_FACTORY = "ReplicaStorageFactory";
340 public static final String GBEAN_REF_BACKING_STRATEGY_FACTORY = "BackingStrategyFactory";
341 public static final String GBEAN_REF_DISPATCHER_HOLDER = "DispatcherHolder";
342
343 static {
344 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic("WADI Session Manager",
345 BasicWADISessionManager.class, NameFactory.GERONIMO_SERVICE);
346
347 infoBuilder.addAttribute(GBEAN_ATTR_WADI_CONFIG_INFO, WADISessionManagerConfigInfo.class, true);
348
349 infoBuilder.addReference(GBEAN_REF_REPLICATION_MANAGER_FACTORY, ReplicationManagerFactory.class,
350 NameFactory.GERONIMO_SERVICE);
351 infoBuilder.addReference(GBEAN_REF_REPLICA_STORAGE_FACTORY, ReplicaStorageFactory.class,
352 NameFactory.GERONIMO_SERVICE);
353 infoBuilder.addReference(GBEAN_REF_BACKING_STRATEGY_FACTORY, BackingStrategyFactory.class,
354 NameFactory.GERONIMO_SERVICE);
355 infoBuilder.addReference(GBEAN_REF_DISPATCHER_HOLDER, DispatcherHolder.class, NameFactory.GERONIMO_SERVICE);
356
357 infoBuilder.addInterface(SessionManager.class);
358 infoBuilder.addInterface(WADISessionManager.class);
359
360 infoBuilder.setConstructor(new String[] { GBEAN_ATTR_WADI_CONFIG_INFO,
361 GBEAN_REF_REPLICATION_MANAGER_FACTORY,
362 GBEAN_REF_REPLICA_STORAGE_FACTORY,
363 GBEAN_REF_BACKING_STRATEGY_FACTORY,
364 GBEAN_REF_DISPATCHER_HOLDER });
365
366 GBEAN_INFO = infoBuilder.getBeanInfo();
367 }
368
369 public static GBeanInfo getGBeanInfo() {
370 return GBEAN_INFO;
371 }
372 }