1 package org.apache.turbine.util.db;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.OutputStream;
21
22 import java.util.StringTokenizer;
23
24 import javax.mail.internet.MimeUtility;
25
26 import org.apache.commons.lang.StringUtils;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import org.apache.turbine.Turbine;
32 import org.apache.turbine.TurbineConstants;
33
34 import org.apache.turbine.util.TurbineException;
35
36 /***
37 * <p>This class generates universally unique id's in the form of a String.
38 * The id has three parts. The first is supposed to be location dependent.
39 * The preferred location parameter is an ethernet (MAC) address, but an IP
40 * can be used as well. if none is supplied a Math.random generated number
41 * will be used. This part of the key will be 48 bits in length.
42 * The second part of the key is time related and will be the lower 48 bits
43 * of the long used to signify the time since Jan. 1, 1970. This will
44 * cause key rollover in the year 6429.
45 * The preceding 12 bytes are Base64 encoded with the characters / and *
46 * replaced by _ (underscore) and - (dash). Resulting in 16 characters.
47 * Finally a counter is used to hand out 4095 keys in between each
48 * timestamp.
49 * The resulting id is a String of 18 characters including:
50 * a-z,A-Z,0-9, and the previously mentioned - and _.</p>
51 *
52 * <p>Note this class does not save any state information, so it is important
53 * that time only moves forward to keep the integrity of the ids. We
54 * might want to consider saving some state info.</p>
55 *
56 * <p>To specify the MAC/Ethernet address, add a uuid.address= property to the
57 * TurbineResources.properties file.</p>
58 *
59 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
60 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
61 * @version $Id: UUIdGenerator.java 264152 2005-08-29 14:50:22Z henning $
62 * @deprecated Use the Unique ID Service
63 */
64 public class UUIdGenerator
65 {
66 /*** Logging */
67 private static Log log = LogFactory.getLog(UUIdGenerator.class);
68
69 private static final String errorString = "uuid.address property in "
70 + "TurbineResources.properties should be a valid IP\n "
71 + "e.g. 18.2.3.100, or an ethernet address e.g. "
72 + "AE:10:3E:de:f5:77 uuid.address was ";
73
74 private byte[] address = new byte[6];
75 private String baseId = null;
76 private int counter = 0;
77
78 /***
79 * Constructor
80 */
81 public UUIdGenerator() throws TurbineException
82 {
83 String addr =
84 Turbine.getConfiguration().getString(TurbineConstants.UUID_ADDRESS_KEY);
85
86 if (StringUtils.isEmpty(addr))
87 {
88 log.info("UUIdGenerator is using a random number as the "
89 + "base for id's. This is not the best method for many "
90 + "purposes, but may be adequate in some circumstances."
91 + " Consider using an IP or ethernet (MAC) address if "
92 + "available. Edit TurbineResources.properties file and "
93 + "add a uuid.address= property.");
94
95 for (int i = 0; i < 6; i++)
96 {
97 address[i] = (byte) (255 * Math.random());
98 }
99 }
100 else
101 {
102 if (addr.indexOf(".") > 0)
103 {
104
105 StringTokenizer stok = new StringTokenizer(addr, ".");
106 if (stok.countTokens() != 4)
107 {
108 throw new TurbineException(errorString + addr);
109 }
110
111
112
113
114 address[0] = (byte) 255;
115 address[1] = (byte) 255;
116 int i = 2;
117 try
118 {
119 while (stok.hasMoreTokens())
120 {
121 address[i++] =
122 Integer.valueOf(stok.nextToken(),
123 16).byteValue();
124 }
125 }
126 catch (Exception e)
127 {
128 throw new TurbineException(errorString + addr, e);
129 }
130 }
131 else if (addr.indexOf(":") > 0)
132 {
133
134 StringTokenizer stok = new StringTokenizer(addr, ":");
135 if (stok.countTokens() != 6)
136 {
137 throw new TurbineException(errorString + addr);
138 }
139 int i = 0;
140 try
141 {
142 while (stok.hasMoreTokens())
143 {
144 address[i++] = Byte.parseByte(stok.nextToken(), 16);
145 }
146 }
147 catch (Exception e)
148 {
149 throw new TurbineException(errorString + addr, e);
150 }
151 }
152 else
153 {
154 throw new TurbineException(errorString + addr);
155 }
156 }
157 }
158
159 /***
160 * Generates the new base id
161 */
162 private void generateNewBaseId() throws Exception
163 {
164 long now = System.currentTimeMillis();
165 byte[] nowBytes = org.apache.java.lang.Bytes.toBytes(now);
166 ByteArrayOutputStream bas = null;
167 OutputStream encodedStream = null;
168 try
169 {
170 bas = new ByteArrayOutputStream(16);
171 encodedStream = MimeUtility.encode(bas, "base64");
172 encodedStream.write(nowBytes);
173 baseId = bas.toString("ISO-8859-1");
174 baseId = baseId.replace('/', '_');
175 baseId = baseId.replace('*', '-');
176 }
177 finally
178 {
179 if (bas != null)
180 {
181 bas.close();
182 }
183 if (encodedStream != null)
184 {
185 encodedStream.close();
186 }
187 }
188 }
189
190 /***
191 * Gets the id
192 * @return the 18 character id
193 */
194 public String getId() throws Exception
195 {
196 int index = ++counter;
197 if (index > 4095)
198 {
199 synchronized (this)
200 {
201 if (counter > 4095)
202 {
203 generateNewBaseId();
204 counter = 0;
205 }
206 else
207 {
208 index = ++counter;
209 }
210 }
211 }
212 StringBuffer idbuf = new StringBuffer(18);
213 idbuf.append(baseId);
214 idbuf.append(countChar[index / 64]);
215 idbuf.append(countChar[index % 64]);
216 return idbuf.toString();
217 }
218
219 /***
220 * characters used in the ID
221 */
222 private static final char[] countChar =
223 {
224 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
225 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
226 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
227 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
228 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
229 '8', '9', '-', '_'
230 };
231 }
232