r6999 - in dumbhippo/trunk: openfire/src/plugins/hippo/src/java/com/dumbhippo/jive server/src/com/dumbhippo/dm server/src/com/dumbhippo/dm/fetch server/src/com/dumbhippo/dm/schema server/src/com/dumbhippo/dm/store server/tests/com/dumbhippo/dm



Author: otaylor
Date: 2007-12-10 11:24:17 -0600 (Mon, 10 Dec 2007)
New Revision: 6999

Added:
   dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/BoundFetch.java
Removed:
   dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/Fetch.java
Modified:
   dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/MultiQueryIQMethod.java
   dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/SingleQueryIQMethod.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/ClientNotification.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/ClientNotificationSet.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/DMSession.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/FetchNode.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/PropertyFetch.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/PropertyFetchNode.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMPropertyHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/FeedPropertyHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/ListResourcePropertyHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/PlainPropertyHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/ResourcePropertyHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/SetResourcePropertyHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/SingleResourcePropertyHolder.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/store/DMStore.java
   dumbhippo/trunk/server/src/com/dumbhippo/dm/store/Registration.java
   dumbhippo/trunk/server/tests/com/dumbhippo/dm/AbstractFetchTests.java
Log:
Rename Fetch to BoundFetch to better reflect function

Modified: dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/MultiQueryIQMethod.java
===================================================================
--- dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/MultiQueryIQMethod.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/MultiQueryIQMethod.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -12,7 +12,7 @@
 
 import com.dumbhippo.dm.DMObject;
 import com.dumbhippo.dm.DMSession;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchNode;
 import com.dumbhippo.dm.parser.FetchParser;
 import com.dumbhippo.dm.parser.ParseException;
@@ -52,7 +52,7 @@
 			throw IQException.createBadRequest("Error in fetch attribute: " + e.getMessage());
 		} 
 		
-		Fetch<K,T> fetch = fetchNode.bind(classHolder);
+		BoundFetch<K,T> fetch = fetchNode.bind(classHolder);
 		
 		XmppFetchVisitor visitor = new XmppFetchVisitor(root, session.getModel());
 		

Modified: dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/SingleQueryIQMethod.java
===================================================================
--- dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/SingleQueryIQMethod.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/openfire/src/plugins/hippo/src/java/com/dumbhippo/jive/SingleQueryIQMethod.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -7,7 +7,7 @@
 
 import com.dumbhippo.dm.DMObject;
 import com.dumbhippo.dm.DMSession;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchNode;
 import com.dumbhippo.dm.schema.DMClassHolder;
 import com.dumbhippo.jive.annotations.IQMethod;
@@ -23,7 +23,7 @@
 	@SuppressWarnings("unchecked")
 	private static void fetchAndVisit(DMSession session, DMObject<?> resultObject, FetchNode fetchNode, XmppFetchVisitor visitor) {
 		DMClassHolder classHolder = resultObject.getClassHolder(); 
-		Fetch fetch = fetchNode.bind(classHolder);
+		BoundFetch fetch = fetchNode.bind(classHolder);
 		
 		fetch.visit(session, classHolder, resultObject, visitor);
 	}

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/ClientNotification.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/ClientNotification.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/ClientNotification.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -3,7 +3,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.schema.DMClassHolder;
 import com.dumbhippo.dm.schema.DMPropertyHolder;
@@ -33,7 +33,7 @@
 		this.client = client;
 	}
 	
-	public <K, T extends DMObject<K>>void addObjectProperties(StoreKey<K,T> key, Fetch<K,? super T> fetch, long propertyMask, Fetch<?,?>[] childFetches, int[] maxes) {
+	public <K, T extends DMObject<K>>void addObjectProperties(StoreKey<K,T> key, BoundFetch<K,? super T> fetch, long propertyMask, BoundFetch<?,?>[] childFetches, int[] maxes) {
 		notifications.add(new ObjectNotification<K,T>(key, fetch, propertyMask, childFetches, maxes));
 	}
 	
@@ -53,12 +53,12 @@
 
 	private static class ObjectNotification<K,T extends DMObject<K>> {
 		private StoreKey<K,T> key;
-		private Fetch<K, ? super T> fetch;
+		private BoundFetch<K, ? super T> fetch;
 		private long propertyMask;
-		private Fetch<?,?>[] childFetches;
+		private BoundFetch<?,?>[] childFetches;
 		private int[] maxes;
 
-		public ObjectNotification(StoreKey<K,T> key, Fetch<K, ? super T> fetch, long propertiesMask, Fetch<?,?>[] childFetches, int[] maxes) {
+		public ObjectNotification(StoreKey<K,T> key, BoundFetch<K, ? super T> fetch, long propertiesMask, BoundFetch<?,?>[] childFetches, int[] maxes) {
 			this.key = key;
 			this.fetch = fetch;
 			this.propertyMask = propertiesMask;

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/ClientNotificationSet.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/ClientNotificationSet.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/ClientNotificationSet.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -8,7 +8,7 @@
 import org.slf4j.Logger;
 
 import com.dumbhippo.GlobalSetup;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.store.StoreClient;
 import com.dumbhippo.dm.store.StoreKey;
 
@@ -25,7 +25,7 @@
 	
 	private Map<StoreClient, ClientNotification> notifications;
 	
-	public <K, T extends DMObject<K>> void addNotification(StoreClient client, StoreKey<K,T> key, Fetch<K,? super T> fetch, long propertyMask, Fetch<?,?>[] childFetches, int[] maxes) {
+	public <K, T extends DMObject<K>> void addNotification(StoreClient client, StoreKey<K,T> key, BoundFetch<K,? super T> fetch, long propertyMask, BoundFetch<?,?>[] childFetches, int[] maxes) {
 		ClientNotification notification = null;
 		
 		if (notifications == null)

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/DMSession.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/DMSession.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/DMSession.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -2,7 +2,7 @@
 
 import javax.persistence.EntityManager;
 
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.schema.DMClassHolder;
 import com.dumbhippo.dm.store.StoreKey;
@@ -83,7 +83,7 @@
 		return find(classHolder, resourceId.substring(lastSlash + 1));
 	}
 	
-	public <K,T extends DMObject<K>> void visitFetch(T object, Fetch<K,? super T> fetch, FetchVisitor visitor) {
+	public <K,T extends DMObject<K>> void visitFetch(T object, BoundFetch<K,? super T> fetch, FetchVisitor visitor) {
 		DMClassHolder<K,T> classHolder = object.getClassHolder();
 		fetch.visit(this, classHolder, object, visitor);
 	}

Copied: dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/BoundFetch.java (from rev 6997, dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/Fetch.java)
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/Fetch.java	2007-12-10 04:54:11 UTC (rev 6997)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/BoundFetch.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -0,0 +1,492 @@
+package com.dumbhippo.dm.fetch;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.slf4j.Logger;
+
+import com.dumbhippo.GlobalSetup;
+import com.dumbhippo.dm.ClientNotificationSet;
+import com.dumbhippo.dm.DMClient;
+import com.dumbhippo.dm.DMObject;
+import com.dumbhippo.dm.DMSession;
+import com.dumbhippo.dm.schema.DMClassHolder;
+import com.dumbhippo.dm.schema.DMPropertyHolder;
+import com.dumbhippo.dm.schema.FeedPropertyHolder;
+import com.dumbhippo.dm.store.StoreClient;
+import com.dumbhippo.dm.store.StoreKey;
+
+public final class BoundFetch<K,T extends DMObject<K>> {
+	@SuppressWarnings("unused")
+	static private final Logger logger = GlobalSetup.getLogger(BoundFetch.class);
+	
+	private PropertyFetch[] properties;
+	private boolean includeDefault;
+	
+	public BoundFetch(PropertyFetch[] properties, boolean includeDefault) {
+		this.properties = properties;
+		this.includeDefault = includeDefault;
+	}
+	
+	public PropertyFetch[] getProperties() {
+		return properties;
+	}
+	
+	public boolean getIncludeDefault() {
+		return includeDefault;
+	}
+	
+	private long propertyOrdering(int i) {
+		// We assume that a property ordering of Long.MAX_VALUE will never occur
+		return i < properties.length ? properties[i].getProperty().getOrdering() : Long.MAX_VALUE;
+	}
+	
+	private long classOrdering(DMPropertyHolder<?,?,?>[] classProperties, int classIndex) {
+		return classIndex < classProperties.length ? classProperties[classIndex].getOrdering() : Long.MAX_VALUE;
+	}
+	
+	private long[] createFeedMinTimestamps(DMClassHolder<?,?> classHolder) {
+		long[] feedMinTimestamps = new long[classHolder.getFeedPropertiesCount()];
+		for (int i = 0; i < feedMinTimestamps.length; i++)
+			feedMinTimestamps[i] = -1;
+		
+		return feedMinTimestamps;
+	}
+	
+	public <U extends T> void visit(DMSession session, DMClassHolder<K,U> classHolder, U object, FetchVisitor visitor, boolean indirect) {
+		DMPropertyHolder<K,U,?>[] classProperties = classHolder.getProperties();
+		BoundFetch<K,? super U> oldFetch;
+		long[] feedMinTimestamps = null;
+		
+		StoreClient storeClient;
+		DMClient client = session.getClient();
+		if (client != null)
+			storeClient = client.getStoreClient();
+		else
+			storeClient = null;
+		
+		boolean needFetch = visitor.getNeedFetch(); 
+		
+		if (storeClient != null)
+			oldFetch = session.getModel().getStore().addRegistration(classHolder, object.getKey(), storeClient, this);
+		else
+			oldFetch = null;
+
+		boolean allFetched = true;
+		boolean noneFetched = true;
+		boolean newAnyFetched = false;
+		
+		int newIndex = 0, oldIndex = 0;
+		long newOrdering = propertyOrdering(0);
+		long oldOrdering = oldFetch != null ? oldFetch.propertyOrdering(0) : Long.MAX_VALUE;
+		for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
+			long classOrdering = classOrdering(classProperties, classIndex);
+
+			while (oldOrdering < classOrdering)
+				oldOrdering = oldFetch.propertyOrdering(++oldIndex);
+			while (newOrdering < classOrdering)
+				newOrdering = propertyOrdering(++newIndex);
+
+			boolean oldFetched = false;
+			BoundFetch<?,?> oldChildren = null;
+			if (oldOrdering == classOrdering) {
+				oldFetched = true; 
+				oldChildren = oldFetch.properties[oldIndex].getChildren();
+			} else if (oldFetch != null && oldFetch.includeDefault && classProperties[classIndex].getDefaultInclude()) {
+				oldFetched = true;
+				oldChildren = classProperties[classIndex].getDefaultChildren();
+			}
+			
+			boolean newFetched = false;
+			BoundFetch<?,?> newChildren = null;
+			if (newOrdering == classOrdering) {
+				newFetched = true;
+				newChildren = properties[newIndex].getChildren();
+			} else if (includeDefault && classProperties[classIndex].getDefaultInclude()) {
+				newFetched = true;
+				newChildren = classProperties[classIndex].getDefaultChildren();
+			}
+			
+			if (oldFetched || newFetched)
+				noneFetched = false;
+			else
+				allFetched = false;
+			
+			if (newFetched && !oldFetched)
+				newAnyFetched = true;
+			
+			if ((oldFetched || newFetched) && classProperties[classIndex] instanceof FeedPropertyHolder) {
+				@SuppressWarnings("unchecked")
+				FeedPropertyHolder<K,T,?,?> property = (FeedPropertyHolder<K,T,?,?>)classProperties[classIndex];
+
+				/* The advantage of always fetching *at least* the default is that 
+				 * then we can merge to fetch specifications without knowing the
+				 * particular value of the max fetch.
+				 */
+				int oldMax = 0;
+				if (oldOrdering == classOrdering) {
+					oldMax = oldFetch.properties[newIndex].getMax();
+					if (oldMax < property.getDefaultMaxFetch())
+						oldMax = property.getDefaultMaxFetch();
+				}
+							
+				int newMax = 0;
+				if (newOrdering == classOrdering) {
+					newMax = properties[newIndex].getMax();
+					if (newMax < property.getDefaultMaxFetch())
+						newMax = property.getDefaultMaxFetch();
+				}
+				
+				if (newMax > oldMax && (newChildren != null || oldChildren != null)) {
+					BoundFetch<?,?> children;
+					
+					if (newChildren == null)
+						children = oldChildren;
+					else if (oldChildren == null)
+						children = newChildren;
+					else
+						children = newChildren.merge(oldChildren);
+					
+					if (feedMinTimestamps == null)
+						feedMinTimestamps = createFeedMinTimestamps(classHolder);
+					int feedPropertyIndex = classHolder.getFeedPropertyIndex(property.getName());
+									
+					feedMinTimestamps[feedPropertyIndex] = property.visitFeedChildren(session, children, oldMax, newMax - oldMax, object, visitor, true);
+				} else if (newChildren != null && (oldChildren == null || newChildren != oldChildren)) {
+					if (feedMinTimestamps == null)
+						feedMinTimestamps = createFeedMinTimestamps(classHolder);
+					int feedPropertyIndex = classHolder.getFeedPropertyIndex(property.getName());
+
+					feedMinTimestamps[feedPropertyIndex] = property.visitFeedChildren(session, newChildren, 0, oldMax, object, visitor, false);
+				}
+			} else if (newChildren != null && (oldChildren == null || newChildren != oldChildren)) {
+				classProperties[classIndex].visitChildren(session, newChildren, object, visitor);
+			}
+		}
+		
+		// If this resource is part of the direct result, we must always include the resource, 
+		//   even if we aren't fetching any properties
+		// If we've never told the client about this resource at all, then we must send the
+		//   the resource (and in particular, it's class) even if we aren't fetching any properties
+		// Otherwise, if there are no new properties to fetch, we are done 
+		if (indirect && oldFetch != null && !newAnyFetched)
+			return;
+		
+		String fetchString = null;
+		if (needFetch == true) {
+			if (noneFetched)
+				fetchString = "";
+			else if (allFetched)
+				fetchString = "*";
+			else {
+				StringBuilder sb = new StringBuilder();
+				
+				newIndex = 0; oldIndex = 0;
+				newOrdering = propertyOrdering(0);
+				oldOrdering = oldFetch != null ? oldFetch.propertyOrdering(0) : Long.MAX_VALUE;
+				for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
+					long classOrdering = classOrdering(classProperties, classIndex);
+
+					while (oldOrdering < classOrdering)
+						oldOrdering = oldFetch.propertyOrdering(++oldIndex);
+					while (newOrdering < classOrdering)
+						newOrdering = propertyOrdering(++newIndex);
+					
+					boolean oldFetched = oldOrdering == classOrdering || (oldFetch != null && oldFetch.includeDefault && classProperties[classIndex].getDefaultInclude());
+					boolean newFetched = newOrdering == classOrdering || (includeDefault && classProperties[classIndex].getDefaultInclude());
+					
+					if (oldFetched || newFetched)
+						appendToFetchString(sb, classProperties[classIndex], classHolder.mustQualifyProperty(classIndex));
+				}
+				
+				fetchString = sb.toString();
+			}
+		}
+		
+		visitor.beginResource(classHolder, object.getKey(), fetchString, indirect);
+
+		newIndex = 0; oldIndex = 0;
+		newOrdering = propertyOrdering(0);
+		oldOrdering = oldFetch != null ? oldFetch.propertyOrdering(0) : Long.MAX_VALUE;
+		for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
+			long classOrdering = classOrdering(classProperties, classIndex);
+
+			while (oldOrdering < classOrdering)
+				oldOrdering = oldFetch.propertyOrdering(++oldIndex);
+			while (newOrdering < classOrdering)
+				newOrdering = propertyOrdering(++newIndex);
+			
+			boolean oldFetched = (oldOrdering == classOrdering) || (oldFetch != null && oldFetch.includeDefault && classProperties[classIndex].getDefaultInclude());
+			boolean newFetched = (newOrdering == classOrdering) || (includeDefault && classProperties[classIndex].getDefaultInclude());
+
+			if ((oldFetched || newFetched) && classProperties[classIndex] instanceof FeedPropertyHolder) {
+				@SuppressWarnings("unchecked")
+				FeedPropertyHolder<K,T,?,?> property = (FeedPropertyHolder<K,T,?,?>)classProperties[classIndex];
+
+				int oldMax =0;
+				if (oldOrdering == classOrdering) {
+					oldMax = oldFetch.properties[newIndex].getMax();
+					if (oldMax < property.getDefaultMaxFetch())
+						oldMax = property.getDefaultMaxFetch();
+				}
+							
+				int newMax = 0;
+				if (newOrdering == classOrdering) {
+					newMax = properties[newIndex].getMax();
+					if (newMax < property.getDefaultMaxFetch())
+						newMax = property.getDefaultMaxFetch();
+				}
+				
+				long minTimestamp;
+				if (feedMinTimestamps != null && newMax <= oldMax) {
+					int feedPropertyIndex = classHolder.getFeedPropertyIndex(property.getName());
+					minTimestamp = feedMinTimestamps[feedPropertyIndex];
+				} else {
+					minTimestamp = 0;
+				}
+
+				if (newMax > oldMax)
+					property.visitFeedProperty(session, oldMax, newMax - oldMax, object, visitor, minTimestamp);
+			} else if (newFetched && !oldFetched) {
+				classProperties[classIndex].visitProperty(session, object, visitor, false);
+			}
+		}
+		
+		visitor.endResource();
+	}
+	
+	public <U extends T>  void visit(DMSession session, DMClassHolder<K,U> classHolder, U object, FetchVisitor visitor) {
+		visit(session, classHolder, object, visitor, false);
+	}
+	
+	private void appendToFetchString(StringBuilder sb, DMPropertyHolder<?,?,?> propertyHolder, boolean qualify) {
+		if (sb.length() > 0)
+			sb.append(";");
+		if (qualify)
+			sb.append(propertyHolder.getPropertyId());
+		else
+			sb.append(propertyHolder.getName());
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (!(o instanceof BoundFetch))
+			return false;
+		
+		BoundFetch<?,?> other = (BoundFetch<?,?>)o;
+		
+		if (includeDefault != other.includeDefault)
+			return false;
+		
+		if (properties.length != other.properties.length)
+			return false;
+		
+		for (int i = 0; i < properties.length; i++)
+			if (!properties[i].equals(other.properties[i]))
+				return false;
+		
+		return true;
+	}
+	
+	@Override
+	public int hashCode() {
+		int value = includeDefault ? 1 : 0;
+ 
+		for (int i = 0; i < properties.length; i++)
+			value = value * 31 + properties[i].hashCode();
+		
+		return value;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder b = new StringBuilder();
+		
+		if (includeDefault)
+			b.append('+');
+		
+		// This method is primarily for our tests. For testing purposes, we want a
+		// human-predictable ordering for properties, instead of a MD5-hash ordering
+		//
+		PropertyFetch[] sortedProperties = properties.clone();
+		Arrays.sort(sortedProperties, new Comparator<PropertyFetch>() {
+			public int compare(PropertyFetch a, PropertyFetch b) {
+				return a.getProperty().getPropertyId().compareTo(b.getProperty().getPropertyId());
+			}
+		});
+			
+		for (int i = 0; i < sortedProperties.length; i++) {
+			if (i != 0 || includeDefault)
+				b.append(';');
+			b.append(sortedProperties[i].toString());
+		}
+		
+		return b.toString();
+	}
+
+	public BoundFetch<?,?> merge(BoundFetch<?,?> other) {
+		int newCount = this.properties.length;
+		boolean changedProperties = false;
+
+		// Count the total number of properties in the merge of the two fetches
+		
+		int thisIndex = 0, otherIndex = 0;
+		long thisOrdering = this.propertyOrdering(0);
+		long otherOrdering = other.propertyOrdering(0);
+		while (thisIndex < this.properties.length || otherIndex < other.properties.length) {
+			if (thisOrdering < otherOrdering) {
+				// Only in this fetch
+				thisOrdering = this.propertyOrdering(++thisIndex);
+			} else if (thisOrdering == otherOrdering) {
+				// In both fetches
+				if (!this.properties[thisIndex].equals(other.properties[otherIndex]))
+					changedProperties = true;
+				thisOrdering = this.propertyOrdering(++thisIndex);
+				otherOrdering = other.propertyOrdering(++otherIndex);
+			} else {
+				// Only in the other fetch
+				newCount++;
+				otherOrdering = other.propertyOrdering(++otherIndex);
+			}
+		}
+		
+		// If the other property is a subset of this one, we can just return this one
+		if (!changedProperties && newCount == this.properties.length && (this.includeDefault || !other.includeDefault))
+			return this;
+		
+		PropertyFetch[] newProperties = new PropertyFetch[newCount];
+		
+		int newIndex = 0;
+		thisIndex = 0; otherIndex = 0;
+		thisOrdering = this.propertyOrdering(0);
+		otherOrdering = other.propertyOrdering(0);
+		while (thisIndex < this.properties.length || otherIndex < other.properties.length) {
+			if (thisOrdering < otherOrdering) {
+				// Only in this fetch
+				newProperties[newIndex++] = this.properties[thisIndex];
+				thisOrdering = this.propertyOrdering(++thisIndex);
+			} else if (thisOrdering == otherOrdering) {
+				// In both fetches
+				newProperties[newIndex++] = this.properties[thisIndex].merge(other.properties[otherIndex]);
+				thisOrdering = this.propertyOrdering(++thisIndex);
+				otherOrdering = other.propertyOrdering(++otherIndex);
+			} else {
+				// Only in the other fetch
+				newProperties[newIndex++] = other.properties[otherIndex];
+				otherOrdering = other.propertyOrdering(++otherIndex);
+			}
+		}
+		
+		@SuppressWarnings("unchecked")
+		BoundFetch<?, ?> newFetch = new BoundFetch(newProperties, this.includeDefault || other.includeDefault);
+		
+		return newFetch;
+	}
+
+	public void resolveNotifications(StoreClient client, StoreKey<K,? extends T> key, long propertyMask, ClientNotificationSet result) {
+		DMPropertyHolder<K,? extends T,?>[] classProperties = key.getClassHolder().getProperties();
+		BoundFetch<?,?>[] childFetches = null;
+		int[] maxes = null;
+		long notifiedMask = 0;
+		
+		long bit = 1;
+		int classIndex = 0;
+		long propertyOrdering = propertyOrdering(0);
+		int propertyIndex = 0;
+		while (propertyMask != 0) {
+			if ((propertyMask & 1) != 0) {
+				long classOrdering = classOrdering(classProperties, classIndex);
+
+				while (propertyOrdering < classOrdering)
+					propertyOrdering = propertyOrdering(++propertyIndex);
+	
+				boolean notified = false;
+				BoundFetch<?,?> childFetch = null;
+				int max = -1;
+
+				if (propertyOrdering == classOrdering) {
+					if (properties[propertyIndex].getNotify()) {
+						notified = true;
+						childFetch = properties[propertyIndex].getChildren();
+						max = properties[propertyIndex].getMax();
+					}
+				} else if (includeDefault && classProperties[classIndex].getDefaultInclude()) {
+					notified = true;
+					childFetch = classProperties[classIndex].getDefaultChildren();
+				}
+				
+				if (notified)
+					notifiedMask |= bit;
+				
+				if (childFetch != null) {
+					if (childFetches == null)
+						childFetches = new BoundFetch[classProperties.length];
+					childFetches[classIndex] = childFetch;
+				}
+				
+				if (max >= 0) {
+					if (maxes == null) {
+						maxes = new int[classProperties.length];
+						for (int i = 0; i < classProperties.length; i++)
+							maxes[i] = -1; 
+					}
+					maxes[classIndex] = max;
+				}
+				
+			}
+			
+			propertyMask >>= 1;
+			bit <<= 1;
+			classIndex++;
+		}
+		
+		if (notifiedMask != 0)
+			result.addNotification(client, key, this, notifiedMask, childFetches, maxes);
+	}
+	
+	public <U extends T> String getFetchString(DMClassHolder<K,U> classHolder) {
+		DMPropertyHolder<K,U,?>[] classProperties = classHolder.getProperties();
+		
+		boolean allFetched = true;
+		boolean noneFetched = true;
+		
+		int propertyIndex = 0;
+		long propertyOrdering = propertyOrdering(0);
+		for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
+			long classOrdering = classOrdering(classProperties, classIndex);
+
+			while (propertyOrdering < classOrdering)
+				propertyOrdering = propertyOrdering(++propertyIndex);
+
+			boolean fetch = propertyOrdering == classOrdering || (includeDefault && classProperties[classIndex].getDefaultInclude());
+			
+			if (fetch)
+				noneFetched = false;
+			else
+				allFetched = false;
+		}
+		
+		if (noneFetched)
+			return "";
+		else if (allFetched)
+			return "*";
+
+		StringBuilder sb = new StringBuilder();
+			
+		propertyIndex = 0;
+		propertyOrdering = propertyOrdering(0);
+		for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
+			long classOrdering = classOrdering(classProperties, classIndex);
+
+			while (propertyOrdering < classOrdering)
+				propertyOrdering = propertyOrdering(++propertyIndex);
+			
+			boolean fetch = propertyOrdering == classOrdering || (includeDefault && classProperties[classIndex].getDefaultInclude());
+			
+			if (fetch)
+				appendToFetchString(sb, classProperties[classIndex], classHolder.mustQualifyProperty(classIndex));
+		}
+			
+		return sb.toString();
+	}
+}

Deleted: dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/Fetch.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/Fetch.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/Fetch.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -1,492 +0,0 @@
-package com.dumbhippo.dm.fetch;
-
-import java.util.Arrays;
-import java.util.Comparator;
-
-import org.slf4j.Logger;
-
-import com.dumbhippo.GlobalSetup;
-import com.dumbhippo.dm.ClientNotificationSet;
-import com.dumbhippo.dm.DMClient;
-import com.dumbhippo.dm.DMObject;
-import com.dumbhippo.dm.DMSession;
-import com.dumbhippo.dm.schema.DMClassHolder;
-import com.dumbhippo.dm.schema.DMPropertyHolder;
-import com.dumbhippo.dm.schema.FeedPropertyHolder;
-import com.dumbhippo.dm.store.StoreClient;
-import com.dumbhippo.dm.store.StoreKey;
-
-public final class Fetch<K,T extends DMObject<K>> {
-	@SuppressWarnings("unused")
-	static private final Logger logger = GlobalSetup.getLogger(Fetch.class);
-	
-	private PropertyFetch[] properties;
-	private boolean includeDefault;
-	
-	public Fetch(PropertyFetch[] properties, boolean includeDefault) {
-		this.properties = properties;
-		this.includeDefault = includeDefault;
-	}
-	
-	public PropertyFetch[] getProperties() {
-		return properties;
-	}
-	
-	public boolean getIncludeDefault() {
-		return includeDefault;
-	}
-	
-	private long propertyOrdering(int i) {
-		// We assume that a property ordering of Long.MAX_VALUE will never occur
-		return i < properties.length ? properties[i].getProperty().getOrdering() : Long.MAX_VALUE;
-	}
-	
-	private long classOrdering(DMPropertyHolder<?,?,?>[] classProperties, int classIndex) {
-		return classIndex < classProperties.length ? classProperties[classIndex].getOrdering() : Long.MAX_VALUE;
-	}
-	
-	private long[] createFeedMinTimestamps(DMClassHolder<?,?> classHolder) {
-		long[] feedMinTimestamps = new long[classHolder.getFeedPropertiesCount()];
-		for (int i = 0; i < feedMinTimestamps.length; i++)
-			feedMinTimestamps[i] = -1;
-		
-		return feedMinTimestamps;
-	}
-	
-	public <U extends T> void visit(DMSession session, DMClassHolder<K,U> classHolder, U object, FetchVisitor visitor, boolean indirect) {
-		DMPropertyHolder<K,U,?>[] classProperties = classHolder.getProperties();
-		Fetch<K,? super U> oldFetch;
-		long[] feedMinTimestamps = null;
-		
-		StoreClient storeClient;
-		DMClient client = session.getClient();
-		if (client != null)
-			storeClient = client.getStoreClient();
-		else
-			storeClient = null;
-		
-		boolean needFetch = visitor.getNeedFetch(); 
-		
-		if (storeClient != null)
-			oldFetch = session.getModel().getStore().addRegistration(classHolder, object.getKey(), storeClient, this);
-		else
-			oldFetch = null;
-
-		boolean allFetched = true;
-		boolean noneFetched = true;
-		boolean newAnyFetched = false;
-		
-		int newIndex = 0, oldIndex = 0;
-		long newOrdering = propertyOrdering(0);
-		long oldOrdering = oldFetch != null ? oldFetch.propertyOrdering(0) : Long.MAX_VALUE;
-		for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
-			long classOrdering = classOrdering(classProperties, classIndex);
-
-			while (oldOrdering < classOrdering)
-				oldOrdering = oldFetch.propertyOrdering(++oldIndex);
-			while (newOrdering < classOrdering)
-				newOrdering = propertyOrdering(++newIndex);
-
-			boolean oldFetched = false;
-			Fetch<?,?> oldChildren = null;
-			if (oldOrdering == classOrdering) {
-				oldFetched = true; 
-				oldChildren = oldFetch.properties[oldIndex].getChildren();
-			} else if (oldFetch != null && oldFetch.includeDefault && classProperties[classIndex].getDefaultInclude()) {
-				oldFetched = true;
-				oldChildren = classProperties[classIndex].getDefaultChildren();
-			}
-			
-			boolean newFetched = false;
-			Fetch<?,?> newChildren = null;
-			if (newOrdering == classOrdering) {
-				newFetched = true;
-				newChildren = properties[newIndex].getChildren();
-			} else if (includeDefault && classProperties[classIndex].getDefaultInclude()) {
-				newFetched = true;
-				newChildren = classProperties[classIndex].getDefaultChildren();
-			}
-			
-			if (oldFetched || newFetched)
-				noneFetched = false;
-			else
-				allFetched = false;
-			
-			if (newFetched && !oldFetched)
-				newAnyFetched = true;
-			
-			if ((oldFetched || newFetched) && classProperties[classIndex] instanceof FeedPropertyHolder) {
-				@SuppressWarnings("unchecked")
-				FeedPropertyHolder<K,T,?,?> property = (FeedPropertyHolder<K,T,?,?>)classProperties[classIndex];
-
-				/* The advantage of always fetching *at least* the default is that 
-				 * then we can merge to fetch specifications without knowing the
-				 * particular value of the max fetch.
-				 */
-				int oldMax = 0;
-				if (oldOrdering == classOrdering) {
-					oldMax = oldFetch.properties[newIndex].getMax();
-					if (oldMax < property.getDefaultMaxFetch())
-						oldMax = property.getDefaultMaxFetch();
-				}
-							
-				int newMax = 0;
-				if (newOrdering == classOrdering) {
-					newMax = properties[newIndex].getMax();
-					if (newMax < property.getDefaultMaxFetch())
-						newMax = property.getDefaultMaxFetch();
-				}
-				
-				if (newMax > oldMax && (newChildren != null || oldChildren != null)) {
-					Fetch<?,?> children;
-					
-					if (newChildren == null)
-						children = oldChildren;
-					else if (oldChildren == null)
-						children = newChildren;
-					else
-						children = newChildren.merge(oldChildren);
-					
-					if (feedMinTimestamps == null)
-						feedMinTimestamps = createFeedMinTimestamps(classHolder);
-					int feedPropertyIndex = classHolder.getFeedPropertyIndex(property.getName());
-									
-					feedMinTimestamps[feedPropertyIndex] = property.visitFeedChildren(session, children, oldMax, newMax - oldMax, object, visitor, true);
-				} else if (newChildren != null && (oldChildren == null || newChildren != oldChildren)) {
-					if (feedMinTimestamps == null)
-						feedMinTimestamps = createFeedMinTimestamps(classHolder);
-					int feedPropertyIndex = classHolder.getFeedPropertyIndex(property.getName());
-
-					feedMinTimestamps[feedPropertyIndex] = property.visitFeedChildren(session, newChildren, 0, oldMax, object, visitor, false);
-				}
-			} else if (newChildren != null && (oldChildren == null || newChildren != oldChildren)) {
-				classProperties[classIndex].visitChildren(session, newChildren, object, visitor);
-			}
-		}
-		
-		// If this resource is part of the direct result, we must always include the resource, 
-		//   even if we aren't fetching any properties
-		// If we've never told the client about this resource at all, then we must send the
-		//   the resource (and in particular, it's class) even if we aren't fetching any properties
-		// Otherwise, if there are no new properties to fetch, we are done 
-		if (indirect && oldFetch != null && !newAnyFetched)
-			return;
-		
-		String fetchString = null;
-		if (needFetch == true) {
-			if (noneFetched)
-				fetchString = "";
-			else if (allFetched)
-				fetchString = "*";
-			else {
-				StringBuilder sb = new StringBuilder();
-				
-				newIndex = 0; oldIndex = 0;
-				newOrdering = propertyOrdering(0);
-				oldOrdering = oldFetch != null ? oldFetch.propertyOrdering(0) : Long.MAX_VALUE;
-				for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
-					long classOrdering = classOrdering(classProperties, classIndex);
-
-					while (oldOrdering < classOrdering)
-						oldOrdering = oldFetch.propertyOrdering(++oldIndex);
-					while (newOrdering < classOrdering)
-						newOrdering = propertyOrdering(++newIndex);
-					
-					boolean oldFetched = oldOrdering == classOrdering || (oldFetch != null && oldFetch.includeDefault && classProperties[classIndex].getDefaultInclude());
-					boolean newFetched = newOrdering == classOrdering || (includeDefault && classProperties[classIndex].getDefaultInclude());
-					
-					if (oldFetched || newFetched)
-						appendToFetchString(sb, classProperties[classIndex], classHolder.mustQualifyProperty(classIndex));
-				}
-				
-				fetchString = sb.toString();
-			}
-		}
-		
-		visitor.beginResource(classHolder, object.getKey(), fetchString, indirect);
-
-		newIndex = 0; oldIndex = 0;
-		newOrdering = propertyOrdering(0);
-		oldOrdering = oldFetch != null ? oldFetch.propertyOrdering(0) : Long.MAX_VALUE;
-		for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
-			long classOrdering = classOrdering(classProperties, classIndex);
-
-			while (oldOrdering < classOrdering)
-				oldOrdering = oldFetch.propertyOrdering(++oldIndex);
-			while (newOrdering < classOrdering)
-				newOrdering = propertyOrdering(++newIndex);
-			
-			boolean oldFetched = (oldOrdering == classOrdering) || (oldFetch != null && oldFetch.includeDefault && classProperties[classIndex].getDefaultInclude());
-			boolean newFetched = (newOrdering == classOrdering) || (includeDefault && classProperties[classIndex].getDefaultInclude());
-
-			if ((oldFetched || newFetched) && classProperties[classIndex] instanceof FeedPropertyHolder) {
-				@SuppressWarnings("unchecked")
-				FeedPropertyHolder<K,T,?,?> property = (FeedPropertyHolder<K,T,?,?>)classProperties[classIndex];
-
-				int oldMax =0;
-				if (oldOrdering == classOrdering) {
-					oldMax = oldFetch.properties[newIndex].getMax();
-					if (oldMax < property.getDefaultMaxFetch())
-						oldMax = property.getDefaultMaxFetch();
-				}
-							
-				int newMax = 0;
-				if (newOrdering == classOrdering) {
-					newMax = properties[newIndex].getMax();
-					if (newMax < property.getDefaultMaxFetch())
-						newMax = property.getDefaultMaxFetch();
-				}
-				
-				long minTimestamp;
-				if (feedMinTimestamps != null && newMax <= oldMax) {
-					int feedPropertyIndex = classHolder.getFeedPropertyIndex(property.getName());
-					minTimestamp = feedMinTimestamps[feedPropertyIndex];
-				} else {
-					minTimestamp = 0;
-				}
-
-				if (newMax > oldMax)
-					property.visitFeedProperty(session, oldMax, newMax - oldMax, object, visitor, minTimestamp);
-			} else if (newFetched && !oldFetched) {
-				classProperties[classIndex].visitProperty(session, object, visitor, false);
-			}
-		}
-		
-		visitor.endResource();
-	}
-	
-	public <U extends T>  void visit(DMSession session, DMClassHolder<K,U> classHolder, U object, FetchVisitor visitor) {
-		visit(session, classHolder, object, visitor, false);
-	}
-	
-	private void appendToFetchString(StringBuilder sb, DMPropertyHolder<?,?,?> propertyHolder, boolean qualify) {
-		if (sb.length() > 0)
-			sb.append(";");
-		if (qualify)
-			sb.append(propertyHolder.getPropertyId());
-		else
-			sb.append(propertyHolder.getName());
-	}
-
-	@Override
-	public boolean equals(Object o) {
-		if (!(o instanceof Fetch))
-			return false;
-		
-		Fetch<?,?> other = (Fetch<?,?>)o;
-		
-		if (includeDefault != other.includeDefault)
-			return false;
-		
-		if (properties.length != other.properties.length)
-			return false;
-		
-		for (int i = 0; i < properties.length; i++)
-			if (!properties[i].equals(other.properties[i]))
-				return false;
-		
-		return true;
-	}
-	
-	@Override
-	public int hashCode() {
-		int value = includeDefault ? 1 : 0;
- 
-		for (int i = 0; i < properties.length; i++)
-			value = value * 31 + properties[i].hashCode();
-		
-		return value;
-	}
-
-	@Override
-	public String toString() {
-		StringBuilder b = new StringBuilder();
-		
-		if (includeDefault)
-			b.append('+');
-		
-		// This method is primarily for our tests. For testing purposes, we want a
-		// human-predictable ordering for properties, instead of a MD5-hash ordering
-		//
-		PropertyFetch[] sortedProperties = properties.clone();
-		Arrays.sort(sortedProperties, new Comparator<PropertyFetch>() {
-			public int compare(PropertyFetch a, PropertyFetch b) {
-				return a.getProperty().getPropertyId().compareTo(b.getProperty().getPropertyId());
-			}
-		});
-			
-		for (int i = 0; i < sortedProperties.length; i++) {
-			if (i != 0 || includeDefault)
-				b.append(';');
-			b.append(sortedProperties[i].toString());
-		}
-		
-		return b.toString();
-	}
-
-	public Fetch<?,?> merge(Fetch<?,?> other) {
-		int newCount = this.properties.length;
-		boolean changedProperties = false;
-
-		// Count the total number of properties in the merge of the two fetches
-		
-		int thisIndex = 0, otherIndex = 0;
-		long thisOrdering = this.propertyOrdering(0);
-		long otherOrdering = other.propertyOrdering(0);
-		while (thisIndex < this.properties.length || otherIndex < other.properties.length) {
-			if (thisOrdering < otherOrdering) {
-				// Only in this fetch
-				thisOrdering = this.propertyOrdering(++thisIndex);
-			} else if (thisOrdering == otherOrdering) {
-				// In both fetches
-				if (!this.properties[thisIndex].equals(other.properties[otherIndex]))
-					changedProperties = true;
-				thisOrdering = this.propertyOrdering(++thisIndex);
-				otherOrdering = other.propertyOrdering(++otherIndex);
-			} else {
-				// Only in the other fetch
-				newCount++;
-				otherOrdering = other.propertyOrdering(++otherIndex);
-			}
-		}
-		
-		// If the other property is a subset of this one, we can just return this one
-		if (!changedProperties && newCount == this.properties.length && (this.includeDefault || !other.includeDefault))
-			return this;
-		
-		PropertyFetch[] newProperties = new PropertyFetch[newCount];
-		
-		int newIndex = 0;
-		thisIndex = 0; otherIndex = 0;
-		thisOrdering = this.propertyOrdering(0);
-		otherOrdering = other.propertyOrdering(0);
-		while (thisIndex < this.properties.length || otherIndex < other.properties.length) {
-			if (thisOrdering < otherOrdering) {
-				// Only in this fetch
-				newProperties[newIndex++] = this.properties[thisIndex];
-				thisOrdering = this.propertyOrdering(++thisIndex);
-			} else if (thisOrdering == otherOrdering) {
-				// In both fetches
-				newProperties[newIndex++] = this.properties[thisIndex].merge(other.properties[otherIndex]);
-				thisOrdering = this.propertyOrdering(++thisIndex);
-				otherOrdering = other.propertyOrdering(++otherIndex);
-			} else {
-				// Only in the other fetch
-				newProperties[newIndex++] = other.properties[otherIndex];
-				otherOrdering = other.propertyOrdering(++otherIndex);
-			}
-		}
-		
-		@SuppressWarnings("unchecked")
-		Fetch<?, ?> newFetch = new Fetch(newProperties, this.includeDefault || other.includeDefault);
-		
-		return newFetch;
-	}
-
-	public void resolveNotifications(StoreClient client, StoreKey<K,? extends T> key, long propertyMask, ClientNotificationSet result) {
-		DMPropertyHolder<K,? extends T,?>[] classProperties = key.getClassHolder().getProperties();
-		Fetch<?,?>[] childFetches = null;
-		int[] maxes = null;
-		long notifiedMask = 0;
-		
-		long bit = 1;
-		int classIndex = 0;
-		long propertyOrdering = propertyOrdering(0);
-		int propertyIndex = 0;
-		while (propertyMask != 0) {
-			if ((propertyMask & 1) != 0) {
-				long classOrdering = classOrdering(classProperties, classIndex);
-
-				while (propertyOrdering < classOrdering)
-					propertyOrdering = propertyOrdering(++propertyIndex);
-	
-				boolean notified = false;
-				Fetch<?,?> childFetch = null;
-				int max = -1;
-
-				if (propertyOrdering == classOrdering) {
-					if (properties[propertyIndex].getNotify()) {
-						notified = true;
-						childFetch = properties[propertyIndex].getChildren();
-						max = properties[propertyIndex].getMax();
-					}
-				} else if (includeDefault && classProperties[classIndex].getDefaultInclude()) {
-					notified = true;
-					childFetch = classProperties[classIndex].getDefaultChildren();
-				}
-				
-				if (notified)
-					notifiedMask |= bit;
-				
-				if (childFetch != null) {
-					if (childFetches == null)
-						childFetches = new Fetch[classProperties.length];
-					childFetches[classIndex] = childFetch;
-				}
-				
-				if (max >= 0) {
-					if (maxes == null) {
-						maxes = new int[classProperties.length];
-						for (int i = 0; i < classProperties.length; i++)
-							maxes[i] = -1; 
-					}
-					maxes[classIndex] = max;
-				}
-				
-			}
-			
-			propertyMask >>= 1;
-			bit <<= 1;
-			classIndex++;
-		}
-		
-		if (notifiedMask != 0)
-			result.addNotification(client, key, this, notifiedMask, childFetches, maxes);
-	}
-	
-	public <U extends T> String getFetchString(DMClassHolder<K,U> classHolder) {
-		DMPropertyHolder<K,U,?>[] classProperties = classHolder.getProperties();
-		
-		boolean allFetched = true;
-		boolean noneFetched = true;
-		
-		int propertyIndex = 0;
-		long propertyOrdering = propertyOrdering(0);
-		for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
-			long classOrdering = classOrdering(classProperties, classIndex);
-
-			while (propertyOrdering < classOrdering)
-				propertyOrdering = propertyOrdering(++propertyIndex);
-
-			boolean fetch = propertyOrdering == classOrdering || (includeDefault && classProperties[classIndex].getDefaultInclude());
-			
-			if (fetch)
-				noneFetched = false;
-			else
-				allFetched = false;
-		}
-		
-		if (noneFetched)
-			return "";
-		else if (allFetched)
-			return "*";
-
-		StringBuilder sb = new StringBuilder();
-			
-		propertyIndex = 0;
-		propertyOrdering = propertyOrdering(0);
-		for (int classIndex = 0; classIndex < classProperties.length; classIndex++) {
-			long classOrdering = classOrdering(classProperties, classIndex);
-
-			while (propertyOrdering < classOrdering)
-				propertyOrdering = propertyOrdering(++propertyIndex);
-			
-			boolean fetch = propertyOrdering == classOrdering || (includeDefault && classProperties[classIndex].getDefaultInclude());
-			
-			if (fetch)
-				appendToFetchString(sb, classProperties[classIndex], classHolder.mustQualifyProperty(classIndex));
-		}
-			
-		return sb.toString();
-	}
-}

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/FetchNode.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/FetchNode.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/FetchNode.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -23,7 +23,7 @@
 		return properties;
 	}
 	
-	public <K,T extends DMObject<K>> Fetch<K,T> bind(DMClassHolder<K,T> classHolder) {
+	public <K,T extends DMObject<K>> BoundFetch<K,T> bind(DMClassHolder<K,T> classHolder) {
 		boolean includeDefault = false;
 		
 		List<PropertyFetch> boundProperties = new ArrayList<PropertyFetch>(properties.length);
@@ -45,7 +45,7 @@
 
 		Collections.sort(boundProperties);
 		
-		return new Fetch<K,T>(boundProperties.toArray(new PropertyFetch[boundProperties.size()]), includeDefault);
+		return new BoundFetch<K,T>(boundProperties.toArray(new PropertyFetch[boundProperties.size()]), includeDefault);
 	}
 	
 	@Override

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/PropertyFetch.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/PropertyFetch.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/PropertyFetch.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -5,18 +5,18 @@
 
 public final class PropertyFetch implements Comparable<PropertyFetch> {
 	private DMPropertyHolder<?,?,?> property;
-	private Fetch<?,?> children;
+	private BoundFetch<?,?> children;
 	private boolean notify;
 	private int max;
 	
-	public PropertyFetch(DMPropertyHolder<?,?,?> property, Fetch<?,?> children, boolean notify, int max) {
+	public PropertyFetch(DMPropertyHolder<?,?,?> property, BoundFetch<?,?> children, boolean notify, int max) {
 		this.property = property;
 		this.children = children;
 		this.notify = notify;
 		this.max = max;
 	}
 
-	public Fetch<?,?> getChildren() {
+	public BoundFetch<?,?> getChildren() {
 		return children;
 	}
 
@@ -37,7 +37,7 @@
 		if (equals(other))
 			return this;
 		
-		Fetch<?, ?> newChildren;
+		BoundFetch<?, ?> newChildren;
 		
 		if (children == null)
 			newChildren = other.children;

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/PropertyFetchNode.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/PropertyFetchNode.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/fetch/PropertyFetchNode.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -42,8 +42,8 @@
 	}
 
 	public <K,T extends DMObject<K>> void bindResourceProperty(ResourcePropertyHolder<?,?,K,T> resourceHolder, List<PropertyFetch> resultList, boolean maybeSkip, boolean notify, int max) {
-		Fetch<K,T> defaultChildren = resourceHolder.getDefaultChildren();
-		Fetch<K,T> boundChildren = null;
+		BoundFetch<K,T> defaultChildren = resourceHolder.getDefaultChildren();
+		BoundFetch<K,T> boundChildren = null;
 		
 		if (maybeSkip && children == null && defaultChildren == null) {
 			return;

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMPropertyHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMPropertyHolder.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/DMPropertyHolder.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -31,7 +31,7 @@
 import com.dumbhippo.dm.annotations.DMProperty;
 import com.dumbhippo.dm.annotations.PropertyType;
 import com.dumbhippo.dm.annotations.ViewerDependent;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.filter.Filter;
 import com.dumbhippo.dm.parser.FilterParser;
@@ -301,7 +301,7 @@
 		return ordering < other.ordering ? -1 : (ordering == other.ordering ? 0 : 1);
 	}
 	
-	public abstract void visitChildren(DMSession session, Fetch<?,?> children, T object, FetchVisitor visitor);
+	public abstract void visitChildren(DMSession session, BoundFetch<?,?> children, T object, FetchVisitor visitor);
 	
 	/**
 	 * 
@@ -315,7 +315,7 @@
 	 */
 	public abstract void visitProperty(DMSession session, T object, FetchVisitor visitor, boolean forceEmpty);
 
-	public abstract Fetch<?,?> getDefaultChildren();
+	public abstract BoundFetch<?,?> getDefaultChildren();
 	public abstract String getDefaultChildrenString();
 	
 	public Class<?> getKeyClass() {

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/FeedPropertyHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/FeedPropertyHolder.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/FeedPropertyHolder.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -11,7 +11,7 @@
 import com.dumbhippo.dm.DMViewpoint;
 import com.dumbhippo.dm.DataModel;
 import com.dumbhippo.dm.annotations.PropertyType;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.filter.AndFilter;
 import com.dumbhippo.dm.filter.CompiledItemFilter;
@@ -109,12 +109,12 @@
 	 *    indicating that we have already returned the current contents of the feed to the client
 	 */
 	@SuppressWarnings("unchecked")
-	public long visitFeedChildren(DMSession session, Fetch<?,?> children, int start, int max, T object, FetchVisitor visitor, boolean forceAll) {
+	public long visitFeedChildren(DMSession session, BoundFetch<?,?> children, int start, int max, T object, FetchVisitor visitor, boolean forceAll) {
 		long minTimestamp = updateFeedTimestamp(session, object);
 		if (forceAll)
 			minTimestamp = 0;
 		
-		Fetch<KI,TI> typedChildren = (Fetch<KI,TI>)children;
+		BoundFetch<KI,TI> typedChildren = (BoundFetch<KI,TI>)children;
 		
 		Iterator<DMFeedItem<TI>> iter = ((DMFeed<TI>)getRawPropertyValue(object)).iterator(start, max, minTimestamp);
 		while (iter.hasNext()) {
@@ -162,7 +162,7 @@
 	
 
 	@Override
-	public void visitChildren(DMSession session, Fetch<?, ?> children, T object, FetchVisitor visitor) {
+	public void visitChildren(DMSession session, BoundFetch<?, ?> children, T object, FetchVisitor visitor) {
 		throw new UnsupportedOperationException("Must use visitFeedChildren");
 	}
 

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/ListResourcePropertyHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/ListResourcePropertyHolder.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/ListResourcePropertyHolder.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -9,7 +9,7 @@
 import com.dumbhippo.dm.DMObject;
 import com.dumbhippo.dm.DMSession;
 import com.dumbhippo.dm.DMViewpoint;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.filter.AndFilter;
 import com.dumbhippo.dm.filter.CompiledListFilter;
@@ -95,8 +95,8 @@
 
 	@Override
 	@SuppressWarnings("unchecked")
-	public void visitChildren(DMSession session, Fetch<?,?> children, T object, FetchVisitor visitor) {
-		Fetch<KI,TI> typedChildren = (Fetch<KI,TI>)children;
+	public void visitChildren(DMSession session, BoundFetch<?,?> children, T object, FetchVisitor visitor) {
+		BoundFetch<KI,TI> typedChildren = (BoundFetch<KI,TI>)children;
 		for (TI value : (List<TI>)getRawPropertyValue(object)) {
 			visitChild(session, typedChildren, value, visitor);
 		}

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/PlainPropertyHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/PlainPropertyHolder.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/PlainPropertyHolder.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -6,7 +6,7 @@
 import com.dumbhippo.dm.DMSession;
 import com.dumbhippo.dm.DMViewpoint;
 import com.dumbhippo.dm.annotations.PropertyType;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.filter.CompiledItemFilter;
 import com.dumbhippo.dm.filter.FilterCompiler;
@@ -99,7 +99,7 @@
 	}
 
 	@Override
-	public Fetch<?,?> getDefaultChildren() {
+	public BoundFetch<?,?> getDefaultChildren() {
 		return null;
 	}
 	
@@ -109,7 +109,7 @@
 	}
 
 	@Override
-	public void visitChildren(DMSession session, Fetch<?, ?> children, T object, FetchVisitor visitor) {
+	public void visitChildren(DMSession session, BoundFetch<?, ?> children, T object, FetchVisitor visitor) {
 	}
 	
 	protected void visitPlainValues(DMSession session, Collection<TI> values, FetchVisitor visitor) {

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/ResourcePropertyHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/ResourcePropertyHolder.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/ResourcePropertyHolder.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -6,7 +6,7 @@
 import com.dumbhippo.dm.DMObject;
 import com.dumbhippo.dm.DMSession;
 import com.dumbhippo.dm.annotations.PropertyType;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchNode;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.parser.FetchParser;
@@ -17,7 +17,7 @@
 	private DMClassHolder<KI,TI> resourceClassHolder;
 	protected Class<TI> itemObjectType;
 	protected Class<KI> itemKeyType;
-	private Fetch<KI,TI> defaultChildren;
+	private BoundFetch<KI,TI> defaultChildren;
 
 	public ResourcePropertyHolder(ResourcePropertyInfo<K,T,KI,TI> propertyInfo) {
 		super(propertyInfo);
@@ -58,7 +58,7 @@
 	}
 
 	@Override
-	public Fetch<KI,TI> getDefaultChildren() {
+	public BoundFetch<KI,TI> getDefaultChildren() {
 		return defaultChildren;
 	}
 	
@@ -101,7 +101,7 @@
 		return session.findUnchecked(itemObjectType, key);
 	}
 	
-	protected void visitChild(DMSession session, Fetch<KI,TI> children, TI value, FetchVisitor visitor) {
+	protected void visitChild(DMSession session, BoundFetch<KI,TI> children, TI value, FetchVisitor visitor) {
 		children.visit(session, resourceClassHolder, value, visitor, true);
 	}
 

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/SetResourcePropertyHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/SetResourcePropertyHolder.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/SetResourcePropertyHolder.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -9,7 +9,7 @@
 import com.dumbhippo.dm.DMObject;
 import com.dumbhippo.dm.DMSession;
 import com.dumbhippo.dm.DMViewpoint;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.filter.AndFilter;
 import com.dumbhippo.dm.filter.CompiledSetFilter;
@@ -95,8 +95,8 @@
 
 	@Override
 	@SuppressWarnings("unchecked")
-	public void visitChildren(DMSession session, Fetch<?,?> children, T object, FetchVisitor visitor) {
-		Fetch<KI,TI> typedChildren = (Fetch<KI,TI>)children;
+	public void visitChildren(DMSession session, BoundFetch<?,?> children, T object, FetchVisitor visitor) {
+		BoundFetch<KI,TI> typedChildren = (BoundFetch<KI,TI>)children;
 		for (TI value : (Set<TI>)getRawPropertyValue(object)) {
 			visitChild(session, typedChildren, value, visitor);
 		}

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/SingleResourcePropertyHolder.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/SingleResourcePropertyHolder.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/schema/SingleResourcePropertyHolder.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -4,7 +4,7 @@
 import com.dumbhippo.dm.DMObject;
 import com.dumbhippo.dm.DMSession;
 import com.dumbhippo.dm.DMViewpoint;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchVisitor;
 import com.dumbhippo.dm.filter.AndFilter;
 import com.dumbhippo.dm.filter.CompiledItemFilter;
@@ -79,8 +79,8 @@
 
 	@Override
 	@SuppressWarnings("unchecked")
-	public void visitChildren(DMSession session, Fetch<?,?> children, T object, FetchVisitor visitor) {
-		Fetch<KI,TI> typedChildren = (Fetch<KI,TI>)children;
+	public void visitChildren(DMSession session, BoundFetch<?,?> children, T object, FetchVisitor visitor) {
+		BoundFetch<KI,TI> typedChildren = (BoundFetch<KI,TI>)children;
 
 		TI value = (TI)getRawPropertyValue(object);
 		if (value != null)

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/store/DMStore.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/store/DMStore.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/store/DMStore.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -14,7 +14,7 @@
 import com.dumbhippo.dm.DMKey;
 import com.dumbhippo.dm.DMObject;
 import com.dumbhippo.dm.NotCachedException;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.schema.DMClassHolder;
 
 public class DMStore {
@@ -172,7 +172,7 @@
 		return new StoreClient(client);
 	}
 	
-	public <K, T extends DMObject<K>> Fetch<K,? super T> addRegistration(DMClassHolder<K,T> classHolder, K key, StoreClient client, Fetch<K,? super T> fetch) {
+	public <K, T extends DMObject<K>> BoundFetch<K,? super T> addRegistration(DMClassHolder<K,T> classHolder, K key, StoreClient client, BoundFetch<K,? super T> fetch) {
 		StoreNode<K,T> node;
 		Registration<K,T> registration;
 		
@@ -185,7 +185,7 @@
 			registration = node.createRegistration(client);
 		} while (registration == null);
 		
-		Fetch<K,? super T> oldFetch = registration.addFetch(fetch);
+		BoundFetch<K,? super T> oldFetch = registration.addFetch(fetch);
 		
 		// If the client is already closed, then we need to remove the registration we added,
 		// since it won't be cleaned up when the client is closed.

Modified: dumbhippo/trunk/server/src/com/dumbhippo/dm/store/Registration.java
===================================================================
--- dumbhippo/trunk/server/src/com/dumbhippo/dm/store/Registration.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/src/com/dumbhippo/dm/store/Registration.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -1,12 +1,12 @@
 package com.dumbhippo.dm.store;
 
 import com.dumbhippo.dm.DMObject;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 
 public class Registration<K, T extends DMObject<K>> {
 	private StoreClient client;
 	private StoreNode<K,T> node;
-	private Fetch<K,? super T> fetch;
+	private BoundFetch<K,? super T> fetch;
 	private long[] feedTxTimestamps;
 	
 	public Registration(StoreNode<K,T> node, StoreClient client) {
@@ -22,12 +22,12 @@
 		return client;
 	}
 
-	public synchronized Fetch<K,? super T> addFetch(Fetch<K,? super T> newFetch) {
-		Fetch<K,? super T> oldFetch = fetch;
+	public synchronized BoundFetch<K,? super T> addFetch(BoundFetch<K,? super T> newFetch) {
+		BoundFetch<K,? super T> oldFetch = fetch;
 		
 		if (oldFetch != null) {
 			@SuppressWarnings("unchecked")
-			Fetch<K, ? super T> mergedFetch = (Fetch<K, ? super T>)oldFetch.merge(newFetch);
+			BoundFetch<K, ? super T> mergedFetch = (BoundFetch<K, ? super T>)oldFetch.merge(newFetch);
 			fetch = mergedFetch;
 		} else
 			fetch = newFetch;
@@ -39,7 +39,7 @@
 		node.removeRegistration(this);
 	}
 
-	public synchronized Fetch<K,? super T> getFetch() {
+	public synchronized BoundFetch<K,? super T> getFetch() {
 		return fetch;
 	}
 

Modified: dumbhippo/trunk/server/tests/com/dumbhippo/dm/AbstractFetchTests.java
===================================================================
--- dumbhippo/trunk/server/tests/com/dumbhippo/dm/AbstractFetchTests.java	2007-12-10 17:15:15 UTC (rev 6998)
+++ dumbhippo/trunk/server/tests/com/dumbhippo/dm/AbstractFetchTests.java	2007-12-10 17:24:17 UTC (rev 6999)
@@ -14,7 +14,7 @@
 
 import com.dumbhippo.GlobalSetup;
 import com.dumbhippo.XmlBuilder;
-import com.dumbhippo.dm.fetch.Fetch;
+import com.dumbhippo.dm.fetch.BoundFetch;
 import com.dumbhippo.dm.fetch.FetchNode;
 import com.dumbhippo.dm.parser.FetchParser;
 import com.dumbhippo.dm.parser.ParseException;
@@ -121,7 +121,7 @@
 	
 	protected <K,T extends DMObject<K>> void doFetchTest(Class<K> keyClass, Class<T> objectClass, T object, String fetchString, String resultId, String... parameters) throws ParseException, FetchValidationException {
 		FetchNode fetchNode = FetchParser.parse(fetchString);
-		Fetch<K,T> fetch = fetchNode.bind(support.getModel().getClassHolder(keyClass, objectClass));
+		BoundFetch<K,T> fetch = fetchNode.bind(support.getModel().getClassHolder(keyClass, objectClass));
 		
 		FetchResultVisitor visitor = new FetchResultVisitor();
 		support.currentSessionRO().visitFetch(object, fetch, visitor);



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