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

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