KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > session > ManagerBase


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
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeSupport JavaDoc;
24 import java.io.DataInputStream JavaDoc;
25 import java.io.File JavaDoc;
26 import java.io.FileInputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.lang.reflect.Method JavaDoc;
29 import java.security.AccessController JavaDoc;
30 import java.security.MessageDigest JavaDoc;
31 import java.security.NoSuchAlgorithmException JavaDoc;
32 import java.security.PrivilegedAction JavaDoc;
33 import java.util.Date JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.Map JavaDoc;
38 import java.util.Random JavaDoc;
39 import java.util.concurrent.ConcurrentHashMap JavaDoc;
40
41 import javax.management.MBeanRegistration JavaDoc;
42 import javax.management.MBeanServer JavaDoc;
43 import javax.management.ObjectName JavaDoc;
44
45 import org.apache.catalina.Container;
46 import org.apache.catalina.Engine;
47 import org.apache.catalina.Manager;
48 import org.apache.catalina.Session;
49 import org.apache.catalina.core.StandardContext;
50 import org.apache.catalina.core.StandardHost;
51 import org.apache.catalina.util.StringManager;
52 import org.apache.commons.logging.Log;
53 import org.apache.commons.logging.LogFactory;
54 import org.apache.tomcat.util.modeler.Registry;
55
56
57 /**
58  * Minimal implementation of the <b>Manager</b> interface that supports
59  * no session persistence or distributable capabilities. This class may
60  * be subclassed to create more sophisticated Manager implementations.
61  *
62  * @author Craig R. McClanahan
63  * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
64  */

65
66 public abstract class ManagerBase implements Manager, MBeanRegistration JavaDoc {
67     protected Log log = LogFactory.getLog(ManagerBase.class);
68
69     // ----------------------------------------------------- Instance Variables
70

71     protected DataInputStream JavaDoc randomIS=null;
72     protected String JavaDoc devRandomSource="/dev/urandom";
73
74     /**
75      * The default message digest algorithm to use if we cannot use
76      * the requested one.
77      */

78     protected static final String JavaDoc DEFAULT_ALGORITHM = "MD5";
79
80
81     /**
82      * The message digest algorithm to be used when generating session
83      * identifiers. This must be an algorithm supported by the
84      * <code>java.security.MessageDigest</code> class on your platform.
85      */

86     protected String JavaDoc algorithm = DEFAULT_ALGORITHM;
87
88
89     /**
90      * The Container with which this Manager is associated.
91      */

92     protected Container container;
93
94
95     /**
96      * Return the MessageDigest implementation to be used when
97      * creating session identifiers.
98      */

99     protected MessageDigest JavaDoc digest = null;
100
101
102     /**
103      * The distributable flag for Sessions created by this Manager. If this
104      * flag is set to <code>true</code>, any user attributes added to a
105      * session controlled by this Manager must be Serializable.
106      */

107     protected boolean distributable;
108
109
110     /**
111      * A String initialization parameter used to increase the entropy of
112      * the initialization of our random number generator.
113      */

114     protected String JavaDoc entropy = null;
115
116
117     /**
118      * The descriptive information string for this implementation.
119      */

120     private static final String JavaDoc info = "ManagerBase/1.0";
121
122
123     /**
124      * The default maximum inactive interval for Sessions created by
125      * this Manager.
126      */

127     protected int maxInactiveInterval = 60;
128
129
130     /**
131      * The session id length of Sessions created by this Manager.
132      */

133     protected int sessionIdLength = 16;
134
135
136     /**
137      * The descriptive name of this Manager implementation (for logging).
138      */

139     protected static String JavaDoc name = "ManagerBase";
140
141
142     /**
143      * A random number generator to use when generating session identifiers.
144      */

145     protected Random JavaDoc random = null;
146
147
148     /**
149      * The Java class name of the random number generator class to be used
150      * when generating session identifiers.
151      */

152     protected String JavaDoc randomClass = "java.security.SecureRandom";
153
154
155     /**
156      * The longest time (in seconds) that an expired session had been alive.
157      */

158     protected int sessionMaxAliveTime;
159
160
161     /**
162      * Average time (in seconds) that expired sessions had been alive.
163      */

164     protected int sessionAverageAliveTime;
165
166
167     /**
168      * Number of sessions that have expired.
169      */

170     protected int expiredSessions = 0;
171
172
173     /**
174      * The set of currently active Sessions for this Manager, keyed by
175      * session identifier.
176      */

177     protected Map JavaDoc sessions = new ConcurrentHashMap JavaDoc();
178
179     // Number of sessions created by this manager
180
protected int sessionCounter=0;
181
182     protected int maxActive=0;
183
184     // number of duplicated session ids - anything >0 means we have problems
185
protected int duplicates=0;
186
187     protected boolean initialized=false;
188     
189     /**
190      * Processing time during session expiration.
191      */

192     protected long processingTime = 0;
193
194     /**
195      * Iteration count for background processing.
196      */

197     private int count = 0;
198
199
200     /**
201      * Frequency of the session expiration, and related manager operations.
202      * Manager operations will be done once for the specified amount of
203      * backgrondProcess calls (ie, the lower the amount, the most often the
204      * checks will occur).
205      */

206     protected int processExpiresFrequency = 6;
207
208     /**
209      * The string manager for this package.
210      */

211     protected static StringManager sm =
212         StringManager.getManager(Constants.Package);
213
214     /**
215      * The property change support for this component.
216      */

217     protected PropertyChangeSupport JavaDoc support = new PropertyChangeSupport JavaDoc(this);
218     
219     
220     // ------------------------------------------------------------- Security classes
221

222
223     private class PrivilegedSetRandomFile implements PrivilegedAction JavaDoc{
224         
225         public Object JavaDoc run(){
226             try {
227                 File JavaDoc f=new File JavaDoc( devRandomSource );
228                 if( ! f.exists() ) return null;
229                 randomIS= new DataInputStream JavaDoc( new FileInputStream JavaDoc(f));
230                 randomIS.readLong();
231                 if( log.isDebugEnabled() )
232                     log.debug( "Opening " + devRandomSource );
233                 return randomIS;
234             } catch (IOException JavaDoc ex){
235                 return null;
236             }
237         }
238     }
239
240
241     // ------------------------------------------------------------- Properties
242

243     /**
244      * Return the message digest algorithm for this Manager.
245      */

246     public String JavaDoc getAlgorithm() {
247
248         return (this.algorithm);
249
250     }
251
252
253     /**
254      * Set the message digest algorithm for this Manager.
255      *
256      * @param algorithm The new message digest algorithm
257      */

258     public void setAlgorithm(String JavaDoc algorithm) {
259
260         String JavaDoc oldAlgorithm = this.algorithm;
261         this.algorithm = algorithm;
262         support.firePropertyChange("algorithm", oldAlgorithm, this.algorithm);
263
264     }
265
266
267     /**
268      * Return the Container with which this Manager is associated.
269      */

270     public Container getContainer() {
271
272         return (this.container);
273
274     }
275
276
277     /**
278      * Set the Container with which this Manager is associated.
279      *
280      * @param container The newly associated Container
281      */

282     public void setContainer(Container container) {
283
284         Container oldContainer = this.container;
285         this.container = container;
286         support.firePropertyChange("container", oldContainer, this.container);
287     }
288
289
290     /** Returns the name of the implementation class.
291      */

292     public String JavaDoc getClassName() {
293         return this.getClass().getName();
294     }
295
296
297     /**
298      * Return the MessageDigest object to be used for calculating
299      * session identifiers. If none has been created yet, initialize
300      * one the first time this method is called.
301      */

302     public synchronized MessageDigest JavaDoc getDigest() {
303
304         if (this.digest == null) {
305             long t1=System.currentTimeMillis();
306             if (log.isDebugEnabled())
307                 log.debug(sm.getString("managerBase.getting", algorithm));
308             try {
309                 this.digest = MessageDigest.getInstance(algorithm);
310             } catch (NoSuchAlgorithmException JavaDoc e) {
311                 log.error(sm.getString("managerBase.digest", algorithm), e);
312                 try {
313                     this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
314                 } catch (NoSuchAlgorithmException JavaDoc f) {
315                     log.error(sm.getString("managerBase.digest",
316                                      DEFAULT_ALGORITHM), e);
317                     this.digest = null;
318                 }
319             }
320             if (log.isDebugEnabled())
321                 log.debug(sm.getString("managerBase.gotten"));
322             long t2=System.currentTimeMillis();
323             if( log.isDebugEnabled() )
324                 log.debug("getDigest() " + (t2-t1));
325         }
326
327         return (this.digest);
328
329     }
330
331
332     /**
333      * Return the distributable flag for the sessions supported by
334      * this Manager.
335      */

336     public boolean getDistributable() {
337
338         return (this.distributable);
339
340     }
341
342
343     /**
344      * Set the distributable flag for the sessions supported by this
345      * Manager. If this flag is set, all user data objects added to
346      * sessions associated with this manager must implement Serializable.
347      *
348      * @param distributable The new distributable flag
349      */

350     public void setDistributable(boolean distributable) {
351
352         boolean oldDistributable = this.distributable;
353         this.distributable = distributable;
354         support.firePropertyChange("distributable",
355                                    new Boolean JavaDoc(oldDistributable),
356                                    new Boolean JavaDoc(this.distributable));
357
358     }
359
360
361     /**
362      * Return the entropy increaser value, or compute a semi-useful value
363      * if this String has not yet been set.
364      */

365     public String JavaDoc getEntropy() {
366
367         // Calculate a semi-useful value if this has not been set
368
if (this.entropy == null) {
369             // Use APR to get a crypto secure entropy value
370
byte[] result = new byte[32];
371             boolean apr = false;
372             try {
373                 String JavaDoc methodName = "random";
374                 Class JavaDoc paramTypes[] = new Class JavaDoc[2];
375                 paramTypes[0] = result.getClass();
376                 paramTypes[1] = int.class;
377                 Object JavaDoc paramValues[] = new Object JavaDoc[2];
378                 paramValues[0] = result;
379                 paramValues[1] = new Integer JavaDoc(32);
380                 Method JavaDoc method = Class.forName("org.apache.tomcat.jni.OS")
381                     .getMethod(methodName, paramTypes);
382                 method.invoke(null, paramValues);
383                 apr = true;
384             } catch (Throwable JavaDoc t) {
385                 // Ignore
386
}
387             if (apr) {
388                 setEntropy(new String JavaDoc(result));
389             } else {
390                 setEntropy(this.toString());
391             }
392         }
393
394         return (this.entropy);
395
396     }
397
398
399     /**
400      * Set the entropy increaser value.
401      *
402      * @param entropy The new entropy increaser value
403      */

404     public void setEntropy(String JavaDoc entropy) {
405
406         String JavaDoc oldEntropy = entropy;
407         this.entropy = entropy;
408         support.firePropertyChange("entropy", oldEntropy, this.entropy);
409
410     }
411
412
413     /**
414      * Return descriptive information about this Manager implementation and
415      * the corresponding version number, in the format
416      * <code>&lt;description&gt;/&lt;version&gt;</code>.
417      */

418     public String JavaDoc getInfo() {
419
420         return (info);
421
422     }
423
424
425     /**
426      * Return the default maximum inactive interval (in seconds)
427      * for Sessions created by this Manager.
428      */

429     public int getMaxInactiveInterval() {
430
431         return (this.maxInactiveInterval);
432
433     }
434
435
436     /**
437      * Set the default maximum inactive interval (in seconds)
438      * for Sessions created by this Manager.
439      *
440      * @param interval The new default value
441      */

442     public void setMaxInactiveInterval(int interval) {
443
444         int oldMaxInactiveInterval = this.maxInactiveInterval;
445         this.maxInactiveInterval = interval;
446         support.firePropertyChange("maxInactiveInterval",
447                                    new Integer JavaDoc(oldMaxInactiveInterval),
448                                    new Integer JavaDoc(this.maxInactiveInterval));
449
450     }
451
452
453     /**
454      * Gets the session id length (in bytes) of Sessions created by
455      * this Manager.
456      *
457      * @return The session id length
458      */

459     public int getSessionIdLength() {
460
461         return (this.sessionIdLength);
462
463     }
464
465
466     /**
467      * Sets the session id length (in bytes) for Sessions created by this
468      * Manager.
469      *
470      * @param idLength The session id length
471      */

472     public void setSessionIdLength(int idLength) {
473
474         int oldSessionIdLength = this.sessionIdLength;
475         this.sessionIdLength = idLength;
476         support.firePropertyChange("sessionIdLength",
477                                    new Integer JavaDoc(oldSessionIdLength),
478                                    new Integer JavaDoc(this.sessionIdLength));
479
480     }
481
482
483     /**
484      * Return the descriptive short name of this Manager implementation.
485      */

486     public String JavaDoc getName() {
487
488         return (name);
489
490     }
491
492     /**
493      * Use /dev/random-type special device. This is new code, but may reduce
494      * the big delay in generating the random.
495      *
496      * You must specify a path to a random generator file. Use /dev/urandom
497      * for linux ( or similar ) systems. Use /dev/random for maximum security
498      * ( it may block if not enough "random" exist ). You can also use
499      * a pipe that generates random.
500      *
501      * The code will check if the file exists, and default to java Random
502      * if not found. There is a significant performance difference, very
503      * visible on the first call to getSession ( like in the first JSP )
504      * - so use it if available.
505      */

506     public void setRandomFile( String JavaDoc s ) {
507         // as a hack, you can use a static file - and genarate the same
508
// session ids ( good for strange debugging )
509
if (System.getSecurityManager() != null){
510             randomIS = (DataInputStream JavaDoc)AccessController.doPrivileged(new PrivilegedSetRandomFile());
511         } else {
512             try{
513                 devRandomSource=s;
514                 File JavaDoc f=new File JavaDoc( devRandomSource );
515                 if( ! f.exists() ) return;
516                 randomIS= new DataInputStream JavaDoc( new FileInputStream JavaDoc(f));
517                 randomIS.readLong();
518                 if( log.isDebugEnabled() )
519                     log.debug( "Opening " + devRandomSource );
520             } catch( IOException JavaDoc ex ) {
521                 try {
522                     randomIS.close();
523                 } catch (Exception JavaDoc e) {
524                     log.warn("Failed to close randomIS.");
525                 }
526                 
527                 randomIS=null;
528             }
529         }
530     }
531
532     public String JavaDoc getRandomFile() {
533         return devRandomSource;
534     }
535
536
537     /**
538      * Return the random number generator instance we should use for
539      * generating session identifiers. If there is no such generator
540      * currently defined, construct and seed a new one.
541      */

542     public Random JavaDoc getRandom() {
543         if (this.random == null) {
544             // Calculate the new random number generator seed
545
long seed = System.currentTimeMillis();
546             long t1 = seed;
547             char entropy[] = getEntropy().toCharArray();
548             for (int i = 0; i < entropy.length; i++) {
549                 long update = ((byte) entropy[i]) << ((i % 8) * 8);
550                 seed ^= update;
551             }
552             try {
553                 // Construct and seed a new random number generator
554
Class JavaDoc clazz = Class.forName(randomClass);
555                 this.random = (Random JavaDoc) clazz.newInstance();
556                 this.random.setSeed(seed);
557             } catch (Exception JavaDoc e) {
558                 // Fall back to the simple case
559
log.error(sm.getString("managerBase.random", randomClass),
560                         e);
561                 this.random = new java.util.Random JavaDoc();
562                 this.random.setSeed(seed);
563             }
564             if(log.isDebugEnabled()) {
565                 long t2=System.currentTimeMillis();
566                 if( (t2-t1) > 100 )
567                     log.debug(sm.getString("managerBase.seeding", randomClass) + " " + (t2-t1));
568             }
569         }
570         
571         return (this.random);
572
573     }
574
575
576     /**
577      * Return the random number generator class name.
578      */

579     public String JavaDoc getRandomClass() {
580
581         return (this.randomClass);
582
583     }
584
585
586     /**
587      * Set the random number generator class name.
588      *
589      * @param randomClass The new random number generator class name
590      */

591     public void setRandomClass(String JavaDoc randomClass) {
592
593         String JavaDoc oldRandomClass = this.randomClass;
594         this.randomClass = randomClass;
595         support.firePropertyChange("randomClass", oldRandomClass,
596                                    this.randomClass);
597
598     }
599
600
601     /**
602      * Gets the number of sessions that have expired.
603      *
604      * @return Number of sessions that have expired
605      */

606     public int getExpiredSessions() {
607         return expiredSessions;
608     }
609
610
611     /**
612      * Sets the number of sessions that have expired.
613      *
614      * @param expiredSessions Number of sessions that have expired
615      */

616     public void setExpiredSessions(int expiredSessions) {
617         this.expiredSessions = expiredSessions;
618     }
619
620     public long getProcessingTime() {
621         return processingTime;
622     }
623
624
625     public void setProcessingTime(long processingTime) {
626         this.processingTime = processingTime;
627     }
628     
629     /**
630      * Return the frequency of manager checks.
631      */

632     public int getProcessExpiresFrequency() {
633
634         return (this.processExpiresFrequency);
635
636     }
637
638     /**
639      * Set the manager checks frequency.
640      *
641      * @param processExpiresFrequency the new manager checks frequency
642      */

643     public void setProcessExpiresFrequency(int processExpiresFrequency) {
644
645         if (processExpiresFrequency <= 0) {
646             return;
647         }
648
649         int oldProcessExpiresFrequency = this.processExpiresFrequency;
650         this.processExpiresFrequency = processExpiresFrequency;
651         support.firePropertyChange("processExpiresFrequency",
652                                    new Integer JavaDoc(oldProcessExpiresFrequency),
653                                    new Integer JavaDoc(this.processExpiresFrequency));
654
655     }
656
657     // --------------------------------------------------------- Public Methods
658

659
660     /**
661      * Implements the Manager interface, direct call to processExpires
662      */

663     public void backgroundProcess() {
664         count = (count + 1) % processExpiresFrequency;
665         if (count == 0)
666             processExpires();
667     }
668
669     /**
670      * Invalidate all sessions that have expired.
671      */

672     public void processExpires() {
673
674         long timeNow = System.currentTimeMillis();
675         Session sessions[] = findSessions();
676         int expireHere = 0 ;
677         
678         if(log.isDebugEnabled())
679             log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
680         for (int i = 0; i < sessions.length; i++) {
681             if (!sessions[i].isValid()) {
682                 expireHere++;
683             }
684         }
685         long timeEnd = System.currentTimeMillis();
686         if(log.isDebugEnabled())
687              log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
688         processingTime += ( timeEnd - timeNow );
689
690     }
691
692     public void destroy() {
693         if( oname != null )
694             Registry.getRegistry(null, null).unregisterComponent(oname);
695         initialized=false;
696         oname = null;
697     }
698     
699     public void init() {
700         if( initialized ) return;
701         initialized=true;
702         
703         if( oname==null ) {
704             try {
705                 StandardContext ctx=(StandardContext)this.getContainer();
706                 Engine eng=(Engine)ctx.getParent().getParent();
707                 domain=ctx.getEngineName();
708                 distributable = ctx.getDistributable();
709                 StandardHost hst=(StandardHost)ctx.getParent();
710                 String JavaDoc path = ctx.getPath();
711                 if (path.equals("")) {
712                     path = "/";
713                 }
714                 oname=new ObjectName JavaDoc(domain + ":type=Manager,path="
715                 + path + ",host=" + hst.getName());
716                 Registry.getRegistry(null, null).registerComponent(this, oname, null );
717             } catch (Exception JavaDoc e) {
718                 log.error("Error registering ",e);
719             }
720         }
721         
722         // Initialize random number generation
723
getRandomBytes(new byte[16]);
724         
725         if(log.isDebugEnabled())
726             log.debug("Registering " + oname );
727                
728     }
729
730     /**
731      * Add this Session to the set of active Sessions for this Manager.
732      *
733      * @param session Session to be added
734      */

735     public void add(Session session) {
736
737         sessions.put(session.getIdInternal(), session);
738         int size = sessions.size();
739         if( size > maxActive ) {
740             maxActive = size;
741         }
742     }
743
744
745     /**
746      * Add a property change listener to this component.
747      *
748      * @param listener The listener to add
749      */

750     public void addPropertyChangeListener(PropertyChangeListener JavaDoc listener) {
751
752         support.addPropertyChangeListener(listener);
753
754     }
755
756
757     /**
758      * Construct and return a new session object, based on the default
759      * settings specified by this Manager's properties. The session
760      * id will be assigned by this method, and available via the getId()
761      * method of the returned session. If a new session cannot be created
762      * for any reason, return <code>null</code>.
763      *
764      * @exception IllegalStateException if a new session cannot be
765      * instantiated for any reason
766      * @deprecated
767      */

768     public Session createSession() {
769         return createSession(null);
770     }
771     
772     
773     /**
774      * Construct and return a new session object, based on the default
775      * settings specified by this Manager's properties. The session
776      * id specified will be used as the session id.
777      * If a new session cannot be created for any reason, return
778      * <code>null</code>.
779      *
780      * @param sessionId The session id which should be used to create the
781      * new session; if <code>null</code>, a new session id will be
782      * generated
783      * @exception IllegalStateException if a new session cannot be
784      * instantiated for any reason
785      */

786     public Session createSession(String JavaDoc sessionId) {
787         
788         // Recycle or create a Session instance
789
Session session = createEmptySession();
790
791         // Initialize the properties of the new session and return it
792
session.setNew(true);
793         session.setValid(true);
794         session.setCreationTime(System.currentTimeMillis());
795         session.setMaxInactiveInterval(this.maxInactiveInterval);
796         if (sessionId == null) {
797             sessionId = generateSessionId();
798         // FIXME WHy we need no duplication check?
799
/*
800              synchronized (sessions) {
801                 while (sessions.get(sessionId) != null) { // Guarantee
802                     // uniqueness
803                     duplicates++;
804                     sessionId = generateSessionId();
805                 }
806             }
807         */

808             
809             // FIXME: Code to be used in case route replacement is needed
810
/*
811         } else {
812             String jvmRoute = getJvmRoute();
813             if (getJvmRoute() != null) {
814                 String requestJvmRoute = null;
815                 int index = sessionId.indexOf(".");
816                 if (index > 0) {
817                     requestJvmRoute = sessionId
818                             .substring(index + 1, sessionId.length());
819                 }
820                 if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute)) {
821                     sessionId = sessionId.substring(0, index) + "." + jvmRoute;
822                 }
823             }
824             */

825         }
826         session.setId(sessionId);
827         sessionCounter++;
828
829         return (session);
830
831     }
832     
833     
834     /**
835      * Get a session from the recycled ones or create a new empty one.
836      * The PersistentManager manager does not need to create session data
837      * because it reads it from the Store.
838      */

839     public Session createEmptySession() {
840         return (getNewSession());
841     }
842
843
844     /**
845      * Return the active Session, associated with this Manager, with the
846      * specified session id (if any); otherwise return <code>null</code>.
847      *
848      * @param id The session id for the session to be returned
849      *
850      * @exception IllegalStateException if a new session cannot be
851      * instantiated for any reason
852      * @exception IOException if an input/output error occurs while
853      * processing this request
854      */

855     public Session findSession(String JavaDoc id) throws IOException JavaDoc {
856
857         if (id == null)
858             return (null);
859         return (Session) sessions.get(id);
860
861     }
862
863
864     /**
865      * Return the set of active Sessions associated with this Manager.
866      * If this Manager has no active Sessions, a zero-length array is returned.
867      */

868     public Session[] findSessions() {
869
870         Session results[] = null;
871         synchronized (sessions) {
872             results = new Session[sessions.size()];
873             results = (Session[]) sessions.values().toArray(results);
874         }
875         return (results);
876
877     }
878
879
880     /**
881      * Remove this Session from the active Sessions for this Manager.
882      *
883      * @param session Session to be removed
884      */

885     public void remove(Session session) {
886
887         sessions.remove(session.getIdInternal());
888
889     }
890
891
892     /**
893      * Remove a property change listener from this component.
894      *
895      * @param listener The listener to remove
896      */

897     public void removePropertyChangeListener(PropertyChangeListener JavaDoc listener) {
898
899         support.removePropertyChangeListener(listener);
900
901     }
902
903
904     // ------------------------------------------------------ Protected Methods
905

906
907     /**
908      * Get new session class to be used in the doLoad() method.
909      */

910     protected StandardSession getNewSession() {
911         return new StandardSession(this);
912     }
913
914
915     protected void getRandomBytes(byte bytes[]) {
916         // Generate a byte array containing a session identifier
917
if (devRandomSource != null && randomIS == null) {
918             setRandomFile(devRandomSource);
919         }
920         if (randomIS != null) {
921             try {
922                 int len = randomIS.read(bytes);
923                 if (len == bytes.length) {
924                     return;
925                 }
926                 if(log.isDebugEnabled())
927                     log.debug("Got " + len + " " + bytes.length );
928             } catch (Exception JavaDoc ex) {
929                 // Ignore
930
}
931             devRandomSource = null;
932             
933             try {
934                 randomIS.close();
935             } catch (Exception JavaDoc e) {
936                 log.warn("Failed to close randomIS.");
937             }
938             
939             randomIS = null;
940         }
941         getRandom().nextBytes(bytes);
942     }
943
944
945     /**
946      * Generate and return a new session identifier.
947      */

948     protected synchronized String JavaDoc generateSessionId() {
949
950         byte random[] = new byte[16];
951         String JavaDoc jvmRoute = getJvmRoute();
952         String JavaDoc result = null;
953
954         // Render the result as a String of hexadecimal digits
955
StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
956         do {
957             int resultLenBytes = 0;
958             if (result != null) {
959                 buffer = new StringBuffer JavaDoc();
960                 duplicates++;
961             }
962
963             while (resultLenBytes < this.sessionIdLength) {
964                 getRandomBytes(random);
965                 random = getDigest().digest(random);
966                 for (int j = 0;
967                 j < random.length && resultLenBytes < this.sessionIdLength;
968                 j++) {
969                     byte b1 = (byte) ((random[j] & 0xf0) >> 4);
970                     byte b2 = (byte) (random[j] & 0x0f);
971                     if (b1 < 10)
972                         buffer.append((char) ('0' + b1));
973                     else
974                         buffer.append((char) ('A' + (b1 - 10)));
975                     if (b2 < 10)
976                         buffer.append((char) ('0' + b2));
977                     else
978                         buffer.append((char) ('A' + (b2 - 10)));
979                     resultLenBytes++;
980                 }
981             }
982             if (jvmRoute != null) {
983                 buffer.append('.').append(jvmRoute);
984             }
985             result = buffer.toString();
986         } while (sessions.containsKey(result));
987         return (result);
988
989     }
990
991
992     // ------------------------------------------------------ Protected Methods
993

994
995     /**
996      * Retrieve the enclosing Engine for this Manager.
997      *
998      * @return an Engine object (or null).
999      */

1000    public Engine getEngine() {
1001        Engine e = null;
1002        for (Container c = getContainer(); e == null && c != null ; c = c.getParent()) {
1003            if (c != null && c instanceof Engine) {
1004                e = (Engine)c;
1005            }
1006        }
1007        return e;
1008    }
1009
1010
1011    /**
1012     * Retrieve the JvmRoute for the enclosing Engine.
1013     * @return the JvmRoute or null.
1014     */

1015    public String JavaDoc getJvmRoute() {
1016        Engine e = getEngine();
1017        return e == null ? null : e.getJvmRoute();
1018    }
1019
1020
1021    // -------------------------------------------------------- Package Methods
1022

1023
1024    public void setSessionCounter(int sessionCounter) {
1025        this.sessionCounter = sessionCounter;
1026    }
1027
1028
1029    /**
1030     * Total sessions created by this manager.
1031     *
1032     * @return sessions created
1033     */

1034    public int getSessionCounter() {
1035        return sessionCounter;
1036    }
1037
1038
1039    /**
1040     * Number of duplicated session IDs generated by the random source.
1041     * Anything bigger than 0 means problems.
1042     *
1043     * @return The count of duplicates
1044     */

1045    public int getDuplicates() {
1046        return duplicates;
1047    }
1048
1049
1050    public void setDuplicates(int duplicates) {
1051        this.duplicates = duplicates;
1052    }
1053
1054
1055    /**
1056     * Returns the number of active sessions
1057     *
1058     * @return number of sessions active
1059     */

1060    public int getActiveSessions() {
1061        return sessions.size();
1062    }
1063
1064
1065    /**
1066     * Max number of concurrent active sessions
1067     *
1068     * @return The highest number of concurrent active sessions
1069     */

1070    public int getMaxActive() {
1071        return maxActive;
1072    }
1073
1074
1075    public void setMaxActive(int maxActive) {
1076        this.maxActive = maxActive;
1077    }
1078
1079
1080    /**
1081     * Gets the longest time (in seconds) that an expired session had been
1082     * alive.
1083     *
1084     * @return Longest time (in seconds) that an expired session had been
1085     * alive.
1086     */

1087    public int getSessionMaxAliveTime() {
1088        return sessionMaxAliveTime;
1089    }
1090
1091
1092    /**
1093     * Sets the longest time (in seconds) that an expired session had been
1094     * alive.
1095     *
1096     * @param sessionMaxAliveTime Longest time (in seconds) that an expired
1097     * session had been alive.
1098     */

1099    public void setSessionMaxAliveTime(int sessionMaxAliveTime) {
1100        this.sessionMaxAliveTime = sessionMaxAliveTime;
1101    }
1102
1103
1104    /**
1105     * Gets the average time (in seconds) that expired sessions had been
1106     * alive.
1107     *
1108     * @return Average time (in seconds) that expired sessions had been
1109     * alive.
1110     */

1111    public int getSessionAverageAliveTime() {
1112        return sessionAverageAliveTime;
1113    }
1114
1115
1116    /**
1117     * Sets the average time (in seconds) that expired sessions had been
1118     * alive.
1119     *
1120     * @param sessionAverageAliveTime Average time (in seconds) that expired
1121     * sessions had been alive.
1122     */

1123    public void setSessionAverageAliveTime(int sessionAverageAliveTime) {
1124        this.sessionAverageAliveTime = sessionAverageAliveTime;
1125    }
1126
1127
1128    /**
1129     * For debugging: return a list of all session ids currently active
1130     *
1131     */

1132    public String JavaDoc listSessionIds() {
1133        StringBuffer JavaDoc sb=new StringBuffer JavaDoc();
1134        Iterator JavaDoc keys = sessions.keySet().iterator();
1135        while (keys.hasNext()) {
1136            sb.append(keys.next()).append(" ");
1137        }
1138        return sb.toString();
1139    }
1140
1141
1142    /**
1143     * For debugging: get a session attribute
1144     *
1145     * @param sessionId
1146     * @param key
1147     * @return The attribute value, if found, null otherwise
1148     */

1149    public String JavaDoc getSessionAttribute( String JavaDoc sessionId, String JavaDoc key ) {
1150        Session s = (Session) sessions.get(sessionId);
1151        if( s==null ) {
1152            if(log.isInfoEnabled())
1153                log.info("Session not found " + sessionId);
1154            return null;
1155        }
1156        Object JavaDoc o=s.getSession().getAttribute(key);
1157        if( o==null ) return null;
1158        return o.toString();
1159    }
1160
1161
1162    /**
1163     * Returns information about the session with the given session id.
1164     *
1165     * <p>The session information is organized as a HashMap, mapping
1166     * session attribute names to the String representation of their values.
1167     *
1168     * @param sessionId Session id
1169     *
1170     * @return HashMap mapping session attribute names to the String
1171     * representation of their values, or null if no session with the
1172     * specified id exists, or if the session does not have any attributes
1173     */

1174    public HashMap JavaDoc getSession(String JavaDoc sessionId) {
1175        Session s = (Session) sessions.get(sessionId);
1176        if (s == null) {
1177            if (log.isInfoEnabled()) {
1178                log.info("Session not found " + sessionId);
1179            }
1180            return null;
1181        }
1182
1183        Enumeration JavaDoc ee = s.getSession().getAttributeNames();
1184        if (ee == null || !ee.hasMoreElements()) {
1185            return null;
1186        }
1187
1188        HashMap JavaDoc map = new HashMap JavaDoc();
1189        while (ee.hasMoreElements()) {
1190            String JavaDoc attrName = (String JavaDoc) ee.nextElement();
1191            map.put(attrName, getSessionAttribute(sessionId, attrName));
1192        }
1193
1194        return map;
1195    }
1196
1197
1198    public void expireSession( String JavaDoc sessionId ) {
1199        Session s=(Session)sessions.get(sessionId);
1200        if( s==null ) {
1201            if(log.isInfoEnabled())
1202                log.info("Session not found " + sessionId);
1203            return;
1204        }
1205        s.expire();
1206    }
1207
1208
1209    public String JavaDoc getLastAccessedTime( String JavaDoc sessionId ) {
1210        Session s=(Session)sessions.get(sessionId);
1211        if( s==null ) {
1212            log.info("Session not found " + sessionId);
1213            return "";
1214        }
1215        return new Date JavaDoc(s.getLastAccessedTime()).toString();
1216    }
1217
1218
1219    // -------------------- JMX and Registration --------------------
1220
protected String JavaDoc domain;
1221    protected ObjectName JavaDoc oname;
1222    protected MBeanServer JavaDoc mserver;
1223
1224    public ObjectName JavaDoc getObjectName() {
1225        return oname;
1226    }
1227
1228    public String JavaDoc getDomain() {
1229        return domain;
1230    }
1231
1232    public ObjectName JavaDoc preRegister(MBeanServer JavaDoc server,
1233                                  ObjectName JavaDoc name) throws Exception JavaDoc {
1234        oname=name;
1235        mserver=server;
1236        domain=name.getDomain();
1237        return name;
1238    }
1239
1240    public void postRegister(Boolean JavaDoc registrationDone) {
1241    }
1242
1243    public void preDeregister() throws Exception JavaDoc {
1244    }
1245
1246    public void postDeregister() {
1247    }
1248
1249}
1250
Popular Tags