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 }