Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » session » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   
   19   package org.apache.catalina.session;
   20   
   21   import java.beans.PropertyChangeEvent;
   22   import java.beans.PropertyChangeListener;
   23   import java.io.IOException;
   24   import java.security.AccessController;
   25   import java.security.PrivilegedActionException;
   26   import java.security.PrivilegedExceptionAction;
   27   import java.util.HashMap;
   28   import java.util.Map;
   29   
   30   import org.apache.catalina.Container;
   31   import org.apache.catalina.Context;
   32   import org.apache.catalina.Lifecycle;
   33   import org.apache.catalina.LifecycleException;
   34   import org.apache.catalina.LifecycleListener;
   35   import org.apache.catalina.Session;
   36   import org.apache.catalina.Store;
   37   import org.apache.catalina.util.LifecycleSupport;
   38   
   39   import org.apache.catalina.security.SecurityUtil;
   40   import org.apache.juli.logging.Log;
   41   import org.apache.juli.logging.LogFactory;
   42   /**
   43    * Extends the <b>ManagerBase</b> class to implement most of the
   44    * functionality required by a Manager which supports any kind of
   45    * persistence, even if onlyfor  restarts.
   46    * <p>
   47    * <b>IMPLEMENTATION NOTE</b>:  Correct behavior of session storing and
   48    * reloading depends upon external calls to the <code>start()</code> and
   49    * <code>stop()</code> methods of this class at the correct times.
   50    *
   51    * @author Craig R. McClanahan
   52    * @author Jean-Francois Arcand
   53    * @version $Revision: 892872 $ $Date: 2009-12-21 17:38:29 +0100 (Mon, 21 Dec 2009) $
   54    */
   55   
   56   public abstract class PersistentManagerBase
   57       extends ManagerBase
   58       implements Lifecycle, PropertyChangeListener {
   59   
   60       private static Log log = LogFactory.getLog(PersistentManagerBase.class);
   61   
   62       // ---------------------------------------------------- Security Classes
   63   
   64       private class PrivilegedStoreClear
   65           implements PrivilegedExceptionAction {
   66   
   67           PrivilegedStoreClear() {            
   68           }
   69   
   70           public Object run() throws Exception{
   71              store.clear();
   72              return null;
   73           }                       
   74       }   
   75        
   76       private class PrivilegedStoreRemove
   77           implements PrivilegedExceptionAction {
   78   
   79           private String id;    
   80               
   81           PrivilegedStoreRemove(String id) {     
   82               this.id = id;
   83           }
   84   
   85           public Object run() throws Exception{
   86              store.remove(id);
   87              return null;
   88           }                       
   89       }   
   90        
   91       private class PrivilegedStoreLoad
   92           implements PrivilegedExceptionAction {
   93   
   94           private String id;    
   95               
   96           PrivilegedStoreLoad(String id) {     
   97               this.id = id;
   98           }
   99   
  100           public Object run() throws Exception{
  101              return store.load(id);
  102           }                       
  103       }   
  104             
  105       private class PrivilegedStoreSave
  106           implements PrivilegedExceptionAction {
  107   
  108           private Session session;    
  109               
  110           PrivilegedStoreSave(Session session) {     
  111               this.session = session;
  112           }
  113   
  114           public Object run() throws Exception{
  115              store.save(session);
  116              return null;
  117           }                       
  118       }   
  119        
  120       private class PrivilegedStoreKeys
  121           implements PrivilegedExceptionAction {
  122   
  123           PrivilegedStoreKeys() {     
  124           }
  125   
  126           public Object run() throws Exception{
  127              return store.keys();
  128           }                       
  129       }
  130   
  131       // ----------------------------------------------------- Instance Variables
  132   
  133   
  134       /**
  135        * The descriptive information about this implementation.
  136        */
  137       private static final String info = "PersistentManagerBase/1.1";
  138   
  139   
  140       /**
  141        * The lifecycle event support for this component.
  142        */
  143       protected LifecycleSupport lifecycle = new LifecycleSupport(this);
  144   
  145   
  146       /**
  147        * The maximum number of active Sessions allowed, or -1 for no limit.
  148        */
  149       protected int maxActiveSessions = -1;
  150   
  151   
  152       /**
  153        * The descriptive name of this Manager implementation (for logging).
  154        */
  155       private static String name = "PersistentManagerBase";
  156   
  157   
  158       /**
  159        * Has this component been started yet?
  160        */
  161       protected boolean started = false;
  162   
  163   
  164       /**
  165        * Store object which will manage the Session store.
  166        */
  167       protected Store store = null;
  168   
  169   
  170       /**
  171        * Whether to save and reload sessions when the Manager <code>unload</code>
  172        * and <code>load</code> methods are called.
  173        */
  174       protected boolean saveOnRestart = true;
  175   
  176   
  177       /**
  178        * How long a session must be idle before it should be backed up.
  179        * -1 means sessions won't be backed up.
  180        */
  181       protected int maxIdleBackup = -1;
  182   
  183   
  184       /**
  185        * Minimum time a session must be idle before it is swapped to disk.
  186        * This overrides maxActiveSessions, to prevent thrashing if there are lots
  187        * of active sessions. Setting to -1 means it's ignored.
  188        */
  189       protected int minIdleSwap = -1;
  190   
  191       /**
  192        * The maximum time a session may be idle before it should be swapped
  193        * to file just on general principle. Setting this to -1 means sessions
  194        * should not be forced out.
  195        */
  196       protected int maxIdleSwap = -1;
  197   
  198   
  199       /**
  200        * Number of session creations that failed due to maxActiveSessions.
  201        */
  202       protected int rejectedSessions = 0;
  203   
  204   
  205       /**
  206        * Processing time during session expiration and passivation.
  207        */
  208       protected long processingTime = 0;
  209   
  210   
  211       /**
  212        * Sessions currently being swapped in and the associated locks
  213        */
  214       private final Map<String,Object> sessionSwapInLocks =
  215       	new HashMap<String,Object>();
  216   
  217   
  218       // ------------------------------------------------------------- Properties
  219   
  220       
  221     
  222   
  223   
  224       /**
  225   	 * Indicates how many seconds old a session can get, after its last use in a
  226   	 * request, before it should be backed up to the store. -1 means sessions
  227   	 * are not backed up.
  228   	 */
  229       public int getMaxIdleBackup() {
  230   
  231           return maxIdleBackup;
  232   
  233       }
  234   
  235   
  236       /**
  237        * Sets the option to back sessions up to the Store after they
  238        * are used in a request. Sessions remain available in memory
  239        * after being backed up, so they are not passivated as they are
  240        * when swapped out. The value set indicates how old a session
  241        * may get (since its last use) before it must be backed up: -1
  242        * means sessions are not backed up.
  243        * <p>
  244        * Note that this is not a hard limit: sessions are checked
  245        * against this age limit periodically according to <b>processExpiresFrequency</b>.
  246        * This value should be considered to indicate when a session is
  247        * ripe for backing up.
  248        * <p>
  249        * So it is possible that a session may be idle for maxIdleBackup +
  250        * processExpiresFrequency * engine.backgroundProcessorDelay seconds, plus the time it takes to handle other
  251        * session expiration, swapping, etc. tasks.
  252        *
  253        * @param backup The number of seconds after their last accessed
  254        * time when they should be written to the Store.
  255        */
  256       public void setMaxIdleBackup (int backup) {
  257   
  258           if (backup == this.maxIdleBackup)
  259               return;
  260           int oldBackup = this.maxIdleBackup;
  261           this.maxIdleBackup = backup;
  262           support.firePropertyChange("maxIdleBackup",
  263                                      new Integer(oldBackup),
  264                                      new Integer(this.maxIdleBackup));
  265   
  266       }
  267   
  268   
  269       /**
  270        * The time in seconds after which a session should be swapped out of
  271        * memory to disk.
  272        */
  273       public int getMaxIdleSwap() {
  274   
  275           return maxIdleSwap;
  276   
  277       }
  278   
  279   
  280       /**
  281        * Sets the time in seconds after which a session should be swapped out of
  282        * memory to disk.
  283        */
  284       public void setMaxIdleSwap(int max) {
  285   
  286           if (max == this.maxIdleSwap)
  287               return;
  288           int oldMaxIdleSwap = this.maxIdleSwap;
  289           this.maxIdleSwap = max;
  290           support.firePropertyChange("maxIdleSwap",
  291                                      new Integer(oldMaxIdleSwap),
  292                                      new Integer(this.maxIdleSwap));
  293   
  294       }
  295   
  296   
  297       /**
  298        * The minimum time in seconds that a session must be idle before
  299        * it can be swapped out of memory, or -1 if it can be swapped out
  300        * at any time.
  301        */
  302       public int getMinIdleSwap() {
  303   
  304           return minIdleSwap;
  305   
  306       }
  307   
  308   
  309       /**
  310        * Sets the minimum time in seconds that a session must be idle before
  311        * it can be swapped out of memory due to maxActiveSession. Set it to -1
  312        * if it can be swapped out at any time.
  313        */
  314       public void setMinIdleSwap(int min) {
  315   
  316           if (this.minIdleSwap == min)
  317               return;
  318           int oldMinIdleSwap = this.minIdleSwap;
  319           this.minIdleSwap = min;
  320           support.firePropertyChange("minIdleSwap",
  321                                      new Integer(oldMinIdleSwap),
  322                                      new Integer(this.minIdleSwap));
  323   
  324       }
  325   
  326   
  327       /**
  328   	 * Set the Container with which this Manager has been associated. If it is a
  329   	 * Context (the usual case), listen for changes to the session timeout
  330   	 * property.
  331   	 * 
  332   	 * @param container
  333   	 *            The associated Container
  334   	 */
  335       public void setContainer(Container container) {
  336   
  337           // De-register from the old Container (if any)
  338           if ((this.container != null) && (this.container instanceof Context))
  339               ((Context) this.container).removePropertyChangeListener(this);
  340   
  341           // Default processing provided by our superclass
  342           super.setContainer(container);
  343   
  344           // Register with the new Container (if any)
  345           if ((this.container != null) && (this.container instanceof Context)) {
  346               setMaxInactiveInterval
  347                   ( ((Context) this.container).getSessionTimeout()*60 );
  348               ((Context) this.container).addPropertyChangeListener(this);
  349           }
  350   
  351       }
  352   
  353   
  354       /**
  355        * Return descriptive information about this Manager implementation and
  356        * the corresponding version number, in the format
  357        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  358        */
  359       public String getInfo() {
  360   
  361           return (info);
  362   
  363       }
  364   
  365   
  366       /**
  367        * Return true, if the session id is loaded in memory
  368        * otherwise false is returned
  369        *
  370        * @param id The session id for the session to be searched for
  371        */
  372       public boolean isLoaded( String id ){
  373           try {
  374               if ( super.findSession(id) != null )
  375                   return true;
  376           } catch (IOException e) {
  377               log.error("checking isLoaded for id, " + id + ", "+e.getMessage(), e);
  378           }
  379           return false;
  380       }
  381   
  382   
  383       /**
  384        * Return the maximum number of active Sessions allowed, or -1 for
  385        * no limit.
  386        */
  387       public int getMaxActiveSessions() {
  388   
  389           return (this.maxActiveSessions);
  390   
  391       }
  392   
  393   
  394       /**
  395        * Set the maximum number of actives Sessions allowed, or -1 for
  396        * no limit.
  397        *
  398        * @param max The new maximum number of sessions
  399        */
  400       public void setMaxActiveSessions(int max) {
  401   
  402           int oldMaxActiveSessions = this.maxActiveSessions;
  403           this.maxActiveSessions = max;
  404           support.firePropertyChange("maxActiveSessions",
  405                                      new Integer(oldMaxActiveSessions),
  406                                      new Integer(this.maxActiveSessions));
  407   
  408       }
  409   
  410   
  411       /** 
  412        * Number of session creations that failed due to maxActiveSessions.
  413        *
  414        * @return The count
  415        */
  416       public int getRejectedSessions() {
  417           return rejectedSessions;
  418       }
  419   
  420       
  421       public void setRejectedSessions(int rejectedSessions) {
  422           this.rejectedSessions = rejectedSessions;
  423       }
  424   
  425       /**
  426        * Return the descriptive short name of this Manager implementation.
  427        */
  428       public String getName() {
  429   
  430           return (name);
  431   
  432       }
  433   
  434   
  435       /**
  436        * Get the started status.
  437        */
  438       protected boolean isStarted() {
  439   
  440           return started;
  441   
  442       }
  443   
  444   
  445       /**
  446        * Set the started flag
  447        */
  448       protected void setStarted(boolean started) {
  449   
  450           this.started = started;
  451   
  452       }
  453   
  454   
  455       /**
  456        * Set the Store object which will manage persistent Session
  457        * storage for this Manager.
  458        *
  459        * @param store the associated Store
  460        */
  461       public void setStore(Store store) {
  462           this.store = store;
  463           store.setManager(this);
  464   
  465       }
  466   
  467   
  468       /**
  469        * Return the Store object which manages persistent Session
  470        * storage for this Manager.
  471        */
  472       public Store getStore() {
  473   
  474           return (this.store);
  475   
  476       }
  477   
  478   
  479   
  480       /**
  481        * Indicates whether sessions are saved when the Manager is shut down
  482        * properly. This requires the unload() method to be called.
  483        */
  484       public boolean getSaveOnRestart() {
  485   
  486           return saveOnRestart;
  487   
  488       }
  489   
  490   
  491       /**
  492        * Set the option to save sessions to the Store when the Manager is
  493        * shut down, then loaded when the Manager starts again. If set to
  494        * false, any sessions found in the Store may still be picked up when
  495        * the Manager is started again.
  496        *
  497        * @param saveOnRestart true if sessions should be saved on restart, false if
  498        *     they should be ignored.
  499        */
  500       public void setSaveOnRestart(boolean saveOnRestart) {
  501   
  502           if (saveOnRestart == this.saveOnRestart)
  503               return;
  504   
  505           boolean oldSaveOnRestart = this.saveOnRestart;
  506           this.saveOnRestart = saveOnRestart;
  507           support.firePropertyChange("saveOnRestart",
  508                                      new Boolean(oldSaveOnRestart),
  509                                      new Boolean(this.saveOnRestart));
  510   
  511       }
  512   
  513   
  514       // --------------------------------------------------------- Public Methods
  515   
  516   
  517       /**
  518        * Clear all sessions from the Store.
  519        */
  520       public void clearStore() {
  521   
  522           if (store == null)
  523               return;
  524   
  525           try {     
  526               if (SecurityUtil.isPackageProtectionEnabled()){
  527                   try{
  528                       AccessController.doPrivileged(new PrivilegedStoreClear());
  529                   }catch(PrivilegedActionException ex){
  530                       Exception exception = ex.getException();
  531                       log.error("Exception clearing the Store: " + exception);
  532                       exception.printStackTrace();                        
  533                   }
  534               } else {
  535                   store.clear();
  536               }
  537           } catch (IOException e) {
  538               log.error("Exception clearing the Store: " + e);
  539               e.printStackTrace();
  540           }
  541   
  542       }
  543   
  544   
  545       /**
  546        * Implements the Manager interface, direct call to processExpires and processPersistenceChecks
  547        */
  548   	public void processExpires() {
  549   		
  550           long timeNow = System.currentTimeMillis();
  551           Session sessions[] = findSessions();
  552           int expireHere = 0 ;
  553           if(log.isDebugEnabled())
  554                log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
  555           for (int i = 0; i < sessions.length; i++) {
  556               if (!sessions[i].isValid()) {
  557                   expiredSessions++;
  558                   expireHere++;
  559               }
  560           }
  561           processPersistenceChecks();
  562           if ((getStore() != null) && (getStore() instanceof StoreBase)) {
  563               ((StoreBase) getStore()).processExpires();
  564           }
  565           
  566           long timeEnd = System.currentTimeMillis();
  567           if(log.isDebugEnabled())
  568                log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
  569           processingTime += (timeEnd - timeNow);
  570    		
  571   	}
  572   
  573   
  574       /**
  575        * Called by the background thread after active sessions have been checked
  576        * for expiration, to allow sessions to be swapped out, backed up, etc.
  577        */
  578       public void processPersistenceChecks() {
  579   
  580           processMaxIdleSwaps();
  581           processMaxActiveSwaps();
  582           processMaxIdleBackups();
  583   
  584       }
  585   
  586   
  587       /**
  588        * Return the active Session, associated with this Manager, with the
  589        * specified session id (if any); otherwise return <code>null</code>.
  590        * This method checks the persistence store if persistence is enabled,
  591        * otherwise just uses the functionality from ManagerBase.
  592        *
  593        * @param id The session id for the session to be returned
  594        *
  595        * @exception IllegalStateException if a new session cannot be
  596        *  instantiated for any reason
  597        * @exception IOException if an input/output error occurs while
  598        *  processing this request
  599        */
  600       public Session findSession(String id) throws IOException {
  601   
  602           Session session = super.findSession(id);
  603           // OK, at this point, we're not sure if another thread is trying to
  604           // remove the session or not so the only way around this is to lock it
  605           // (or attempt to) and then try to get it by this session id again. If
  606           // the other code ran swapOut, then we should get a null back during
  607           // this run, and if not, we lock it out so we can access the session
  608           // safely.
  609           if(session != null) {
  610               synchronized(session){
  611                   session = super.findSession(session.getIdInternal());
  612                   if(session != null){
  613                      // To keep any external calling code from messing up the
  614                      // concurrency.
  615                      session.access();
  616                      session.endAccess();
  617                   }
  618               }
  619           }
  620           if (session != null)
  621               return (session);
  622   
  623           // See if the Session is in the Store
  624           session = swapIn(id);
  625           return (session);
  626   
  627       }
  628   
  629       /**
  630        * Remove this Session from the active Sessions for this Manager,
  631        * but not from the Store. (Used by the PersistentValve)
  632        *
  633        * @param session Session to be removed
  634        */
  635       public void removeSuper(Session session) {
  636           super.remove (session);
  637       }
  638   
  639       /**
  640        * Load all sessions found in the persistence mechanism, assuming
  641        * they are marked as valid and have not passed their expiration
  642        * limit. If persistence is not supported, this method returns
  643        * without doing anything.
  644        * <p>
  645        * Note that by default, this method is not called by the MiddleManager
  646        * class. In order to use it, a subclass must specifically call it,
  647        * for example in the start() and/or processPersistenceChecks() methods.
  648        */
  649       public void load() {
  650   
  651           // Initialize our internal data structures
  652           sessions.clear();
  653   
  654           if (store == null)
  655               return;
  656   
  657           String[] ids = null;
  658           try {
  659               if (SecurityUtil.isPackageProtectionEnabled()){
  660                   try{
  661                       ids = (String[])
  662                           AccessController.doPrivileged(new PrivilegedStoreKeys());
  663                   }catch(PrivilegedActionException ex){
  664                       Exception exception = ex.getException();
  665                       log.error("Exception in the Store during load: "
  666                                 + exception);
  667                       exception.printStackTrace();                        
  668                   }
  669               } else {
  670                   ids = store.keys();
  671               }
  672           } catch (IOException e) {
  673               log.error("Can't load sessions from store, " + e.getMessage(), e);
  674               return;
  675           }
  676   
  677           int n = ids.length;
  678           if (n == 0)
  679               return;
  680   
  681           if (log.isDebugEnabled())
  682               log.debug(sm.getString("persistentManager.loading", String.valueOf(n)));
  683   
  684           for (int i = 0; i < n; i++)
  685               try {
  686                   swapIn(ids[i]);
  687               } catch (IOException e) {
  688                   log.error("Failed load session from store, " + e.getMessage(), e);
  689               }
  690   
  691       }
  692   
  693   
  694       /**
  695        * Remove this Session from the active Sessions for this Manager,
  696        * and from the Store.
  697        *
  698        * @param session Session to be removed
  699        */
  700       public void remove(Session session) {
  701   
  702           super.remove (session);
  703   
  704           if (store != null){
  705               removeSession(session.getIdInternal());
  706           }
  707       }
  708   
  709       
  710       /**
  711        * Remove this Session from the active Sessions for this Manager,
  712        * and from the Store.
  713        *
  714        * @param id Session's id to be removed
  715        */    
  716       protected void removeSession(String id){
  717           try {
  718               if (SecurityUtil.isPackageProtectionEnabled()){
  719                   try{
  720                       AccessController.doPrivileged(new PrivilegedStoreRemove(id));
  721                   }catch(PrivilegedActionException ex){
  722                       Exception exception = ex.getException();
  723                       log.error("Exception in the Store during removeSession: "
  724                                 + exception);
  725                       exception.printStackTrace();                        
  726                   }
  727               } else {
  728                    store.remove(id);
  729               }               
  730           } catch (IOException e) {
  731               log.error("Exception removing session  " + e.getMessage());
  732               e.printStackTrace();
  733           }        
  734       }
  735   
  736       /**
  737        * Save all currently active sessions in the appropriate persistence
  738        * mechanism, if any.  If persistence is not supported, this method
  739        * returns without doing anything.
  740        * <p>
  741        * Note that by default, this method is not called by the MiddleManager
  742        * class. In order to use it, a subclass must specifically call it,
  743        * for example in the stop() and/or processPersistenceChecks() methods.
  744        */
  745       public void unload() {
  746   
  747           if (store == null)
  748               return;
  749   
  750           Session sessions[] = findSessions();
  751           int n = sessions.length;
  752           if (n == 0)
  753               return;
  754   
  755           if (log.isDebugEnabled())
  756               log.debug(sm.getString("persistentManager.unloading",
  757                                String.valueOf(n)));
  758   
  759           for (int i = 0; i < n; i++)
  760               try {
  761                   swapOut(sessions[i]);
  762               } catch (IOException e) {
  763                   ;   // This is logged in writeSession()
  764               }
  765   
  766       }
  767   
  768   
  769       // ------------------------------------------------------ Protected Methods
  770   
  771   
  772       /**
  773        * Look for a session in the Store and, if found, restore
  774        * it in the Manager's list of active sessions if appropriate.
  775        * The session will be removed from the Store after swapping
  776        * in, but will not be added to the active session list if it
  777        * is invalid or past its expiration.
  778        */
  779       protected Session swapIn(String id) throws IOException {
  780   
  781           if (store == null)
  782               return null;
  783   
  784           Object swapInLock = null;
  785   
  786           /*
  787            * The purpose of this sync and these locks is to make sure that a
  788            * session is only loaded once. It doesn't matter if the lock is removed
  789            * and then another thread enters this method and tries to load the same
  790            * session. That thread will re-create a swapIn lock for that session,
  791            * quickly find that the session is already in sessions, use it and
  792            * carry on.
  793            */
  794           synchronized (this) {
  795               swapInLock = sessionSwapInLocks.get(id);
  796               if (swapInLock == null) {
  797                   swapInLock = new Object();
  798                   sessionSwapInLocks.put(id, swapInLock);
  799               }
  800           }
  801   
  802           Session session = null;
  803   
  804           synchronized (swapInLock) {
  805               // First check to see if another thread has loaded the session into
  806               // the manager
  807               session = sessions.get(id);
  808   
  809               if (session == null) {
  810                   try {
  811                       if (SecurityUtil.isPackageProtectionEnabled()){
  812                           try {
  813                               session = (Session) AccessController.doPrivileged(
  814                                       new PrivilegedStoreLoad(id));
  815                           } catch (PrivilegedActionException ex) {
  816                               Exception e = ex.getException();
  817                               log.error(sm.getString(
  818                                       "persistentManager.swapInException", id),
  819                                       e);
  820                               if (e instanceof IOException){
  821                                   throw (IOException)e;
  822                               } else if (e instanceof ClassNotFoundException) {
  823                                   throw (ClassNotFoundException)e;
  824                               }
  825                           }
  826                       } else {
  827                            session = store.load(id);
  828                       }
  829                   } catch (ClassNotFoundException e) {
  830                       String msg = sm.getString(
  831                               "persistentManager.deserializeError", id);
  832                       log.error(msg, e);
  833                       throw new IllegalStateException(msg, e);
  834                   }
  835   
  836                   if (session != null && !session.isValid()) {
  837                       log.error(sm.getString(
  838                               "persistentManager.swapInInvalid", id));
  839                       session.expire();
  840                       removeSession(id);
  841                       session = null;
  842                   }
  843   
  844                   if (session != null) {
  845                       if(log.isDebugEnabled())
  846                           log.debug(sm.getString("persistentManager.swapIn", id));
  847   
  848                       session.setManager(this);
  849                       // make sure the listeners know about it.
  850                       ((StandardSession)session).tellNew();
  851                       add(session);
  852                       ((StandardSession)session).activate();
  853                       // endAccess() to ensure timeouts happen correctly.
  854                       // access() to keep access count correct or it will end up
  855                       // negative
  856                       session.access();
  857                       session.endAccess();
  858                   }
  859               }
  860           }
  861   
  862           // Make sure the lock is removed
  863           synchronized (this) {
  864               sessionSwapInLocks.remove(id);
  865           }
  866   
  867           return (session);
  868   
  869       }
  870   
  871   
  872       /**
  873        * Remove the session from the Manager's list of active
  874        * sessions and write it out to the Store. If the session
  875        * is past its expiration or invalid, this method does
  876        * nothing.
  877        *
  878        * @param session The Session to write out.
  879        */
  880       protected void swapOut(Session session) throws IOException {
  881   
  882           if (store == null || !session.isValid()) {
  883               return;
  884           }
  885   
  886           ((StandardSession)session).passivate();
  887           writeSession(session);
  888           super.remove(session);
  889           session.recycle();
  890   
  891       }
  892   
  893   
  894       /**
  895        * Write the provided session to the Store without modifying
  896        * the copy in memory or triggering passivation events. Does
  897        * nothing if the session is invalid or past its expiration.
  898        */
  899       protected void writeSession(Session session) throws IOException {
  900   
  901           if (store == null || !session.isValid()) {
  902               return;
  903           }
  904   
  905           try {
  906               if (SecurityUtil.isPackageProtectionEnabled()){
  907                   try{
  908                       AccessController.doPrivileged(new PrivilegedStoreSave(session));
  909                   }catch(PrivilegedActionException ex){
  910                       Exception exception = ex.getException();
  911                       log.error("Exception in the Store during writeSession: "
  912                                 + exception);
  913                       exception.printStackTrace();                        
  914                   }
  915               } else {
  916                    store.save(session);
  917               }   
  918           } catch (IOException e) {
  919               log.error(sm.getString
  920                   ("persistentManager.serializeError", session.getIdInternal(), e));
  921               throw e;
  922           }
  923   
  924       }
  925   
  926   
  927       // ------------------------------------------------------ Lifecycle Methods
  928   
  929   
  930       /**
  931        * Add a lifecycle event listener to this component.
  932        *
  933        * @param listener The listener to add
  934        */
  935       public void addLifecycleListener(LifecycleListener listener) {
  936   
  937           lifecycle.addLifecycleListener(listener);
  938   
  939       }
  940   
  941   
  942       /**
  943        * Get the lifecycle listeners associated with this lifecycle. If this 
  944        * Lifecycle has no listeners registered, a zero-length array is returned.
  945        */
  946       public LifecycleListener[] findLifecycleListeners() {
  947   
  948           return lifecycle.findLifecycleListeners();
  949   
  950       }
  951   
  952   
  953       /**
  954        * Remove a lifecycle event listener from this component.
  955        *
  956        * @param listener The listener to remove
  957        */
  958       public void removeLifecycleListener(LifecycleListener listener) {
  959   
  960           lifecycle.removeLifecycleListener(listener);
  961   
  962       }
  963   
  964   
  965       /**
  966        * Prepare for the beginning of active use of the public methods of this
  967        * component.  This method should be called after <code>configure()</code>,
  968        * and before any of the public methods of the component are utilized.
  969        *
  970        * @exception LifecycleException if this component detects a fatal error
  971        *  that prevents this component from being used
  972        */
  973       public void start() throws LifecycleException {
  974   
  975           // Validate and update our current component state
  976           if (started) {
  977               log.info(sm.getString("standardManager.alreadyStarted"));
  978               return;
  979           }
  980           if( ! initialized )
  981               init();
  982           
  983           lifecycle.fireLifecycleEvent(START_EVENT, null);
  984           started = true;
  985   
  986           // Force initialization of the random number generator
  987           if (log.isDebugEnabled())
  988               log.debug("Force random number initialization starting");
  989           String dummy = generateSessionId();
  990           if (log.isDebugEnabled())
  991               log.debug("Force random number initialization completed");
  992   
  993           if (store == null)
  994               log.error("No Store configured, persistence disabled");
  995           else if (store instanceof Lifecycle)
  996               ((Lifecycle)store).start();
  997   
  998       }
  999   
 1000   
 1001       /**
 1002        * Gracefully terminate the active use of the public methods of this
 1003        * component.  This method should be the last one called on a given
 1004        * instance of this component.
 1005        *
 1006        * @exception LifecycleException if this component detects a fatal error
 1007        *  that needs to be reported
 1008        */
 1009      public void stop() throws LifecycleException {
 1010   
 1011           if (log.isDebugEnabled())
 1012               log.debug("Stopping");
 1013   
 1014           // Validate and update our current component state
 1015           if (!isStarted()) {
 1016               log.info(sm.getString("standardManager.notStarted"));
 1017               return;
 1018           }
 1019           
 1020           lifecycle.fireLifecycleEvent(STOP_EVENT, null);
 1021           setStarted(false);
 1022   
 1023           if (getStore() != null && saveOnRestart) {
 1024               unload();
 1025           } else {
 1026               // Expire all active sessions
 1027               Session sessions[] = findSessions();
 1028               for (int i = 0; i < sessions.length; i++) {
 1029                   StandardSession session = (StandardSession) sessions[i];
 1030                   if (!session.isValid())
 1031                       continue;
 1032                   session.expire();
 1033               }
 1034           }
 1035   
 1036           if (getStore() != null && getStore() instanceof Lifecycle)
 1037               ((Lifecycle)getStore()).stop();
 1038   
 1039           // Require a new random number generator if we are restarted
 1040           this.random = null;
 1041   
 1042           if( initialized )
 1043               destroy();
 1044   
 1045       }
 1046   
 1047   
 1048       // ----------------------------------------- PropertyChangeListener Methods
 1049   
 1050   
 1051       /**
 1052        * Process property change events from our associated Context.
 1053        *
 1054        * @param event The property change event that has occurred
 1055        */
 1056       public void propertyChange(PropertyChangeEvent event) {
 1057   
 1058           // Validate the source of this event
 1059           if (!(event.getSource() instanceof Context))
 1060               return;
 1061           Context context = (Context) event.getSource();
 1062   
 1063           // Process a relevant property change
 1064           if (event.getPropertyName().equals("sessionTimeout")) {
 1065               try {
 1066                   setMaxInactiveInterval
 1067                       ( ((Integer) event.getNewValue()).intValue()*60 );
 1068               } catch (NumberFormatException e) {
 1069                   log.error(sm.getString("standardManager.sessionTimeout",
 1070                                    event.getNewValue().toString()));
 1071               }
 1072           }
 1073   
 1074       }
 1075   
 1076   
 1077       // ------------------------------------------------------ Protected Methods
 1078   
 1079   
 1080       /**
 1081        * Swap idle sessions out to Store if they are idle too long.
 1082        */
 1083       protected void processMaxIdleSwaps() {
 1084   
 1085           if (!isStarted() || maxIdleSwap < 0)
 1086               return;
 1087   
 1088           Session sessions[] = findSessions();
 1089           long timeNow = System.currentTimeMillis();
 1090   
 1091           // Swap out all sessions idle longer than maxIdleSwap
 1092           if (maxIdleSwap >= 0) {
 1093               for (int i = 0; i < sessions.length; i++) {
 1094                   StandardSession session = (StandardSession) sessions[i];
 1095                   synchronized (session) {
 1096                       if (!session.isValid())
 1097                           continue;
 1098                       int timeIdle = // Truncate, do not round up
 1099                           (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
 1100                       if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) {
 1101                           if (session.accessCount != null &&
 1102                                   session.accessCount.get() > 0) {
 1103                                   // Session is currently being accessed - skip it
 1104                                   continue;
 1105                               }
 1106                           if (log.isDebugEnabled())
 1107                               log.debug(sm.getString
 1108                                   ("persistentManager.swapMaxIdle",
 1109                                    session.getIdInternal(), new Integer(timeIdle)));
 1110                           try {
 1111                               swapOut(session);
 1112                           } catch (IOException e) {
 1113                               ;   // This is logged in writeSession()
 1114                           }
 1115                       }
 1116                   }
 1117               }
 1118           }
 1119   
 1120       }
 1121   
 1122   
 1123       /**
 1124        * Swap idle sessions out to Store if too many are active
 1125        */
 1126       protected void processMaxActiveSwaps() {
 1127   
 1128           if (!isStarted() || getMaxActiveSessions() < 0)
 1129               return;
 1130   
 1131           Session sessions[] = findSessions();
 1132   
 1133           // FIXME: Smarter algorithm (LRU)
 1134           if (getMaxActiveSessions() >= sessions.length)
 1135               return;
 1136   
 1137           if(log.isDebugEnabled())
 1138               log.debug(sm.getString
 1139                   ("persistentManager.tooManyActive",
 1140                    new Integer(sessions.length)));
 1141   
 1142           int toswap = sessions.length - getMaxActiveSessions();
 1143           long timeNow = System.currentTimeMillis();
 1144   
 1145           for (int i = 0; i < sessions.length && toswap > 0; i++) {
 1146               StandardSession session =  (StandardSession) sessions[i];
 1147               synchronized (session) {
 1148                   int timeIdle = // Truncate, do not round up
 1149                       (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
 1150                   if (timeIdle > minIdleSwap) {
 1151                       if (session.accessCount != null &&
 1152                               session.accessCount.get() > 0) {
 1153                               // Session is currently being accessed - skip it
 1154                               continue;
 1155                           }
 1156                       if(log.isDebugEnabled())
 1157                           log.debug(sm.getString
 1158                               ("persistentManager.swapTooManyActive",
 1159                                session.getIdInternal(), new Integer(timeIdle)));
 1160                       try {
 1161                           swapOut(session);
 1162                       } catch (IOException e) {
 1163                           ;   // This is logged in writeSession()
 1164                       }
 1165                       toswap--;
 1166                   }
 1167               }
 1168           }
 1169   
 1170       }
 1171   
 1172   
 1173       /**
 1174        * Back up idle sessions.
 1175        */
 1176       protected void processMaxIdleBackups() {
 1177   
 1178           if (!isStarted() || maxIdleBackup < 0)
 1179               return;
 1180   
 1181           Session sessions[] = findSessions();
 1182           long timeNow = System.currentTimeMillis();
 1183   
 1184           // Back up all sessions idle longer than maxIdleBackup
 1185           if (maxIdleBackup >= 0) {
 1186               for (int i = 0; i < sessions.length; i++) {
 1187                   StandardSession session = (StandardSession) sessions[i];
 1188                   synchronized (session) {
 1189                       if (!session.isValid())
 1190                           continue;
 1191                       int timeIdle = // Truncate, do not round up
 1192                           (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
 1193                       if (timeIdle > maxIdleBackup) {
 1194                           if (log.isDebugEnabled())
 1195                               log.debug(sm.getString
 1196                                   ("persistentManager.backupMaxIdle",
 1197                                   session.getIdInternal(), new Integer(timeIdle)));
 1198       
 1199                           try {
 1200                               writeSession(session);
 1201                           } catch (IOException e) {
 1202                               ;   // This is logged in writeSession()
 1203                           }
 1204                       }
 1205                   }
 1206               }
 1207           }
 1208   
 1209       }
 1210   
 1211   }

Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » session » [javadoc | source]