User: jules_gosnell Date: 02/01/06 15:54:16 Modified: jetty/src/main/org/jboss/jetty DistributedSessionManager.java Added: jetty/src/main/org/jboss/jetty AbstractHttpSessionData.java Log: abstract out the pieces that need to plug into Sacha's JMX Session stuff fix up javadoc for generated code too Revision Changes Path 1.3 +213 -97 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.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- DistributedSessionManager.java 2002/01/04 18:21:15 1.2 +++ DistributedSessionManager.java 2002/01/06 23:54:16 1.3 @@ -5,11 +5,18 @@ * See terms of license at gnu.org. */ -// $Id: DistributedSessionManager.java,v 1.2 2002/01/04 18:21:15 jules_gosnell Exp $ +// $Id: DistributedSessionManager.java,v 1.3 2002/01/06 23:54:16 jules_gosnell Exp $ -// A Jetty HttpServer with the interface expected by JBoss' -// J2EEDeployer... +// 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 + package org.jboss.jetty; import java.rmi.RemoteException; @@ -35,56 +42,148 @@ import org.mortbay.jetty.servlet.ServletHandler; import org.mortbay.util.LifeCycle; -/* --------------------------------------------------------------------- */ +//---------------------------------------- + + /** + * An abstraction of a manager for the distributed store of HttpSessions * - * @version $Id: DistributedSessionManager.java,v 1.2 2002/01/04 18:21:15 jules_gosnell Exp $ - * @author [EMAIL PROTECTED] + * @author <a href="mailto:jules_gosnell@@yahoo.com">Jules Gosnell</a> + * @version 1.0 + * @since 1.0 */ -public class DistributedSessionManager - extends org.mortbay.jetty.servlet.HashSessionManager +interface AbstractDistributedStore +{ + public String nextId(); + public AbstractHttpSessionData make(); + public AbstractHttpSessionData get(String id); + public void set(String id, AbstractHttpSessionData data); +} + +//---------------------------------------- + +/** + * An implementation of a manager of a CMP based distributed store of HttpSessions + * + * @author <a href="mailto:jules_gosnell@@yahoo.com">Jules Gosnell</a> + * @version 1.0 + * @since 1.0 + * @see AbstractDistributedStore + */ +class EJBDistributedStore + implements AbstractDistributedStore { - static InitialContext _jndiContext; + Logger _log = Logger.getLogger(getClass().getName()); + InitialContext _jndiContext; + CoarseHttpSessionHome _home; + String _name="ejb/jetty/CoarseHttpSession"; // TODO - parameterise - static + EJBDistributedStore() { try { _jndiContext=new InitialContext(); + Object o=_jndiContext.lookup(_name); + _home=(CoarseHttpSessionHome)PortableRemoteObject.narrow(o, CoarseHttpSessionHome.class); + _log.info("Support for EJB-based Distributed HttpSessions loaded: "+_home); } catch (NamingException e) { - Logger.getLogger("DistributedSessionManager"). - warn("WARNING: could not get JNDI Context - DistributedSessions are DISABLED"); + _log.warn("WARNING: Support for EJB-based Distributed HttpSessions does not appear to be loaded"); } } - - Logger _log; - JBossWebApplicationContext _context; - CoarseHttpSessionHome _home; - DistributedSessionManager(JBossWebApplicationContext context) + /** + * create a new HttpSessionData instance, of the correct type for + * this distributed store + * + */ + public AbstractHttpSessionData + make() { - super(context.getServletHandler()); + return new CoarseHttpSessionData(); + } - _context=context; - _log = Logger.getLogger(getClass().getName()+"#" +_context.getContextPath()); + /** + * retrieve HttpSessionData from a distributed store + * + * @param id a <code>String</code> value + */ + public AbstractHttpSessionData + get(String id) + { + AbstractHttpSessionData data=null; try { - if (_jndiContext!=null) - { - Object o=_jndiContext.lookup("ejb/jetty/CoarseHttpSession"); // TODO - parameterise - _home=(CoarseHttpSessionHome)PortableRemoteObject.narrow(o, CoarseHttpSessionHome.class); - _log.info("Support for Distributed HttpSessions loaded: "+_home); - } + CoarseHttpSession ejb=_home.findByPrimaryKey(id); + data= ejb.getData(); + ejb.remove(); + ejb=null; } - catch (NamingException e) + catch (RemoteException e) + {} + catch (FinderException e) + {} + catch (RemoveException e) + {} + catch (Exception e) + {} + + return data; + } + + /** + * submit HttpSessionData to a distributed store + * + * @param id a <code>String</code> value + * @param data an <code>AbstractHttpSessionData</code> value + */ + public void + set(String id, AbstractHttpSessionData data) + { + try { - _log.warn("WARNING: Support for Distributed HttpSessions does not appear to be loaded"); + CoarseHttpSession ejb=_home.create((CoarseHttpSessionData)data); + ejb=null; } + catch (RemoteException e) + {} + catch (CreateException e) + {} + } + + // dummy implementation + static int _nextId=0; + + public synchronized String + nextId() + { + return "uid-"+_nextId++; } +} +/* --------------------------------------------------------------------- */ +/** + * + * @version $Id: DistributedSessionManager.java,v 1.3 2002/01/06 23:54:16 jules_gosnell Exp $ + * @author [EMAIL PROTECTED] + */ +public class DistributedSessionManager + extends org.mortbay.jetty.servlet.HashSessionManager +{ + Logger _log; + JBossWebApplicationContext _context; + static AbstractDistributedStore _manager=new EJBDistributedStore(); // hardwired for the moment - TODO + + DistributedSessionManager(JBossWebApplicationContext context) + { + super(context.getServletHandler()); + + _context=context; + _log =Logger.getLogger(getClass().getName()+"#" +_context.getContextPath()); + } + public HttpSession getHttpSession(String id) { @@ -92,23 +191,8 @@ HttpSession s = (HttpSession)_sessions.get(id); // 2. check distributed store - if (s==null && _home!=null) - { - try - { - CoarseHttpSession ejb=_home.findByPrimaryKey(id); - s=new DistributedSession(id, ejb); - } - catch (RemoteException e) - { - } - catch (FinderException e) - { - } - catch (Exception e) - { - } - } + if (s==null && _manager!=null) + s=new DistributedSession(id, _manager.get(id)); return s; } @@ -130,7 +214,7 @@ // { // HttpSession session=super.newHttpSession(); // String id=session.getId(); - // _log.info("creating distributed state for session: "+id); + // _log.info("creating distributed data for session: "+id); // return session; // } @@ -190,102 +274,134 @@ // create a completely new session DistributedSession() { - super(); + _id =_manager.nextId(); _log=Logger.getLogger(getClass().getName()+"#" +getId()); + _log.info("new: "+getId()); + + int dftMaxIdleSecs=_dftMaxIdleSecs; + + if (dftMaxIdleSecs>=0) + _maxIdleMs=dftMaxIdleSecs*1000; } // reactivate a passivated session - DistributedSession(String id, CoarseHttpSession ejb) + DistributedSession(String id, AbstractHttpSessionData data) { _id=id; _log=Logger.getLogger(getClass().getName()+"#" +getId()); + + activate(data); + } - activate(ejb); + protected void + activate(AbstractHttpSessionData data) + { + activate(data, true); } protected synchronized void - activate(CoarseHttpSession ejb) + activate(AbstractHttpSessionData data, boolean activateAttributes) { if (_invalid) throw new IllegalStateException(); _values = new HashMap(11); + _values.putAll(data.getAttributes()); + _created =data.getCreationTime(); + _accessed =data.getLastAccessedTime(); + _maxIdleMs =data.getMaxInactiveInterval()*1000; + _newSession =false; - // initialise state from EJB, then remove ejb - in a single transaction... - - // this is currently two operations - getData() and remove(). It - // would benefit from being enclosed by a UserTransaction... - try - { - CoarseHttpSessionData data=ejb.getData(); - - _values.putAll(data.getAttributes()); - _created =data.getCreationTime(); - _accessed =data.getLastAccessedTime(); - _maxIdleMs =data.getMaxInactiveInterval()*1000; - _newSession =false; - - _log.info("Session activated: "+ejb); - ejb.remove(); - ejb=null; - } - catch (RemoteException e) - {} - catch (RemoveException e) - {} - // send activate events to listening attributes - if (_values.size()>0) + if (activateAttributes && _values.size()>0) { + boolean warn=!data.getAttributesWerePassivated(); HttpSessionEvent event=new HttpSessionEvent(this); Iterator i = _values.values().iterator(); - while (i.hasNext()) - activateValue(i.next(), event); + + try + { + while (i.hasNext()) + activateValue(i.next(), event, warn); + } + catch (Exception e) + { + _log.error("Problem whilst activating session attributes", e); + } } + _log.info("Session activated: "+getId()); } protected void - activateValue(Object attribute, HttpSessionEvent event) + activateValue(Object attribute, HttpSessionEvent event, boolean warn) { if (attribute!=null && 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 synchronized void + protected void passivate() { + passivate(true); + } + + // 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. + + // how can we prevent this, without throwing a lock around every + // attribute access ? + + // 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 + + protected synchronized void + passivate(boolean passivateAttributes) + { if (_invalid) throw new IllegalStateException(); - if (_home!=null && _values.size()>0) + if (_manager!=null && + _values.size()>0) // not sure about 2nd test - TODO { - // send passivate events to listening attributes... - HttpSessionEvent event=new HttpSessionEvent(this); - Iterator i = _values.values().iterator(); - while (i.hasNext()) - passivateValue(i.next(), event); + 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); + } + } // should we bother to remove ourselves from our manager's // session list ? - // create and EJB and dump state into it - in a single transaction - CoarseHttpSessionData data=new CoarseHttpSessionData(); + // 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()); - - try - { - CoarseHttpSession ejb=_home.create(data); - _log.info("Session passivated: "+ejb); - ejb=null; - } - catch (RemoteException e) - {} - catch (CreateException e) - {} + data.setAttributesWerePassivated(passivateAttributes); + _manager.set(getId(), data); } + + _log.info("Session passivated: "+getId()); } protected void 1.1 contrib/jetty/src/main/org/jboss/jetty/AbstractHttpSessionData.java Index: AbstractHttpSessionData.java =================================================================== package org.jboss.jetty; //---------------------------------------- import java.util.Map; //---------------------------------------- /** * An abstraction of the data used for the distributed store of HttpSessions * * @author <a href="mailto:jules_gosnell@@yahoo.com">Jules Gosnell</a> * @version 1.0 * @since 1.0 */ public interface AbstractHttpSessionData { // from javax.servlet.http.HttpSession public long getCreationTime(); public String getId(); public long getLastAccessedTime(); public int getMaxInactiveInterval(); public void setMaxInactiveInterval(int maxInactiveInterval); // extra accessors public Map getAttributes(); public void setAttributes(Map attributes); public void setId(String id); public void setCreationTime(long creationTime); public void setLastAccessedTime(long lastAccessedTime); // extra attributes public boolean getAttributesWerePassivated(); public void setAttributesWerePassivated(boolean attributesWerePassivated); }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development