User: jules_gosnell Date: 02/01/12 02:57:45 Modified: jetty/src/main/org/jboss/jetty DistributedSessionManager.java JBossLogSink.java JBossWebApplicationContext.java Log: disable DistributedSessionmanager, temporarily, whilst I do some more work on it. Revision Changes Path 1.4 +910 -203 contrib/jetty/src/main/org/jboss/jetty/DistributedSessionManager.java Index: DistributedSessionManager.java =================================================================== RCS file: /cvsroot/jboss/contrib/jetty/src/main/org/jboss/jetty/DistributedSessionManager.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- DistributedSessionManager.java 2002/01/06 23:54:16 1.3 +++ DistributedSessionManager.java 2002/01/12 10:57:45 1.4 @@ -5,25 +5,33 @@ * See terms of license at gnu.org. */ -// $Id: DistributedSessionManager.java,v 1.3 2002/01/06 23:54:16 jules_gosnell Exp $ +// $Id: DistributedSessionManager.java,v 1.4 2002/01/12 10:57:45 jules_gosnell Exp $ // TODO -// 1. abstract out ID allocation and move into DistributedStore -// 2. keep all state in HttpSessionState objects -// 3. keep all HttpSessionState instances in DistributedStore -// 4. we need to know when the data is dirty - will DAOs do this for us ? -// 5. we need a handler to flush dirty state to the DistributedStore after each request -// 6. choice of DistributedStore and frequency of flushing should be parameterisable -// 7. remember whether attributes were properly passivated +// keep all state in HttpSessionState objects +// keep all HttpSessionState instances in Store +// rename a few things +// test.... +// release !!!! + package org.jboss.jetty; +//---------------------------------------- + import java.rmi.RemoteException; import java.util.ArrayList; +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.Enumeration; import java.util.EventListener; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map.Entry; +import java.util.Map; import javax.ejb.CreateException; import javax.ejb.FinderException; import javax.ejb.ObjectNotFoundException; @@ -31,20 +39,26 @@ import javax.naming.InitialContext; import javax.naming.NamingException; import javax.rmi.PortableRemoteObject; +import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionListener; import javax.servlet.http.HttpSessionActivationListener; +import javax.servlet.http.HttpSessionAttributeListener; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; +import javax.servlet.http.HttpSessionContext; import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; import org.jboss.jetty.interfaces.CoarseHttpSession; -import org.jboss.jetty.interfaces.CoarseHttpSessionHome; import org.jboss.jetty.interfaces.CoarseHttpSessionData; +import org.jboss.jetty.interfaces.CoarseHttpSessionHome; import org.jboss.logging.Logger; import org.mortbay.jetty.servlet.ServletHandler; +import org.mortbay.jetty.servlet.SessionContext; import org.mortbay.util.LifeCycle; //---------------------------------------- - /** * An abstraction of a manager for the distributed store of HttpSessions * @@ -52,7 +66,7 @@ * @version 1.0 * @since 1.0 */ -interface AbstractDistributedStore +interface AbstractStore { public String nextId(); public AbstractHttpSessionData make(); @@ -68,10 +82,10 @@ * @author <a href="mailto:jules_gosnell@@yahoo.com">Jules Gosnell</a> * @version 1.0 * @since 1.0 - * @see AbstractDistributedStore + * @see AbstractStore */ class EJBDistributedStore - implements AbstractDistributedStore + implements AbstractStore { Logger _log = Logger.getLogger(getClass().getName()); InitialContext _jndiContext; @@ -152,294 +166,987 @@ catch (CreateException e) {} } - - // dummy implementation - static int _nextId=0; + final Object _idLock=new Object(); + long _nextId=0; public synchronized String nextId() + { + long id; + synchronized (_idLock) { + id=_nextId++; + } + return ""+System.currentTimeMillis()+"-"+id; + } +} + +//------------------------------------------------------------------------------ + +interface AbstractScavenger +{ + public void register(AbstractScavenged session, long timeRemaining); + public void reregister(AbstractScavenged session, long timeRemaining); + public void deregister(AbstractScavenged session); + + public void start(); + public void stop(); +} + +interface AbstractScavenged +{ + public long getTimeRemaining(long now); +} + +//------------------------------------------------------------------------------ + +class LocalHttpSessionScavenger + implements AbstractScavenger +{ + long _smallestRemainingTime; + + // called by HttpSession[Manager] + + // [(r/d)e]registering a session should not result in any calls on + // the session - thus contention is kept at a minimum... + + List _sessions; + + class Pair + { + long _timeRemaining; + final AbstractScavenged _session; + + Pair(long timeRemaining, AbstractScavenged session) + { + _timeRemaining=timeRemaining; + _session=session; + } + + void + update(long now) + { + _timeRemaining=_session.getTimeRemaining(now); + } + + public int + compare(Object o1, Object o2) + { + return (int)(((Pair)o1)._timeRemaining-((Pair)o2)._timeRemaining); + } + + public boolean + equals(Object object) + { + return ((Pair)object)._timeRemaining==_timeRemaining; + } + } + + public synchronized void + register(AbstractScavenged session, long timeRemaining) + { + if (timeRemaining<0) + return; // never timeout + + stop(); + + Pair pair=new Pair(timeRemaining, session); + + update(System.currentTimeMillis()); // update all timeRemainings + _sessions.add(pair); + Collections.sort(_sessions); // sort by timeRemaining + + _smallestRemainingTime=((Pair)_sessions.get(0))._timeRemaining; + + start(); + } + + public synchronized void + reregister(AbstractScavenged session, long timeRemaining) + { + // could be optimised - but this is simpler for the moment... + deregister(session); + register(session, timeRemaining); + } + + public synchronized void + deregister(AbstractScavenged session) + { + stop(); + + Pair p=find(session); + _sessions.remove(p); + + update(System.currentTimeMillis()); // update all timeRemainings + Collections.sort(_sessions); // sort by timeRemaining + + _smallestRemainingTime=((Pair)_sessions.get(0))._timeRemaining; + + start(); + } + + // utils... + + Pair + find(AbstractScavenged session) + { + Iterator i=_sessions.iterator(); + while (i.hasNext()) + { + Pair p=(Pair)i.next(); + if (p._session==session) + return p; + } + return null; + } + + void + update(long now) { - return "uid-"+_nextId++; + Iterator i=_sessions.iterator(); + while (i.hasNext()) + ((Pair)i.next()).update(now); } + + // thread + + // sleep for smallest timeRemaining() + // wake up + // refresh timeRemaining() on expired sessions - removing stale ones + // go back to sleep + + // questions - what happens if smallest timeRemaining() changes + // whilst thread is asleep - can I wake it... + + public synchronized void + start() + {} + + public synchronized void + stop() + {} + + synchronized void + loop() + { + Pair p=(Pair)_sessions.get(0); + + } +} + +// Scavenging is done for us by HA - Dummy implementation - does nothing... +class + DistributedHttpSessionScavenger + implements AbstractScavenger +{ + public void + register(AbstractScavenged session, long timeRemaining) + {} + + public void + deregister(AbstractScavenged session) + {} + + public void + reregister(AbstractScavenged session, long timeRemaining) + {} + + + public void + start() + {} + + public void + stop() + {} } /* --------------------------------------------------------------------- */ /** * - * @version $Id: DistributedSessionManager.java,v 1.3 2002/01/06 23:54:16 jules_gosnell Exp $ + * @version $Id: DistributedSessionManager.java,v 1.4 2002/01/12 10:57:45 jules_gosnell Exp $ * @author [EMAIL PROTECTED] */ + public class DistributedSessionManager - extends org.mortbay.jetty.servlet.HashSessionManager + implements org.mortbay.jetty.servlet.SessionManager { - Logger _log; - JBossWebApplicationContext _context; - static AbstractDistributedStore _manager=new EJBDistributedStore(); // hardwired for the moment - TODO + static AbstractStore _store =new EJBDistributedStore(); // hardwired for the moment - TODO + static AbstractScavenger _scavenger =new LocalHttpSessionScavenger(); // breaks confinement + + final Logger _log; + final JBossWebApplicationContext _context; + final ServletHandler _handler; + final ArrayList _sessionListeners =new ArrayList(); + final ArrayList _sessionAttributeListeners =new ArrayList(); + final Map _sessions =new HashMap(); + final boolean _isDistributed =true; + volatile boolean _isStarted =false; // TODO + volatile int _dftMaxIdleSecs =-1; // negative means never timeout... + //---------------------------------------- + DistributedSessionManager(JBossWebApplicationContext context) { - super(context.getServletHandler()); - _context=context; + _handler=_context.getServletHandler(); _log =Logger.getLogger(getClass().getName()+"#" +_context.getContextPath()); } + //---------------------------------------- + // factory + public HttpSession - getHttpSession(String id) + newHttpSession() + { + String id=getStore().nextId(); + DistributedSession session = new DistributedSession(this, id, _dftMaxIdleSecs); + + putSession(id,session); + notifySessionCreated(session); + getScavenger().register(session, _dftMaxIdleSecs*1000); + + return session; + } + + public void + destroyHttpSession(DistributedSession session) + { + getScavenger().deregister(session); + removeSession(session); + notifySessionDestroyed(session); + session.destroy(); + } + + public void + passivateHttpSession(DistributedSession session) { + getScavenger().deregister(session); + removeSession(session); + session.passivate(); + } + + public HttpSession + getHttpSession(String id) // hopefully local and distributed store will become same + { + HttpSession s=null; + // 1. check local store - HttpSession s = (HttpSession)_sessions.get(id); + s = getSession(id); // 2. check distributed store - if (s==null && _manager!=null) - s=new DistributedSession(id, _manager.get(id)); + if (s==null && _store!=null) + s=new DistributedSession(this, id, _store.get(id)); return s; } - // we have to create a DistributedSession instead of a standard Session - public synchronized HttpSession - newHttpSession() + // wrappers to access session table... + + DistributedSession + getSession(String id) { - DistributedSession session = new DistributedSession(); - session.setMaxInactiveInterval(_dftMaxIdleSecs); - _sessions.put(session.getId(),session); - - for(int i=0;i<_sessionListeners.size();i++) - ((HttpSessionListener)_sessionListeners.get(i)) - .sessionCreated(session.getHttpSessionEvent()); - return session; + synchronized (_sessions) {return (DistributedSession)_sessions.get(id);} + } + + void + putSession(String id, DistributedSession session) + { + synchronized (_sessions) {_sessions.put(id, session);} } - // { - // HttpSession session=super.newHttpSession(); - // String id=session.getId(); - // _log.info("creating distributed data for session: "+id); - // return session; - // } - - // public synchronized void setMaxInactiveInterval(int seconds) {} - // public synchronized void setScavangePeriod(int seconds) {} - // public void addEventListener(EventListener listener) throws IllegalArgumentException {} - // public void removeEventListener(EventListener listener) {} + void + removeSession(DistributedSession session) + { + synchronized (_sessions) {_sessions.remove(session.getId());} + } + //---------------------------------------- // lifecycle - // public boolean isStarted() {} + public boolean + isStarted() + { + return _isStarted; + } public void start() throws Exception { - super.start(); + _isStarted=true; + // sessions are activated lazily... } public void - stop() + stop() // TODO { - // passivate all sessions... + _isStarted=false; // TODO + + // tidy up all sessions... ArrayList sessions = new ArrayList(_sessions.values()); for (Iterator i = sessions.iterator(); i.hasNext(); ) { - DistributedSession session = (DistributedSession)i.next(); - session.passivate(); + DistributedSession session=(DistributedSession)i.next(); + if (_isDistributed) + passivateHttpSession(session); + else + destroyHttpSession(session); } + } + + //---------------------------------------- + // SessionManager API + + public synchronized + void setMaxInactiveInterval(int seconds) // TODO + { + _dftMaxIdleSecs = seconds; + } + + //---------------------------------------- + + // extra accessors to make relationship with session more + // explicit... + + AbstractScavenger + getScavenger() // TODO + { + return _scavenger; + } + + AbstractStore + getStore() // TODO + { + return _store; + } - // by calling clear we ensure that attributes will not be sent - // AttributeRemoved events by super() - is this correct - // behaviour...? - _sessions.clear(); + ServletHandler + getHandler() // TODO + { + return _handler; + } - super.stop(); + ServletContext + getServletContext() // TODO + { + return getHandler().getServletContext(); } + + //---------------------------------------- + // Listeners - // scavenging + // Listeners are added before requests start coming in, so this code + // needs no synchronisation... - // private void scavenge() {} - // - // class SessionScavenger - // extends Thread - // { - // public void run() {} - // SessionScavenger() {} - // } - // - class DistributedSession - extends org.mortbay.jetty.servlet.HashSessionManager.Session + public void + addEventListener(EventListener listener) + throws IllegalArgumentException { - Logger _log; + boolean known=false; + if (listener instanceof HttpSessionAttributeListener) + { + _sessionAttributeListeners.add(listener); + known=true; + } + if (listener instanceof HttpSessionListener) + { + _sessionListeners.add(listener); + known=true; + } + + if (!known) + throw new IllegalArgumentException("Unknown listener "+listener); + } - // lifecycle - needs init/ctor and destroy()... + public void + removeEventListener(EventListener listener) + { + if (listener instanceof HttpSessionAttributeListener) + _sessionAttributeListeners.remove(listener); + if (listener instanceof HttpSessionListener) + _sessionListeners.remove(listener); + } - // create a completely new session - DistributedSession() + void + notifyAttributeAdded(HttpSession session, String key, Object value) + { + if (_sessionAttributeListeners.size()>0) { - _id =_manager.nextId(); - _log=Logger.getLogger(getClass().getName()+"#" +getId()); - _log.info("new: "+getId()); + HttpSessionBindingEvent event = + new HttpSessionBindingEvent(session, key, value); + + for(int i=0;i<_sessionAttributeListeners.size();i++) + ((HttpSessionAttributeListener) + _sessionAttributeListeners.get(i)).attributeAdded(event); + } + } - int dftMaxIdleSecs=_dftMaxIdleSecs; + void + notifyAttributeReplaced(HttpSession session, String key, Object value) + { + if (_sessionAttributeListeners.size()>0) + { + HttpSessionBindingEvent event = + new HttpSessionBindingEvent(session, key, value); - if (dftMaxIdleSecs>=0) - _maxIdleMs=dftMaxIdleSecs*1000; + for(int i=0;i<_sessionAttributeListeners.size();i++) + ((HttpSessionAttributeListener) + _sessionAttributeListeners.get(i)).attributeReplaced(event); } + } - // reactivate a passivated session - DistributedSession(String id, AbstractHttpSessionData data) + void + notifyAttributeRemoved(HttpSession session, String key, Object value) + { + if (_sessionAttributeListeners.size()>0) { - _id=id; - _log=Logger.getLogger(getClass().getName()+"#" +getId()); + HttpSessionBindingEvent event = + new HttpSessionBindingEvent(session, key, value); - activate(data); + for(int i=0;i<_sessionAttributeListeners.size();i++) + ((HttpSessionAttributeListener) + _sessionAttributeListeners.get(i)).attributeRemoved(event); } + } - protected void - activate(AbstractHttpSessionData data) + void + notifySessionCreated(HttpSession session) + { + if (_sessionListeners.size()>0) { - activate(data, true); + HttpSessionEvent event = new HttpSessionEvent(session); + + for(int i=0;i<_sessionListeners.size();i++) + ((HttpSessionListener)_sessionListeners.get(i)) + .sessionCreated(event); } + } - protected synchronized void - activate(AbstractHttpSessionData data, boolean activateAttributes) + void + notifySessionDestroyed(HttpSession session) + { + if (_sessionListeners.size()>0) { - if (_invalid) throw new IllegalStateException(); + HttpSessionEvent event = new HttpSessionEvent(session); + + for(int i=0;i<_sessionListeners.size();i++) + ((HttpSessionListener)_sessionListeners.get(i)) + .sessionDestroyed(event); + } + } +} + +/** + * Implementation of HttpSession with support for a DistributedStore + * + * @author <a href="mailto:jules_gosnell@@yahoo.com">Jules Gosnell</a> + * @version 1.0 + * @since 1.0 + * @see javax.servlet.http.HttpSession + */ + +interface AbstractHttpSession + extends HttpSession, AbstractScavenged, org.mortbay.jetty.servlet.SessionManager.Session +{ +} + +class DistributedSession + implements AbstractHttpSession +{ + final DistributedSessionManager _manager; + final String _id; + final Logger _log; + final long _creationTime; + final HashMap _attributes; + + final boolean _heldByValue =true; // attributes are held in store by value, not reference + final boolean _accessDirties =true; // updating _lastAccessedTime dirties session + final boolean _snapshotNeedsActivation =true; // they will not have been properly passivated + final boolean _isDistributed =true; + volatile boolean _isNew =true; // risky ! + volatile boolean _isValid =true; // risky ! + volatile boolean _isDirty =false; // needs storing + + final Object _lastAccessedTimeLock =new Object(); + long _lastAccessedTime; - _values = new HashMap(11); - _values.putAll(data.getAttributes()); - _created =data.getCreationTime(); - _accessed =data.getLastAccessedTime(); - _maxIdleMs =data.getMaxInactiveInterval()*1000; - _newSession =false; + final Object _maxInactiveIntervalLock =new Object(); + int _maxInactiveInterval; - // send activate events to listening attributes - if (activateAttributes && _values.size()>0) + //---------------------------------------- + + // create a completely new session + DistributedSession(DistributedSessionManager manager,String id, int maxInactiveInterval) + { + // final + _manager =manager; + _id =id; + _log =Logger.getLogger(getClass().getName()+"#" +getId()); + _creationTime =System.currentTimeMillis(); + _attributes =new HashMap(11); + + // non-final - no need to lock in ctor + _lastAccessedTime =_creationTime; + _maxInactiveInterval =maxInactiveInterval; + } + + // reactivate a passivated session + DistributedSession(DistributedSessionManager manager, String id, AbstractHttpSessionData data) + { + // assume we own 'data' and don't have to synchronise access + + // final + _manager =manager; + _id =id; + _log =Logger.getLogger(getClass().getName()+"#" +getId()); + _creationTime =data.getCreationTime(); + _attributes =new HashMap(data.getAttributes().size()); // we could just cast... + + // volatile + _isNew =false; + + // non-final + _lastAccessedTime =data.getLastAccessedTime(); // no need to lock in ctor + _maxInactiveInterval =data.getMaxInactiveInterval(); // no need to lock in ctor + + _attributes.putAll(data.getAttributes()); + + // send activate events to listening attributes + if (_snapshotNeedsActivation && _attributes.size()>0) + { + boolean warn=!data.getAttributesWerePassivated(); + HttpSessionEvent event=new HttpSessionEvent(this); + Iterator i = _attributes.values().iterator(); + + try { - boolean warn=!data.getAttributesWerePassivated(); - HttpSessionEvent event=new HttpSessionEvent(this); - Iterator i = _values.values().iterator(); + while (i.hasNext()) + notifySessionDidActivate(i.next(), event, warn); + } + catch (Exception e) + { + _log.error("Problem whilst activating session attributes", e); + } + } + _log.info("Session activated: "+getId()); + } - try - { - while (i.hasNext()) - activateValue(i.next(), event, warn); - } - catch (Exception e) - { - _log.error("Problem whilst activating session attributes", e); - } + void + destroy() + { + synchronized (_attributes) { + Iterator iter = _attributes.entrySet().iterator(); // guarded + while (iter.hasNext()) + { + Entry entry = (Entry)iter.next(); + String key = (String)entry.getKey(); + Object value = entry.getValue(); + + iter.remove(); + + notifyValueUnbound(key, value); + _manager.notifyAttributeRemoved(this, key, value); } - _log.info("Session activated: "+getId()); } + } - protected void - activateValue(Object attribute, HttpSessionEvent event, boolean warn) - { - if (attribute!=null && attribute instanceof HttpSessionActivationListener) + //---------------------------------------- + // AbstractScavenged + + public long + getTimeRemaining(long now) + { + long timeAllowed,timeTaken; + + // watch out for deadlock + synchronized (_lastAccessedTimeLock) { + synchronized (_maxInactiveIntervalLock){ + timeAllowed=_maxInactiveInterval*1000; + timeTaken=now-_lastAccessedTime; + } + } + + return timeAllowed-timeTaken; + } + + //---------------------------------------- + + // Greg's API - where does he use it ? Should be inheriting it from + // some interface... + + public void + access() + { + setLastAccessedTime(System.currentTimeMillis()); + } + + public void + setLastAccessedTime(long time) + { + synchronized (_lastAccessedTimeLock) { + if (_lastAccessedTime!=time) // guarded + { + _lastAccessedTime=time; // guarded + if (_accessDirties) // final + _isDirty=true; // volatile + } + _isNew=false; // volatile + } + } + + //---------------------------------------- + // HttpSession API + + public String + getId() + { + return _id; // final + } + + public long + getCreationTime() + throws IllegalStateException + { + if (!isValid()) throw new IllegalStateException(); + + return _creationTime; // final + } + + public long + getLastAccessedTime() + { + synchronized (_lastAccessedTimeLock) {return _lastAccessedTime;} // guarded + } + + public int + getMaxInactiveInterval() + { + synchronized (_maxInactiveIntervalLock){return _maxInactiveInterval;} // guarded + } + + public ServletContext + getServletContext() + { + return _manager.getServletContext(); + } + + /** + * @deprecated + */ + public HttpSessionContext + getSessionContext() // TODO + { + return SessionContext.NULL_IMPL; + } + + public boolean + isValid() + { + return _isValid; // volatile + } + + public void + setMaxInactiveInterval(int secs) + { + synchronized (_maxInactiveIntervalLock) { + if (_maxInactiveInterval!=secs) // guarded { - _log.warn("WARNING: About to activate a session attribute that was not passivated: "+attribute); - _log.warn("WARNING: This was probably due to an uncontrolled server shutdown."); - ((HttpSessionActivationListener)attribute) - .sessionDidActivate(event); + _maxInactiveInterval=secs; // guarded + _isDirty=true; // volatile } } + + _manager.getScavenger().reregister(this, secs*1000); + } + + public void + invalidate() + throws IllegalStateException + { + _isValid=false; + _manager.destroyHttpSession(this); + } - protected void - passivate() + public boolean + isNew() + throws IllegalStateException + { + if (!isValid()) throw new IllegalStateException(); + + return _isNew; // volatile + } + + // attributes + + public Object + getAttribute(String name) + throws IllegalStateException + { + if (!isValid()) throw new IllegalStateException(); + + synchronized (_attributes) { + return _attributes.get(name); + } + } + + public Enumeration + getAttributeNames() + throws IllegalStateException + { + if (!isValid()) throw new IllegalStateException(); + + // make the Collection whilst synchronised, in case another + // request modifies _attributes whilst we are copying out of it. + synchronized (_attributes) { + return Collections.enumeration(_attributes.keySet()); + } + } + + public void + setAttribute(String name, Object value) + throws IllegalStateException + { + if (value==null) { - passivate(true); + // the javadoc says if the value is null, this is the same as + // remove... + removeAttribute(name); + return; } - // PROBLEM: If passivate is going to be called not simply as a - // Session is shutdown, but also during the active life of a - // session, then there is a chance that one request may be - // adding/removing attributes whilst another thread is passivating - // the session. + if (!isValid()) throw new IllegalStateException(); - // how can we prevent this, without throwing a lock around every - // attribute access ? + Object oldValue; + synchronized (_attributes) { + oldValue = _attributes.put(name,value); + } - // I think this is not the only place where concurrency represents - // a threat to the attributes - theseshould all be considered in a - // rationalisation of HttpSession implementations... - Jules + if (oldValue==value) + { + if (_heldByValue) // TODO + _isDirty=true; // the contents of value may have changed - protected synchronized void - passivate(boolean passivateAttributes) + // perhaps we should raise an 'attributeReplaced' here ? + // this should be configurable - TODO + } + else { - if (_invalid) throw new IllegalStateException(); + _isDirty=true; - if (_manager!=null && - _values.size()>0) // not sure about 2nd test - TODO - { - if (passivateAttributes) - { - // send passivate events to listening attributes... - HttpSessionEvent event=new HttpSessionEvent(this); - Iterator i = _values.values().iterator(); - - try - { - while (i.hasNext()) - passivateValue(i.next(), event); - } - catch (Exception e) - { - _log.error("Problem whilst passivating session attributes", e); - } - } + // perhaps this test should have been 'equals()' - but I + // figure that would be too expensive... - TODO - // should we bother to remove ourselves from our manager's - // session list ? + Object tmp=value; // assume an attribute was added - // create and EJB and dump data into it - in a single transaction - AbstractHttpSessionData data=_manager.make(); - data.setId(getId()); - data.setAttributes(_values); - data.setCreationTime(getCreationTime()); - data.setLastAccessedTime(getLastAccessedTime()); - data.setMaxInactiveInterval(getMaxInactiveInterval()); - data.setAttributesWerePassivated(passivateAttributes); - _manager.set(getId(), data); + // notify the old value if necessary + if (oldValue!=null) + { + notifyValueUnbound(name, oldValue); + tmp=oldValue; // actually - an attribute was replaced } - _log.info("Session passivated: "+getId()); + // notify the new value if necessary + notifyValueBound(name, value); + + // notfy the session listeners... + + // we don't need to synchronise access to this ArrayList, + // because all modifications to it would have been complete + // before the first request comes through. + + if (oldValue==null) + _manager.notifyAttributeAdded(this, name, value); + else + _manager.notifyAttributeReplaced(this, name, oldValue); + } + } + + public void + removeAttribute(String name) + throws IllegalStateException + { + if (!isValid()) throw new IllegalStateException(); + + Object oldValue=null; + synchronized (_attributes) { + oldValue=_attributes.remove(name); } - protected void - passivateValue(Object attribute, HttpSessionEvent event) + if (oldValue!=null) { - if (attribute!=null && attribute instanceof HttpSessionActivationListener) - ((HttpSessionActivationListener)attribute) - .sessionWillPassivate(event); - } - - // void destroy() {} - // HttpSessionEvent getHttpSessionEvent() {} - // public void access() {} - // public boolean isValid() {} - // public ServletContext getServletContext() {} - // public String getId() throws IllegalStateException {} - // public long getCreationTime() throws IllegalStateException {} - // public long getLastAccessedTime() throws IllegalStateException {} - // public int getMaxInactiveInterval() {} - // public HttpSessionContext getSessionContext() throws IllegalStateException {} - // public void setMaxInactiveInterval(int secs) {} - // public synchronized void invalidate() throws IllegalStateException {} - // public boolean isNew() throws IllegalStateException {} - - // attributes - - // public Object getAttribute(String name) {} - // public Enumeration getAttributeNames() {} - // public void setAttribute(String name, Object value) {} - // public void removeAttribute(String name) {} - - // public Object getValue(String name) throws IllegalStateException {} - // public synchronized String[] getValueNames() throws IllegalStateException {} - // public void putValue(String name, Object value) throws IllegalStateException {} - // public void removeValue(String name) throws IllegalStateException {} + // we did remove an attribute... + _isDirty=true; - // private void bindValue(String name, Object value) {} - // private void unbindValue(String name, Object value) {} + // notify the old value if necessary + notifyValueUnbound(name, oldValue); + _manager.notifyAttributeRemoved(this, name, oldValue); + } + } + /** + * @deprecated + */ + public Object + getValue(String name) + throws IllegalStateException + { + return getAttribute(name); + } + + /** + * @deprecated + */ + public String[] + getValueNames() + throws IllegalStateException + { + if (!isValid()) throw new IllegalStateException(); + + // ouch - this is an expensive one... + synchronized (_attributes) { + return (String[])_attributes.keySet().toArray(new String[_attributes.size()]); + } } + + /** + * @deprecated + */ + public void + putValue(String name, Object value) + throws IllegalStateException + { + setAttribute(name, value); + } + + /** + * @deprecated + */ + public void + removeValue(String name) + throws IllegalStateException + { + removeAttribute(name); + } + + //---------------------------------------- + // IMPLEMENTATION + //---------------------------------------- + // notification + + protected void + notifyValueBound(String name, Object value) + { + if (value instanceof HttpSessionBindingListener) + ((HttpSessionBindingListener)value) + .valueBound(new HttpSessionBindingEvent(this,name)); + } + + protected void + notifyValueUnbound(String name, Object value) + { + if (value instanceof HttpSessionBindingListener) + ((HttpSessionBindingListener)value) + .valueUnbound(new HttpSessionBindingEvent(this,name)); + } + + protected void + notifySessionDidActivate(Object attribute, HttpSessionEvent event, boolean warn) + { + if (attribute instanceof HttpSessionActivationListener) + { + _log.warn("WARNING: About to activate a session attribute that was not passivated: "+attribute); + _log.warn("WARNING: This was probably due to an uncontrolled server shutdown."); + ((HttpSessionActivationListener)attribute) + .sessionDidActivate(event); + } + } + + protected void + notifySessionWillPassivate(Object attribute, HttpSessionEvent event) + { + if (attribute instanceof HttpSessionActivationListener) + ((HttpSessionActivationListener)attribute) + .sessionWillPassivate(event); + } + + //---------------------------------------- + + protected void + snapshot() + { + store(false, false); + } + + protected void + passivate() + { + store(true, true); + } + + protected synchronized void + store(boolean notifyAttributes, boolean shutdown) + { + // if there are no changes and this is not the final passivation + // during a controlled shutdown of webapp or webcontainer, we + // can avoid doing any work. - check - TODO. + if (!_isDirty && !shutdown) + return; + + if (_manager.getStore()!=null) + { + // whilst this method is synchronized, _attributes may still be + // modified via their public access which only synchronise on + // _attributes itself. In order to cause as little contention for + // the _attributes map as possible I am going to try taking a copy + // here - otherwise we will have to hang on to a ock on it for + // ages. + + // copy is a shallow, not deep, copy. If attributes within it + // are being modified by another thread whilst being + // passivated, it is their responsibility to synchronise so + // that we see a consistent state... + + HashMap copy=null; + synchronized (_attributes) { + int size=_attributes.size(); + if (size>0) + { + copy=new HashMap(size); + copy.putAll(_attributes); + } + } + + if (notifyAttributes && copy!=null) + { + // send passivate events to listening attributes... + HttpSessionEvent event=new HttpSessionEvent(this); + Iterator i = copy.values().iterator(); + + try + { + while (i.hasNext()) + notifySessionWillPassivate(i.next(), event); + } + catch (Exception e) + { + _log.error("Problem whilst passivating session attributes", e); + } + } + + // create distributed store and dump data into it. + // how could we ensure this was a single transaction - TODO + AbstractHttpSessionData data=_manager.getStore().make(); + data.setId(getId()); + data.setAttributes(copy); + data.setCreationTime(getCreationTime()); + data.setLastAccessedTime(getLastAccessedTime()); + data.setMaxInactiveInterval(getMaxInactiveInterval()); + data.setAttributesWerePassivated(notifyAttributes); + _manager.getStore().set(getId(), data); + + _log.info("Session passivated: "+getId()); + } + } + + //---------------------------------------- } 1.9 +3 -3 contrib/jetty/src/main/org/jboss/jetty/JBossLogSink.java Index: JBossLogSink.java =================================================================== RCS file: /cvsroot/jboss/contrib/jetty/src/main/org/jboss/jetty/JBossLogSink.java,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- JBossLogSink.java 2001/12/09 06:05:49 1.8 +++ JBossLogSink.java 2002/01/12 10:57:45 1.9 @@ -5,7 +5,7 @@ * See terms of license at gnu.org. */ -// $Id: JBossLogSink.java,v 1.8 2001/12/09 06:05:49 user57 Exp $ +// $Id: JBossLogSink.java,v 1.9 2002/01/12 10:57:45 jules_gosnell Exp $ package org.jboss.jetty; @@ -24,14 +24,14 @@ * This class bidges the API between Jetty and Log4J. * * @author <a href="mailto:">Jules Gosnell</a> - * @version $Id: JBossLogSink.java,v 1.8 2001/12/09 06:05:49 user57 Exp $ + * @version $Id: JBossLogSink.java,v 1.9 2002/01/12 10:57:45 jules_gosnell Exp $ * @since 1.0 * @see org.mortbay.util.LogSink */ public class JBossLogSink implements LogSink { - Logger _log; + Logger _log; boolean _started = false; HashMap _dispatch = new HashMap(); 1.13 +6 -6 contrib/jetty/src/main/org/jboss/jetty/JBossWebApplicationContext.java Index: JBossWebApplicationContext.java =================================================================== RCS file: /cvsroot/jboss/contrib/jetty/src/main/org/jboss/jetty/JBossWebApplicationContext.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- JBossWebApplicationContext.java 2002/01/03 20:51:05 1.12 +++ JBossWebApplicationContext.java 2002/01/12 10:57:45 1.13 @@ -5,7 +5,7 @@ * See terms of license at gnu.org. */ -// $Id: JBossWebApplicationContext.java,v 1.12 2002/01/03 20:51:05 jules_gosnell Exp $ +// $Id: JBossWebApplicationContext.java,v 1.13 2002/01/12 10:57:45 jules_gosnell Exp $ // A Jetty HttpServer with the interface expected by JBoss' // J2EEDeployer... @@ -113,11 +113,11 @@ { //_log.info("Don't moan : "+element); } - else if ("distributable".equals(element)) - { - _distributed=true; - getServletHandler().setSessionManager(new DistributedSessionManager(this)); - } + // else if ("distributable".equals(element)) + // { + // _distributed=true; + // getServletHandler().setSessionManager(new DistributedSessionManager(this)); + // } // these are handled by Jetty else super.initWebXmlElement(element, node);
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development