r6983 - in dumbhippo/trunk/server: src/com/dumbhippo/dm src/com/dumbhippo/dm/schema src/com/dumbhippo/server/dm tests/com/dumbhippo/dm



Author: otaylor
Date: 2007-12-06 17:29:41 -0600 (Thu, 06 Dec 2007)
New Revision: 6983

Added:
   dumbhippo/trunk/server/src/com/dumbhippo/dm/DMInjectionLookup.java
Modified:
   dumbhippo/trunk/server/src/com/dumbhippo/dm/DataModel.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMClassHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMPropertyHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/server/dm/DataService.java
   dumbhippo/trunk/server/tests/com/dumbhippo/dm/FilterCompilerTests.java
   dumbhippo/trunk/server/tests/com/dumbhippo/dm/TestSupport.java
Log:
DMClassHolder DMPropertyHolder: Don't add inherited properties in
  base classes multiple times

DMInjectionLookup DataModel DMClassHolder: Allow users of the data
  model to custom injection.

DataService DMClassHolder: Move @EJB handling to DataService, add
  handling of @WebServiceCache.

TestSupport FilterCompilerTests: Adapt to new signature of DataModel
  constructor


Added: dumbhippo/trunk/server/src/com/dumbhippo/dm/DMInjectionLookup.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/DMInjectionLookup.java	2007-12-06 22:27:23 UTC (rev 6982)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/DMInjectionLookup.java	2007-12-06 23:29:41 UTC (rev 6983)
@@ -0,0 +1,41 @@
+package com.dumbhippo.dm;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * This interface allows system creating a DataModel to customize how property
+ * injection for DMObject instances works. To process a field for injection,
+ * the following steps are taken:
+ * 
+ *  A) injectionLookup.getInjectionByAnnotations() is called; if it returns
+ *     not-null, that value is used
+ *  B) if the @Inject annotation is present:
+ *    B1) injectionLookup.getInjectionByType is called;  if it returns
+ *      not-null, that value is used
+ *    B2) default injection types such as DMSession and EntityManager are checked for,
+ *      if one is found, the cooresponding value is used 
+ *    B3) otherwise, an exception is raised
+ *  C) any other built-in annotations are checked for 
+ */
+public interface DMInjectionLookup {
+	/**
+	 * Determine the value to inject into a property based on the annotations of the
+	 * property.
+	 * 
+	 * @param valueType the type of the property's value
+	 * @param annotations annotations on the property (the field or method)
+	 * @return the value to inject into the property, or null if no injection is known 
+	 *   based on the annotations.
+	 */
+	Object getInjectionByAnnotations(Class<?> valueType, Annotation[] annotations, DMSession session);
+
+	
+	/**
+	 * Determine the value to inject into a property annotated with @Inject
+	 * 
+	 * @param valueType the type of the property's value
+	 * @return the value to inject into the property, or null if no injection is known for
+	 *    the type.
+	 */
+	Object getInjectionByType(Class<?> valueType, DMSession session);
+}

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/DataModel.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/DataModel.java	2007-12-06 22:27:23 UTC (rev 6982)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/DataModel.java	2007-12-06 23:29:41 UTC (rev 6983)
@@ -36,6 +36,7 @@
 	private String baseUrl;
 	private DMSessionMap sessionMap = new DMSessionMapJTA();
 	private EntityManagerFactory emf = null;
+	private DMInjectionLookup injectionLookup;
 	private ChangeNotifier notifier;
 	private Map<Class<?>, DMClassHolder<?,?>> classes = new HashMap<Class<?>, DMClassHolder<?,?>>();
 	private Map<String, DMClassHolder<?,?>> classesByBase = new HashMap<String, DMClassHolder<?,?>>();
@@ -64,6 +65,7 @@
 	public DataModel(String                       baseUrl,
 			         DMSessionMap                 sessionMap,
 			         EntityManagerFactory         emf,
+			         DMInjectionLookup            injectionLookup,
 			         ChangeNotifier               notifier,
 			         Class<? extends DMViewpoint> viewpointClass,
 			         DMViewpoint                  systemViewpoint) {
@@ -81,6 +83,7 @@
 		
 		this.sessionMap = sessionMap;
 		this.emf = emf;
+		this.injectionLookup = injectionLookup;
 		this.notifier = notifier;
 		this.viewpointClass = viewpointClass;
 		this.systemViewpoint = systemViewpoint;
@@ -135,6 +138,10 @@
 		return emf.createEntityManager();
 	}
 	
+	public DMInjectionLookup getInjectionLookup() {
+		return injectionLookup;
+	}
+	
 	public DMClassHolder<?, ? extends DMObject<?>> getClassHolder(Class<?> tClass) {
 		DMClassHolder<?,?> classHolder = classes.get(tClass);
 		
@@ -231,7 +238,7 @@
 	public DMStore getStore() {
 		return store;
 	}
-
+	
 	public long getTimestamp() {
 		// FIXME: This doesn't fully work in a clustered configuration; we should use
 		// timestamps/serials from the invalidation protocol instead.

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMClassHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMClassHolder.java	2007-12-06 22:27:23 UTC (rev 6982)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMClassHolder.java	2007-12-06 23:29:41 UTC (rev 6983)
@@ -29,6 +29,7 @@
 
 import com.dumbhippo.GlobalSetup;
 import com.dumbhippo.dm.BadIdException;
+import com.dumbhippo.dm.DMInjectionLookup;
 import com.dumbhippo.dm.DMObject;
 import com.dumbhippo.dm.DMSession;
 import com.dumbhippo.dm.DMViewpoint;
@@ -204,22 +205,6 @@
 		}
 	}
 	
-	public void processInjections(DMSession session, T t) {
-		Class<?> clazz = baseClass;
-		while (clazz != null) {
-			for (Field field : clazz.getDeclaredFields()) {
-				if (field.isAnnotationPresent(Inject.class)) {
-					injectField(session, t, field);
-				} else if (field.isAnnotationPresent(EJB.class)) {
-					Object bean = EJBUtil.defaultLookup(field.getType());
-					setField(t, field, bean);			
-				}
-			}
-			
-			clazz = clazz.getSuperclass();
-		}
-	}
-	
 	public Filter getUncompiledFilter() {
 		return filter;
 	}
@@ -302,19 +287,50 @@
 		}
 	}
 
-	private void injectField(DMSession session, T t, Field field) {
-		if (field.getType() == EntityManager.class) {
-			setField(t, field, session.getInjectableEntityManager());
-		} else if (field.getType() == DMSession.class) {
-			setField(t, field, session);
-		} else if (DMViewpoint.class.isAssignableFrom(field.getType())) {
+	public void processInjections(DMSession session, T t) {
+		DMInjectionLookup injectionLookup = model.getInjectionLookup();
+		
+		Class<?> clazz = baseClass;
+		while (clazz != null) {
+			for (Field field : clazz.getDeclaredFields()) {
+				Object injection = null;
+				
+				if (injectionLookup != null)
+					injection = injectionLookup.getInjectionByAnnotations(field.getType(), field.getAnnotations(), session);
+
+				if (injection == null && field.isAnnotationPresent(Inject.class)) {
+					if (injectionLookup != null)
+						injection = injectionLookup.getInjectionByType(field.getType(), session);
+					if (injection == null)
+						injection = getInjectionByType(field.getType(), session);
+				}
+				
+				if (injection != null)
+					setField(t, field, injection);			
+				
+				if (field.isAnnotationPresent(EJB.class)) {
+					Object bean = EJBUtil.defaultLookup(field.getType());
+					setField(t, field, bean);			
+				}
+			}
+			
+			clazz = clazz.getSuperclass();
+		}
+	}
+	
+	private Object getInjectionByType(Class<?> type, DMSession session) {
+		if (type == EntityManager.class) {
+			return session.getInjectableEntityManager();
+		} else if (type == DMSession.class) {
+			return session;
+		} else if (DMViewpoint.class.isAssignableFrom(type)) {
 			// We use a isAssignableFrom check here to allow people to @Inject fields
 			// that are subclasses of DMViewpoint. If the type of the @Inject field
 			// is a subtype of DMViewpoint not compatible with the the viewpoint of
 			// the DMSession, then this we'll get a ClassCastException here
-			setField(t, field, session.getViewpoint());
+			return session.getViewpoint();
 		} else { 
-			throw new RuntimeException("@Inject annotation found field of unknown type " + field.getType().getName());
+			throw new RuntimeException("@Inject annotation found field of unknown type " + type.getName());
 		}
 	}
 
@@ -396,11 +412,15 @@
 					@SuppressWarnings("unchecked")
 					DMPropertyHolder<K,T,?> property = (DMPropertyHolder<K,T,?>)parentClassHolder.getProperty(i);
 					
-					foundProperties.add(property);
-					if (!nameCount.containsKey(property.getName()))
-						nameCount.put(property.getName(), 1);
-					else
-						nameCount.put(property.getName(), 1 + nameCount.get(property.getName()));
+					// Only get properties declared in the parent class, we'll pick up inherited
+					// properties as we walk further up the inheritance chain
+					if (property.getPropertyInfo().getDeclaringType() == parentClass) {
+						foundProperties.add(property);
+						if (!nameCount.containsKey(property.getName()))
+							nameCount.put(property.getName(), 1);
+						else
+							nameCount.put(property.getName(), 1 + nameCount.get(property.getName()));
+					}
 				}
 			}
 			

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMPropertyHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMPropertyHolder.java	2007-12-06 22:27:23 UTC (rev 6982)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMPropertyHolder.java	2007-12-06 23:29:41 UTC (rev 6983)
@@ -234,6 +234,10 @@
 		return annotation.defaultMaxFetch();
 	}
 	
+	protected PropertyInfo getPropertyInfo() {
+		return propertyInfo;
+	}
+	
 	abstract public Object dehydrate(Object value);
 	abstract public Object rehydrate(DMViewpoint viewpoint, K key, Object value, DMSession session, boolean filter);
 	abstract public Object filter(DMViewpoint viewpoint, K key, Object value);

Modified: dumbhippo/trunk/server/src/com/dumbhippo/server/dm/DataService.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/server/dm/DataService.java	2007-12-06 22:27:23 UTC (rev 6982)
+++ dumbhippo/trunk/server/src/com/dumbhippo/server/dm/DataService.java	2007-12-06 23:29:41 UTC (rev 6983)
@@ -1,5 +1,8 @@
 package com.dumbhippo.server.dm;
 
+import java.lang.annotation.Annotation;
+
+import javax.ejb.EJB;
 import javax.jms.JMSException;
 import javax.jms.Message;
 import javax.jms.ObjectMessage;
@@ -13,6 +16,8 @@
 import com.dumbhippo.Site;
 import com.dumbhippo.dm.ChangeNotificationSet;
 import com.dumbhippo.dm.ChangeNotifier;
+import com.dumbhippo.dm.DMInjectionLookup;
+import com.dumbhippo.dm.DMSession;
 import com.dumbhippo.dm.DMSessionMapJTA;
 import com.dumbhippo.dm.DataModel;
 import com.dumbhippo.dm.JBossInjectableEntityManagerFactory;
@@ -26,6 +31,8 @@
 import com.dumbhippo.server.util.EJBUtil;
 import com.dumbhippo.server.views.SystemViewpoint;
 import com.dumbhippo.server.views.Viewpoint;
+import com.dumbhippo.services.caches.CacheFactory;
+import com.dumbhippo.services.caches.WebServiceCache;
 
 public class DataService extends ServiceMBeanSupport implements DataServiceMBean, ChangeNotifier {
 	static public final String TOPIC_NAME = "topic/DataModelTopic";
@@ -38,6 +45,25 @@
 	private Thread topicConsumerThread;
 	
 	private static DataService instance;
+
+	private class InjectionLookup implements DMInjectionLookup {
+		public Object getInjectionByAnnotations(Class<?> valueType, Annotation[] annotations, DMSession session) {
+			for (Annotation annotation : annotations) {
+				if (annotation instanceof EJB)
+					return EJBUtil.defaultLookup(valueType);
+				else if (annotation instanceof WebServiceCache) {
+					CacheFactory cacheFactory = EJBUtil.defaultLookup(CacheFactory.class);
+					return cacheFactory.lookup(valueType);
+				}
+			}
+			
+			return null;
+		}
+
+		public Object getInjectionByType(Class<?> valueType, DMSession session) {
+			return null;
+		}
+	}
 	
 	// This service is started before HippoService, which sets up the tree cache and updates db schemas.
 	// Thus, don't try to use the database in here.

Modified: dumbhippo/trunk/server/tests/com/dumbhippo/dm/FilterCompilerTests.java
===================================================================
--- dumbhippo/trunk/server/tests/com/dumbhippo/dm/FilterCompilerTests.java	2007-12-06 22:27:23 UTC (rev 6982)
+++ dumbhippo/trunk/server/tests/com/dumbhippo/dm/FilterCompilerTests.java	2007-12-06 23:29:41 UTC (rev 6983)
@@ -31,7 +31,7 @@
 	protected void setUp()  {
 		// The model is only used for the viewpoint class and the class pool; we don't
 		// want to set up a real model, because we want to avoid compiling filters.
-		model = new DataModel("http://mugshot.org";, null, null, null,
+		model = new DataModel("http://mugshot.org";, null, null, null, null,
 							  TestViewpoint.class, new TestViewpoint(null));
 	}
 	

Modified: dumbhippo/trunk/server/tests/com/dumbhippo/dm/TestSupport.java
===================================================================
--- dumbhippo/trunk/server/tests/com/dumbhippo/dm/TestSupport.java	2007-12-06 22:27:23 UTC (rev 6982)
+++ dumbhippo/trunk/server/tests/com/dumbhippo/dm/TestSupport.java	2007-12-06 23:29:41 UTC (rev 6983)
@@ -36,7 +36,7 @@
 		model = new DataModel("http://mugshot.org";,
 							  new TestSessionMap(delegateEmf),
 							  testEmf,
-							  null,
+							  null, null,
 							  TestViewpoint.class,
 							  new TestViewpoint(null));
 		model.addDMClass(TestUserDMO.class);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]