Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Licensed to the Apache Software Foundation (ASF) under one or more
    * contributor license agreements.  See the NOTICE file distributed with
    * this work for additional information regarding copyright ownership.
    * The ASF licenses this file to You under the Apache License, Version 2.0
    * (the "License"); you may not use this file except in compliance with
    * the License.  You may obtain a copy of the License at
    * 
    *      http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  
  package org.apache.catalina.session;
  
  import static org.jboss.web.CatalinaMessages.MESSAGES;
  
  import java.util.HashMap;
  import java.util.Map;
  
Extends the ManagerBase class to implement most of the functionality required by a Manager which supports any kind of persistence, even if onlyfor restarts.

IMPLEMENTATION NOTE: Correct behavior of session storing and reloading depends upon external calls to the start() and stop() methods of this class at the correct times.

Author(s):
Craig R. McClanahan
Jean-Francois Arcand
Version:
$Revision: 1857 $ $Date: 2011-10-27 18:52:51 +0200 (Thu, 27 Oct 2011) $
  
  
  public abstract class PersistentManagerBase
      extends ManagerBase
      implements LifecyclePropertyChangeListener {
  
      // ---------------------------------------------------- Security Classes
  
      private class PrivilegedStoreClear
          implements PrivilegedExceptionAction {
  
          PrivilegedStoreClear() {            
          }
  
          public Object run() throws Exception{
             .clear();
             return null;
          }                       
      }   
       
      private class PrivilegedStoreRemove
          implements PrivilegedExceptionAction {
  
          private String id;    
              
          PrivilegedStoreRemove(String id) {     
              this. = id;
          }
  
          public Object run() throws Exception{
             .remove();
             return null;
          }                       
      }   
       
      private class PrivilegedStoreLoad
          implements PrivilegedExceptionAction {
  
          private String id;    
              
          PrivilegedStoreLoad(String id) {     
              this. = id;
          }
  
          public Object run() throws Exception{
            return .load();
         }                       
     }   
           
     private class PrivilegedStoreSave
         implements PrivilegedExceptionAction {
 
         private Session session;    
             
         PrivilegedStoreSave(Session session) {     
             this. = session;
         }
 
         public Object run() throws Exception{
            .save();
            return null;
         }                       
     }   
      
     private class PrivilegedStoreKeys
         implements PrivilegedExceptionAction {
 
         PrivilegedStoreKeys() {     
         }
 
         public Object run() throws Exception{
            return .keys();
         }                       
     }
 
     // ----------------------------------------------------- Instance Variables
 

    
The descriptive information about this implementation.
 
     private static final String info = "PersistentManagerBase/1.1";


    
The lifecycle event support for this component.
 
     protected LifecycleSupport lifecycle = new LifecycleSupport(this);


    
The maximum number of active Sessions allowed, or -1 for no limit.
 
     protected int maxActiveSessions = -1;


    
The descriptive name of this Manager implementation (for logging).
 
     private static String name = "PersistentManagerBase";


    
Has this component been started yet?
 
     protected boolean started = false;


    
Store object which will manage the Session store.
 
     protected Store store = null;


    
Whether to save and reload sessions when the Manager unload and load methods are called.
 
     protected boolean saveOnRestart = true;


    
How long a session must be idle before it should be backed up. -1 means sessions won't be backed up.
 
     protected int maxIdleBackup = -1;


    
Minimum time a session must be idle before it is swapped to disk. This overrides maxActiveSessions, to prevent thrashing if there are lots of active sessions. Setting to -1 means it's ignored.
 
     protected int minIdleSwap = -1;

    
The maximum time a session may be idle before it should be swapped to file just on general principle. Setting this to -1 means sessions should not be forced out.
 
     protected int maxIdleSwap = -1;


    
Number of session creations that failed due to maxActiveSessions.
 
     protected int rejectedSessions = 0;


    
Processing time during session expiration and passivation.
 
     protected long processingTime = 0;


    
Sessions currently being swapped in and the associated locks
 
     private final Map<String,ObjectsessionSwapInLocks =
         new HashMap<String,Object>();
 
 
     // ------------------------------------------------------------- Properties
 
    
  


    
Indicates how many seconds old a session can get, after its last use in a request, before it should be backed up to the store. -1 means sessions are not backed up.
 
     public int getMaxIdleBackup() {
 
         return ;
 
     }


    
Sets the option to back sessions up to the Store after they are used in a request. Sessions remain available in memory after being backed up, so they are not passivated as they are when swapped out. The value set indicates how old a session may get (since its last use) before it must be backed up: -1 means sessions are not backed up.

Note that this is not a hard limit: sessions are checked against this age limit periodically according to processExpiresFrequency. This value should be considered to indicate when a session is ripe for backing up.

So it is possible that a session may be idle for maxIdleBackup + processExpiresFrequency * engine.backgroundProcessorDelay seconds, plus the time it takes to handle other session expiration, swapping, etc. tasks.

Parameters:
backup The number of seconds after their last accessed time when they should be written to the Store.
 
     public void setMaxIdleBackup (int backup) {
 
         if (backup == this.)
             return;
         int oldBackup = this.;
         this. = backup;
         .firePropertyChange("maxIdleBackup",
                                    new Integer(oldBackup),
                                    new Integer(this.));
 
     }


    
The time in seconds after which a session should be swapped out of memory to disk.
 
     public int getMaxIdleSwap() {
 
         return ;
 
     }


    
Sets the time in seconds after which a session should be swapped out of memory to disk.
 
     public void setMaxIdleSwap(int max) {
 
         if (max == this.)
             return;
         int oldMaxIdleSwap = this.;
         this. = max;
         .firePropertyChange("maxIdleSwap",
                                    new Integer(oldMaxIdleSwap),
                                    new Integer(this.));
 
     }


    
The minimum time in seconds that a session must be idle before it can be swapped out of memory, or -1 if it can be swapped out at any time.
 
     public int getMinIdleSwap() {
 
         return ;
 
     }


    
Sets the minimum time in seconds that a session must be idle before it can be swapped out of memory due to maxActiveSession. Set it to -1 if it can be swapped out at any time.
 
     public void setMinIdleSwap(int min) {
 
         if (this. == min)
             return;
         int oldMinIdleSwap = this.;
         this. = min;
         .firePropertyChange("minIdleSwap",
                                    new Integer(oldMinIdleSwap),
                                    new Integer(this.));
 
     }


    
Set the Container with which this Manager has been associated. If it is a Context (the usual case), listen for changes to the session timeout property.

Parameters:
container The associated Container
 
     public void setContainer(Container container) {
 
         // De-register from the old Container (if any)
         if ((this. != null) && (this. instanceof Context))
             ((Contextthis.).removePropertyChangeListener(this);
 
         // Default processing provided by our superclass
         super.setContainer(container);
 
         // Register with the new Container (if any)
         if ((this. != null) && (this. instanceof Context)) {
             ((Contextthis.).addPropertyChangeListener(this);
         }
 
     }


    
Return descriptive information about this Manager implementation and the corresponding version number, in the format <description>/<version>.
 
     public String getInfo() {
 
         return ();
 
     }


    
Return true, if the session id is loaded in memory otherwise false is returned

Parameters:
id The session id for the session to be searched for
 
     public boolean isLoadedString id ){
         try {
             if ( super.findSession(id) != null )
                 return true;
         } catch (IOException e) {
         }
         return false;
     }


    
Return the maximum number of active Sessions allowed, or -1 for no limit.
 
     public int getMaxActiveSessions() {
 
         return (this.);
 
     }


    
Set the maximum number of active Sessions allowed, or -1 for no limit.

Parameters:
max The new maximum number of sessions
 
     public void setMaxActiveSessions(int max) {
 
         int oldMaxActiveSessions = this.;
         this. = max;
         .firePropertyChange("maxActiveSessions",
                                    new Integer(oldMaxActiveSessions),
                                    new Integer(this.));
 
     }


    
Number of session creations that failed due to maxActiveSessions.

Returns:
The count
 
     public int getRejectedSessions() {
         return ;
     }
 
     
     public void setRejectedSessions(int rejectedSessions) {
         this. = rejectedSessions;
     }

    
Return the descriptive short name of this Manager implementation.
 
     public String getName() {
 
         return ();
 
     }


    
Get the started status.
 
     protected boolean isStarted() {
 
         return ;
 
     }


    
Set the started flag
 
     protected void setStarted(boolean started) {
 
         this. = started;
 
     }


    
Set the Store object which will manage persistent Session storage for this Manager.

Parameters:
store the associated Store
 
     public void setStore(Store store) {
         this. = store;
         store.setManager(this);
 
     }


    
Return the Store object which manages persistent Session storage for this Manager.
 
     public Store getStore() {
 
         return (this.);
 
     }



    
Indicates whether sessions are saved when the Manager is shut down properly. This requires the unload() method to be called.
 
     public boolean getSaveOnRestart() {
 
         return ;
 
     }


    
Set the option to save sessions to the Store when the Manager is shut down, then loaded when the Manager starts again. If set to false, any sessions found in the Store may still be picked up when the Manager is started again.

Parameters:
saveOnRestart true if sessions should be saved on restart, false if they should be ignored.
 
     public void setSaveOnRestart(boolean saveOnRestart) {
 
         if (saveOnRestart == this.)
             return;
 
         boolean oldSaveOnRestart = this.;
         this. = saveOnRestart;
         .firePropertyChange("saveOnRestart",
                                    new Boolean(oldSaveOnRestart),
                                    new Boolean(this.));
 
     }
 
 
     // --------------------------------------------------------- Public Methods
 

    
Clear all sessions from the Store.
 
     public void clearStore() {
 
         if ( == null)
             return;
 
         try {     
             if (SecurityUtil.isPackageProtectionEnabled()){
                 try{
                     AccessController.doPrivileged(new PrivilegedStoreClear());
                 }catch(PrivilegedActionException ex){
                     Exception exception = ex.getException();
                     ..persistentManagerStoreClearException(exception);
                 }
             } else {
                 .clear();
             }
         } catch (IOException e) {
         }
 
     }


    
Implements the Manager interface, direct call to processExpires and processPersistenceChecks
 
     public void processExpires() {
         
         long timeNow = System.currentTimeMillis();
         Session sessions[] = findSessions();
         int expireHere = 0 ;
             ..debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
         for (int i = 0; i < sessions.lengthi++) {
             if (!sessions[i].isValid()) {
                 ++;
                 expireHere++;
             }
         }
         processPersistenceChecks();
         if ((getStore() != null) && (getStore() instanceof StoreBase)) {
             ((StoreBasegetStore()).processExpires();
         }
         
         long timeEnd = System.currentTimeMillis();
             ..debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
          += (timeEnd - timeNow);
         
     }


    
Called by the background thread after active sessions have been checked for expiration, to allow sessions to be swapped out, backed up, etc.
 
     public void processPersistenceChecks() {
 
         processMaxIdleSwaps();
         processMaxActiveSwaps();
         processMaxIdleBackups();
 
     }


    
Return the active Session, associated with this Manager, with the specified session id (if any); otherwise return null. This method checks the persistence store if persistence is enabled, otherwise just uses the functionality from ManagerBase.

Parameters:
id The session id for the session to be returned
Throws:
java.lang.IllegalStateException if a new session cannot be instantiated for any reason
java.io.IOException if an input/output error occurs while processing this request
 
     public Session findSession(String idthrows IOException {
 
         Session session = super.findSession(id);
         // OK, at this point, we're not sure if another thread is trying to
         // remove the session or not so the only way around this is to lock it
         // (or attempt to) and then try to get it by this session id again. If
         // the other code ran swapOut, then we should get a null back during
         // this run, and if not, we lock it out so we can access the session
         // safely.
         if(session != null) {
             synchronized(session){
                 session = super.findSession(session.getIdInternal());
                 if(session != null){
                    // To keep any external calling code from messing up the
                    // concurrency.
                    session.access();
                    session.endAccess();
                 }
             }
         }
         if (session != null)
             return (session);
 
         // See if the Session is in the Store
         session = swapIn(id);
         return (session);
 
     }

    
Remove this Session from the active Sessions for this Manager, but not from the Store. (Used by the PersistentValve)

Parameters:
session Session to be removed
 
     public void removeSuper(Session session) {
         super.remove (session);
     }

    
Load all sessions found in the persistence mechanism, assuming they are marked as valid and have not passed their expiration limit. If persistence is not supported, this method returns without doing anything.

Note that by default, this method is not called by the MiddleManager class. In order to use it, a subclass must specifically call it, for example in the start() and/or processPersistenceChecks() methods.

 
     public void load() {
 
         // Initialize our internal data structures
         .clear();
 
         if ( == null)
             return;
 
         String[] ids = null;
         try {
             if (SecurityUtil.isPackageProtectionEnabled()){
                 try{
                     ids = (String[])
                         AccessController.doPrivileged(new PrivilegedStoreKeys());
                 }catch(PrivilegedActionException ex){
                     Exception exception = ex.getException();
                     ..persistentManagerLoadFailed(exception);                        
                 }
             } else {
                 ids = .keys();
             }
         } catch (IOException e) {
             ..persistentManagerLoadFailed(e);                        
             return;
         }
 
         int n = ids.length;
         if (n == 0)
             return;
 
         for (int i = 0; i < ni++)
             try {
                 swapIn(ids[i]);
             } catch (IOException e) {
                 ..persistentManagerLoadFailed(e);                        
             }
 
     }


    
Remove this Session from the active Sessions for this Manager, and from the Store.

Parameters:
session Session to be removed
 
     public void remove(Session session) {
 
         super.remove (session);
 
         if ( != null){
             removeSession(session.getIdInternal());
         }
     }

    
    
Remove this Session from the active Sessions for this Manager, and from the Store.

Parameters:
id Session's id to be removed
     
     protected void removeSession(String id){
         try {
             if (SecurityUtil.isPackageProtectionEnabled()){
                 try{
                     AccessController.doPrivileged(new PrivilegedStoreRemove(id));
                 }catch(PrivilegedActionException ex){
                     Exception exception = ex.getException();
                     ..persistentManagerSessionRemoveFailed(idexception);
                 }
             } else {
                  .remove(id);
             }               
         } catch (IOException e) {
         }        
     }

    
Save all currently active sessions in the appropriate persistence mechanism, if any. If persistence is not supported, this method returns without doing anything.

Note that by default, this method is not called by the MiddleManager class. In order to use it, a subclass must specifically call it, for example in the stop() and/or processPersistenceChecks() methods.

 
     public void unload() {
 
         if ( == null)
             return;
 
         Session sessions[] = findSessions();
         int n = sessions.length;
         if (n == 0)
             return;
 
 
         for (int i = 0; i < ni++)
             try {
                 swapOut(sessions[i]);
             } catch (IOException e) {
                 ;   // This is logged in writeSession()
             }
 
     }
 
 
     // ------------------------------------------------------ Protected Methods
 

    
Look for a session in the Store and, if found, restore it in the Manager's list of active sessions if appropriate. The session will be removed from the Store after swapping in, but will not be added to the active session list if it is invalid or past its expiration.
 
     protected Session swapIn(String idthrows IOException {
 
         if ( == null)
             return null;
 
         Object swapInLock = null;
 
         /*
          * The purpose of this sync and these locks is to make sure that a
          * session is only loaded once. It doesn't matter if the lock is removed
          * and then another thread enters this method and tries to load the same
          * session. That thread will re-create a swapIn lock for that session,
          * quickly find that the session is already in sessions, use it and
          * carry on.
          */
         synchronized (this) {
             swapInLock = .get(id);
             if (swapInLock == null) {
                 swapInLock = new Object();
                 .put(idswapInLock);
             }
         }
 
         Session session = null;
 
         synchronized (swapInLock) {
             // First check to see if another thread has loaded the session into
             // the manager
             session = .get(id);
 
             if (session == null) {
                 try {
                     if (SecurityUtil.isPackageProtectionEnabled()){
                         try {
                             session = (Session) AccessController.doPrivileged(
                                     new PrivilegedStoreLoad(id));
                         } catch (PrivilegedActionException ex) {
                             Exception e = ex.getException();
                             ..persistentManagerSwapInFailed(ide);
                             if (e instanceof IOException){
                                 throw (IOException)e;
                             } else if (e instanceof ClassNotFoundException) {
                                 throw (ClassNotFoundException)e;
                             }
                         }
                     } else {
                          session = .load(id);
                     }
                 } catch (ClassNotFoundException e) {
                     throw .persistentManagerDeserializeError(ide);
                 }
 
                 if (session != null && !session.isValid()) {
                     ..persistentManagerSwapInInvalid(id);
                     session.expire();
                     removeSession(id);
                     session = null;
                 }
 
                 if (session != null) {
                     ..sessionSwapIn(id);
                     session.setManager(this);
                     // make sure the listeners know about it.
                     ((StandardSession)session).tellNew();
                     add(session);
                     ((StandardSession)session).activate();
                     // endAccess() to ensure timeouts happen correctly.
                     // access() to keep access count correct or it will end up
                     // negative
                     session.access();
                     session.endAccess();
                 }
             }
         }
 
         // Make sure the lock is removed
         synchronized (this) {
             .remove(id);
         }
 
         return (session);
 
     }


    
Remove the session from the Manager's list of active sessions and write it out to the Store. If the session is past its expiration or invalid, this method does nothing.

Parameters:
session The Session to write out.
 
     protected void swapOut(Session sessionthrows IOException {
 
         if ( == null || !session.isValid()) {
             return;
         }
 
         ((StandardSession)session).passivate();
         writeSession(session);
         super.remove(session);
         session.recycle();
 
     }


    
Write the provided session to the Store without modifying the copy in memory or triggering passivation events. Does nothing if the session is invalid or past its expiration.
 
     protected void writeSession(Session sessionthrows IOException {
 
         if ( == null || !session.isValid()) {
             return;
         }
 
         try {
             if (SecurityUtil.isPackageProtectionEnabled()){
                 try{
                     AccessController.doPrivileged(new PrivilegedStoreSave(session));
                 }catch(PrivilegedActionException ex){
                     Exception exception = ex.getException();
                     ..persistentManagerStoreSaveError(session.getIdInternal(), exception);
                 }
             } else {
                  .save(session);
             }   
         } catch (IOException e) {
             throw e;
         }
 
     }
 
 
     // ------------------------------------------------------ Lifecycle Methods
 

    
Add a lifecycle event listener to this component.

Parameters:
listener The listener to add
 
     public void addLifecycleListener(LifecycleListener listener) {
 
         .addLifecycleListener(listener);
 
     }


    
Get the lifecycle listeners associated with this lifecycle. If this Lifecycle has no listeners registered, a zero-length array is returned.
 
 
         return .findLifecycleListeners();
 
     }


    
Remove a lifecycle event listener from this component.

Parameters:
listener The listener to remove
 
     public void removeLifecycleListener(LifecycleListener listener) {
 
         .removeLifecycleListener(listener);
 
     }


    
Prepare for the beginning of active use of the public methods of this component. This method should be called after configure(), and before any of the public methods of the component are utilized.

Throws:
org.apache.catalina.LifecycleException if this component detects a fatal error that prevents this component from being used
 
     public void start() throws LifecycleException {
 
         // Validate and update our current component state
         if () {
             return;
         }
         if( !  )
             init();
         
         .fireLifecycleEvent(null);
          = true;
 
         if ( == null)
         else if ( instanceof Lifecycle)
             ((Lifecycle)).start();
 
     }


    
Gracefully terminate the active use of the public methods of this component. This method should be the last one called on a given instance of this component.

Throws:
org.apache.catalina.LifecycleException if this component detects a fatal error that needs to be reported
 
    public void stop() throws LifecycleException {
 
         // Validate and update our current component state
         if (!isStarted()) {
             return;
         }
         
         .fireLifecycleEvent(null);
         setStarted(false);
 
         if (getStore() != null && ) {
             unload();
         } else {
             // Expire all active sessions
             Session sessions[] = findSessions();
             for (int i = 0; i < sessions.lengthi++) {
                 StandardSession session = (StandardSessionsessions[i];
                 if (!session.isValid())
                     continue;
                 session.expire();
             }
         }
 
         if (getStore() != null && getStore() instanceof Lifecycle)
             ((Lifecycle)getStore()).stop();
        if )
            destroy();
    }
    // ----------------------------------------- PropertyChangeListener Methods


    
Process property change events from our associated Context.

Parameters:
event The property change event that has occurred
    public void propertyChange(PropertyChangeEvent event) {
        // Validate the source of this event
        if (!(event.getSource() instanceof Context))
            return;
        Context context = (Contextevent.getSource();
        // Process a relevant property change
        if (event.getPropertyName().equals("sessionTimeout")) {
            try {
                setMaxInactiveInterval
                    ( ((Integerevent.getNewValue()).intValue()*60 );
            } catch (NumberFormatException e) {
            }
        }
    }
    // ------------------------------------------------------ Protected Methods


    
Swap idle sessions out to Store if they are idle too long.
    protected void processMaxIdleSwaps() {
        if (!isStarted() ||  < 0)
            return;
        Session sessions[] = findSessions();
        long timeNow = System.currentTimeMillis();
        // Swap out all sessions idle longer than maxIdleSwap
        if ( >= 0) {
            for (int i = 0; i < sessions.lengthi++) {
                StandardSession session = (StandardSessionsessions[i];
                synchronized (session) {
                    if (!session.isValid())
                        continue;
                    int timeIdle = // Truncate, do not round up
                        (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
                    if (timeIdle >  && timeIdle > ) {
                        if (session.accessCount != null &&
                                session.accessCount.get() > 0) {
                            // Session is currently being accessed - skip it
                            continue;
                        }
                        ..sessionSwapOut(session.getIdInternal(), timeIdle);
                        try {
                            swapOut(session);
                        } catch (IOException e) {
                            ;   // This is logged in writeSession()
                        }
                    }
                }
            }
        }
    }


    
Swap idle sessions out to Store if too many are active
    protected void processMaxActiveSwaps() {
        if (!isStarted() || getMaxActiveSessions() < 0)
            return;
        Session sessions[] = findSessions();
        // FIXME: Smarter algorithm (LRU)
        if (getMaxActiveSessions() >= sessions.length)
            return;
        int toswap = sessions.length - getMaxActiveSessions();
        long timeNow = System.currentTimeMillis();
        for (int i = 0; i < sessions.length && toswap > 0; i++) {
            StandardSession session =  (StandardSessionsessions[i];
            synchronized (session) {
                int timeIdle = // Truncate, do not round up
                    (int) ((timeNow - session.getThisAccessedTimeInternal()) / 1000L);
                if (timeIdle > ) {
                    if (session.accessCount != null &&
                            session.accessCount.get() > 0) {
                        // Session is currently being accessed - skip it
                        continue;
                    }
                    ..persistentManagerSwapIdleSession(session.getIdInternal(), timeIdle);
                    try {
                        swapOut(session);
                    } catch (IOException e) {
                        // This is logged in writeSession()
                    }
                    toswap--;
                }
            }
        }
    }


    
Back up idle sessions.
    protected void processMaxIdleBackups() {
        if (!isStarted() ||  < 0)
            return;
        Session sessions[] = findSessions();
        long timeNow = System.currentTimeMillis();
        // Back up all sessions idle longer than maxIdleBackup
        if ( >= 0) {
            for (int i = 0; i < sessions.lengthi++) {
                StandardSession session = (StandardSessionsessions[i];
                synchronized (session) {
                    if (!session.isValid())
                        continue;
                    int timeIdle = // Truncate, do not round up
                        (int) ((timeNow - session.getLastAccessedTime()) / 1000L);
                    if (timeIdle > ) {
                        ..persistentManagerBackupSession(session.getIdInternal(), timeIdle);
                        try {
                            writeSession(session);
                        } catch (IOException e) {
                            ;   // This is logged in writeSession()
                        }
                    }
                }
            }
        }
    }
New to GrepCode? Check out our FAQ X