View Javadoc

1   package org.apache.turbine.util;
2   
3   /*
4    * Copyright 2001-2005 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.util.Random;
20  
21  /***
22   * This class generates a unique 10+ character id.  This is good for
23   * authenticating users or tracking users around.
24   *
25   * <p>This code was borrowed from Apache
26   * JServ.JServServletManager.java.  It is what Apache JServ uses to
27   * generate session ids for users.  Unfortunately, it was not included
28   * in Apache JServ as a class, so I had to create one here in order to
29   * use it.
30   *
31   * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
32   * @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
33   * @version $Id: GenerateUniqueId.java 264148 2005-08-29 14:21:04Z henning $
34   */
35  public class GenerateUniqueId
36  {
37      /*
38       * Create a suitable string for session identification.  Use
39       * synchronized count and time to ensure uniqueness.  Use random
40       * string to ensure the timestamp cannot be guessed by programmed
41       * attack.
42       *
43       * Format of id is <6 chars random><3 chars time><1+ char count>
44       */
45      static private int session_count = 0;
46      static private long lastTimeVal = 0;
47      static private Random randomSource = new java.util.Random();
48  
49      // MAX_RADIX is 36
50  
51      /*
52       * We want to have a random string with a length of 6 characters.
53       * Since we encode it BASE 36, we've to modulo it with the
54       * following value:
55       */
56      public final static long maxRandomLen = 2176782336L; // 36 ** 6
57  
58      /*
59       * The session identifier must be unique within the typical
60       * lifespan of a Session; the value can roll over after that.  3
61       * characters: (this means a roll over after over a day, which is
62       * much larger than a typical lifespan)
63       */
64      public final static long maxSessionLifespanTics = 46656; // 36 ** 3
65  
66      /*
67       * Millisecons between different tics.  So this means that the
68       * 3-character time string has a new value every 2 seconds:
69       */
70      public final static long ticDifference = 2000;
71  
72      /***
73       * Get the unique id.
74       *
75       * <p>NOTE: This must work together with
76       * get_jserv_session_balance() in jserv_balance.c
77       *
78       * @return A String with the new unique id.
79       */
80      static synchronized public String getIdentifier()
81      {
82          StringBuffer sessionId = new StringBuffer();
83  
84          // Random value.
85          long n = randomSource.nextLong();
86          if (n < 0) n = -n;
87          n %= maxRandomLen;
88  
89          // Add maxLen to pad the leading characters with '0'; remove
90          // first digit with substring.
91          n += maxRandomLen;
92          sessionId.append(Long.toString(n, Character.MAX_RADIX)
93                  .substring(1));
94  
95          long timeVal = (System.currentTimeMillis() / ticDifference);
96  
97          // Cut.
98          timeVal %= maxSessionLifespanTics;
99  
100         // Padding, see above.
101         timeVal += maxSessionLifespanTics;
102 
103         sessionId.append(Long.toString(timeVal, Character.MAX_RADIX)
104                 .substring(1));
105 
106         /*
107          * Make the string unique: append the session count since last
108          * time flip.
109          */
110 
111         // Count sessions only within tics.  So the 'real' session
112         // count isn't exposed to the public.
113         if (lastTimeVal != timeVal)
114         {
115             lastTimeVal = timeVal;
116             session_count = 0;
117         }
118         sessionId.append(Long.toString(++session_count,
119                 Character.MAX_RADIX));
120 
121         return sessionId.toString();
122     }
123 
124     /***
125      * Get the unique id.
126      *
127      * @param jsIdent A String.
128      * @return A String with the new unique id.
129      */
130     synchronized public String getIdentifier(String jsIdent)
131     {
132         if (jsIdent != null && jsIdent.length() > 0)
133         {
134             return getIdentifier() + "." + jsIdent;
135         }
136         return getIdentifier();
137     }
138 
139     /***
140      * Simple test of the functionality.
141      *
142      * @param args A String[] with the command line arguments.
143      */
144     public static void main(String[] args)
145     {
146         System.out.println(GenerateUniqueId.getIdentifier());
147         System.out.println(GenerateUniqueId.getIdentifier());
148         System.out.println(GenerateUniqueId.getIdentifier());
149         System.out.println(GenerateUniqueId.getIdentifier());
150     }
151 }