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         if (_context != null)
    171         {
    172             // Look for a session cookie name
    173             String tmp=_context.getInitParameter(SessionManager.__SessionCookieProperty);
    174             if (tmp!=null)
    175                 _sessionCookie=tmp;
    176
    177             tmp=_context.getInitParameter(SessionManager.__SessionURLProperty);
    178             if (tmp!=null)
    179             {
    180                 _sessionURL=(tmp==null||"none".equals(tmp))?null:tmp;
    181                 _sessionURLPrefix=(tmp==null||"none".equals(tmp))?null:(";"+_sessionURL+"=");
    182             }
    183
    184             // set up the max session cookie age if it isn't already
    185             if (_maxCookieAge==-1)
    186             {
    187                 tmp=_context.getInitParameter(SessionManager.__MaxAgeProperty);
    188                 if (tmp!=null)
    189                     _maxCookieAge=Integer.parseInt(tmp.trim());
    190             }
    191             // set up the session domain if it isn't already
    192             if (_sessionDomain==null)
    193             {
    194                 // only try the context initParams
    195                 _sessionDomain=_context.getInitParameter(SessionManager.__SessionDomainProperty);
    196             }
    197
    198             // set up the sessionPath if it isn't already
    199             if (_sessionPath==null)
    200             {
    201                 // only the context initParams
    202                 _sessionPath=_context.getInitParameter(SessionManager.__SessionPathProperty);
    203             }
    204         }
    205
    206         super.doStart();
    207     }
    208
    209     /* ------------------------------------------------------------ */
    210     public void doStop() throws Exception
    211     {
    212         super.doStop();
    213
    214         invalidateSessions();
    215
    216         _loader=null;
    217     }
    218
    219     /* ------------------------------------------------------------ */
    220     /**
    221      * @return Returns the httpOnly.
    222      */
    223     public boolean getHttpOnly()
    224     {
    225         return _httpOnly;
    226     }
    227
    228     /* ------------------------------------------------------------ */
    229     public HttpSession getHttpSession(String nodeId)
    230     {
    231         String cluster_id = getIdManager().getClusterId(nodeId);
    232
    233         synchronized (this)
    234         {
    235             Session session = getSession(cluster_id);
    236
    237             if (session!=null && !session.getNodeId().equals(nodeId))
    238                 session.setIdChanged(true);
    239             return session;
    240         }
    241     }
    242
    243     /* ------------------------------------------------------------ */
    244     /* ------------------------------------------------------------ */
    245     /**
    246      * @return Returns the metaManager used for cross context session management
    247      */
    248     public SessionIdManager getIdManager()
    249     {
    250         return _sessionIdManager;
    251     }
    252
    253     /* ------------------------------------------------------------ */
    254     public int getMaxCookieAge()
    255     {
    256         return _maxCookieAge;
    257     }
    258
    259     /* ------------------------------------------------------------ */
    260     /**
    261      * @return seconds
    262      */
    263     public int getMaxInactiveInterval()
    264     {
    265         return _dftMaxIdleSecs;
    266     }
    267
    268     /* ------------------------------------------------------------ */
    269     public int getMaxSessions()
    270     {
    271         return _maxSessions;
    272     }
    273
    274     /* ------------------------------------------------------------ */
    275     /**
    276      * @deprecated use {@link #getIdManager()}
    277      */
    278     public SessionIdManager getMetaManager()
    279     {
    280         return getIdManager();
    281     }
    282
    283     /* ------------------------------------------------------------ */
    284     public int getMinSessions()
    285     {
    286         return _minSessions;
    287     }
    288
    289     /* ------------------------------------------------------------ */
    290     public int getRefreshCookieAge()
    291     {
    292         return _refreshCookieAge;
    293     }
    294
    295
    296     /* ------------------------------------------------------------ */
    297     /**
    298      * @return Returns the secureCookies.
    299      */
    300     public boolean getSecureCookies()
    301     {
    302         return _secureCookies;
    303     }
    304
    305     /* ------------------------------------------------------------ */
    306     public String getSessionCookie()
    307     {
    308         return _sessionCookie;
    309     }
    310
    311     /* ------------------------------------------------------------ */
    312     public Cookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure)
    313     {
    314         if (isUsingCookies())
    315         {
    316             String id = getNodeId(session);
    317             Cookie cookie=getHttpOnly()?new HttpOnlyCookie(_sessionCookie,id):new Cookie(_sessionCookie,id);
    318
    319             cookie.setPath((contextPath==null||contextPath.length()==0)?"/":contextPath);
    320             cookie.setMaxAge(getMaxCookieAge());
    321             cookie.setSecure(requestIsSecure&&getSecureCookies());
    322
    323             // set up the overrides
    324             if (_sessionDomain!=null)
    325                 cookie.setDomain(_sessionDomain);
    326             if (_sessionPath!=null)
    327                 cookie.setPath(_sessionPath);
    328
    329             return cookie;
    330         }
    331         return null;
    332     }
    333
    334     public String getSessionDomain()
    335     {
    336         return _sessionDomain;
    337     }
    338
    339     /* ------------------------------------------------------------ */
    340     /**
    341      * @return Returns the sessionHandler.
    342      */
    343     public SessionHandler getSessionHandler()
    344     {
    345         return _sessionHandler;
    346     }
    347
    348     /* ------------------------------------------------------------ */
    349     /**
    350      * @deprecated.  Need to review if it is needed.
    351      */
    352     public abstract Map getSessionMap();
    353
    354     /* ------------------------------------------------------------ */
    355     public String getSessionPath()
    356     {
    357         return _sessionPath;
    358     }
    359
    360     /* ------------------------------------------------------------ */
    361     public abstract int getSessions();
    362
    363     /* ------------------------------------------------------------ */
    364     public String getSessionURL()
    365     {
    366         return _sessionURL;
    367     }
    368
    369     /* ------------------------------------------------------------ */
    370     public String getSessionURLPrefix()
    371     {
    372         return _sessionURLPrefix;
    373     }
    374
    375     /* ------------------------------------------------------------ */
    376     /**
    377      * @return Returns the usingCookies.
    378      */
    379     public boolean isUsingCookies()
    380     {
    381         return _usingCookies;
    382     }
    383
    384     /* ------------------------------------------------------------ */
    385     public boolean isValid(HttpSession session)
    386     {
    387         Session s = ((SessionIf)session).getSession();
    388         return s.isValid();
    389     }
    390
    391     /* ------------------------------------------------------------ */
    392     public String getClusterId(HttpSession session)
    393     {
    394         Session s = ((SessionIf)session).getSession();
    395         return s.getClusterId();
    396     }
    397
    398     /* ------------------------------------------------------------ */
    399     public String getNodeId(HttpSession session)
    400     {
    401         Session s = ((SessionIf)session).getSession();
    402         return s.getNodeId();
    403     }
    404
    405     /* ------------------------------------------------------------ */
    406     /**
    407      * Create a new HttpSession for a request
    408      */
    409     public HttpSession newHttpSession(HttpServletRequest request)
    410     {
    411         Session session=newSession(request);
    412         session.setMaxInactiveInterval(_dftMaxIdleSecs);
    413         addSession(session,true);
    414         return session;
    415     }
    416
    417     /* ------------------------------------------------------------ */
    418     public void removeEventListener(EventListener listener)
    419     {
    420         if (listener instanceof HttpSessionAttributeListener)
    421             _sessionAttributeListeners=LazyList.remove(_sessionAttributeListeners,listener);
    422         if (listener instanceof HttpSessionListener)
    423             _sessionListeners=LazyList.remove(_sessionListeners,listener);
    424     }
    425
    426     /* ------------------------------------------------------------ */
    427     public void resetStats()
    428     {
    429         _minSessions=getSessions();
    430         _maxSessions=getSessions();
    431     }
    432
    433     /* ------------------------------------------------------------ */
    434     /**
    435      * @param httpOnly
    436      *            The httpOnly to set.
    437      */
    438     public void setHttpOnly(boolean httpOnly)
    439     {
    440         _httpOnly=httpOnly;
    441     }
    442
    443
    444     /* ------------------------------------------------------------ */
    445     /**
    446      * @param metaManager The metaManager used for cross context session management.
    447      */
    448     public void setIdManager(SessionIdManager metaManager)
    449     {
    450         _sessionIdManager=metaManager;
    451     }
    452
    453     /* ------------------------------------------------------------ */
    454     public void setMaxCookieAge(int maxCookieAgeInSeconds)
    455     {
    456         _maxCookieAge=maxCookieAgeInSeconds;
    457
    458         if (_maxCookieAge>0 && _refreshCookieAge==0)
    459             _refreshCookieAge=_maxCookieAge/3;
    460
    461     }
    462
    463     /* ------------------------------------------------------------ */
    464     /**
    465      * @param seconds
    466      */
    467     public void setMaxInactiveInterval(int seconds)
    468     {
    469         _dftMaxIdleSecs=seconds;
    470     }
    471
    472     /* ------------------------------------------------------------ */
    473     /**
    474      * @deprecated use {@link #setIdManager(SessionIdManager)}
    475      */
    476     public void setMetaManager(SessionIdManager metaManager)
    477     {
    478         setIdManager(metaManager);
    479     }
    480
    481     /* ------------------------------------------------------------ */
    482     public void setRefreshCookieAge(int ageInSeconds)
    483     {
    484         _refreshCookieAge=ageInSeconds;
    485     }
    486
    487
    488     /* ------------------------------------------------------------ */
    489     /**
    490      * @param secureCookies
    491      *            The secureCookies to set.
    492      */
    493     public void setSecureCookies(boolean secureCookies)
    494     {
    495         _secureCookies=secureCookies;
    496     }
    497
    498     /* ------------------------------------------------------------ */
    499     public void setSessionCookie(String cookieName)
    500     {
    501         _sessionCookie=cookieName;
    502     }
    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     /* ------------------------------------------------------------ */
    547     protected abstract void addSession(Session session);
    548
    549     /* ------------------------------------------------------------ */
    550     /**
    551      * Add the session Registers the session with this manager and registers the
    552      * session ID with the sessionIDManager;
    553      */
    554     protected void addSession(Session session, boolean created)
    555     {
    556         synchronized (_sessionIdManager)
    557         {
    558             _sessionIdManager.addSession(session);
    559             synchronized (this)
    560             {
    561                 addSession(session);
    562                 if (getSessions()>this._maxSessions)
    563                     this._maxSessions=getSessions();
    564             }
    565         }
    566
    567         if (!created)
    568         {
    569             session.didActivate();
    570         }
    571         else if (_sessionListeners!=null)
    572         {
    573             HttpSessionEvent event=new HttpSessionEvent(session);
    574             for (int i=0; i<LazyList.size(_sessionListeners); i++)
    575                 ((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionCreated(event);
    576         }
    577     }
    578
    579     /* ------------------------------------------------------------ */
    580     /**
    581      * Get a known existingsession
    582      * @param idInCluster The session ID in the cluster, stripped of any worker name.
    583      * @return A Session or null if none exists.
    584      */
    585     public abstract Session getSession(String idInCluster);
    586
    587     /* ------------------------------------------------------------ */
    588     protected abstract void invalidateSessions();
    589
    590
    591     /* ------------------------------------------------------------ */
    592     /**
    593      * Create a new session instance
    594      * @param request
    595      * @return
    596      */
    597     protected abstract Session newSession(HttpServletRequest request);
    598
    599
    600
    601     /* ------------------------------------------------------------ */
    602     /**
    603      * @return true if the cluster node id (worker id) is returned as part of the session id by {@link HttpSession#getId()}. Default is false.
    604      */
    605     public boolean isNodeIdInSessionId()
    606     {
    607         return _nodeIdInSessionId;
    608     }
    609
    610     /* ------------------------------------------------------------ */
    611     /**
    612      * @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.
    613      */
    614     public void setNodeIdInSessionId(boolean nodeIdInSessionId)
    615     {
    616         _nodeIdInSessionId=nodeIdInSessionId;
    617     }
    618
    619     /* ------------------------------------------------------------ */
    620     /** Remove session from manager
    621      * @param session The session to remove
    622      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
    623      * {@link SessionIdManager#invalidateAll(String)} should be called.
    624      */
    625     public void removeSession(HttpSession session, boolean invalidate)
    626     {
    627         Session s = ((SessionIf)session).getSession();
    628         removeSession(s,invalidate);
    629     }
    630
    631     /* ------------------------------------------------------------ */
    632     /** Remove session from manager
    633      * @param session The session to remove
    634      * @param invalidate True if {@link HttpSessionListener#sessionDestroyed(HttpSessionEvent)} and
    635      * {@link SessionIdManager#invalidateAll(String)} should be called.
    636      */
    637     public void removeSession(Session session, boolean invalidate)
    638     {
    639         // Remove session from context and global maps
    640         boolean removed = false;
    641         synchronized (this)
    642         {
    643             //take this session out of the map of sessions for this context
    644             if (getSession(session.getClusterId()) != null)
    645             {
    646                 removed = true;
    647                 removeSession(session.getClusterId());
    648             }
    649         }
    650
    651         if (removed && invalidate)
    652         {
    653             // Remove session from all context and global id maps
    654             _sessionIdManager.removeSession(session);
    655             _sessionIdManager.invalidateAll(session.getClusterId());
    656         }
    657
    658         if (invalidate && _sessionListeners!=null)
    659         {
    660             HttpSessionEvent event=new HttpSessionEvent(session);
    661             for (int i=LazyList.size(_sessionListeners); i-->0;)
    662                 ((HttpSessionListener)LazyList.get(_sessionListeners,i)).sessionDestroyed(event);
    663         }
    664         if (!invalidate)
    665         {
    666             session.willPassivate();
    667         }
    668     }
    669
    670     /* ------------------------------------------------------------ */
    671     protected abstract void removeSession(String idInCluster);
    672
    673     /* ------------------------------------------------------------ */
    674     /**
    675      * Null returning implementation of HttpSessionContext
    676      *
    677      * @author Greg Wilkins (gregw)
    678      */
    679     public static class NullSessionContext implements HttpSessionContext
    680     {
    681         /* ------------------------------------------------------------ */
    682         private NullSessionContext()
    683         {
    684         }
    685
    686         /* ------------------------------------------------------------ */
    687         /**
    688          * @deprecated From HttpSessionContext
    689          */
    690         public Enumeration getIds()
    691         {
    692             return Collections.enumeration(Collections.EMPTY_LIST);
    693         }
    694
    695         /* ------------------------------------------------------------ */
    696         /**
    697          * @deprecated From HttpSessionContext
    698          */
    699         public HttpSession getSession(String id)
    700         {
    701             return null;
    702         }
    703     }
    704
    705     /* ------------------------------------------------------------ */
    706     /* ------------------------------------------------------------ */
    707     /* ------------------------------------------------------------ */
    708     /**
    709      * Interface that any session wrapper should implement so that
    710      * SessionManager may access the Jetty session implementation.
    711      *
    712      */
    713     public interface SessionIf extends HttpSession
    714     {
    715         public Session getSession();
    716     }
    717
    718     /* ------------------------------------------------------------ */
    719     /* ------------------------------------------------------------ */
    720     /* ------------------------------------------------------------ */
    721     /**
    722      *
    723      * <p>
    724      * Implements {@link javax.servlet.HttpSession} from the {@link javax.servlet} package.
    725      * </p>
    726      * @author gregw
    727      *
    728      */
    729     public abstract class Session implements SessionIf, Serializable
    730     {
    731         protected final String _clusterId;
    732         protected final String _nodeId;
    733         protected boolean _idChanged;
    734         protected final long _created;
    735         protected long _cookieSet;
    736         protected long _accessed;
    737         protected long _lastAccessed;
    738         protected boolean _invalid;
    739         protected boolean _doInvalidate;
    740         protected long _maxIdleMs=_dftMaxIdleSecs*1000;
    741         protected boolean _newSession;
    742         protected Map _values;
    743         protected int _requests;
    744
    745         /* ------------------------------------------------------------- */
    746         protected Session(HttpServletRequest request)
    747         {
    748             _newSession=true;
    749             _created=System.currentTimeMillis();
    750             _clusterId=_sessionIdManager.newSessionId(request,_created);
    751             _nodeId=_sessionIdManager.getNodeId(_clusterId,request);
    752             _accessed=_created;
    753             _requests=1;
    754         }
    755
    756         /* ------------------------------------------------------------- */
    757         protected Session(long created, String clusterId)
    758         {
    759             _created=created;
    760             _clusterId=clusterId;
    761             _nodeId=_sessionIdManager.getNodeId(_clusterId,null);
    762             _accessed=_created;
    763         }
    764
    765         /* ------------------------------------------------------------- */
    766         public Session getSession()
    767         {
    768             return this;
    769         }
    770
    771         /* ------------------------------------------------------------- */
    772         protected void initValues()
    773         {
    774             _values=newAttributeMap();
    775         }
    776
    777         /* ------------------------------------------------------------ */
    778         public synchronized Object getAttribute(String name)
    779         {
    780             if (_invalid)
    781                 throw new IllegalStateException();
    782
    783             if (null == _values)
    784                 return null;
    785
    786             return _values.get(name);
    787         }
    788
    789         /* ------------------------------------------------------------ */
    790         public synchronized Enumeration getAttributeNames()
    791         {
    792             if (_invalid)
    793                 throw new IllegalStateException();
    794             List names=_values==null?Collections.EMPTY_LIST:new ArrayList(_values.keySet());
    795             return Collections.enumeration(names);
    796         }
    797
    798         /* ------------------------------------------------------------- */
    799         public long getCookieSetTime()
    800         {
    801             return _cookieSet;
    802         }
    803
    804         /* ------------------------------------------------------------- */
    805         public long getCreationTime() throws IllegalStateException
    806         {
    807             if (_invalid)
    808                 throw new IllegalStateException();
    809             return _created;
    810         }
    811
    812         /* ------------------------------------------------------------ */
    813         public String getId() throws IllegalStateException
    814         {
    815             return _nodeIdInSessionId?_nodeId:_clusterId;
    816         }
    817
    818         /* ------------------------------------------------------------- */
    819         protected String getNodeId()
    820         {
    821             return _nodeId;
    822         }
    823
    824         /* ------------------------------------------------------------- */
    825         protected String getClusterId()
    826         {
    827             return _clusterId;
    828         }
    829
    830         /* ------------------------------------------------------------- */
    831         public long getLastAccessedTime() throws IllegalStateException
    832         {
    833             if (_invalid)
    834                 throw new IllegalStateException();
    835             return _lastAccessed;
    836         }
    837
    838         /* ------------------------------------------------------------- */
    839         public int getMaxInactiveInterval()
    840         {
    841             if (_invalid)
    842                 throw new IllegalStateException();
    843             return (int)(_maxIdleMs/1000);
    844         }
    845
    846         /* ------------------------------------------------------------ */
    847         /*
    848          * @see javax.servlet.http.HttpSession#getServletContext()
    849          */
    850         public ServletContext getServletContext()
    851         {
    852             return _context;
    853         }
    854
    855         /* ------------------------------------------------------------- */
    856         /**
    857          * @deprecated
    858          */
    859         public HttpSessionContext getSessionContext() throws IllegalStateException
    860         {
    861             if (_invalid)
    862                 throw new IllegalStateException();
    863             return __nullSessionContext;
    864         }
    865
    866         /* ------------------------------------------------------------- */
    867         /**
    868          * @deprecated As of Version 2.2, this method is replaced by
    869          *             {@link #getAttribute}
    870          */
    871         public Object getValue(String name) throws IllegalStateException
    872         {
    873             return getAttribute(name);
    874         }
    875
    876         /* ------------------------------------------------------------- */
    877         /**
    878          * @deprecated As of Version 2.2, this method is replaced by
    879          *             {@link #getAttributeNames}
    880          */
    881         public synchronized String[] getValueNames() throws IllegalStateException
    882         {
    883             if (_invalid)
    884                 throw new IllegalStateException();
    885             if (_values==null)
    886                 return new String[0];
    887             String[] a=new String[_values.size()];
    888             return (String[])_values.keySet().toArray(a);
    889         }
    890
    891         /* ------------------------------------------------------------ */
    892         protected void access(long time)
    893         {
    894             synchronized(this)
    895             {
    896                 _newSession=false;
    897                 _lastAccessed=_accessed;
    898                 _accessed=time;
    899                 _requests++;
    900             }
    901         }
    902
    903         /* ------------------------------------------------------------ */
    904         protected void complete()
    905         {
    906             synchronized(this)
    907             {
    908                 _requests--;
    909                 if (_doInvalidate && _requests<=0  )
    910                     doInvalidate();
    911             }
    912         }
    913
    914
    915         /* ------------------------------------------------------------- */
    916         protected void timeout() throws IllegalStateException
    917         {
    918             // remove session from context and invalidate other sessions with same ID.
    919             removeSession(this,true);
    920
    921             // Notify listeners and unbind values
    922             synchronized (this)
    923             {
    924                 if (!_invalid)
    925                 {
    926                     if (_requests<=0)
    927                         doInvalidate();
    928                     else
    929                         _doInvalidate=true;
    930                 }
    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 }