r6998 - in dumbhippo/trunk/server: src/com/dumbhippo/dm/annotations src/com/dumbhippo/dm/schema tests/com/dumbhippo/dm tests/com/dumbhippo/dm/dm
- From: commits mugshot org
- To: online-desktop-list gnome org
- Subject: r6998 - in dumbhippo/trunk/server: src/com/dumbhippo/dm/annotations src/com/dumbhippo/dm/schema tests/com/dumbhippo/dm tests/com/dumbhippo/dm/dm
- Date: Mon, 10 Dec 2007 11:15:17 -0600 (CST)
Author: otaylor
Date: 2007-12-10 11:15:15 -0600 (Mon, 10 Dec 2007)
New Revision: 6998
Added:
dumbhippo/trunk/server/src/com/dumbhippo/dm/annotations/MetaConstruct.java
Modified:
dumbhippo/trunk/server/src/com/dumbhippo/dm/annotations/DMO.java
dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMClassHolder.java
dumbhippo/trunk/server/tests/com/dumbhippo/dm/InheritanceTests.java
dumbhippo/trunk/server/tests/com/dumbhippo/dm/dm/TestSuperUserDMO.java
Log:
DMO InheritanceTests TestSuperUserDMO DMClassHolder: Make resourceBase property
of the @DMO annotation optional; require it on base classes, require it not to
be present on subclasses.
MetaConstruct DMClassHolder: Add @MetaConstruct annotation that marks a property
on a DMO base class as meaning "this method maps from a key object to the class
to use to construct an instance corresponding to that key"
DMClassHolder: Track whether the DMClassHolder is subclassed (not curently
used)
Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/annotations/DMO.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/annotations/DMO.java 2007-12-10 04:54:11 UTC (rev 6997)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/annotations/DMO.java 2007-12-10 17:15:15 UTC (rev 6998)
@@ -9,5 +9,5 @@
@Target(ElementType.TYPE)
public @interface DMO {
String classId();
- String resourceBase();
+ String resourceBase() default "";
}
Added: dumbhippo/trunk/server/src/com/dumbhippo/dm/annotations/MetaConstruct.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/annotations/MetaConstruct.java 2007-12-10 04:54:11 UTC (rev 6997)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/annotations/MetaConstruct.java 2007-12-10 17:15:15 UTC (rev 6998)
@@ -0,0 +1,16 @@
+package com.dumbhippo.dm.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation applied to a method of a baseclass of an inheritance heirarchy of
+ * DMObject's to indicate that the method takes a key as an argument, and
+ * returns the class of the DMObject to construct for the key.
+ */
+ Retention(RetentionPolicy.RUNTIME)
+ Target(ElementType.METHOD)
+public @interface MetaConstruct {
+}
Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMClassHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMClassHolder.java 2007-12-10 04:54:11 UTC (rev 6997)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMClassHolder.java 2007-12-10 17:15:15 UTC (rev 6998)
@@ -3,6 +3,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
@@ -37,6 +38,7 @@
import com.dumbhippo.dm.annotations.DMFilter;
import com.dumbhippo.dm.annotations.DMO;
import com.dumbhippo.dm.annotations.Inject;
+import com.dumbhippo.dm.annotations.MetaConstruct;
import com.dumbhippo.dm.filter.CompiledFilter;
import com.dumbhippo.dm.filter.CompiledItemFilter;
import com.dumbhippo.dm.filter.CompiledListFilter;
@@ -55,8 +57,11 @@
private DataModel model;
private Class<T> dmoClass;
+ DMClassHolder<K,? extends DMObject<K>> baseClassHolder;
+ private boolean subclassed = false;
private Class<K> keyClass;
private Constructor<K> keyStringConstructor;
+ private Method metaConstructor;
private Constructor<? extends T> wrapperConstructor;
private DMPropertyHolder<K,T,?>[] properties;
private boolean[] mustQualify;
@@ -104,6 +109,44 @@
throw new RuntimeException(dmoClass.getName() + ": classId '" + annotation.classId() + "' is not a valid URI");
}
+ Class<?> parentClass = dmoClass.getSuperclass();
+ while (parentClass != null) {
+ if (parentClass.isAnnotationPresent(DMO.class)) {
+ DMClassHolder<?,?> classHolder = model.getClassHolder(parentClass);
+ if (classHolder.getKeyClass() != keyClass) {
+ throw new RuntimeException(dmoClass.getName() + ": parent class " + parentClass.getName() + " has a different key type");
+ }
+ @SuppressWarnings("unchecked")
+ DMClassHolder<K,T> tmpHolder = (DMClassHolder<K,T>)classHolder;
+ baseClassHolder = tmpHolder;
+ baseClassHolder.subclassed = true;
+ }
+
+ parentClass = parentClass.getSuperclass();
+ }
+
+ if ("".equals(annotation.resourceBase())) {
+ if (baseClassHolder == null)
+ throw new RuntimeException(dmoClass.getName() + ": resourceBase must be specified for base class in DMO inheritance heirarchy");
+ } else {
+ if (baseClassHolder != null)
+ throw new RuntimeException(dmoClass.getName() + ": resourceBase must not be specified for derived DMO class");
+ }
+
+ for (Method method : dmoClass.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(MetaConstruct.class)) {
+ if (metaConstructor != null)
+ throw new RuntimeException(dmoClass.getName() + ": Two @MetaConstruct method");
+ if (!(Class.class.isAssignableFrom(method.getReturnType())))
+ throw new RuntimeException(dmoClass.getName() + ": @MetaConstruct method must return a class");
+ if (method.getParameterTypes().length != 1)
+ throw new RuntimeException(dmoClass.getName() + ": @MetaConstruct method must take a single parameter");
+ if (!method.getParameterTypes()[0].isAssignableFrom(keyClass))
+ throw new RuntimeException(dmoClass.getName() + ": @MetaConstruct method parameter must match key type");
+
+ metaConstructor = method;
+ }
+ }
buildWrapperClass();
@@ -137,7 +180,10 @@
}
public String getResourceBase() {
- return annotation.resourceBase();
+ if (baseClassHolder != null)
+ return baseClassHolder.getResourceBase();
+ else
+ return annotation.resourceBase();
}
public String getClassId() {
@@ -195,11 +241,10 @@
public boolean mustQualifyProperty(int propertyIndex) {
return mustQualify[propertyIndex];
}
-
- public T createInstance(Object key, DMSession session) {
+
+ public T createInstance(K key, DMSession session) {
try {
- T result = wrapperConstructor.newInstance(key, session);
- return result;
+ return wrapperConstructor.newInstance(key, session);
} catch (Exception e) {
throw new RuntimeException("Error creating instance of class " + dmoClass.getName(), e);
}
@@ -233,20 +278,41 @@
}
public String makeResourceId(K key) {
- return model.getBaseUrl() + annotation.resourceBase() + "/" + key.toString();
+ return model.getBaseUrl() + getResourceBase() + "/" + key.toString();
}
public String makeRelativeId(K key) {
- return annotation.resourceBase() + "/" + key.toString();
+ return getResourceBase() + "/" + key.toString();
}
- public StoreKey<K,T> makeStoreKey(String string) throws BadIdException {
+ @SuppressWarnings("unchecked")
+ private DMClassHolder<K,? extends T> getClassHolderForKey(K key) {
+ if (metaConstructor != null) {
+ try {
+ Class<?> clazz = (Class<?>)metaConstructor.invoke(null, new Object[] { key });
+ return (DMClassHolder<K,? extends T>)model.getClassHolder(clazz);
+ } catch (Exception e) {
+ throw new RuntimeException("Error calling metaconstructor of class " + dmoClass.getName(), e);
+ }
+ } else {
+ return this;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public StoreKey<K,? extends T> makeStoreKey(K key) {
+ DMClassHolder subClassHolder = getClassHolderForKey(key);
+ return new StoreKey(subClassHolder, key);
+ }
+
+ public StoreKey<K,? extends T> makeStoreKey(String string) throws BadIdException {
+
if (keyClass == Guid.class) {
try {
Guid guid = new Guid(string);
@SuppressWarnings("unchecked")
- StoreKey<K,T> key = new StoreKey(this, guid);
+ StoreKey<K,? extends T> key = makeStoreKey((K)guid);
return key;
} catch (ParseException e) {
throw new BadIdException("Invalid GUID in resourceId");
@@ -254,25 +320,23 @@
} else if (keyClass == String.class) {
@SuppressWarnings("unchecked")
- StoreKey<K,T> key = new StoreKey(this, string);
+ StoreKey<K,? extends T> key = makeStoreKey((K)string);
return key;
} else if (keyClass == Long.class) {
try {
Long l = Long.parseLong(string);
@SuppressWarnings("unchecked")
- StoreKey<K,T> key = new StoreKey(this, l);
+ StoreKey<K,? extends T> key = makeStoreKey((K)l);
return key;
} catch (NumberFormatException e) {
throw new BadIdException("Invalid long in resourceId");
}
} else {
try {
- Object keyObject = keyStringConstructor.newInstance(string);
+ K keyObject = keyStringConstructor.newInstance(string);
- @SuppressWarnings("unchecked")
- StoreKey<K,T> key = new StoreKey(this, keyObject);
- return key;
+ return makeStoreKey(keyObject);
} catch (InstantiationException e) {
throw new RuntimeException("Error creating key object from string", e);
} catch (IllegalAccessException e) {
Modified: dumbhippo/trunk/server/tests/com/dumbhippo/dm/InheritanceTests.java
===================================================================
--- dumbhippo/trunk/server/tests/com/dumbhippo/dm/InheritanceTests.java 2007-12-10 04:54:11 UTC (rev 6997)
+++ dumbhippo/trunk/server/tests/com/dumbhippo/dm/InheritanceTests.java 2007-12-10 17:15:15 UTC (rev 6998)
@@ -39,7 +39,7 @@
superUserDMO = session.find(TestSuperUserDMO.class, guid);
assertTrue(superUserDMO != null);
assertEquals(guid.toString(), superUserDMO.getKey().toString());
- assertEquals("http://mugshot.org/o/test/superUser/" + guid, superUserDMO.getResourceId());
+ assertEquals("http://mugshot.org/o/test/user/" + guid, superUserDMO.getResourceId());
assertEquals("*The Nose*", superUserDMO.getName());
assertEquals("The ability to tell if leftovers have gone bad", superUserDMO.getSuperPower());
Modified: dumbhippo/trunk/server/tests/com/dumbhippo/dm/dm/TestSuperUserDMO.java
===================================================================
--- dumbhippo/trunk/server/tests/com/dumbhippo/dm/dm/TestSuperUserDMO.java 2007-12-10 04:54:11 UTC (rev 6997)
+++ dumbhippo/trunk/server/tests/com/dumbhippo/dm/dm/TestSuperUserDMO.java 2007-12-10 17:15:15 UTC (rev 6998)
@@ -8,7 +8,12 @@
import com.dumbhippo.dm.persistence.TestSuperUser;
import com.dumbhippo.identity20.Guid;
- DMO(classId="http://mugshot.org/p/o/test/superUser", resourceBase="/o/test/superUser")
+// FIXME: This is not actually valid inheritance since it must be possible to
+// determine the class in the inheritance heirarchy from the key; but it works
+// for what we are testing at the moment because we explicitly
+// em.find(TestSuperUser.DMO.class)
+
+ DMO(classId="http://mugshot.org/p/o/test/superUser")
public abstract class TestSuperUserDMO extends TestUserDMO {
@SuppressWarnings("unused")
static private final Logger logger = GlobalSetup.getLogger(TestSuperUserDMO.class);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]