mirror of https://github.com/apache/openjpa.git
OPENJPA-545 committing patch provided by Jeremy Bauer
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@671319 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
37cb4af35d
commit
fb78813259
|
@ -3545,6 +3545,10 @@ public class BrokerImpl
|
||||||
return UUIDHexSeq.getInstance();
|
return UUIDHexSeq.getInstance();
|
||||||
case ValueStrategies.UUID_STRING:
|
case ValueStrategies.UUID_STRING:
|
||||||
return UUIDStringSeq.getInstance();
|
return UUIDStringSeq.getInstance();
|
||||||
|
case ValueStrategies.UUID_TYPE4_HEX:
|
||||||
|
return UUIDType4HexSeq.getInstance();
|
||||||
|
case ValueStrategies.UUID_TYPE4_STRING:
|
||||||
|
return UUIDType4StringSeq.getInstance();
|
||||||
case ValueStrategies.SEQUENCE:
|
case ValueStrategies.SEQUENCE:
|
||||||
SequenceMetaData smd = (fmd == null)
|
SequenceMetaData smd = (fmd == null)
|
||||||
? meta.getIdentitySequenceMetaData()
|
? meta.getIdentitySequenceMetaData()
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class UUIDHexSeq
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Object next(StoreContext ctx, ClassMetaData meta) {
|
public synchronized Object next(StoreContext ctx, ClassMetaData meta) {
|
||||||
_last = UUIDGenerator.nextHex();
|
_last = UUIDGenerator.nextHex(UUIDGenerator.TYPE1);
|
||||||
return _last;
|
return _last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class UUIDStringSeq
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Object next(StoreContext ctx, ClassMetaData meta) {
|
public synchronized Object next(StoreContext ctx, ClassMetaData meta) {
|
||||||
_last = UUIDGenerator.nextString();
|
_last = UUIDGenerator.nextString(UUIDGenerator.TYPE1);
|
||||||
return _last;
|
return _last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.kernel;
|
||||||
|
|
||||||
|
import org.apache.openjpa.lib.util.UUIDGenerator;
|
||||||
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sequence for generating 32-character hex Type 4 UUID strings.
|
||||||
|
*
|
||||||
|
* @author Jeremy Bauer
|
||||||
|
*/
|
||||||
|
public class UUIDType4HexSeq
|
||||||
|
implements Seq {
|
||||||
|
|
||||||
|
private static final UUIDType4HexSeq _instance = new UUIDType4HexSeq();
|
||||||
|
|
||||||
|
private String _last = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the singleton instance.
|
||||||
|
*/
|
||||||
|
public static UUIDType4HexSeq getInstance() {
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide constructor.
|
||||||
|
*/
|
||||||
|
private UUIDType4HexSeq() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(int type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Object next(StoreContext ctx, ClassMetaData meta) {
|
||||||
|
_last = UUIDGenerator.nextHex(UUIDGenerator.TYPE4);
|
||||||
|
return _last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Object current(StoreContext ctx, ClassMetaData meta) {
|
||||||
|
return _last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void allocate(int additional, StoreContext ctx, ClassMetaData meta) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.kernel;
|
||||||
|
|
||||||
|
import org.apache.openjpa.lib.util.UUIDGenerator;
|
||||||
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sequence for generating 16-character UUID strings.
|
||||||
|
*
|
||||||
|
* @author Jeremy Bauer
|
||||||
|
*/
|
||||||
|
public class UUIDType4StringSeq
|
||||||
|
implements Seq {
|
||||||
|
|
||||||
|
private static final UUIDType4StringSeq _instance = new UUIDType4StringSeq();
|
||||||
|
|
||||||
|
private String _last = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the singleton instance.
|
||||||
|
*/
|
||||||
|
public static UUIDType4StringSeq getInstance() {
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide constructor.
|
||||||
|
*/
|
||||||
|
private UUIDType4StringSeq() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(int type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Object next(StoreContext ctx, ClassMetaData meta) {
|
||||||
|
_last = UUIDGenerator.nextString(UUIDGenerator.TYPE4);
|
||||||
|
return _last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Object current(StoreContext ctx, ClassMetaData meta) {
|
||||||
|
return _last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void allocate(int additional, StoreContext ctx, ClassMetaData meta) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -68,6 +68,16 @@ public class ValueStrategies {
|
||||||
*/
|
*/
|
||||||
public static final int UUID_HEX = 6;
|
public static final int UUID_HEX = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "uuid-type4-string" value strategy.
|
||||||
|
*/
|
||||||
|
public static final int UUID_TYPE4_STRING = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "uuid-type4-hex" value strategy.
|
||||||
|
*/
|
||||||
|
public static final int UUID_TYPE4_HEX = 8;
|
||||||
|
|
||||||
private static final Localizer _loc = Localizer.forPackage
|
private static final Localizer _loc = Localizer.forPackage
|
||||||
(ValueStrategies.class);
|
(ValueStrategies.class);
|
||||||
|
|
||||||
|
@ -82,6 +92,8 @@ public class ValueStrategies {
|
||||||
_map.put("increment", Numbers.valueOf(INCREMENT));
|
_map.put("increment", Numbers.valueOf(INCREMENT));
|
||||||
_map.put("uuid-string", Numbers.valueOf(UUID_STRING));
|
_map.put("uuid-string", Numbers.valueOf(UUID_STRING));
|
||||||
_map.put("uuid-hex", Numbers.valueOf(UUID_HEX));
|
_map.put("uuid-hex", Numbers.valueOf(UUID_HEX));
|
||||||
|
_map.put("uuid-type4-string", Numbers.valueOf(UUID_TYPE4_STRING));
|
||||||
|
_map.put("uuid-type4-hex", Numbers.valueOf(UUID_TYPE4_HEX));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -160,9 +160,13 @@ public class ImplHelper {
|
||||||
return JavaTypes.convert(smd.getInstance(ctx.getClassLoader()).
|
return JavaTypes.convert(smd.getInstance(ctx.getClassLoader()).
|
||||||
next(ctx, meta), typeCode);
|
next(ctx, meta), typeCode);
|
||||||
case ValueStrategies.UUID_STRING:
|
case ValueStrategies.UUID_STRING:
|
||||||
return UUIDGenerator.nextString();
|
return UUIDGenerator.nextString(UUIDGenerator.TYPE1);
|
||||||
case ValueStrategies.UUID_HEX:
|
case ValueStrategies.UUID_HEX:
|
||||||
return UUIDGenerator.nextHex();
|
return UUIDGenerator.nextHex(UUIDGenerator.TYPE1);
|
||||||
|
case ValueStrategies.UUID_TYPE4_STRING:
|
||||||
|
return UUIDGenerator.nextString(UUIDGenerator.TYPE4);
|
||||||
|
case ValueStrategies.UUID_TYPE4_HEX:
|
||||||
|
return UUIDGenerator.nextHex(UUIDGenerator.TYPE4);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,16 +22,18 @@ import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import org.apache.commons.lang.exception.NestableRuntimeException;
|
import org.apache.commons.lang.exception.NestableRuntimeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UUID value generator. Based on the time-based generator in the Apache
|
* UUID value generator. Type 1 generator is based on the time-based generator
|
||||||
* Commons Id project: http://jakarta.apache.org/commons/sandbox/id/uuid.html
|
* in the Apache Commons Id project: http://jakarta.apache.org/commons/sandbox
|
||||||
|
* /id/uuid.html The type 4 generator uses the standard Java UUID generator.
|
||||||
*
|
*
|
||||||
* The code has been vastly simplified and modified to replace the ethernet
|
* The type 1 code has been vastly simplified and modified to replace the
|
||||||
* address of the host machine with the IP, since we do not want to require
|
* ethernet address of the host machine with the IP, since we do not want to
|
||||||
* native libs and Java cannot access the MAC address directly.
|
* require native libs and Java cannot access the MAC address directly.
|
||||||
*
|
*
|
||||||
* In spirit, implements the IETF UUID draft specification, found here:<br />
|
* In spirit, implements the IETF UUID draft specification, found here:<br />
|
||||||
* http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01
|
* http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/draft-leach-uuids-guids-01
|
||||||
|
@ -43,6 +45,10 @@ import org.apache.commons.lang.exception.NestableRuntimeException;
|
||||||
*/
|
*/
|
||||||
public class UUIDGenerator {
|
public class UUIDGenerator {
|
||||||
|
|
||||||
|
// supported UUID types
|
||||||
|
public static final int TYPE1 = 1;
|
||||||
|
public static final int TYPE4 = 4;
|
||||||
|
|
||||||
// indexes within the uuid array for certain boundaries
|
// indexes within the uuid array for certain boundaries
|
||||||
private static final byte IDX_TIME_HI = 6;
|
private static final byte IDX_TIME_HI = 6;
|
||||||
private static final byte IDX_TYPE = 6; // multiplexed
|
private static final byte IDX_TYPE = 6; // multiplexed
|
||||||
|
@ -68,13 +74,12 @@ public class UUIDGenerator {
|
||||||
private final static byte TYPE_TIME_BASED = 0x10;
|
private final static byte TYPE_TIME_BASED = 0x10;
|
||||||
|
|
||||||
// random number generator used to reduce conflicts with other JVMs, and
|
// random number generator used to reduce conflicts with other JVMs, and
|
||||||
// hasher for strings. note that secure random is very slow the first time
|
// hasher for strings.
|
||||||
// it is used; consider switching to a standard random
|
private static Random RANDOM;
|
||||||
private static final Random RANDOM = new SecureRandom();
|
|
||||||
|
|
||||||
// 4-byte IP address + 2 random bytes to compensate for the fact that
|
// 4-byte IP address + 2 random bytes to compensate for the fact that
|
||||||
// the MAC address is usually 6 bytes
|
// the MAC address is usually 6 bytes
|
||||||
private static final byte[] IP;
|
private static byte[] IP;
|
||||||
|
|
||||||
// counter is initialized to 0 and is incremented for each uuid request
|
// counter is initialized to 0 and is incremented for each uuid request
|
||||||
// within the same timestamp window.
|
// within the same timestamp window.
|
||||||
|
@ -88,12 +93,21 @@ public class UUIDGenerator {
|
||||||
// when it overflows
|
// when it overflows
|
||||||
private static long _lastMillis = 0L;
|
private static long _lastMillis = 0L;
|
||||||
private static final int MAX_14BIT = 0x3FFF;
|
private static final int MAX_14BIT = 0x3FFF;
|
||||||
private static short _seq = (short) RANDOM.nextInt(MAX_14BIT);
|
private static short _seq = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Static initializer to get the IP address of the host machine.
|
* Initializer for type 1 UUIDs. Creates random generator and genenerates
|
||||||
|
* the node portion of the UUID using the IP address.
|
||||||
*/
|
*/
|
||||||
static {
|
private static synchronized void initializeForType1()
|
||||||
|
{
|
||||||
|
if (RANDOM != null)
|
||||||
|
return;
|
||||||
|
// note that secure random is very slow the first time
|
||||||
|
// it is used; consider switching to a standard random
|
||||||
|
RANDOM = new SecureRandom();
|
||||||
|
_seq = (short) RANDOM.nextInt(MAX_14BIT);
|
||||||
|
|
||||||
byte[] ip = null;
|
byte[] ip = null;
|
||||||
try {
|
try {
|
||||||
ip = InetAddress.getLocalHost().getAddress();
|
ip = InetAddress.getLocalHost().getAddress();
|
||||||
|
@ -103,13 +117,25 @@ public class UUIDGenerator {
|
||||||
|
|
||||||
IP = new byte[6];
|
IP = new byte[6];
|
||||||
RANDOM.nextBytes(IP);
|
RANDOM.nextBytes(IP);
|
||||||
System.arraycopy(ip, 0, IP, 2, ip.length);
|
System.arraycopy(ip, 0, IP, 2, ip.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a unique UUID value.
|
* Return a unique UUID value.
|
||||||
*/
|
*/
|
||||||
public static byte[] next() {
|
public static byte[] next(int type) {
|
||||||
|
if (type == TYPE4) {
|
||||||
|
return createType4();
|
||||||
|
}
|
||||||
|
return createType1();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates a type 1 UUID
|
||||||
|
*/
|
||||||
|
public static byte[] createType1() {
|
||||||
|
if (RANDOM == null)
|
||||||
|
initializeForType1();
|
||||||
// set ip addr
|
// set ip addr
|
||||||
byte[] uuid = new byte[16];
|
byte[] uuid = new byte[16];
|
||||||
System.arraycopy(IP, 0, uuid, 10, IP.length);
|
System.arraycopy(IP, 0, uuid, 10, IP.length);
|
||||||
|
@ -147,11 +173,32 @@ public class UUIDGenerator {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates a type 4 UUID
|
||||||
|
*/
|
||||||
|
private static byte[] createType4() {
|
||||||
|
UUID type4 = UUID.randomUUID();
|
||||||
|
byte[] uuid = new byte[16];
|
||||||
|
longToBytes(type4.getMostSignificantBits(), uuid, 0);
|
||||||
|
longToBytes(type4.getLeastSignificantBits(), uuid, 8);
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Converts a long to byte values, setting them in a byte array
|
||||||
|
* at a given starting position.
|
||||||
|
*/
|
||||||
|
private static void longToBytes(long longVal, byte[] buf, int sPos) {
|
||||||
|
sPos += 7;
|
||||||
|
for(int i = 0; i < 8; i++)
|
||||||
|
buf[sPos-i] = (byte)(longVal >>> (i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the next unique uuid value as a 16-character string.
|
* Return the next unique uuid value as a 16-character string.
|
||||||
*/
|
*/
|
||||||
public static String nextString() {
|
public static String nextString(int type) {
|
||||||
byte[] bytes = next();
|
byte[] bytes = next(type);
|
||||||
try {
|
try {
|
||||||
return new String(bytes, "ISO-8859-1");
|
return new String(bytes, "ISO-8859-1");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -162,8 +209,8 @@ public class UUIDGenerator {
|
||||||
/**
|
/**
|
||||||
* Return the next unique uuid value as a 32-character hex string.
|
* Return the next unique uuid value as a 32-character hex string.
|
||||||
*/
|
*/
|
||||||
public static String nextHex() {
|
public static String nextHex(int type) {
|
||||||
return Base16Encoder.encode(next());
|
return Base16Encoder.encode(next(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -174,6 +221,8 @@ public class UUIDGenerator {
|
||||||
*/
|
*/
|
||||||
// package-visibility for testing
|
// package-visibility for testing
|
||||||
static long getTime() {
|
static long getTime() {
|
||||||
|
if (RANDOM == null)
|
||||||
|
initializeForType1();
|
||||||
long newTime = getUUIDTime();
|
long newTime = getUUIDTime();
|
||||||
if (newTime <= _lastMillis) {
|
if (newTime <= _lastMillis) {
|
||||||
incrementSequence();
|
incrementSequence();
|
||||||
|
|
|
@ -33,13 +33,39 @@ public class TestUUIDGenerator extends TestCase {
|
||||||
public void testUniqueString() {
|
public void testUniqueString() {
|
||||||
Set seen = new HashSet();
|
Set seen = new HashSet();
|
||||||
for (int i = 0; i < 10000; i++)
|
for (int i = 0; i < 10000; i++)
|
||||||
assertTrue(seen.add(UUIDGenerator.nextString()));
|
assertTrue(seen.add(
|
||||||
|
UUIDGenerator.nextString(UUIDGenerator.TYPE1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUniqueHex() {
|
public void testUniqueHex() {
|
||||||
Set seen = new HashSet();
|
Set seen = new HashSet();
|
||||||
for (int i = 0; i < 10000; i++)
|
for (int i = 0; i < 10000; i++)
|
||||||
assertTrue(seen.add(UUIDGenerator.nextHex()));
|
assertTrue(seen.add(
|
||||||
|
UUIDGenerator.nextHex(UUIDGenerator.TYPE1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testUniqueType4String() {
|
||||||
|
Set seen = new HashSet();
|
||||||
|
for (int i = 0; i < 10000; i++)
|
||||||
|
assertTrue(seen.add(
|
||||||
|
UUIDGenerator.nextString(UUIDGenerator.TYPE4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testUniqueType4Hex() {
|
||||||
|
Set seen = new HashSet();
|
||||||
|
for (int i = 0; i < 10000; i++)
|
||||||
|
assertTrue(seen.add(
|
||||||
|
UUIDGenerator.nextHex(UUIDGenerator.TYPE4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testUniqueMixedTypesHex() {
|
||||||
|
Set seen = new HashSet();
|
||||||
|
for (int i = 0; i < 10000; i++) {
|
||||||
|
int type = (i % 2 == 0) ?
|
||||||
|
UUIDGenerator.TYPE4 : UUIDGenerator.TYPE1;
|
||||||
|
assertTrue(seen.add(
|
||||||
|
UUIDGenerator.nextHex(type)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetTime() {
|
public void testGetTime() {
|
||||||
|
|
|
@ -43,14 +43,31 @@ public class GeneratedValues {
|
||||||
sequenceName="org.apache.openjpa.persistence.generationtype.CustomSeq()")
|
sequenceName="org.apache.openjpa.persistence.generationtype.CustomSeq()")
|
||||||
private int customSeqWithIndirectionField;
|
private int customSeqWithIndirectionField;
|
||||||
|
|
||||||
|
@GeneratedValue(generator="uuid-hex")
|
||||||
|
private String uuidhex;
|
||||||
|
|
||||||
|
@GeneratedValue(generator="uuid-string")
|
||||||
|
private String uuidstring;
|
||||||
|
|
||||||
|
@GeneratedValue(generator="uuid-type4-hex")
|
||||||
|
private String uuidT4hex;
|
||||||
|
|
||||||
|
@GeneratedValue(generator="uuid-type4-string")
|
||||||
|
private String uuidT4string;
|
||||||
|
|
||||||
public GeneratedValues() {
|
public GeneratedValues() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeneratedValues(int id, long field) {
|
public GeneratedValues(int id, long field, String uh, String us,
|
||||||
|
String ut4h, String ut4s) {
|
||||||
super();
|
super();
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.field = field;
|
this.field = field;
|
||||||
|
this.uuidhex = uh;
|
||||||
|
this.uuidstring = us;
|
||||||
|
this.uuidT4hex = ut4h;
|
||||||
|
this.uuidT4string = ut4s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
|
@ -76,4 +93,36 @@ public class GeneratedValues {
|
||||||
public int getCustomSeqWithIndirectionField() {
|
public int getCustomSeqWithIndirectionField() {
|
||||||
return customSeqWithIndirectionField;
|
return customSeqWithIndirectionField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUuidhex(String uuidhex) {
|
||||||
|
this.uuidhex = uuidhex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuidhex() {
|
||||||
|
return uuidhex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuidstring(String uuidstring) {
|
||||||
|
this.uuidstring = uuidstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuidstring() {
|
||||||
|
return uuidstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuidT4hex(String uuidT4hex) {
|
||||||
|
this.uuidT4hex = uuidT4hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuidT4hex() {
|
||||||
|
return uuidT4hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuidT4string(String uuidT4string) {
|
||||||
|
this.uuidT4string = uuidT4string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUuidT4string() {
|
||||||
|
return uuidT4string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,12 +46,16 @@ public class TestGeneratedValues extends SingleEMFTestCase {
|
||||||
|
|
||||||
assertFalse(gv.getId() == gv2.getId());
|
assertFalse(gv.getId() == gv2.getId());
|
||||||
assertFalse(gv.getField() == gv2.getField());
|
assertFalse(gv.getField() == gv2.getField());
|
||||||
|
assertFalse(gv.getUuidstring().equals(gv2.getUuidstring()));
|
||||||
|
assertFalse(gv.getUuidhex().equals(gv2.getUuidhex()));
|
||||||
|
assertFalse(gv.getUuidT4hex().equals(gv2.getUuidT4hex()));
|
||||||
|
assertFalse(gv.getUuidT4string().equals(gv2.getUuidT4string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testInitialValues() {
|
public void testInitialValues() {
|
||||||
EntityManager em = emf.createEntityManager();
|
EntityManager em = emf.createEntityManager();
|
||||||
|
|
||||||
GeneratedValues gv = new GeneratedValues(7, 9);
|
GeneratedValues gv = new GeneratedValues(7, 9, "a", "b", "c", "d");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
|
@ -133,4 +137,82 @@ public class TestGeneratedValues extends SingleEMFTestCase {
|
||||||
|
|
||||||
assertNotEquals(0, gv.getCustomSeqWithIndirectionField());
|
assertNotEquals(0, gv.getCustomSeqWithIndirectionField());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testUUIDGenerators() {
|
||||||
|
EntityManager em = emf.createEntityManager();
|
||||||
|
|
||||||
|
GeneratedValues gv = new GeneratedValues();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist(gv);
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
int id = gv.getId();
|
||||||
|
|
||||||
|
assertTrue(isStringUUID(gv.getUuidT4string(), 4));
|
||||||
|
assertTrue(isStringUUID(gv.getUuidstring(), 1));
|
||||||
|
assertTrue(isHexUUID(gv.getUuidhex(), 1));
|
||||||
|
assertTrue(isHexUUID(gv.getUuidT4hex(), 4));
|
||||||
|
|
||||||
|
em.clear();
|
||||||
|
|
||||||
|
GeneratedValues gv2 = em.find(GeneratedValues.class, id);
|
||||||
|
assertNotNull(gv2);
|
||||||
|
// The string value could contain null values and such so length
|
||||||
|
// calculations may be non-deterministic. For string generators,
|
||||||
|
// simply ensure the fields are populated (not null).
|
||||||
|
assertNotNull(gv2.getUuidstring());
|
||||||
|
assertTrue(isHexUUID(gv2.getUuidhex(), 1));
|
||||||
|
assertNotNull(gv2.getUuidT4string());
|
||||||
|
assertTrue(isHexUUID(gv2.getUuidT4hex(), 4));
|
||||||
|
|
||||||
|
// Compare original hex values with new values. They should be equal.
|
||||||
|
// Note: UUID 'string' values are not compared. In most cases they will
|
||||||
|
// be the same, but in an environment where data is converted to
|
||||||
|
// a considerably different character encoding of the database (ex.
|
||||||
|
// Unicode -> EBCDIC) upon persistence, the uuid string returned by the
|
||||||
|
// database may not be equal to the original value. This is a common
|
||||||
|
// issue with string data, but even more likely for a uuids given that
|
||||||
|
// uuid strings are produced from pseudo-random byte arrays, which yield
|
||||||
|
// all sorts of variant characters.
|
||||||
|
assertTrue(gv.getId() == gv2.getId());
|
||||||
|
assertTrue(gv.getField() == gv2.getField());
|
||||||
|
assertTrue(gv.getUuidhex().equals(gv2.getUuidhex()));
|
||||||
|
assertTrue(gv.getUuidT4hex().equals(gv2.getUuidT4hex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify a uuid string is 16 characters long and is the expected type.
|
||||||
|
*/
|
||||||
|
private boolean isStringUUID(String value, int type) {
|
||||||
|
if (value.length() != 16)
|
||||||
|
return false;
|
||||||
|
byte version = (byte)(value.charAt(6) >>> 4);
|
||||||
|
if (type != version) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify a uuid hex string value is 32 characters long, consists entirely
|
||||||
|
* of hex digits and is the correct version.
|
||||||
|
*/
|
||||||
|
private boolean isHexUUID(String value, int type) {
|
||||||
|
if (value.length() != 32)
|
||||||
|
return false;
|
||||||
|
char[] chArr = value.toCharArray();
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
char ch = chArr[i];
|
||||||
|
if (!(Character.isDigit(ch) ||
|
||||||
|
(ch >= 'a' && ch <= 'f') ||
|
||||||
|
(ch >= 'A' && ch <= 'F')))
|
||||||
|
return false;
|
||||||
|
if (i == 12) {
|
||||||
|
if (type == 1 && ch != '1')
|
||||||
|
return false;
|
||||||
|
if (type == 4 && ch != '4')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,18 @@ public class ExtensionsEntity {
|
||||||
@GeneratedValue(generator = "uuid-hex")
|
@GeneratedValue(generator = "uuid-hex")
|
||||||
@Column(name = "UUID_HEX")
|
@Column(name = "UUID_HEX")
|
||||||
private String uuid;
|
private String uuid;
|
||||||
|
|
||||||
|
@GeneratedValue(generator = "uuid-string")
|
||||||
|
@Column(name = "UUID_STRING")
|
||||||
|
private String uuidString;
|
||||||
|
|
||||||
|
@GeneratedValue(generator = "uuid-type4-hex")
|
||||||
|
@Column(name = "UUIDT4_HEX")
|
||||||
|
private String uuidT4Hex;
|
||||||
|
|
||||||
|
@GeneratedValue(generator = "uuid-type4-string")
|
||||||
|
@Column(name = "UUIDT4_STRING")
|
||||||
|
private String uuidT4String;
|
||||||
|
|
||||||
@Basic(fetch = FetchType.LAZY)
|
@Basic(fetch = FetchType.LAZY)
|
||||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "system")
|
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "system")
|
||||||
|
|
|
@ -72,6 +72,12 @@ public class TestExtensionAnnotations
|
||||||
public void testValueStrategy() {
|
public void testValueStrategy() {
|
||||||
assertEquals(ValueStrategies.UUID_HEX,
|
assertEquals(ValueStrategies.UUID_HEX,
|
||||||
_mapping.getField("uuid").getValueStrategy());
|
_mapping.getField("uuid").getValueStrategy());
|
||||||
|
assertEquals(ValueStrategies.UUID_STRING,
|
||||||
|
_mapping.getField("uuidString").getValueStrategy());
|
||||||
|
assertEquals(ValueStrategies.UUID_TYPE4_HEX,
|
||||||
|
_mapping.getField("uuidT4Hex").getValueStrategy());
|
||||||
|
assertEquals(ValueStrategies.UUID_TYPE4_STRING,
|
||||||
|
_mapping.getField("uuidT4String").getValueStrategy());
|
||||||
FieldMapping seq = _mapping.getFieldMapping("seq");
|
FieldMapping seq = _mapping.getFieldMapping("seq");
|
||||||
assertEquals(ValueStrategies.SEQUENCE, seq.getValueStrategy());
|
assertEquals(ValueStrategies.SEQUENCE, seq.getValueStrategy());
|
||||||
assertEquals("system", seq.getValueSequenceName());
|
assertEquals("system", seq.getValueSequenceName());
|
||||||
|
|
|
@ -1220,6 +1220,10 @@ public class AnnotationPersistenceMetaDataParser
|
||||||
return ValueStrategies.UUID_HEX;
|
return ValueStrategies.UUID_HEX;
|
||||||
if (Generator.UUID_STRING.equals(generator))
|
if (Generator.UUID_STRING.equals(generator))
|
||||||
return ValueStrategies.UUID_STRING;
|
return ValueStrategies.UUID_STRING;
|
||||||
|
if (Generator.UUID_TYPE4_HEX.equals(generator))
|
||||||
|
return ValueStrategies.UUID_TYPE4_HEX;
|
||||||
|
if (Generator.UUID_TYPE4_STRING.equals(generator))
|
||||||
|
return ValueStrategies.UUID_TYPE4_STRING;
|
||||||
throw new MetaDataException(_loc.get("generator-bad-strategy",
|
throw new MetaDataException(_loc.get("generator-bad-strategy",
|
||||||
context, generator));
|
context, generator));
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,8 @@ public interface Generator {
|
||||||
|
|
||||||
public static final String UUID_HEX = "uuid-hex";
|
public static final String UUID_HEX = "uuid-hex";
|
||||||
public static final String UUID_STRING = "uuid-string";
|
public static final String UUID_STRING = "uuid-string";
|
||||||
|
public static final String UUID_TYPE4_STRING = "uuid-type4-string";
|
||||||
|
public static final String UUID_TYPE4_HEX = "uuid-type4-hex";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sequence name.
|
* The sequence name.
|
||||||
|
|
|
@ -830,7 +830,7 @@ on any field, not just identity fields. Before using the <literal>IDENTITY
|
||||||
<xref linkend="ref_guide_pc_oid_pkgen_autoinc"/> in the Reference Guide.
|
<xref linkend="ref_guide_pc_oid_pkgen_autoinc"/> in the Reference Guide.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
OpenJPA also offers two additional generator strategies for non-numeric fields,
|
OpenJPA also offers additional generator strategies for non-numeric fields,
|
||||||
which you can access by setting <literal>strategy</literal> to <literal>AUTO
|
which you can access by setting <literal>strategy</literal> to <literal>AUTO
|
||||||
</literal> (the default), and setting the <literal>generator</literal> string
|
</literal> (the default), and setting the <literal>generator</literal> string
|
||||||
to:
|
to:
|
||||||
|
@ -851,9 +851,9 @@ to:
|
||||||
uuid-string
|
uuid-string
|
||||||
</primary>
|
</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<literal>uuid-string</literal>: OpenJPA will generate a 128-bit UUID unique
|
<literal>uuid-string</literal>: OpenJPA will generate a 128-bit type 1 UUID
|
||||||
within the network, represented as a 16-character string. For more information
|
unique within the network, represented as a 16-character string. For more
|
||||||
on UUIDs, see the IETF UUID draft specification at:
|
information on UUIDs, see the IETF UUID draft specification at:
|
||||||
<ulink url="http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/">
|
<ulink url="http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/">
|
||||||
http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/</ulink>
|
http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/</ulink>
|
||||||
</para>
|
</para>
|
||||||
|
@ -874,7 +874,48 @@ http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/</ulink>
|
||||||
</primary>
|
</primary>
|
||||||
</indexterm>
|
</indexterm>
|
||||||
<literal>uuid-hex</literal>: Same as <literal> uuid-string</literal>, but
|
<literal>uuid-hex</literal>: Same as <literal> uuid-string</literal>, but
|
||||||
represents the UUID as a 32-character hexadecimal string.
|
represents the type 1 UUID as a 32-character hexadecimal string.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<indexterm>
|
||||||
|
<primary>
|
||||||
|
mapping metadata
|
||||||
|
</primary>
|
||||||
|
<secondary>
|
||||||
|
uuid-type4-string
|
||||||
|
</secondary>
|
||||||
|
</indexterm>
|
||||||
|
<indexterm>
|
||||||
|
<primary>
|
||||||
|
uuid-type4-string
|
||||||
|
</primary>
|
||||||
|
</indexterm>
|
||||||
|
<literal>uuid-type4-string</literal>: OpenJPA will generate a 128-bit type 4
|
||||||
|
pseudo-random UUID, represented as a 16-character string. For more
|
||||||
|
information on UUIDs, see the IETF UUID draft specification at:
|
||||||
|
<ulink url="http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/">
|
||||||
|
http://www1.ics.uci.edu/~ejw/authoring/uuid-guid/</ulink>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<indexterm>
|
||||||
|
<primary>
|
||||||
|
mapping metadata
|
||||||
|
</primary>
|
||||||
|
<secondary>
|
||||||
|
uuid-type4-hex
|
||||||
|
</secondary>
|
||||||
|
</indexterm>
|
||||||
|
<indexterm>
|
||||||
|
<primary>
|
||||||
|
uuid-type4-hex
|
||||||
|
</primary>
|
||||||
|
</indexterm>
|
||||||
|
<literal>uuid-type4-hex</literal>: Same as <literal> uuid-type4-string</literal>
|
||||||
|
, but represents the type 4 UUID as a 32-character hexadecimal string.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
Loading…
Reference in New Issue