Permalink
Browse files

TimestampIdGenerator.java was not working right, fixed it. Also impro…

…ved IdAccessor.java

Signed-off-by: gburgett <gordon.burgett@gmail.com>
  • Loading branch information...
1 parent 20d2ce4 commit 0d0197547579ad609888bf924974a4d5ebe3bb2e @gburgett committed Feb 9, 2013
@@ -22,7 +22,7 @@
import java.util.Objects;
import org.xflatdb.xflat.convert.PojoConverter;
import org.xflatdb.xflat.db.IdGenerator;
-import org.xflatdb.xflat.db.IntegerIdGenerator;
+import org.xflatdb.xflat.db.BigIntIdGenerator;
import org.xflatdb.xflat.db.TimestampIdGenerator;
import org.xflatdb.xflat.db.UuidIdGenerator;
import org.xflatdb.xflat.db.XFlatDatabase;
@@ -92,8 +92,9 @@ public DatabaseConfig(){
this.defaultTableConfig = new TableConfig();
this.idGeneratorStrategy = Arrays.asList(
UuidIdGenerator.class,
- TimestampIdGenerator.class,
- IntegerIdGenerator.class);
+ BigIntIdGenerator.class,
+ TimestampIdGenerator.class
+ );
}
private DatabaseConfig(DatabaseConfig other){
@@ -28,6 +28,8 @@
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.xflatdb.xflat.convert.ConversionException;
import org.xflatdb.xflat.convert.ConversionNotSupportedException;
import org.xflatdb.xflat.convert.ConversionService;
@@ -115,13 +115,13 @@ public String convert(Object source) {
@Override
public java.text.DateFormat initialValue(){
//SimpleDateFormat is not thread-safe
- return new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
+ return new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
}
};
public static final Converter<String, Date> StringToDateConverter = new Converter<String, Date>(){
@Override
public Date convert(String source) throws ConversionException {
- try{
+ try{
return format.get().parse(source);
}catch(ParseException ex){
throw new ConversionException("error parsing date", ex);
@@ -15,7 +15,7 @@
*/
package org.xflatdb.xflat.db;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
import org.jdom2.Element;
/**
@@ -24,9 +24,9 @@
* {@link String} IDs.
* @author gordon
*/
-public class IntegerIdGenerator extends IdGenerator {
+public class BigIntIdGenerator extends IdGenerator {
- private AtomicInteger lastId = new AtomicInteger(0);
+ private AtomicLong lastId = new AtomicLong(0);
@Override
public boolean supports(Class<?> idType) {
@@ -40,10 +40,10 @@ public boolean supports(Class<?> idType) {
@Override
public Object generateNewId(Class<?> idType) {
- int id = lastId.incrementAndGet();
+ long id = lastId.incrementAndGet();
if(Integer.class.equals(idType)){
- return new Integer(id);
+ return new Integer((int)id);
}
if(Float.class.equals(idType)){
return new Float(id);
@@ -55,7 +55,7 @@ public Object generateNewId(Class<?> idType) {
return new Long(id);
}
if(String.class.equals(idType)){
- return Integer.toString(id);
+ return Long.toString(id);
}
throw new UnsupportedOperationException("Unsupported ID type " + idType);
@@ -81,7 +81,7 @@ public String idToString(Object id) {
return Integer.toString(((Double)id).intValue());
}
if(Long.class.equals(idType)){
- return Integer.toString(((Long)id).intValue());
+ return ((Long)id).toString();
}
throw new UnsupportedOperationException("Unsupported ID type " + idType);
@@ -125,7 +125,7 @@ public Object stringToId(String id, Class<?> idType) {
*/
@Override
public void saveState(Element state){
- state.setAttribute("maxId", Integer.toString(this.lastId.get()), XFlatDatabase.xFlatNs);
+ state.setAttribute("maxId", Long.toString(this.lastId.get()), XFlatDatabase.xFlatNs);
}
/**
@@ -135,7 +135,7 @@ public void saveState(Element state){
@Override
public void loadState(Element state){
String maxId = state.getAttributeValue("maxId", XFlatDatabase.xFlatNs);
- this.lastId.set(Integer.parseInt(maxId));
+ this.lastId.set(Long.parseLong(maxId));
}
}
@@ -78,10 +78,15 @@ private IdAccessor(Class<T> pojoType, PropertyDescriptor idProperty, Field idFie
PropertyDescriptor idProp = null;
Field idField = null;
+
try{
- idProp = getIdProperty(pojoType);
- if(idProp == null){
- idField = getIdField(pojoType);
+ Object idPropOrField = getIdPropertyOrField(pojoType);
+ if(idPropOrField instanceof PropertyDescriptor){
+ idProp = (PropertyDescriptor)idPropOrField;
+ }
+ else{
+ idField = (Field)idPropOrField;
+ idField.setAccessible(true);
}
}
catch(IntrospectionException ex){
@@ -145,7 +150,7 @@ private IdAccessor(Class<T> pojoType, PropertyDescriptor idProperty, Field idFie
return XPathFactory.instance().compile(expression, Filters.fpassthrough(), null, namespaces == null ? Collections.EMPTY_LIST : namespaces);
}
- private static PropertyDescriptor getIdProperty(Class<?> pojoType) throws IntrospectionException{
+ private static Object getIdPropertyOrField(Class<?> pojoType) throws IntrospectionException{
List<PropertyDescriptor> descriptors = new ArrayList<>();
for(PropertyDescriptor p : Introspector.getBeanInfo(pojoType).getPropertyDescriptors()){
@@ -161,20 +166,9 @@ private static PropertyDescriptor getIdProperty(Class<?> pojoType) throws Intros
}
}
- //try properties named ID
- for(PropertyDescriptor p : descriptors){
- if("id".equalsIgnoreCase(p.getName())){
- return p;
- }
- }
-
- return null;
- }
-
- private static Field getIdField(Class<?> pojoType){
List<Field> fields = new ArrayList<>();
- for(Field f : pojoType.getFields()){
+ for(Field f : pojoType.getDeclaredFields()){
if(Object.class.equals(f.getDeclaringClass()))
continue;
@@ -192,6 +186,13 @@ private static Field getIdField(Class<?> pojoType){
}
}
+ //try properties named ID
+ for(PropertyDescriptor p : descriptors){
+ if("id".equalsIgnoreCase(p.getName())){
+ return p;
+ }
+ }
+
//try fields named ID
for(Field f : fields){
if("id".equalsIgnoreCase(f.getName())){
@@ -15,13 +15,10 @@
*/
package org.xflatdb.xflat.db;
+import java.text.ParseException;
import java.util.Date;
+import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicLong;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import org.xflatdb.xflat.XFlatException;
-import org.xflatdb.xflat.convert.ConversionException;
-import org.xflatdb.xflat.convert.converters.StringConverters;
import org.jdom2.Element;
/**
@@ -34,7 +31,18 @@
*/
public class TimestampIdGenerator extends IdGenerator {
- AtomicLong lastDate = new AtomicLong(0l);
+ private AtomicLong lastDate = new AtomicLong(0l);
+
+ public static final ThreadLocal<java.text.DateFormat> format =
+ new ThreadLocal<java.text.DateFormat>(){
+ @Override
+ public java.text.DateFormat initialValue(){
+ //SimpleDateFormat is not thread-safe
+ java.text.SimpleDateFormat ret = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
+ ret.setTimeZone(TimeZone.getTimeZone("UTC"));
+ return ret;
+ }
+ };
@Override
public boolean supports(Class<?> idType) {
@@ -63,13 +71,8 @@ public Object generateNewId(Class<?> idType) {
if(Date.class.equals(idType)){
return ret;
}
- if(String.class.equals(idType)){
- try {
- return StringConverters.DateToStringConverter.convert(ret);
- } catch (ConversionException ex) {
- //Should never happen
- throw new XFlatException("Unable to convert Integer to String", ex);
- }
+ if(String.class.equals(idType)){
+ return format.get().format(ret);
}
throw new UnsupportedOperationException("Unsupported ID type " + idType);
@@ -94,11 +97,8 @@ else if(Long.class.equals(clazz)){
else{
throw new UnsupportedOperationException("Unknown ID type " + id.getClass());
}
- try {
- return StringConverters.DateToStringConverter.convert(ret);
- } catch (ConversionException ex) {
- return "0";
- }
+
+ return format.get().format(ret);
}
@Override
@@ -114,8 +114,8 @@ public Object stringToId(String id, Class<?> idType) {
}
else{
try {
- date = StringConverters.StringToDateConverter.convert(id);
- } catch (ConversionException ex) {
+ date = format.get().parse(id);
+ } catch (ParseException ex) {
date = new Date(0);
}
}
@@ -0,0 +1,20 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.xflatdb.xflat.db;
+
+/**
+ *
+ * @author Gordon
+ */
+public class BigIntIdGeneratorTest extends IdGeneratorTestsBase<BigIntIdGenerator> {
+
+ @Override
+ protected BigIntIdGenerator getInstance() {
+ return new BigIntIdGenerator();
+ }
+
+
+
+}
@@ -17,7 +17,7 @@
import org.xflatdb.xflat.db.TimestampIdGenerator;
import org.xflatdb.xflat.db.XFlatDatabase;
-import org.xflatdb.xflat.db.IntegerIdGenerator;
+import org.xflatdb.xflat.db.BigIntIdGenerator;
import org.xflatdb.xflat.TableConfig;
import java.io.File;
import java.io.IOException;
@@ -157,7 +157,7 @@ public void testInsertMany_QueriesAll() throws Exception {
db.getConversionService().addConverter(Element.class, Foo.class, new Foo.FromElementConverter());
db.configureTable("Foo", new TableConfig()
- .withIdGenerator(IntegerIdGenerator.class));
+ .withIdGenerator(BigIntIdGenerator.class));
db.Initialize();
try{
@@ -206,7 +206,7 @@ public void testInsertMany_DeleteMatching() throws Exception {
db.getConversionService().addConverter(Element.class, Foo.class, new Foo.FromElementConverter());
db.configureTable("Foo", new TableConfig()
- .withIdGenerator(IntegerIdGenerator.class));
+ .withIdGenerator(BigIntIdGenerator.class));
db.Initialize();
@@ -326,7 +326,7 @@ public void testInsert_Resume_ValidatesConfig() throws Exception {
//use a different ID generator
db.configureTable("Foo", new TableConfig()
- .withIdGenerator(IntegerIdGenerator.class));
+ .withIdGenerator(BigIntIdGenerator.class));
boolean didThrow = false;
try {
@@ -0,0 +1,75 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.xflatdb.xflat.db;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Gordon
+ */
+public abstract class IdGeneratorTestsBase<T extends IdGenerator> {
+
+ protected abstract T getInstance();
+
+
+ @Test
+ public void testGenerateIds_HeavyUse_GeneratesUniqueIds() throws Exception {
+ System.out.println("testGenerateIds_HeavyUse_GeneratesUniqueIds");
+
+ final T instance = getInstance();
+
+ final Set<List<String>> ids = Collections.synchronizedSet(new HashSet<List<String>>());
+
+ Runnable r = new Runnable(){
+ @Override
+ public void run() {
+ List<String> idList = new ArrayList<>(500);
+
+ for(int i = 0; i < 500; i++){
+ idList.add((String)instance.generateNewId(String.class));
+ }
+
+ ids.add(idList);
+ }
+ };
+
+ Thread th1 = new Thread(r);
+ Thread th2 = new Thread(r);
+ Thread th3 = new Thread(r);
+
+ String start = (String)instance.generateNewId(String.class);
+
+ th1.start();
+ th2.start();
+ th3.start();
+ r.run();
+
+ th1.join();
+ th2.join();
+ th3.join();
+
+ String end = (String)instance.generateNewId(String.class);
+
+
+ int maxUniquifier = 0;
+
+ Set<String> finalIds = new HashSet<>();
+ for(List<String> idList : ids){
+ for(String l : idList){
+ assertTrue("Duplicate IDs generated: " + l, finalIds.add(l));
+ }
+ }
+
+ System.out.println("Max uniquifier: " + maxUniquifier);
+ }
+}
Oops, something went wrong.

0 comments on commit 0d01975

Please sign in to comment.