View Javadoc

    1   // ========================================================================
    2   // Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
    3   // ------------------------------------------------------------------------
    4   // Licensed under the Apache License, Version 2.0 (the "License");
    5   // you may not use this file except in compliance with the License.
    6   // You may obtain a copy of the License at
    7   // http://www.apache.org/licenses/LICENSE-2.0
    8   // Unless required by applicable law or agreed to in writing, software
    9   // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  // ========================================================================
    14
    15  package org.mortbay.jetty.servlet;
    16
    17  import java.io.Serializable;
    18  import java.util.ArrayList;
    19  import java.util.Collections;
    20  import java.util.Enumeration;
    21  import java.util.EventListener;
    22  import java.util.Iterator;
    23  import java.util.List;
    24  import java.util.Map;
    25
    26  import javax.servlet.ServletContext;
    27  import javax.servlet.http.Cookie;
    28  import javax.servlet.http.HttpServletRequest;
    29  import javax.servlet.http.HttpSession;
    30  import javax.servlet.http.HttpSessionActivationListener;
    31  import javax.servlet.http.HttpSessionAttributeListener;
    32  import javax.servlet.http.HttpSessionBindingEvent;
    33  import javax.servlet.http.HttpSessionBindingListener;
    34  import javax.servlet.http.HttpSessionContext;
    35  import javax.servlet.http.HttpSessionEvent;
    36  import javax.servlet.http.HttpSessionListener;
    37
    38  import org.mortbay.component.AbstractLifeCycle;
    39  import org.mortbay.jetty.HttpOnlyCookie;
    40  import org.mortbay.jetty.Server;
    41  import org.mortbay.jetty.SessionIdManager;
    42  import org.mortbay.jetty.SessionManager;
    43  import org.mortbay.jetty.handler.ContextHandler;
    44  import org.mortbay.util.LazyList;
    45
    46  /* ------------------------------------------------------------ */
    47  /**
    48   * An Abstract implementation of SessionManager. The partial implementation of
    49   * SessionManager interface provides the majority of the handling required to
    50   * implement a SessionManager. Concrete implementations of SessionManager based
    51   * on AbstractSessionManager need only implement the newSession method to return
    52   * a specialized version of the Session inner class that provides an attribute
    53   * Map.
    54   * <p>
    55   * If the property
    56   * org.mortbay.jetty.servlet.AbstractSessionManager.23Notifications is set to
    57   * true, the 2.3 servlet spec notification style will be used.
    58   * <p>
    59   *
    60   * @author Greg Wilkins (gregw)
    61   */
    62  public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager
    63  {
    64      /* ------------------------------------------------------------ */
    65      public final static int __distantFuture=60*60*24*7*52*20;
    66
    67      private static final HttpSessionContext __nullSessionContext=new NullSessionContext();
    68
    69      private boolean _usingCookies=true;
    70
    71      /* ------------------------------------------------------------ */
    72      // Setting of max inactive interval for new sessions
    73      // -1 means no timeout
    74      protected int _dftMaxIdleSecs=-1;
    75      protected SessionHandler _sessionHandler;
    76      protected boolean _httpOnly=false;
    77      protected int _maxSessions=0;
    78
    79      protected int _minSessions=0;
    80      protected SessionIdManager _sessionIdManager;
    81      protected boolean _secureCookies=false;
    82      protected Object _sessionAttributeListeners;
    83      protected Object _sessionListeners;
    84
    85      protected ClassLoader _loader;
    86      protected ContextHandler.SContext _context;
    87      protected String _sessionCookie=__DefaultSessionCookie;
    88      protected String _sessionURL=__DefaultSessionURL;
    89      protected String _sessionURLPrefix=";"+_sessionURL+"=";
    90      protected String _sessionDomain;
    91      protected String _sessionPath;
    92      protected int _maxCookieAge=-1;
    93      protected int _refreshCookieAge;
    94      protected boolean _nodeIdInSessionId;
    95
    96      /* ------------------------------------------------------------ */
    97      public AbstractSessionManager()
    98      {
    99      }
    100
    101     /* ------------------------------------------------------------ */
    102     public Cookie access(HttpSession session,boolean secure)
    103     {
    104         long now=System.currentTimeMillis();
    105
    106         Session s = ((SessionIf)session).getSession();
    107         s.access(now);
    108
    109         // Do we need to refresh the cookie?
    110         if (isUsingCookies() &&
    111             (s.isIdChanged() ||
    112              (getMaxCookieAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge()))
    113             )
    114            )
    115         {
    116             Cookie cookie=getSessionCookie(session,_context.getContextPath(),secure);
    117             s.cookieSet();
    118             s.setIdChanged(false);
    119             return cookie;
    120         }
    121
    122         return null;
    123     }
    124
    125     /* ------------------------------------------------------------ */
    126     public void addEventListener(EventListener listener)
    127     {
    128         if (listener instanceof HttpSessionAttributeListener)
    129             _sessionAttributeListeners=LazyList.add(_sessionAttributeListeners,listener);
    130         if (listener instanceof HttpSessionListener)
    131             _sessionListeners=LazyList.add(_sessionListeners,listener);
    132     }
    133
    134     /* ------------------------------------------------------------ */
    135     public void clearEventListeners()
    136     {
    137         _sessionAttributeListeners=null;
    138         _sessionListeners=null;
    139     }
    140
    141     /* ------------------------------------------------------------ */
    142     public void complete(HttpSession session)
    143     {
    144         Session s = ((SessionIf)session).getSession();
    145         s.complete();
    146     }
    147
    148     /* ------------------------------------------------------------ */
    149     public void doStart() throws Exception
    150     {
    151         _context=ContextHandler.getCurrentContext();
    152         _loader=Thread.currentThread().getContextClassLoader();
    153
    154         if (_sessionIdManager==null)
    155         {
    156             Server server=getSessionHandler().getServer();
    157             synchronized (server)
    158             {
    159                 _sessionIdManager=server.getSessionIdManager();
    160                 if (_sessionIdManager==null)
    161                 {
    162                     _sessionIdManager=new HashSessionIdManager();
    163                     server.setSessionIdManager(_sessionIdManager);
    164                 }
    165             }
    166         }
    167         if (!_sessionIdManager.isStarted())
    168             _sessionIdManager.start();
    169
    170         // Look for a session cookie name
    171         String tmp=_context.getInitParameter(SessionManager.__SessionCookieProperty);
    172         if (tmp!=null)
    173             _sessionCookie=tmp;
    174
    175         tmp=_context.getInitParameter(SessionManager.__SessionURLProperty);
    176         if (tmp!=null)
    177         {
    178             _sessionURL=(tmp==null||"none".equals(tmp))?null:tmp;
    179             _sessionURLPrefix=(tmp==null||"none".equals(tmp))?null:(";"+_sessionURL+"=");
    180         }
    181
    182         // set up the max session cookie age if it isn't already
    183         if (_maxCookieAge==-1)
    184         {
    185             if (_context!=null)
    186             {
    187                 String str=_context.getInitParameter(SessionManager.__MaxAgeProperty);
    188                 if (str!=null)
    189                     _maxCookieAge=Integer.parseInt(str.trim());
    190             }
    191         }
    192         // set up the session domain if it isn't already
    193         if (_sessionDomain==null)
    194         {
    195             // only try the context initParams
    196             if (_context!=null)
    197                 _sessionDomain=_context.getInitParameter(SessionManager.__SessionDomainProperty);
    198         }
    199
    200         // set up the sessionPath if it isn't already
    201         if (_sessionPath==null)
    202         {
    203             // only the context initParams
    204             if (_context!=null)
    205                 _sessionPath=_context.getInitParameter(SessionManager.__SessionPathProperty);
    206         }
    207
    208         super.doStart();
    209     }
    210
    211     /* ------------------------------------------------------------ */
    212     public void doStop() throws Exception
    213     {
    214         super.doStop();
    215
    216         invalidateSessions();
    217
    218         _loader=null;
    219     }
    220
    221     /* ------------------------------------------------------------ */
    222     /**
    223      * @return Returns the httpOnly.
    224      */
    225     public boolean getHttpOnly()
    226     {
    227         return _httpOnly;
    228     }
    229
    230     /* ------------------------------------------------------------ */
    231     public HttpSession getHttpSession(String nodeId)
    232     {
    233         String cluster_id = getIdManager().getClusterId(nodeId);
    234
    235         synchronized (this)
    236         {
    237             Session session = getSession(cluster_id);
    238
    239             if (session!=null && !session.getNodeId().equals(nodeId))
    240                 session.setIdChanged(true);
    241             return session;
    242         }
    243     }
    244
    245     /* ------------------------------------------------------------ */
    246     /* ------------------------------------------------------------ */
    247     /**
    248      * @return Returns the metaManager used for cross context session management
    249      */
    250     public SessionIdManager getIdManager()
    251     {
    252         return _sessionIdManager;
    253     }
    254
    255     /* ------------------------------------------------------------ */
    256     public int getMaxCookieAge()
    257     {
    258         return _maxCookieAge;
    259     }
    260
    261     /* ------------------------------------------------------------ */
    262     /**
    263      * @return seconds
    264      */
    265     public int getMaxInactiveInterval()
    266     {
    267         return _dftMaxIdleSecs;
    268     }
    269
    270     /* ------------------------------------------------------------ */
    271     public int getMaxSessions()
    272     {
    273         return _maxSessions;
    274     }
    275
    276     /* ------------------------------------------------------------ */
    277     /**
    278      * @deprecated use {@link #getIdManager()}
    279      */
    280     public SessionIdManager getMetaManager()
    281     {
    282         return getIdManager();
    283     }
    284
    285     /* ------------------------------------------------------------ */
    286     public int getMinSessions()
    287     {
    288         return _minSessions;
    289     }
    290
    291     /* ------------------------------------------------------------ */
    292     public int getRefreshCookieAge()
    293     {
    294         return _refreshCookieAge;
    295     }
    296
    297
    298     /* ------------------------------------------------------------ */
    299     /**
    300      * @return Returns the secureCookies.
    301      */
    302     public boolean getSecureCookies()
    303     {
    304         return _secureCookies;
    305     }
    306
    307     /* ------------------------------------------------------------ */
    308     public String getSessionCookie()
    309     {
    310         return _sessionCookie;
    311     }
    312
    313     /* ------------------------------------------------------------ */
    314     public Cookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure)
    315     {
    316         if (isUsingCookies())
    317         {
    318             String id = getNodeId(session);
    319             Cookie cookie=getHttpOnly()?new HttpOnlyCookie(_sessionCookie,id):new Cookie(_sessionCookie,id);
    320
    321             cookie.setPath((contextPath==null||contextPath.length()==0)?"/":contextPath);
    322             cookie.setMaxAge(getMaxCookieAge());
    323             cookie.setSecure(requestIsSecure&&getSecureCookies());
    324
    325             // set up the overrides
    326             if (_sessionDomain!=null)
    327                 cookie.setDomain(_sessionDomain);
    328             if (_sessionPath!=null)
    329                 cookie.setPath(_sessionPath);
    330
    331             return cookie;
    332         }
    333         return null;
    334     }
    335
    336     public String getSessionDomain()
    337     {
    338         return _sessionDomain;
    339     }
    340
    341     /* ------------------------------------------------------------ */
    342     /**
    343      * @return Returns the sessionHandler.
    344      */
    345     public SessionHandler getSessionHandler()
    346     {
    347         return _sessionHandler;
    348     }
    349
    350     /* ------------------------------------------------------------ */
    351     /**
    352      * @deprecated.  Need to review if it is needed.
    353      */
    354     public abstract Map getSessionMap();
    355
    356     /* ------------------------------------------------------------ */
    357     public String getSessionPath()
    358     {
    359         return _sessionPath;
    360     }
    361
    362     /* ------------------------------------------------------------ */
    363     public abstract int getSessions();
    364
    365     /* ------------------------------------------------------------ */
    366     public String getSessionURL()
    367     {
    368         return _sessionURL;
    369     }
    370
    371     /* ------------------------------------------------------------ */
    372     public String getSessionURLPrefix()
    373     {
    374         return _sessionURLPrefix;
    375     }
    376
    377     /* ------------------------------------------------------------ */
    378     /**
    379      * @return Returns the usingCookies.
    380      */
    381     public boolean isUsingCookies()
    382     {
    383         return _usingCookies;
    384     }
    385
    386     /* ------------------------------------------------------------ */
    387     public boolean isValid(HttpSession session)
    388     {
    389         Session s = ((SessionIf)session).getSession();
    390         return s.isValid();
    391     }
    392
    393     /* ------------------------------------------------------------ */
    394     public String getClusterId(HttpSession session)
    395     {
    396         Session s = ((SessionIf)session).getSession();
    397         return s.getClusterId();
    398     }
    399
    400     /* ------------------------------------------------------------ */
    401     public String getNodeId(HttpSession session)
    402     {
    403         Session s = ((SessionIf)session).getSession();
    404         return s.getNodeId();
    405     }
    406
    407     /* ------------------------------------------------------------ */
    408     /**
    409      * Create a new HttpSession for a request
    410      */
    411     public HttpSession newHttpSession(HttpServletRequest request)
    412     {
    413         Session session=newSession(request);
    414         session.setMaxInactiveInterval(_dftMaxIdleSecs);
    415         addSession(session,true);
    416         return session;
    417     }
    418
    419     /* ------------------------------------------------------------ */
    420     public void removeEventListener(EventListener listener)
    421     {
    422         if (listener instanceof HttpSessionAttributeListener)
    423             _sessionAttributeListeners=LazyList.remove(_sessionAttributeListeners,listener);
    424         if (listener instanceof HttpSessionListener)
    425             _sessionListeners=LazyList.remove(_sessionListeners,listener);
    426     }
    427
    428     /* ------------------------------------------------------------ */
    429     public void resetStats()
    430     {
    431         _minSessions=getSessions();
    432         _maxSessions=getSessions();
    433     }
    434
    435     /* ------------------------------------------------------------ */
    436     /**
    437      * @param httpOnly
    438      *            The httpOnly to set.
    439      */
    440     public void setHttpOnly(boolean httpOnly)
    441     {
    442         _httpOnly=httpOnly;
    443     }
    444
    445
    446     /* ------------------------------------------------------------ */
    447     /**
    448      * @param metaManager The metaManager used for cross context session management.
    449      */
    450     public void setIdManager(SessionIdManager metaManager)
    451     {
    452         _sessionIdManager=metaManager;
    453     }
    454
    455     /* ------------------------------------------------------------ */
    456     public void setMaxCookieAge(int maxCookieAgeInSeconds)
    457     {
    458         _maxCookieAge=maxCookieAgeInSeconds;
    459
    460         if (_maxCookieAge>0 && _refreshCookieAge==0)
    461             _refreshCookieAge=_maxCookieAge/3;
    462
    463     }
    464
    465     /* ------------------------------------------------------------ */
    466     /**
    467      * @param seconds
    468      */
    469     public void setMaxInactiveInterval(int seconds)
    470     {
    471         _dftMaxIdleSecs=seconds;
    472     }
    473
    474     /* ------------------------------------------------------------ */
    475     /**
    476      * @deprecated use {@link #setIdManager(SessionIdManager)}
    477      */
    478     public void setMetaManager(SessionIdManager metaManager)
    479     {
    480         setIdManager(metaManager);
    481     }
    482
    483     /* ------------------------------------------------------------ */
    484     public void setRefreshCookieAge(int ageInSeconds)
    485     {
    486         _refreshCookieAge=ageInSeconds;
    487     }
    488
    489
    490     /* ------------------------------------------------------------ */
    491     /**
    492      * @param secureCookies
    493      *            The secureCookies to set.
    494      */
    495     public void setSecureCookies(boolean secureCookies)
    496     {
    497         _secureCookies=secureCookies;
    498     }
    499
    500     public void setSessionCookie(String cookieName)
    501     {
    502         _sessionCookie=cookieName;
    503     }
    504
    505     public void setSessionDomain(String domain)
    506     {
    507         _sessionDomain=domain;
    508     }
    509
    510     /* ------------------------------------------------------------ */
    511     /**
    512      * @param sessionHandler
    513      *            The sessionHandler to set.
    514      */
    515     public void setSessionHandler(SessionHandler sessionHandler)
    516     {
    517         _sessionHandler=sessionHandler;
    518     }
    519
    520     /* ------------------------------------------------------------ */
    521     public void setSessionPath(String path)
    522     {
    523         _sessionPath=path;
    524     }
    525
    526     /* ------------------------------------------------------------ */
    527     /** Set the session ID URL parameter name
    528      * @param param The parameter name for session id URL rewriting (null or "none" for no rewriting).
    529      */
    530     public void setSessionURL(String param)
    531     {
    532         _sessionURL=(param==null||"none".equals(param))?null:param;
    533         _sessionURLPrefix=(param==null||"none".equals(param))?null:(";"+_sessionURL+"=");
    534     }
    535     /* ------------------------------------------------------------ */
    536     /**
    537      * @param usingCookies
    538      *            The usingCookies to set.
    539      */
    540     public void setUsingCookies(boolean usingCookies)
    541     {
    542         _usingCookies=usingCookies;
    543     }
    544
    545
    546     protected abstract void addSession(Session session);
    547
    548     /* ------------------------------------------------------------ */
    549     /**
    550      * Add the session Registers the session with this manager and registers the
    551      * session ID with the sessionIDManager;
    552      */
    553     protected void addSession(Session session, boolean created)
    554     {
    555         synchronized (_sessionIdManager)
    556         {
    557             _sessionIdManager.addSession(session);
    558             synchronized (this)
    559             {
    560                 addSession(session);
    561                 if (getSessions()>this._maxSessions)
    562                     this._maxSessions=getSessions();
    563             }
    564         }
    565
    566         if (!created)
    567         {
    568             session.didActivate();
    569         }
    570         else if (_sessionListeners!=null)
    571         {
    572             HttpSessionEvent event=new HttpSessionEvent(session);
    573             for (int i=0; i<LazyList.size(_sessionListeners); i++)
    574                 ((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionCreated(event);
    575         }
    576     }
    577
    578     /* ------------------------------------------------------------ */
    579     /**
    580      * Get a known existingsession
    581      * @param idInCluster The session ID in the cluster, stripped of any worker name.
    582      * @return A Session or null if none exists.
    583      */
    584     public abstract Session getSession(String idInCluster);
    585
    586     protected abstract void invalidateSessions();
    587
    588
    589     /* ------------------------------------------------------------ */
    590     /**
    591      * Create a new session instance
    592      * @param request
    593      * @return
    594      */
    595     protected abstract Session newSession(HttpServletRequest request);
    596
    597
    598
    599     /* ------------------------------------------------------------ */
    600     /**
    601      * @return true if the cluster node id (worker id) is returned as part of the session id by {@link HttpSession#getId()}. Default is false.
    602      */
    603     public boolean isNodeIdInSessionId()
    604     {
    605         return _nodeIdInSessionId;
    606     }
    607
    608     /* ------------------------------------------------------------ */
    609     /**
    610      * @param nodeIdInSessionId true if the cluster node id (worker id) will be returned as part of the session id by {@link HttpSession#getId()}. Default is false.
    611      */
    612     public void setNodeIdInSessionId(boolean nodeIdInSessionId)
    613     {
    614         _nodeIdInSessionId=nodeIdInSessionId;
    615     }
    616
    617     /* ------------------------------------------------------------ */
    618     /** Remove session from manager
    619      * @param session The session to remove
    620      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
    621      * {@link SessionIdManager#invalidateAll(String)} should be called.
    622      */
    623     public void removeSession(HttpSession session, boolean invalidate)
    624     {
    625         Session s = ((SessionIf)session).getSession();
    626         removeSession(s,invalidate);
    627     }
    628
    629     /* ------------------------------------------------------------ */
    630     /** Remove session from manager
    631      * @param session The session to remove
    632      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
    633      * {@link SessionIdManager#invalidateAll(String)} should be called.
    634      */
    635     public void removeSession(Session session, boolean invalidate)
    636     {
    637         // Remove session from context and global maps
    638         synchronized (_sessionIdManager)
    639         {
    640             boolean removed = false;
    641
    642             synchronized (this)
    643             {
    644                 //take this session out of the map of sessions for this context
    645                 if (getSession(session.getClusterId()) != null)
    646                 {
    647                     removed = true;
    648                     removeSession(session.getClusterId());
    649                 }
    650             }
    651
    652             if (removed)
    653             {
    654                 // Remove session from all context and global id maps
    655                 _sessionIdManager.removeSession(session);
    656                 if (invalidate)
    657                     _sessionIdManager.invalidateAll(session.getClusterId());
    658             }
    659         }
    660
    661         if (invalidate && _sessionListeners!=null)
    662         {
    663             HttpSessionEvent event=new HttpSessionEvent(session);
    664             for (int i=LazyList.size(_sessionListeners); i-->0;)
    665                 ((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionDestroyed(event);
    666         }
    667         if (!invalidate)
    668         {
    669             session.willPassivate();
    670         }
    671     }
    672
    673     /* ------------------------------------------------------------ */
    674     protected abstract void removeSession(String idInCluster);
    675
    676     /* ------------------------------------------------------------ */
    677     /**
    678      * Null returning implementation of HttpSessionContext
    679      *
    680      * @author Greg Wilkins (gregw)
    681      */
    682     public static class NullSessionContext implements HttpSessionContext
    683     {
    684         /* ------------------------------------------------------------ */
    685         private NullSessionContext()
    686         {
    687         }
    688
    689         /* ------------------------------------------------------------ */
    690         /**
    691          * @deprecated From HttpSessionContext
    692          */
    693         public Enumeration getIds()
    694         {
    695             return Collections.enumeration(Collections.EMPTY_LIST);
    696         }
    697
    698         /* ------------------------------------------------------------ */
    699         /**
    700          * @deprecated From HttpSessionContext
    701          */
    702         public HttpSession getSession(String id)
    703         {
    704             return null;
    705         }
    706     }
    707
    708     /* ------------------------------------------------------------ */
    709     /* ------------------------------------------------------------ */
    710     /* ------------------------------------------------------------ */
    711     /**
    712      * Interface that any session wrapper should implement so that
    713      * SessionManager may access the Jetty session implementation.
    714      *
    715      */
    716     public interface SessionIf extends HttpSession
    717     {
    718         public Session getSession();
    719     }
    720
    721     /* ------------------------------------------------------------ */
    722     /* ------------------------------------------------------------ */
    723     /* ------------------------------------------------------------ */
    724     /**
    725      *
    726      * <p>
    727      * Implements {@link javax.servlet.HttpSession} from the {@link javax.servlet} package.
    728      * </p>
    729      * @author gregw
    730      *
    731      */
    732     public abstract class Session implements SessionIf, Serializable
    733     {
    734         protected final String _clusterId;
    735         protected final String _nodeId;
    736         protected boolean _idChanged;
    737         protected final long _created;
    738         protected long _cookieSet;
    739         protected long _accessed;
    740         protected long _lastAccessed;
    741         protected boolean _invalid;
    742         protected boolean _doInvalidate;
    743         protected long _maxIdleMs=_dftMaxIdleSecs*1000;
    744         protected boolean _newSession;
    745         protected Map _values;
    746         protected int _requests;
    747
    748         /* ------------------------------------------------------------- */
    749         protected Session(HttpServletRequest request)
    750         {
    751             _newSession=true;
    752             _created=System.currentTimeMillis();
    753             _clusterId=_sessionIdManager.newSessionId(request,_created);
    754             _nodeId=_sessionIdManager.getNodeId(_clusterId,request);
    755             _accessed=_created;
    756             _requests=1;
    757         }
    758
    759         /* ------------------------------------------------------------- */
    760         protected Session(long created, String clusterId)
    761         {
    762             _created=created;
    763             _clusterId=clusterId;
    764             _nodeId=_sessionIdManager.getNodeId(_clusterId,null);
    765             _accessed=_created;
    766         }
    767
    768         /* ------------------------------------------------------------- */
    769         public Session getSession()
    770         {
    771             return this;
    772         }
    773
    774         /* ------------------------------------------------------------- */
    775         protected void initValues()
    776         {
    777             _values=newAttributeMap();
    778         }
    779
    780         /* ------------------------------------------------------------ */
    781         public synchronized Object getAttribute(String name)
    782         {
    783             if (_invalid)
    784                 throw new IllegalStateException();
    785
    786             if (null == _values)
    787                 return null;
    788
    789             return _values.get(name);
    790         }
    791
    792         /* ------------------------------------------------------------ */
    793         public synchronized Enumeration getAttributeNames()
    794         {
    795             if (_invalid)
    796                 throw new IllegalStateException();
    797             List names=_values==null?Collections.EMPTY_LIST:new ArrayList(_values.keySet());
    798             return Collections.enumeration(names);
    799         }
    800
    801         /* ------------------------------------------------------------- */
    802         public long getCookieSetTime()
    803         {
    804             return _cookieSet;
    805         }
    806
    807         /* ------------------------------------------------------------- */
    808         public long getCreationTime() throws IllegalStateException
    809         {
    810             if (_invalid)
    811                 throw new IllegalStateException();
    812             return _created;
    813         }
    814
    815         /* ------------------------------------------------------------ */
    816         public String getId() throws IllegalStateException
    817         {
    818             return _nodeIdInSessionId?_nodeId:_clusterId;
    819         }
    820
    821         /* ------------------------------------------------------------- */
    822         protected String getNodeId()
    823         {
    824             return _nodeId;
    825         }
    826
    827         /* ------------------------------------------------------------- */
    828         protected String getClusterId()
    829         {
    830             return _clusterId;
    831         }
    832
    833         /* ------------------------------------------------------------- */
    834         public long getLastAccessedTime() throws IllegalStateException
    835         {
    836             if (_invalid)
    837                 throw new IllegalStateException();
    838             return _lastAccessed;
    839         }
    840
    841         /* ------------------------------------------------------------- */
    842         public int getMaxInactiveInterval()
    843         {
    844             if (_invalid)
    845                 throw new IllegalStateException();
    846             return (int)(_maxIdleMs/1000);
    847         }
    848
    849         /* ------------------------------------------------------------ */
    850         /*
    851          * @see javax.servlet.http.HttpSession#getServletContext()
    852          */
    853         public ServletContext getServletContext()
    854         {
    855             return _context;
    856         }
    857
    858         /* ------------------------------------------------------------- */
    859         /**
    860          * @deprecated
    861          */
    862         public HttpSessionContext getSessionContext() throws IllegalStateException
    863         {
    864             if (_invalid)
    865                 throw new IllegalStateException();
    866             return __nullSessionContext;
    867         }
    868
    869         /* ------------------------------------------------------------- */
    870         /**
    871          * @deprecated As of Version 2.2, this method is replaced by
    872          *             {@link #getAttribute}
    873          */
    874         public Object getValue(String name) throws IllegalStateException
    875         {
    876             return getAttribute(name);
    877         }
    878
    879         /* ------------------------------------------------------------- */
    880         /**
    881          * @deprecated As of Version 2.2, this method is replaced by
    882          *             {@link #getAttributeNames}
    883          */
    884         public synchronized String[] getValueNames() throws IllegalStateException
    885         {
    886             if (_invalid)
    887                 throw new IllegalStateException();
    888             if (_values==null)
    889                 return new String[0];
    890             String[] a=new String[_values.size()];
    891             return (String[])_values.keySet().toArray(a);
    892         }
    893
    894         /* ------------------------------------------------------------ */
    895         protected void access(long time)
    896         {
    897             synchronized(this)
    898             {
    899                 _newSession=false;
    900                 _lastAccessed=_accessed;
    901                 _accessed=time;
    902                 _requests++;
    903             }
    904         }
    905
    906         /* ------------------------------------------------------------ */
    907         protected void complete()
    908         {
    909             synchronized(this)
    910             {
    911                 _requests--;
    912                 if (_doInvalidate && _requests<=0  )
    913                     doInvalidate();
    914             }
    915         }
    916
    917
    918         /* ------------------------------------------------------------- */
    919         protected void timeout() throws IllegalStateException
    920         {
    921             // remove session from context and invalidate other sessions with same ID.
    922             removeSession(this,true);
    923
    924             // Notify listeners and unbind values
    925             synchronized (this)
    926             {
    927                 if (_requests<=0)
    928                     doInvalidate();
    929                 else
    930                     _doInvalidate=true;
    931             }
    932         }
    933
    934         /* ------------------------------------------------------------- */
    935         public void invalidate() throws IllegalStateException
    936         {
    937             // remove session from context and invalidate other sessions with same ID.
    938             removeSession(this,true);
    939             doInvalidate();
    940         }
    941
    942         /* ------------------------------------------------------------- */
    943         protected void doInvalidate() throws IllegalStateException
    944         {
    945             try
    946             {
    947                 // Notify listeners and unbind values
    948                 if (_invalid)
    949                     throw new IllegalStateException();
    950
    951                 while (_values!=null && _values.size()>0)
    952                 {
    953                     ArrayList keys;
    954                     synchronized (this)
    955                     {
    956                         keys=new ArrayList(_values.keySet());
    957                     }
    958
    959                     Iterator iter=keys.iterator();
    960                     while (iter.hasNext())
    961                     {
    962                         String key=(String)iter.next();
    963
    964                         Object value;
    965                         synchronized (this)
    966                         {
    967                             value=_values.remove(key);
    968                         }
    969                         unbindValue(key,value);
    970
    971                         if (_sessionAttributeListeners!=null)
    972                         {
    973                             HttpSessionBindingEvent event=new HttpSessionBindingEvent(this,key,value);
    974
    975                             for (int i=0; i<LazyList.size(_sessionAttributeListeners); i++)
    976                                 ((HttpSessionAttributeListener)LazyList.get(_sessionAttributeListeners,i)).attributeRemoved(event);
    977                         }
    978                     }
    979                 }
    980             }
    981             finally
    982             {
    983                 // mark as invalid
    984                 _invalid=true;
    985             }
    986         }
    987
    988         /* ------------------------------------------------------------- */
    989         public boolean isIdChanged()
    990         {
    991             return _idChanged;
    992         }
    993
    994         /* ------------------------------------------------------------- */
    995         public boolean isNew() throws IllegalStateException
    996         {
    997             if (_invalid)
    998                 throw new IllegalStateException();
    999             return _newSession;
    1000         }
    1001
    1002         /* ------------------------------------------------------------- */
    1003         /**
    1004          * @deprecated As of Version 2.2, this method is replaced by
    1005          *             {@link #setAttribute}
    1006          */
    1007         public void putValue(java.lang.String name, java.lang.Object value) throws IllegalStateException
    1008         {
    1009             setAttribute(name,value);
    1010         }
    1011
    1012         /* ------------------------------------------------------------ */
    1013         public synchronized void removeAttribute(String name)
    1014         {
    1015             if (_invalid)
    1016                 throw new IllegalStateException();
    1017             if (_values==null)
    1018                 return;
    1019
    1020             Object old=_values.remove(name);
    1021             if (old!=null)
    1022             {
    1023                 unbindValue(name,old);
    1024                 if (_sessionAttributeListeners!=null)
    1025                 {
    1026                     HttpSessionBindingEvent event=new HttpSessionBindingEvent(this,name,old);
    1027
    1028                     for (int i=0; i<LazyList.size(_sessionAttributeListeners); i++)
    1029                         ((HttpSessionAttributeListener)LazyList.get(_sessionAttributeListeners,i)).attributeRemoved(event);
    1030                 }
    1031             }
    1032         }
    1033
    1034         /* ------------------------------------------------------------- */
    1035         /**
    1036          * @deprecated As of Version 2.2, this method is replaced by
    1037          *             {@link #removeAttribute}
    1038          */
    1039         public void removeValue(java.lang.String name) throws IllegalStateException
    1040         {
    1041             removeAttribute(name);
    1042         }
    1043
    1044         /* ------------------------------------------------------------ */
    1045         public synchronized void setAttribute(String name, Object value)
    1046         {
    1047             if (value==null)
    1048             {
    1049                 removeAttribute(name);
    1050                 return;
    1051             }
    1052
    1053             if (_invalid)
    1054                 throw new IllegalStateException();
    1055             if (_values==null)
    1056                 _values=newAttributeMap();
    1057             Object oldValue=_values.put(name,value);
    1058
    1059             if (oldValue==null || !value.equals(oldValue))
    1060             {
    1061                 unbindValue(name,oldValue);
    1062                 bindValue(name,value);
    1063
    1064                 if (_sessionAttributeListeners!=null)
    1065                 {
    1066                     HttpSessionBindingEvent event=new HttpSessionBindingEvent(this,name,oldValue==null?value:oldValue);
    1067
    1068                     for (int i=0; i<LazyList.size(_sessionAttributeListeners); i++)
    1069                     {
    1070                         HttpSessionAttributeListener l=(HttpSessionAttributeListener)LazyList.get(_sessionAttributeListeners,i);
    1071
    1072                         if (oldValue==null)
    1073                             l.attributeAdded(event);
    1074                         else if (value==null)
    1075                             l.attributeRemoved(event);
    1076                         else
    1077                             l.attributeReplaced(event);
    1078                     }
    1079                 }
    1080             }
    1081         }
    1082
    1083         /* ------------------------------------------------------------- */
    1084         public void setIdChanged(boolean changed)
    1085         {
    1086             _idChanged=changed;
    1087         }
    1088
    1089         /* ------------------------------------------------------------- */
    1090         public void setMaxInactiveInterval(int secs)
    1091         {
    1092             _maxIdleMs=(long)secs*1000;
    1093         }
    1094
    1095         /* ------------------------------------------------------------- */
    1096         public String toString()
    1097         {
    1098             return this.getClass().getName()+":"+getId()+"@"+hashCode();
    1099         }
    1100
    1101         /* ------------------------------------------------------------- */
    1102         /** If value implements HttpSessionBindingListener, call valueBound() */
    1103         protected void bindValue(java.lang.String name, Object value)
    1104         {
    1105             if (value!=null&&value instanceof HttpSessionBindingListener)
    1106                 ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this,name));
    1107         }
    1108
    1109         /* ------------------------------------------------------------ */
    1110         protected boolean isValid()
    1111         {
    1112             return !_invalid;
    1113         }
    1114
    1115         /* ------------------------------------------------------------ */
    1116         protected abstract Map newAttributeMap();
    1117
    1118         /* ------------------------------------------------------------- */
    1119         protected void cookieSet()
    1120         {
    1121             _cookieSet=_accessed;
    1122         }
    1123
    1124         /* ------------------------------------------------------------- */
    1125         /** If value implements HttpSessionBindingListener, call valueUnbound() */
    1126         protected void unbindValue(java.lang.String name, Object value)
    1127         {
    1128             if (value!=null&&value instanceof HttpSessionBindingListener)
    1129                 ((HttpSessionBindingListener)value).valueUnbound(new HttpSessionBindingEvent(this,name));
    1130         }
    1131
    1132         /* ------------------------------------------------------------- */
    1133         protected synchronized void willPassivate()
    1134         {
    1135             HttpSessionEvent event = new HttpSessionEvent(this);
    1136             for (Iterator iter = _values.values().iterator(); iter.hasNext();)
    1137             {
    1138                 Object value = iter.next();
    1139                 if (value instanceof HttpSessionActivationListener)
    1140                 {
    1141                     HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
    1142                     listener.sessionWillPassivate(event);
    1143                 }
    1144             }
    1145         }
    1146
    1147         /* ------------------------------------------------------------- */
    1148         protected synchronized void didActivate()
    1149         {
    1150             HttpSessionEvent event = new HttpSessionEvent(this);
    1151             for (Iterator iter = _values.values().iterator(); iter.hasNext();)
    1152             {
    1153                 Object value = iter.next();
    1154                 if (value instanceof HttpSessionActivationListener)
    1155                 {
    1156                     HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
    1157                     listener.sessionDidActivate(event);
    1158                 }
    1159             }
    1160         }
    1161     }
    1162 }