-
Notifications
You must be signed in to change notification settings - Fork 1
/
TinyUUID.java
221 lines (198 loc) · 6.85 KB
/
TinyUUID.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*
* Copyright (c) 2017 by Oliver Boehm
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* (c)reated 11.12.2017 by oboehm (ob@oasd.de)
*/
package de.jfachwert.util;
import de.jfachwert.AbstractFachwert;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Base64;
import java.util.UUID;
/**
* Die Klasse TinyUUID ist ein einfacher Wrapper um UUID mit dem Ziel, eine
* kuerzere Praesentation als das Original zur Verfuegung zu stellen. Die
* Original-UUID hat eine Laenge von 35 Zeichen, belegt aber intern nur
* 128 Bits oder 16 Bytes. Damit laeest sich der Speicheraufwand um ueber 50%
* reduzieren.
*
* <p>
* Die Klasse implementiert besitzt die wichtigsten Methoden und Konstruktoren
* der {@link UUID}-Klasse, sodass sie als Ersatz fuer diese Klasse verwendet
* werden kann.
* </p>
*
* @author oboehm
* @since 0.6+ (11.12.2017)
*/
public class TinyUUID extends AbstractFachwert<UUID> {
/** Minimale UUID. */
public static final TinyUUID MIN = new TinyUUID("00000000-0000-0000-0000-000000000000");
/** Maximale UUID (die aber als Nummer negativ ist). */
public static final TinyUUID MAX = new TinyUUID("ffffffff-ffff-ffff-ffff-ffffffffffff");
/**
* Instantiiert eine neue TinyUUID.
*
* @param uuid gueltige UUID
*/
public TinyUUID(UUID uuid) {
super(uuid);
}
/**
* Instantiiert eine eine neue TinyUUID anhand eines Strings. Dieser kann
* sowohl in Form einer UUID ("4e8108fa-e517-41bd-8372-a828843030ba") als
* auch in Form ohne Trennzeichen ("4e8108fae51741bd8372a828843030ba")
* angegeben werden.
*
* @param uuid z.B. "4e8108fa-e517-41bd-8372-a828843030ba"
*/
public TinyUUID(String uuid) {
this(new BigInteger(uuid.replaceAll("-", ""), 16));
}
/**
* Instantiiert eine neue TinyUUID. Die uebergebene Zahl wird dabei auf
* 128 Bit normalisiert, damit es beim Vergleich keine Ueberraschungen
* wegen unterschiedlichem Vorzeichen gibt.
*
* @param number 128-Bit-Zahl
*/
public TinyUUID(BigInteger number) {
this(UUID.fromString(toString(number)));
}
/**
* Instantiiert eine neue TinyUUID.
*
* @param bytes 16 Bytes
*/
public TinyUUID(byte[] bytes) {
this(UUID.fromString(toString(bytes)));
}
private static byte[] to16Bytes(BigInteger number) {
return to16Bytes(number.toByteArray());
}
private static byte[] to16Bytes(byte[] bytes) {
if (bytes.length > 15) {
return Arrays.copyOfRange(bytes, bytes.length - 16, bytes.length);
} else {
byte[] bytes16 = new byte[16];
System.arraycopy(bytes, 0, bytes16, 16 - bytes.length, bytes.length);
return bytes16;
}
}
/**
* Liefert die UUID als 128-Bit-Zahl zurueck. Diese kann auch negative
* sein.
*
* @return Zahl
*/
public BigInteger toNumber() {
UUID uuid = this.getCode();
//return BigInteger.valueOf(uuid.getLeastSignificantBits()).multiply(LIMIT_INT).add(BigInteger.valueOf(uuid.getMostSignificantBits()));
return new BigInteger(uuid.toString().replaceAll("-", ""), 16);
}
/**
* Liefert die 128-Bit-Zahl als Byte-Array zurueck.
*
* @return 16-stelliges Byte-Array
*/
public byte[] toBytes() {
byte[] bytes = this.toNumber().toByteArray();
return to16Bytes(bytes);
}
/**
* Liefert die {@link UUID} zurueck. Darueber kann man auf die weniger
* wichtigen Methoden von {@link UUID} zurueckgreifen, die in dieser Klasse
* fehlen.
*
* @return die {@link UUID}
*/
public UUID getUUID() {
return UUID.fromString(toString());
}
/**
* Liefert die unteren 64 Bits der 128-bittigen UUID.
*
* @return die ersten 64 Bits
*/
public long getLeastSignificantBits() {
return this.getUUID().getLeastSignificantBits();
}
/**
* Liefert die oberen 64 Bits der 128-bittigen UUID.
*
* @return die oberen 64 Bits
*/
public long getMostSignificantBits() {
return this.getUUID().getMostSignificantBits();
}
/**
* Da {@link TinyUUID} als Ersatz fuer die {@link UUID}-Klasse gedacht ist,
* liefert sie das gleiche Ergebnis wie die {@link UUID}-Klasse.
*
* @return z.B. "d9b67549-3c53-42f2-a394-33f990e697ce"
*/
@Override
public String toString() {
return this.getCode().toString();
}
private static String toString(BigInteger number) {
byte[] bytes = to16Bytes(number);
return toString(bytes);
}
private static String toString(byte[] bytes) {
return String.format("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
}
/**
* Liefert eine verkuerzte Darstellung einer UUID als String. Die Laenge
* reduziert sich dadurch auf 22 Zeichen. Diese kann z.B. dazu genutzt
* werden, um eine UUID platzsparend abzuspeichern, wenn man dazu nicht
* das Ergebnis aus {@link #toBytes()} (16 Bytes) verwenden will.
*
* @return 22 Zeichen, z.B. "ix9de14vQgGKwXZUaruCzw"
*/
public String toShortString() {
return Base64.getEncoder().withoutPadding().encodeToString(toBytes());
}
/**
* Aehnlich wie {@link UUID#fromString(String)} wird hier eine
* {@link TinyUUID} anhand des uebergebenen Strings erzeugt.
* Der uebergebene String kann dabei das Format einer UUID
* besitzen, kann aber auch ein Ergebnis von {@link #toShortString()}
* sein.
*
* @param id z.B. "ix9de14vQgGKwXZUaruCzw"
* @return a TinyUUID
*/
public static TinyUUID fromString(String id) {
switch (id.length()) {
case 22:
byte [] bytes = Base64.getDecoder().decode(id);
return new TinyUUID(bytes);
default:
return new TinyUUID(UUID.fromString(id));
}
}
/**
* Dies ist das Gegenstueck zur {@link UUID#randomUUID()}, nur dass hier
* bereits eine {@link TinyUUID} erzeugt wird.
*
* @return zufaellige UUID
*/
public static TinyUUID randomUUID() {
return new TinyUUID(UUID.randomUUID());
}
}