User: jules_gosnell Date: 02/01/13 05:26:45 Added: jetty/src/main/org/jboss/jetty/session AbstractHttpSessionData.java CoarseDistributedStore.java DistributedHttpSession.java DistributedHttpSessionManager.java Log: split src into dirs check in latest DistributedSession code Revision Changes Path 1.1 contrib/jetty/src/main/org/jboss/jetty/session/AbstractHttpSessionData.java Index: AbstractHttpSessionData.java =================================================================== /* * jBoss, the OpenSource EJB server * * Distributable under GPL license. * See terms of license at gnu.org. */ // $Id: AbstractHttpSessionData.java,v 1.1 2002/01/13 13:26:45 jules_gosnell Exp $ //---------------------------------------- package org.jboss.jetty.session; //---------------------------------------- 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); } 1.1 contrib/jetty/src/main/org/jboss/jetty/session/CoarseDistributedStore.java Index: CoarseDistributedStore.java =================================================================== /* * jBoss, the OpenSource EJB server * * Distributable under GPL license. * See terms of license at gnu.org. */ // $Id: CoarseDistributedStore.java,v 1.1 2002/01/13 13:26:45 jules_gosnell Exp $ //---------------------------------------- package org.jboss.jetty.session; //---------------------------------------- import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.FinderException; import javax.ejb.RemoveException; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.rmi.PortableRemoteObject; import org.jboss.jetty.interfaces.CoarseHttpSession; import org.jboss.jetty.interfaces.CoarseHttpSessionData; import org.jboss.jetty.interfaces.CoarseHttpSessionHome; import org.jboss.logging.Logger; //---------------------------------------- /** * An abstraction of a manager for the distributed store of HttpSessions * * @author <a href="mailto:jules_gosnell@@yahoo.com">Jules Gosnell</a> * @version 1.0 * @since 1.0 */ interface AbstractStore { 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 AbstractStore */ class EJBDistributedStore implements AbstractStore { Logger _log = Logger.getLogger(getClass().getName()); InitialContext _jndiContext; CoarseHttpSessionHome _home; String _name="ejb/jetty/CoarseHttpSession"; // TODO - parameterise 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) { _log.warn("WARNING: Support for EJB-based Distributed HttpSessions does not appear to be loaded"); } } /** * create a new HttpSessionData instance, of the correct type for * this distributed store * */ public AbstractHttpSessionData make() { return new CoarseHttpSessionData(); } /** * retrieve HttpSessionData from a distributed store * * @param id a <code>String</code> value */ public AbstractHttpSessionData get(String id) { AbstractHttpSessionData data=null; try { CoarseHttpSession ejb=_home.findByPrimaryKey(id); data= ejb.getData(); ejb.remove(); ejb=null; } 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 { CoarseHttpSession ejb=_home.create((CoarseHttpSessionData)data); ejb=null; } catch (RemoteException e) {} catch (CreateException e) {} } final Object _idLock=new Object(); long _nextId=0; public synchronized String nextId() { long id; synchronized (_idLock) { id=_nextId++; } return ""+System.currentTimeMillis()+"-"+id; } } 1.1 contrib/jetty/src/main/org/jboss/jetty/session/DistributedHttpSession.java Index: DistributedHttpSession.java =================================================================== /** * 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 */ //---------------------------------------- package org.jboss.jetty.session; //---------------------------------------- import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionContext; import javax.servlet.http.HttpSessionEvent; import org.jboss.logging.Logger; import org.mortbay.jetty.servlet.SessionContext; //---------------------------------------- interface AbstractHttpSession extends HttpSession, org.mortbay.jetty.servlet.SessionManager.Session { } class DistributedHttpSession implements AbstractHttpSession { final DistributedHttpSessionManager _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; final Object _maxInactiveIntervalLock =new Object(); int _maxInactiveInterval; //---------------------------------------- // create a completely new session DistributedHttpSession(DistributedHttpSessionManager 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 DistributedHttpSession(DistributedHttpSessionManager 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 { while (i.hasNext()) notifySessionDidActivate(i.next(), event, warn); } catch (Exception e) { _log.error("Problem whilst activating session attributes", e); } } _log.info("Session activated: "+getId()); } 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); } } } //---------------------------------------- // 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 { _maxInactiveInterval=secs; // guarded _isDirty=true; // volatile } } _manager.getScavenger().reregister(this, System.currentTimeMillis(), (long)secs*1000); } public void invalidate() throws IllegalStateException { _isValid=false; _manager.destroyHttpSession(this); } 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) { // the javadoc says if the value is null, this is the same as // remove... removeAttribute(name); return; } if (!isValid()) throw new IllegalStateException(); Object oldValue; synchronized (_attributes) { oldValue = _attributes.put(name,value); } if (oldValue==value) { if (_heldByValue) // TODO _isDirty=true; // the contents of value may have changed // perhaps we should raise an 'attributeReplaced' here ? // this should be configurable - TODO } else { _isDirty=true; // perhaps this test should have been 'equals()' - but I // figure that would be too expensive... - TODO Object tmp=value; // assume an attribute was added // notify the old value if necessary if (oldValue!=null) { notifyValueUnbound(name, oldValue); tmp=oldValue; // actually - an attribute was replaced } // 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); } if (oldValue!=null) { // we did remove an attribute... _isDirty=true; // 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.1 contrib/jetty/src/main/org/jboss/jetty/session/DistributedHttpSessionManager.java Index: DistributedHttpSessionManager.java =================================================================== /* * jBoss, the OpenSource EJB server * * Distributable under GPL license. * See terms of license at gnu.org. */ // $Id: DistributedHttpSessionManager.java,v 1.1 2002/01/13 13:26:45 jules_gosnell Exp $ // TODO // keep all state in HttpSessionState objects // keep all HttpSessionState instances in Store // rename a few things // test.... // release !!!! //---------------------------------------- package org.jboss.jetty.session; //---------------------------------------- import java.util.ArrayList; import java.util.EventListener; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import org.jboss.jetty.JBossWebApplicationContext; import org.jboss.jetty.util.AbstractTimeOutManager; import org.jboss.jetty.util.NaiveTimeOutManager; import org.jboss.logging.Logger; import org.mortbay.jetty.servlet.ServletHandler; //------------------------------------------------------------------------------ /** * * @version $Id: DistributedHttpSessionManager.java,v 1.1 2002/01/13 13:26:45 jules_gosnell Exp $ * @author [EMAIL PROTECTED] */ public class DistributedHttpSessionManager implements org.mortbay.jetty.servlet.SessionManager { static AbstractStore _store =new EJBDistributedStore(); // hardwired for the moment - TODO final AbstractTimeOutManager _scavenger =new NaiveTimeOutManager(5*1000, new MyTimeOutNotifier()); final Logger _log; final JBossWebApplicationContext _context; final ServletHandler _handler; final List _sessionListeners =new ArrayList(); final List _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... //---------------------------------------- class MyTimeOutNotifier implements AbstractTimeOutManager.TimeOutNotifier { public void timeOut(Object object) { destroyHttpSession((DistributedHttpSession)object); } } //---------------------------------------- public DistributedHttpSessionManager(JBossWebApplicationContext context) { _context=context; _handler=_context.getServletHandler(); _log =Logger.getLogger(getClass().getName()+"#" +_context.getContextPath()); } //---------------------------------------- // factory public HttpSession newHttpSession() { String id=getStore().nextId(); DistributedHttpSession session = new DistributedHttpSession(this, id, _dftMaxIdleSecs); putSession(id,session); notifySessionCreated(session); getScavenger().register(session, System.currentTimeMillis(), _dftMaxIdleSecs*1000); return session; } public void destroyHttpSession(DistributedHttpSession session) { getScavenger().deregister(session); removeSession(session); notifySessionDestroyed(session); session.destroy(); } public void passivateHttpSession(DistributedHttpSession session) { getScavenger().deregister(session); removeSession(session); session.passivate(); } public HttpSession getHttpSession(String id) // hopefully local and distributed store will become same { DistributedHttpSession session=null; // 1. check local store session = getSession(id); // 2. check distributed store if (session==null && _store!=null) { session=new DistributedHttpSession(this, id, _store.get(id)); putSession(id,session); notifySessionCreated(session); getScavenger().register(session, System.currentTimeMillis(), session.getMaxInactiveInterval()*1000); } return session; } // wrappers to access session table... DistributedHttpSession getSession(String id) { synchronized (_sessions) {return (DistributedHttpSession)_sessions.get(id);} } void putSession(String id, DistributedHttpSession session) { synchronized (_sessions) {_sessions.put(id, session);} } void removeSession(DistributedHttpSession session) { synchronized (_sessions) {_sessions.remove(session.getId());} } //---------------------------------------- // lifecycle public boolean isStarted() { return _isStarted; } public void start() throws Exception { _isStarted=true; // sessions are activated lazily... } public void stop() // TODO { _isStarted=false; // TODO // tidy up all sessions... List sessions = new ArrayList(_sessions.values()); for (Iterator i = sessions.iterator(); i.hasNext(); ) { DistributedHttpSession session=(DistributedHttpSession)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... AbstractTimeOutManager getScavenger() // TODO { return _scavenger; } AbstractStore getStore() // TODO { return _store; } ServletHandler getHandler() // TODO { return _handler; } ServletContext getServletContext() // TODO { return getHandler().getServletContext(); } //---------------------------------------- // Listeners // Listeners are added before requests start coming in, so this code // needs no synchronisation... public void addEventListener(EventListener listener) throws IllegalArgumentException { 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); } public void removeEventListener(EventListener listener) { if (listener instanceof HttpSessionAttributeListener) _sessionAttributeListeners.remove(listener); if (listener instanceof HttpSessionListener) _sessionListeners.remove(listener); } void notifyAttributeAdded(HttpSession session, String key, Object value) { if (_sessionAttributeListeners.size()>0) { HttpSessionBindingEvent event = new HttpSessionBindingEvent(session, key, value); for(int i=0;i<_sessionAttributeListeners.size();i++) ((HttpSessionAttributeListener) _sessionAttributeListeners.get(i)).attributeAdded(event); } } void notifyAttributeReplaced(HttpSession session, String key, Object value) { if (_sessionAttributeListeners.size()>0) { HttpSessionBindingEvent event = new HttpSessionBindingEvent(session, key, value); for(int i=0;i<_sessionAttributeListeners.size();i++) ((HttpSessionAttributeListener) _sessionAttributeListeners.get(i)).attributeReplaced(event); } } void notifyAttributeRemoved(HttpSession session, String key, Object value) { if (_sessionAttributeListeners.size()>0) { HttpSessionBindingEvent event = new HttpSessionBindingEvent(session, key, value); for(int i=0;i<_sessionAttributeListeners.size();i++) ((HttpSessionAttributeListener) _sessionAttributeListeners.get(i)).attributeRemoved(event); } } void notifySessionCreated(HttpSession session) { if (_sessionListeners.size()>0) { HttpSessionEvent event = new HttpSessionEvent(session); for(int i=0;i<_sessionListeners.size();i++) ((HttpSessionListener)_sessionListeners.get(i)) .sessionCreated(event); } } void notifySessionDestroyed(HttpSession session) { if (_sessionListeners.size()>0) { HttpSessionEvent event = new HttpSessionEvent(session); for(int i=0;i<_sessionListeners.size();i++) ((HttpSessionListener)_sessionListeners.get(i)) .sessionDestroyed(event); } } }
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development