001package 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 024import 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$ 039 */ 040public 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 StringBuilder sessionId = new StringBuilder(); 088 089 // Random value. 090 long n = randomSource.nextLong(); 091 if (n < 0) 092 { 093 n = -n; 094 } 095 n %= maxRandomLen; 096 097 // Add maxLen to pad the leading characters with '0'; remove 098 // first digit with substring. 099 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}