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 1709648 2015-10-20 17:08:10Z 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 StringBuilder sessionId = new StringBuilder();
88
89 // Random value.
90 long n = randomSource.nextLong();
91 if (n < 0)
92 {
93 n = -n;
94 }
95 n %= maxRandomLen;
96
97 // Add maxLen to pad the leading characters with '0'; remove
98 // first digit with substring.
99 n += maxRandomLen;
100 sessionId.append(Long.toString(n, Character.MAX_RADIX)
101 .substring(1));
102
103 long timeVal = (System.currentTimeMillis() / ticDifference);
104
105 // Cut.
106 timeVal %= maxSessionLifespanTics;
107
108 // Padding, see above.
109 timeVal += maxSessionLifespanTics;
110
111 sessionId.append(Long.toString(timeVal, Character.MAX_RADIX)
112 .substring(1));
113
114 /*
115 * Make the string unique: append the session count since last
116 * time flip.
117 */
118
119 // Count sessions only within tics. So the 'real' session
120 // count isn't exposed to the public.
121 if (lastTimeVal != timeVal)
122 {
123 lastTimeVal = timeVal;
124 session_count = 0;
125 }
126 sessionId.append(Long.toString(++session_count,
127 Character.MAX_RADIX));
128
129 return sessionId.toString();
130 }
131
132 /**
133 * Get the unique id.
134 *
135 * @param jsIdent A String.
136 * @return A String with the new unique id.
137 */
138 synchronized public String getIdentifier(String jsIdent)
139 {
140 if (jsIdent != null && jsIdent.length() > 0)
141 {
142 return getIdentifier() + "." + jsIdent;
143 }
144 return getIdentifier();
145 }
146
147 /**
148 * Simple test of the functionality.
149 *
150 * @param args A String[] with the command line arguments.
151 */
152 public static void main(String[] args)
153 {
154 System.out.println(GenerateUniqueId.getIdentifier());
155 System.out.println(GenerateUniqueId.getIdentifier());
156 System.out.println(GenerateUniqueId.getIdentifier());
157 System.out.println(GenerateUniqueId.getIdentifier());
158 }
159 }