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