1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.services.uuid.BasicUUID |
4 | |
5 | Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.impl.services.uuid; |
22 | |
23 | import org.apache.derby.iapi.services.io.FormatIdUtil; |
24 | import org.apache.derby.iapi.services.io.StoredFormatIds; |
25 | import org.apache.derby.iapi.services.io.Formatable; |
26 | |
27 | import org.apache.derby.catalog.UUID; |
28 | |
29 | import java.io.ObjectOutput; |
30 | import java.io.ObjectInput; |
31 | import java.io.IOException; |
32 | |
33 | import java.io.StringReader; |
34 | |
35 | |
36 | public class BasicUUID implements UUID, Formatable |
37 | { |
38 | /* |
39 | ** Fields of BasicUUID |
40 | */ |
41 | |
42 | private long majorId; // only using 48 bits |
43 | private long timemillis; |
44 | private int sequence; |
45 | |
46 | /* |
47 | ** Methods of BasicUUID |
48 | */ |
49 | |
50 | /** |
51 | Constructor only called by BasicUUIDFactory. |
52 | **/ |
53 | public BasicUUID(long majorId, long timemillis, int sequence) |
54 | { |
55 | this.majorId = majorId; |
56 | this.timemillis = timemillis; |
57 | this.sequence = sequence; |
58 | } |
59 | |
60 | /** |
61 | Constructor only called by BasicUUIDFactory. |
62 | Constructs a UUID from the string representation |
63 | produced by toString. |
64 | @see BasicUUID#toString |
65 | **/ |
66 | public BasicUUID(String uuidstring) |
67 | { |
68 | StringReader sr = new StringReader(uuidstring); |
69 | sequence = (int) readMSB(sr); |
70 | |
71 | long ltimemillis = readMSB(sr) << 32; |
72 | ltimemillis += readMSB(sr) << 16; |
73 | ltimemillis += readMSB(sr); |
74 | timemillis = ltimemillis; |
75 | majorId = readMSB(sr); |
76 | } |
77 | |
78 | /** |
79 | Constructor only called by BasicUUIDFactory. |
80 | Constructs a UUID from the byte array representation |
81 | produced by toByteArrayio. |
82 | @see BasicUUID#toByteArray |
83 | **/ |
84 | public BasicUUID(byte[] b) |
85 | { |
86 | int lsequence = 0; |
87 | for (int ix = 0; ix < 4; ix++) |
88 | { |
89 | lsequence = lsequence << 8; |
90 | lsequence = lsequence | (0xff & b[ix]); |
91 | } |
92 | |
93 | long ltimemillis = 0; |
94 | for (int ix = 4; ix < 10; ix++) |
95 | { |
96 | ltimemillis = ltimemillis << 8; |
97 | ltimemillis = ltimemillis | (0xff & b[ix]); |
98 | } |
99 | |
100 | long linetaddr = 0; |
101 | for (int ix = 10; ix < 16; ix++) |
102 | { |
103 | linetaddr = linetaddr << 8; |
104 | linetaddr = linetaddr | (0xff & b[ix]); |
105 | } |
106 | |
107 | sequence = lsequence; |
108 | timemillis = ltimemillis; |
109 | majorId = linetaddr; |
110 | } |
111 | |
112 | /* |
113 | * Formatable methods |
114 | */ |
115 | |
116 | // no-arg constructor, required by Formatable |
117 | public BasicUUID() { super(); } |
118 | |
119 | /** |
120 | Write this out. |
121 | @exception IOException error writing to log stream |
122 | */ |
123 | public void writeExternal(ObjectOutput out) throws IOException |
124 | { |
125 | // RESOLVE: write out the byte array instead? |
126 | out.writeLong(majorId); |
127 | out.writeLong(timemillis); |
128 | out.writeInt(sequence); |
129 | } |
130 | |
131 | /** |
132 | Read this in |
133 | @exception IOException error reading from log stream |
134 | */ |
135 | public void readExternal(ObjectInput in) throws IOException |
136 | { |
137 | majorId = in.readLong(); |
138 | timemillis = in.readLong(); |
139 | sequence = in.readInt(); |
140 | } |
141 | |
142 | /** |
143 | Return my format identifier. |
144 | */ |
145 | public int getTypeFormatId() { |
146 | return StoredFormatIds.BASIC_UUID; |
147 | } |
148 | |
149 | private static void writeMSB(char[] data, int offset, long value, int nbytes) |
150 | { |
151 | for (int i = nbytes - 1; i >= 0; i--) |
152 | { |
153 | long b = (value & (255L << (8 * i))) >>> (8 * i); |
154 | |
155 | int c = (int) ((b & 0xf0) >> 4); |
156 | data[offset++] = (char) (c < 10 ? c + '0' : (c - 10) + 'a'); |
157 | c = (int) (b & 0x0f); |
158 | data[offset++] = (char) (c < 10 ? c + '0' : (c - 10) + 'a'); |
159 | } |
160 | } |
161 | |
162 | /** |
163 | Read a long value, msb first, from its character |
164 | representation in the string reader, using '-' or |
165 | end of string to delimit. |
166 | **/ |
167 | private static long readMSB(StringReader sr) |
168 | { |
169 | long value = 0; |
170 | |
171 | try |
172 | { |
173 | int c; |
174 | while ((c = sr.read()) != -1) |
175 | { |
176 | if (c == '-') |
177 | break; |
178 | value <<= 4; |
179 | |
180 | int nibble; |
181 | if (c <= '9') |
182 | nibble = c - '0'; |
183 | else if (c <= 'F') |
184 | nibble = c - 'A' + 10; |
185 | else |
186 | nibble = c - 'a' + 10; |
187 | value += nibble; |
188 | } |
189 | } |
190 | catch (Exception e) |
191 | { |
192 | } |
193 | |
194 | return value; |
195 | } |
196 | |
197 | /* |
198 | ** Methods of UUID |
199 | */ |
200 | |
201 | /** |
202 | Implement value equality. |
203 | |
204 | **/ |
205 | public boolean equals(Object otherObject) |
206 | { |
207 | if (!(otherObject instanceof BasicUUID)) |
208 | return false; |
209 | |
210 | BasicUUID other = (BasicUUID) otherObject; |
211 | |
212 | return (this.sequence == other.sequence) |
213 | && (this.timemillis == other.timemillis) |
214 | && (this.majorId == other.majorId); |
215 | } |
216 | |
217 | /** |
218 | Provide a hashCode which is compatible with |
219 | the equals() method. |
220 | **/ |
221 | public int hashCode() |
222 | { |
223 | long hc = majorId ^ timemillis; |
224 | |
225 | return sequence ^ ((int) (hc >> 4)); |
226 | } |
227 | |
228 | /** |
229 | Produce a string representation of this UUID which |
230 | can be passed to UUIDFactory.recreateUUID later on |
231 | to reconstruct it. The funny representation is |
232 | designed to (sort of) match the format of Microsoft's |
233 | UUIDGEN utility. |
234 | */ |
235 | public String toString() {return stringWorkhorse( '-' );} |
236 | |
237 | /** |
238 | Produce a string representation of this UUID which |
239 | is suitable for use as a unique ANSI identifier. |
240 | */ |
241 | public String toANSIidentifier() {return "U" + stringWorkhorse( 'X' );} |
242 | |
243 | /** |
244 | * Private workhorse of the string making routines. |
245 | * |
246 | * @param separator Character to separate number blocks. |
247 | * Null means do not include a separator. |
248 | * |
249 | * @return string representation of UUID. |
250 | */ |
251 | public String stringWorkhorse( char separator ) |
252 | { |
253 | char[] data = new char[36]; |
254 | |
255 | writeMSB(data, 0, (long) sequence, 4); |
256 | |
257 | int offset = 8; |
258 | if (separator != 0) data[offset++] = separator; |
259 | |
260 | long ltimemillis = timemillis; |
261 | writeMSB(data, offset, (ltimemillis & 0x0000ffff00000000L) >>> 32, 2); |
262 | offset += 4; |
263 | if (separator != 0) data[offset++] = separator; |
264 | writeMSB(data, offset, (ltimemillis & 0x00000000ffff0000L) >>> 16, 2); |
265 | offset += 4; |
266 | if (separator != 0) data[offset++] = separator; |
267 | writeMSB(data, offset, (ltimemillis & 0x000000000000ffffL), 2); |
268 | offset += 4; |
269 | if (separator != 0) data[offset++] = separator; |
270 | writeMSB(data, offset, majorId, 6); |
271 | offset += 12; |
272 | |
273 | return new String(data, 0, offset); |
274 | } |
275 | |
276 | /** |
277 | Store this UUID in a byte array. Arrange the bytes in the UUID |
278 | in the same order the code which stores a UUID in a string |
279 | does. |
280 | |
281 | @see org.apache.derby.catalog.UUID#toByteArray |
282 | */ |
283 | public byte[] toByteArray() |
284 | { |
285 | byte[] result = new byte[16]; |
286 | |
287 | int lsequence = sequence; |
288 | result[0] = (byte)(lsequence >>> 24); |
289 | result[1] = (byte)(lsequence >>> 16); |
290 | result[2] = (byte)(lsequence >>> 8); |
291 | result[3] = (byte)lsequence; |
292 | |
293 | long ltimemillis = timemillis; |
294 | result[4] = (byte)(ltimemillis >>> 40); |
295 | result[5] = (byte)(ltimemillis >>> 32); |
296 | result[6] = (byte)(ltimemillis >>> 24); |
297 | result[7] = (byte)(ltimemillis >>> 16); |
298 | result[8] = (byte)(ltimemillis >>> 8); |
299 | result[9] = (byte)ltimemillis; |
300 | |
301 | long linetaddr = majorId; |
302 | result[10] = (byte)(linetaddr >>> 40); |
303 | result[11] = (byte)(linetaddr >>> 32); |
304 | result[12] = (byte)(linetaddr >>> 24); |
305 | result[13] = (byte)(linetaddr >>> 16); |
306 | result[14] = (byte)(linetaddr >>> 8); |
307 | result[15] = (byte)linetaddr; |
308 | |
309 | return result; |
310 | } |
311 | |
312 | /** |
313 | Clone this UUID. |
314 | |
315 | @return a copy of this UUID |
316 | */ |
317 | public UUID cloneMe() |
318 | { |
319 | return new BasicUUID(majorId, timemillis, sequence); |
320 | } |
321 | |
322 | public String toHexString() {return stringWorkhorse( (char) 0 );} |
323 | } |
324 | |