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    }