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