1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.id.uuid.state;
19
20 import java.io.IOException;
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23 import java.util.Collection;
24 import java.util.Iterator;
25 import java.util.Random;
26 import java.util.StringTokenizer;
27
28 import org.apache.commons.id.DecoderException;
29 import org.apache.commons.discovery.tools.DiscoverClass;
30 import org.apache.commons.id.uuid.Bytes;
31 import org.apache.commons.id.uuid.Constants;
32 import org.apache.commons.id.uuid.clock.Clock;
33 import org.apache.commons.id.uuid.clock.OverClockedException;
34 import org.apache.commons.id.DigestUtils;
35 import org.apache.commons.id.Hex;
36
37
38
39
40
41
42
43
44 public final class StateHelper implements Constants {
45
46 public static final String UUID_CLOCK_IMPL_PROPERTY_KEY = Clock.class.getName();
47
48
49 public static final String UUID_STATE_IMPL_PROPERTY_KEY = State.class.getName();
50
51
52 public static final int NODE_ID_BYTE_LENGTH = 6;
53
54
55 public static final short BYTES_IN_SHORT = 2;
56
57
58 public static final short SHIFT_BY_BYTE = 8;
59
60
61 public static final short HOSTNAME_MAX_CHAR_LEN = 255;
62
63
64 private static final int MULTICAST_BIT_SET = 0x80;
65
66
67 private static final short LONG_CHAR_LEN = 19;
68
69
70 private static final int BUF_PAGE_SZ = 1024;
71
72
73 protected static final String XML_DOC_START = "<?xml version=\"1.0\""
74 + " encoding=\"UTF-8\" ?>"
75 + "\n<!DOCTYPE uuidstate [\n"
76 + " <!ELEMENT uuidstate (node*)>\n"
77 + " <!ELEMENT node EMPTY>\n"
78 + " <!ATTLIST node id ID #REQUIRED>\n"
79 + " <!ATTLIST node clocksequence CDATA #IMPLIED>\n"
80 + " <!ATTLIST node lasttimestamp CDATA #IMPLIED>\n]>"
81 + "\n<uuidstate synchInterval=\"";
82
83
84 protected static final String XML_DOC_START_END = "\">";
85
86 protected static final String XML_NODE_TAG_START = "\n\t<node id=\"";
87
88 protected static final String XML_NODE_TAG_AFTER_ID = "\" clocksequence=\"";
89
90 protected static final String XML_NODE_TAG_AFTER_CSEQ = "\" timestamp=\"";
91
92 protected static final String XML_NODE_TAG_END = "\" />";
93
94 protected static final String XML_DOC_END = "\n</uuidstate>";
95
96
97 private static final short MAC_ADDRESS_TOKEN_COUNT = 6;
98
99
100 private static final short MAC_ADDRESS_CHAR_LENGTH = 17;
101
102
103 private StateHelper() {
104 super();
105 }
106
107
108
109
110
111
112
113 public static byte[] randomNodeIdentifier() {
114
115 byte[] seed = new byte[UUID_BYTE_LENGTH];
116
117
118 int bufSize = (LONG_CHAR_LEN * 2) + HOSTNAME_MAX_CHAR_LEN + (2 * BUF_PAGE_SZ);
119 StringBuffer randInfo = new StringBuffer(bufSize);
120
121 long time = 0;
122 try {
123 time = getClockImpl().getUUIDTime();
124 } catch (OverClockedException oce) {
125 time = System.currentTimeMillis();
126 }
127 randInfo.append(time);
128
129
130 try {
131 InetAddress address = InetAddress.getLocalHost();
132 randInfo.append(address.getHostName());
133 } catch (UnknownHostException ukhe) {
134 randInfo.append("Host Unknown");
135 }
136
137 randInfo.append(new Object().hashCode());
138
139
140 Collection info = System.getProperties().values();
141 Iterator it = info.iterator();
142 while (it.hasNext()) {
143 randInfo.append(it.next());
144 }
145
146 seed = DigestUtils.md5(randInfo.toString());
147
148
149 byte[] raw = new byte[NODE_ID_BYTE_LENGTH];
150 System.arraycopy(seed, 0, raw, 0, NODE_ID_BYTE_LENGTH);
151
152
153 raw[0] |= MULTICAST_BIT_SET;
154
155 return raw;
156 }
157
158
159
160
161
162
163 public static short newClockSequence() {
164 Random random = new Random();
165 byte[] bytes = new byte[BYTES_IN_SHORT];
166 random.nextBytes(bytes);
167 return (short) (Bytes.toShort(bytes) & 0x3FFF);
168 }
169
170
171
172
173
174
175 public static Clock getClockImpl() {
176 Clock c = null;
177 try {
178 DiscoverClass dc = new DiscoverClass();
179 c = (Clock) dc.newInstance(
180 Clock.class,
181 Clock.DEFAULT_CLOCK_IMPL);
182 } catch (Exception ex) {
183
184 }
185 return c;
186 }
187
188
189
190
191
192
193 public static State getStateImpl() {
194 State s = null;
195 try {
196 DiscoverClass dc = new DiscoverClass();
197 s = (State) dc.newInstance(
198 State.class,
199 State.DEFAULT_STATE_IMPL);
200 } catch (Exception ex) {
201
202 }
203 return s;
204 }
205
206
207
208
209
210
211
212
213
214
215 public static byte[] decodeMACAddress(String address) {
216 StringBuffer buf = new StringBuffer(MAC_ADDRESS_TOKEN_COUNT * 2);
217 StringTokenizer tokens = new StringTokenizer(address, "-");
218 if (tokens.countTokens() != MAC_ADDRESS_TOKEN_COUNT) {
219 return null;
220 } else {
221 for (int i = 0; i < MAC_ADDRESS_TOKEN_COUNT; i++) {
222 buf.append(tokens.nextToken());
223 }
224 }
225 try {
226 char[] c = buf.toString().toCharArray();
227 return Hex.decodeHex(c);
228 } catch (DecoderException de) {
229 de.printStackTrace();
230 return null;
231 }
232 }
233
234
235
236
237
238
239
240
241
242
243
244 public static String encodeMACAddress(byte[] address) throws IOException {
245 char[] chars = Hex.encodeHex(address);
246 StringBuffer buf = new StringBuffer(MAC_ADDRESS_CHAR_LENGTH);
247 for (int i = 0; i < chars.length; i++) {
248 buf.append(chars[i]);
249 if (i != chars.length - 1 && i % 2 != 0) {
250 buf.append("-");
251 }
252 }
253 return buf.toString().toUpperCase();
254 }
255 }