001 package org.apache.turbine.util;
002
003
004 /*
005 * Licensed to the Apache Software Foundation (ASF) under one
006 * or more contributor license agreements. See the NOTICE file
007 * distributed with this work for additional information
008 * regarding copyright ownership. The ASF licenses this file
009 * to you under the Apache License, Version 2.0 (the
010 * "License"); you may not use this file except in compliance
011 * with the License. You may obtain a copy of the License at
012 *
013 * http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing,
016 * software distributed under the License is distributed on an
017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018 * KIND, either express or implied. See the License for the
019 * specific language governing permissions and limitations
020 * under the License.
021 */
022
023
024 import java.util.Random;
025
026 /**
027 * This class generates a unique 10+ character id. This is good for
028 * authenticating users or tracking users around.
029 *
030 * <p>This code was borrowed from Apache
031 * JServ.JServServletManager.java. It is what Apache JServ uses to
032 * generate session ids for users. Unfortunately, it was not included
033 * in Apache JServ as a class, so I had to create one here in order to
034 * use it.
035 *
036 * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
037 * @author <a href="mailto:neeme@one.lv">Neeme Praks</a>
038 * @version $Id: GenerateUniqueId.java 615328 2008-01-25 20:25:05Z tv $
039 */
040 public class GenerateUniqueId
041 {
042 /*
043 * Create a suitable string for session identification. Use
044 * synchronized count and time to ensure uniqueness. Use random
045 * string to ensure the timestamp cannot be guessed by programmed
046 * attack.
047 *
048 * Format of id is <6 chars random><3 chars time><1+ char count>
049 */
050 static private int session_count = 0;
051 static private long lastTimeVal = 0;
052 static private Random randomSource = new java.util.Random();
053
054 // MAX_RADIX is 36
055
056 /*
057 * We want to have a random string with a length of 6 characters.
058 * Since we encode it BASE 36, we've to modulo it with the
059 * following value:
060 */
061 public final static long maxRandomLen = 2176782336L; // 36 ** 6
062
063 /*
064 * The session identifier must be unique within the typical
065 * lifespan of a Session; the value can roll over after that. 3
066 * characters: (this means a roll over after over a day, which is
067 * much larger than a typical lifespan)
068 */
069 public final static long maxSessionLifespanTics = 46656; // 36 ** 3
070
071 /*
072 * Millisecons between different tics. So this means that the
073 * 3-character time string has a new value every 2 seconds:
074 */
075 public final static long ticDifference = 2000;
076
077 /**
078 * Get the unique id.
079 *
080 * <p>NOTE: This must work together with
081 * get_jserv_session_balance() in jserv_balance.c
082 *
083 * @return A String with the new unique id.
084 */
085 static synchronized public String getIdentifier()
086 {
087 StringBuffer sessionId = new StringBuffer();
088
089 // Random value.
090 long n = randomSource.nextLong();
091 if (n < 0) n = -n;
092 n %= maxRandomLen;
093
094 // Add maxLen to pad the leading characters with '0'; remove
095 // first digit with substring.
096 n += maxRandomLen;
097 sessionId.append(Long.toString(n, Character.MAX_RADIX)
098 .substring(1));
099
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 }