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 }