1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.geronimo.clustering.wadi;
19
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.regex.Pattern;
27
28 import javax.servlet.ServletContext;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.geronimo.clustering.Node;
33 import org.apache.geronimo.clustering.Session;
34 import org.apache.geronimo.clustering.SessionAlreadyExistException;
35 import org.apache.geronimo.clustering.SessionListener;
36 import org.apache.geronimo.clustering.SessionManager;
37 import org.apache.geronimo.gbean.GBeanInfo;
38 import org.apache.geronimo.gbean.GBeanInfoBuilder;
39 import org.apache.geronimo.gbean.GBeanLifecycle;
40 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
41 import org.codehaus.wadi.Collapser;
42 import org.codehaus.wadi.Contextualiser;
43 import org.codehaus.wadi.Emoter;
44 import org.codehaus.wadi.Evicter;
45 import org.codehaus.wadi.Immoter;
46 import org.codehaus.wadi.Invocation;
47 import org.codehaus.wadi.InvocationException;
48 import org.codehaus.wadi.Manager;
49 import org.codehaus.wadi.ManagerConfig;
50 import org.codehaus.wadi.Motable;
51 import org.codehaus.wadi.PoolableInvocationWrapperPool;
52 import org.codehaus.wadi.SessionPool;
53 import org.codehaus.wadi.Streamer;
54 import org.codehaus.wadi.group.Dispatcher;
55 import org.codehaus.wadi.impl.AbsoluteEvicter;
56 import org.codehaus.wadi.impl.ClusterContextualiser;
57 import org.codehaus.wadi.impl.ClusteredManager;
58 import org.codehaus.wadi.impl.DummyContextualiser;
59 import org.codehaus.wadi.impl.DummyReplicaterFactory;
60 import org.codehaus.wadi.impl.HashingCollapser;
61 import org.codehaus.wadi.impl.HybridRelocater;
62 import org.codehaus.wadi.impl.MemoryContextualiser;
63 import org.codehaus.wadi.impl.SerialContextualiser;
64 import org.codehaus.wadi.impl.SerialContextualiserFrontingMemory;
65 import org.codehaus.wadi.impl.SimpleSessionPool;
66 import org.codehaus.wadi.impl.SimpleStreamer;
67 import org.codehaus.wadi.impl.SimpleValuePool;
68 import org.codehaus.wadi.impl.StatelessContextualiser;
69 import org.codehaus.wadi.replication.contextualizer.ReplicaAwareContextualiser;
70 import org.codehaus.wadi.replication.manager.ReplicaterAdapterFactory;
71 import org.codehaus.wadi.replication.manager.ReplicationManager;
72 import org.codehaus.wadi.replication.manager.ReplicationManagerFactory;
73 import org.codehaus.wadi.replication.manager.basic.SessionReplicationManager;
74 import org.codehaus.wadi.replication.storage.ReplicaStorage;
75 import org.codehaus.wadi.replication.storage.ReplicaStorageFactory;
76 import org.codehaus.wadi.replication.strategy.BackingStrategyFactory;
77 import org.codehaus.wadi.servicespace.ServiceRegistry;
78 import org.codehaus.wadi.servicespace.ServiceSpaceName;
79 import org.codehaus.wadi.servicespace.basic.BasicServiceSpace;
80 import org.codehaus.wadi.web.WebSession;
81 import org.codehaus.wadi.web.WebSessionPool;
82 import org.codehaus.wadi.web.impl.AtomicallyReplicableSessionFactory;
83 import org.codehaus.wadi.web.impl.DistributableAttributesFactory;
84 import org.codehaus.wadi.web.impl.DistributableValueFactory;
85 import org.codehaus.wadi.web.impl.DummyRouter;
86 import org.codehaus.wadi.web.impl.DummyStatefulHttpServletRequestWrapperPool;
87 import org.codehaus.wadi.web.impl.StandardSessionWrapperFactory;
88 import org.codehaus.wadi.web.impl.WebSessionToSessionPoolAdapter;
89
90 import EDU.oswego.cs.dl.util.concurrent.Sync;
91
92 /**
93 *
94 * @version $Rev$ $Date$
95 */
96 public class BasicWADISessionManager implements GBeanLifecycle, SessionManager, WADISessionManager {
97 private static final Log log = LogFactory.getLog(BasicWADISessionManager.class);
98
99 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
134 Contextualiser contextualiser = new DummyContextualiser();
135
136
137
138
139
140
141
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
148 contextualiser = new SerialContextualiser(contextualiser, collapser, mmap);
149
150
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
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
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
190
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 }