You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by si...@apache.org on 2011/06/07 18:40:32 UTC

svn commit: r1133089 - in /labs/magma/trunk/database-mongodb/src: main/java/org/apache/magma/database/mongo/ test/java/org/apache/magma/database/mongo/ test/java/org/apache/magma/database/mongo/test/domain/

Author: simoneg
Date: Tue Jun  7 16:40:31 2011
New Revision: 1133089

URL: http://svn.apache.org/viewvc?rev=1133089&view=rev
Log:
Preliminary, yet to be completely functional, support for embedded entities.
Sparse fixes on optimistic locking support

Added:
    labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/SubEntitiesTest.java   (with props)
    labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphNode.java   (with props)
    labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphRoot.java   (with props)
Modified:
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanCollectionModifiedListener.java
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanMapModifiedListener.java
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityDoc.aj
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityFindMains.aj
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityLazyRelations.aj
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityTransactionMethods.aj
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoUtils.java
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/Transaction.java
    labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/TransactionPart.java
    labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/BSONPieces.java
    labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/TransactionPartWritingTest.java
    labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/F1Team.java
    labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/Settings.java

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanCollectionModifiedListener.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanCollectionModifiedListener.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanCollectionModifiedListener.java (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanCollectionModifiedListener.java Tue Jun  7 16:40:31 2011
@@ -33,6 +33,8 @@ public class BeanCollectionModifiedListe
 		for (Object ac : delegate) {
 			if (ac instanceof MongoEntity) {
 				bsonList.add(MongoUtils.getMongoId((MongoEntity) ac));
+				if (prop.isSubEntity())
+					((MongoEntity)ac).joined(bean);
 			} else {
 				bsonList.add(MongoUtils.convertToMongo(ac));
 			}

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanMapModifiedListener.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanMapModifiedListener.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanMapModifiedListener.java (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/BeanMapModifiedListener.java Tue Jun  7 16:40:31 2011
@@ -57,6 +57,8 @@ public class BeanMapModifiedListener imp
 			Object val = entry.getValue();
 			if (val instanceof MongoEntity) {
 				MongoEntity mpval = (MongoEntity) val;
+				if (pi.isSubEntity() || mpval.beanData().isJpaSubEntity())
+					mpval.joined(bean);
 				bson.put(k, MongoUtils.getMongoId(mpval));
 			} else {
 				bson.put(k, MongoUtils.convertToMongo(val));

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityDoc.aj
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityDoc.aj?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityDoc.aj (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityDoc.aj Tue Jun  7 16:40:31 2011
@@ -1,6 +1,9 @@
 package org.apache.magma.database.mongo;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Set;
+import java.util.List;
 
 import javax.persistence.Transient;
 
@@ -14,6 +17,7 @@ import org.aspectj.lang.reflect.MethodSi
 import org.bson.BSONObject;
 
 import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
 
 public aspect MongoEntityDoc {
 
@@ -126,6 +130,7 @@ public aspect MongoEntityDoc {
 					bh.getValue(piname);
 				}
 			}
+			this.entityDocNeedsInit = false;
 		}
 	}
 	
@@ -133,4 +138,25 @@ public aspect MongoEntityDoc {
 		return this.myTransaction;
 	}
 		
+	BSONObject MongoEntity.findSub(String id) {
+		BSONObject md = checkGetBson();
+		return MongoUtils.findSub(id, md);
+	}
+	
+	List<String> MongoEntity.getSubIds() {
+		BSONObject md = checkGetBson();
+		Object beansobj = md.get("_beans");
+		if (beansobj == null || !(beansobj instanceof List)) return Collections.emptyList();
+		List<String> ret = new ArrayList<String>();
+		List beanslist = (List) beansobj;
+		for (Object object : beanslist) {
+			if (object == null || !(object instanceof BSONObject)) continue;
+			BSONObject subdb = (BSONObject) object;
+			String subid = (String) subdb.get("_id");
+			ret.add(subid);
+		}		
+		return ret;
+	}
+	
+	
 }

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityFindMains.aj
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityFindMains.aj?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityFindMains.aj (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityFindMains.aj Tue Jun  7 16:40:31 2011
@@ -37,9 +37,7 @@ public aspect MongoEntityFindMains {
 		dones.put(this,"a");
 		boolean loadedOnly = !cascade.equals(CascadeType.REMOVE);
 		BeanData bd = this.beanData();
-		if (!bd.isJpaSubEntity()) {
-			set.put(this,state);
-		}
+		set.put(this,state);
 		BeanHandler bh = this.handler();
 		List<PropertyInfo> rels = bd.getJpaRelationFields();
 		for (PropertyInfo pi : rels) {
@@ -90,7 +88,7 @@ public aspect MongoEntityFindMains {
 					loadeds.remove(val);					
 				}
 				for (Object object : loadeds) {
-					if (pi.isJpaDeleteOrphans()) {
+					if (pi.isJpaDeleteOrphans() || pi.isSubEntity()) {
 						((MongoEntity)object).findMainEntities(CascadeType.REMOVE, set, MainState.DELETEORPHAN, dones);
 					} else {
 						((MongoEntity)object).findMainEntities(cascade, set, MainState.ORPHAN, dones);

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityLazyRelations.aj
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityLazyRelations.aj?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityLazyRelations.aj (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityLazyRelations.aj Tue Jun  7 16:40:31 2011
@@ -28,6 +28,7 @@ import org.aspectj.lang.reflect.MethodSi
 import org.bson.BSONObject;
 
 import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
 
 public aspect MongoEntityLazyRelations {
 

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityTransactionMethods.aj
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityTransactionMethods.aj?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityTransactionMethods.aj (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoEntityTransactionMethods.aj Tue Jun  7 16:40:31 2011
@@ -23,10 +23,12 @@ public aspect MongoEntityTransactionMeth
 
 	private boolean MongoEntity.dirty = true;
 	private TransactionPart MongoEntity.part = null;
+	private MongoEntity MongoEntity.dirtyDelegate = null;
 	
 	TransactionPart MongoEntity.getPart() {
 		if (part == null) {
 			part = new TransactionPart();
+			part.init(this);
 		}
 		return part;
 	}
@@ -41,6 +43,27 @@ public aspect MongoEntityTransactionMeth
 
 	void MongoEntity.dirtied() {
 		this.dirty = true;
+		if (dirtyDelegate != null) {
+			dirtyDelegate.dirtied();
+		}
+	}
+	
+	void MongoEntity.joined(MongoEntity entity) {
+		if (dirtyDelegate != null) {
+			if (dirtyDelegate == entity) return;
+			dirtyDelegate.findRoot().getPart().disjoin(getPart());
+			getPart().populateBasics(this);
+		}
+		dirtyDelegate = entity;
+		getPart().joined(dirtyDelegate.findRoot().getPart());
+		if (entity != null && this.isDirty()) {
+			entity.dirtied();
+		}
+	}
+	
+	MongoEntity MongoEntity.findRoot() {
+		if (dirtyDelegate == null) return this;
+		return dirtyDelegate.findRoot();
 	}
 	
 	void MongoEntity.dirtyRemoved(PropertyInfo pi) {
@@ -71,8 +94,6 @@ public aspect MongoEntityTransactionMeth
 				}
 				bean.checkGetBson().put("_id", okval);
 				bean.dirtied();
-			} else if (pi.isSubEntity()) {
-				// TODO persist of an embedded doc
 			} else if (pi.isBasicType() || (pi.getType() != null && Enum.class.isAssignableFrom(pi.getType()))) {
 				// Basic types goes straight
 				bean.checkGetBson().put(pi.getJpaColName(), MongoUtils.convertToMongo(val));
@@ -106,6 +127,9 @@ public aspect MongoEntityTransactionMeth
 			}
 		}
 		proceed(bean, val);
+		if (pi.isSubEntity() && val != null && val instanceof MongoEntity) {
+			((MongoEntity)val).joined(bean);
+		}
 		bean.dirtyHandleProperty(pi, val);
 	}
 	

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoUtils.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoUtils.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoUtils.java (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/MongoUtils.java Tue Jun  7 16:40:31 2011
@@ -14,6 +14,8 @@ import org.apache.magma.conversion.Conve
 import org.apache.magma.database.InstallIdByDefault.WithDefaultId;
 import org.bson.BSONObject;
 
+import com.mongodb.BasicDBList;
+
 public class MongoUtils {
 
 	public static Object convertFromMongo(Object val, Class type) {
@@ -42,7 +44,6 @@ public class MongoUtils {
 			}
 		}
 		if (val instanceof Boolean) return val;
-		// TODO case of a subentity
 		if (val instanceof String) {
 			Converter c = Converters.getConverterFor(type);
 			if (c != null) {
@@ -58,7 +59,6 @@ public class MongoUtils {
 		if (val instanceof String) return val;
 		if (val instanceof Boolean) return val;
 		if (val instanceof MongoEntity) {
-			// TODO case of a subentity
 			return getMongoId((MongoEntity) val);
 		}
 		Class type = val.getClass();
@@ -72,7 +72,6 @@ public class MongoUtils {
 
 	public static String getMongoId(MongoEntity keyobj) {
 		keyobj.checkGetBson();
-		// XXX (??) add the class, so that polymorphic strctures can be restored
 		if (keyobj instanceof WithDefaultId) {
 			long id = ((WithDefaultId) keyobj).getId();
 			return Long.toHexString(id);
@@ -151,4 +150,42 @@ public class MongoUtils {
 		};
 	}
 	
+	public static BSONObject findSub(String id, BSONObject mainobj) {
+		Object beansobj = mainobj.get("_beans");
+		if (beansobj == null || !(beansobj instanceof List)) return null;
+		List beanslist = (List) beansobj;
+		for (Object object : beanslist) {
+			if (object == null || !(object instanceof BSONObject)) continue;
+			BSONObject subdb = (BSONObject) object;
+			String subid = (String) subdb.get("_id");
+			if (subid!= null && subid.equals(id)) return subdb; 
+		}
+		return null;
+	}
+
+	public static void addSub(BSONObject mainobj, BSONObject beanpart) {
+		Object beansobj = mainobj.get("_beans");
+		if (beansobj == null || !(beansobj instanceof List)) {
+			beansobj = new BasicDBList();
+			mainobj.put("_beans", beansobj);
+		}
+		List beanslist = (List) beansobj;
+		beanslist.add(beanpart);
+	}
+
+	public static void removeSub(String id, BSONObject mainobj) {
+		Object beansobj = mainobj.get("_beans");
+		if (beansobj == null || !(beansobj instanceof List)) return;
+		List beanslist = (List) beansobj;
+		if (beanslist.size() == 0) return;
+		for (Iterator iterator = beanslist.iterator(); iterator.hasNext();) {
+			Object object = (Object) iterator.next();
+			if (object == null || !(object instanceof BSONObject)) continue;
+			BSONObject subdb = (BSONObject) object;
+			String subid = (String) subdb.get("_id");
+			if (subid!= null && subid.equals(id)) {
+				iterator.remove();
+			}
+		}
+	}
 }

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/Transaction.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/Transaction.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/Transaction.java (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/Transaction.java Tue Jun  7 16:40:31 2011
@@ -44,6 +44,8 @@ public class Transaction {
 	private MongoDatabase db;
 	
 	private Map<String, MongoEntity> mainCache = new HashMap<String, MongoEntity>();
+	private Map<String,String> subsCache = new HashMap<String, String>();
+	
 	private WriteConcern writeConcern;
 	private List<MongoCursor> cursors = new ArrayList<MongoCursor>();
 	private Set<MongoEntity> confirmedSave = new HashSet<MongoEntity>();
@@ -83,11 +85,23 @@ public class Transaction {
 	
 	public <T extends MongoEntity> T checkCache(Class<T> clazz, String id) {
 		T ret = (T) mainCache.get(id);
+		if (ret != null) return ret;
+		String mainid = subsCache.get(id);
+		if (mainid == null) return null;
+		MongoEntity main = mainCache.get(mainid);
+		if (main == null) return null;
+		BSONObject subobj = main.findSub(id);
+		if (subobj == null) return null;
+		ret = (T) instantiateSub(main, clazz, subobj);
 		return ret;
 	}
 	
 	public void cache(String id, MongoEntity obj) {		
 		mainCache.put(id, obj);
+		List<String> subIds = obj.getSubIds();
+		for (String subid : subIds) {
+			subsCache.put(subid, id);
+		}
 	}		
 	
 	
@@ -196,11 +210,9 @@ public class Transaction {
 	
 
 	public void save(MongoEntity mpbean) {
-		mpbean.prepareForDb(this);
 		confirmedSave.add(mpbean);
 		Map<MongoEntity,MainState> mains = mpbean.findMainEntities(CascadeType.PERSIST);
 		for (MongoEntity entity : mains.keySet()) {
-			entity.prepareForDb(this);
 			entity.setOnDb(true);
 			addEntity(entity);
 			if (entity.isFromDb()) {
@@ -214,12 +226,10 @@ public class Transaction {
 
 
 	public void delete(MongoEntity mpbean) {
-		mpbean.prepareForDb(this);
-		mpbean.dirtied();
 		confirmedDelete.add(mpbean);
 		Map<MongoEntity,MainState> mains = mpbean.findMainEntities(CascadeType.REMOVE);
 		for (MongoEntity entity : mains.keySet()) {
-			entity.prepareForDb(this);
+			entity.dirtied();
 			entity.setOnDb(false);			
 			TransactionPart entpart = addEntity(entity);
 			entpart.deleted();
@@ -329,7 +339,7 @@ public class Transaction {
 		if (insert) return;
 		if (wr.getN() == 0) {
 			if (entity != null) {
-				throw new OptimisticLockException(entity);
+				throw new OptimisticLockException("While saving " + entity.getClass() + " : " + entity.checkGetBson().get("_id")+ " ver " + entity.checkGetBson().get("version"), null, entity);
 			}
 			throw new MagmaException("Server returned 0 inserts while saving {0}", entity != null ? entity : "transaction");
 		}		
@@ -363,6 +373,7 @@ public class Transaction {
 		for (MongoEntity ent : this.confirmedSave) {
 			TransactionPart part = ent.getPart();
 			if (part == null) continue;
+			// TODO Since this is not ordered, deletes could appear after cascades, deleting otherwise cascaded entities
 			Map<MongoEntity,MainState> mains = ent.findMainEntities(CascadeType.PERSIST);
 			for (Map.Entry<MongoEntity, MainState> entry : mains.entrySet()) {
 				MainState state = entry.getValue();
@@ -383,21 +394,45 @@ public class Transaction {
 		}
 		
 		for (MongoEntity deleting : todelete) {
+			if (tosave.contains(deleting)) continue;
 			deleting.getPart().deleted();
 			deleting.dirtied();
 			tosave.add(deleting);
 		}
 		
-		for (Iterator iterator = tosave.iterator(); iterator.hasNext();) {
-			MongoEntity saving = (MongoEntity) iterator.next();
-			if (saving.isFromDb() && !saving.isDirty())
-				iterator.remove();
-		}
+		{
+			Set<MongoEntity> mains = null;
+			do {
+				mains = new HashSet<MongoEntity>();
+				for (Iterator iterator = tosave.iterator(); iterator.hasNext();) {
+					MongoEntity saving = (MongoEntity) iterator.next();
+					if (saving.isFromDb() && !saving.isDirty()) {
+						iterator.remove();
+						continue;
+					}
+					
+					
+					this.addEntity(saving);
+					if (!saving.isFromDb())
+						saving.getPart().populateBasics(saving);
+
+					// FIXME remove this, is only for testing
+					saving.getPart().check();
+					
+					MongoEntity root = saving.findRoot();
+					// If this one is not a main entity, remove it from saving list and add the real entity to it
+					if (root != saving) {
+						iterator.remove();
+						mains.add(root);
+					}
+				}
+			} while (tosave.addAll(mains));
+		}		
 		
 		if (tosave.size() == 0) return;
 		
 		BasicDBObject entlist = new BasicDBObject();
-		
+
 		for (MongoEntity ent : tosave) {
 			MongoCollection coll = getCollection(ent.getClass());
 			String id = MongoUtils.getMongoId(ent);
@@ -424,7 +459,6 @@ public class Transaction {
 				TransactionPart part = ent.getPart();
 				MongoCollection coll = getCollection(ent.getClass());
 				String id = MongoUtils.getMongoId(ent);
-				WriteResult wr = null;
 				
 				BasicDBObject search = new BasicDBObject("_id", id);
 				if (ent.isFromDb()) {
@@ -456,7 +490,7 @@ public class Transaction {
 							search.append(vf.getJpaColName(), version);
 							bh.setValue(vf.getName(), version + 1);
 							nversion = version + 1;
-							// We need this because setVersion is not weaved by MongoPersistedImpl casue of LTW bugs 
+							// We need this because setVersion is not weaved by MongoEntity Impls cause of LTW bugs 
 							ent.checkGetBson().put(vf.getJpaColName(), version + 1);
 							bh.commit();
 						}
@@ -466,7 +500,6 @@ public class Transaction {
 					this.checkResult(coll.update(search, update, false, false, writeConcern), false, ent);
 				} else {
 					BasicDBObject insert = new BasicDBObject();
-					part.populateBasics(ent);
 					insert.put("version", 1);
 					BasicDBList trlist = new BasicDBList();
 					trlist.add(part);
@@ -552,6 +585,7 @@ public class Transaction {
 		}
 		this.cursors.clear();
 		this.mainCache.clear();
+		this.subsCache.clear();
 	}
 	
 	public MongoMetadata getMeta() {
@@ -567,4 +601,18 @@ public class Transaction {
 	}
 
 
+	public MongoEntity instantiateSub(MongoEntity main, Class clazz, BSONObject subobj) {
+		addEntity(main);
+		
+		MongoEntity subent = MongoUtils.convertToObject(clazz, subobj);
+		addEntity(subent);
+		subent.setFromDb(main.isFromDb());
+		subent.joined(main);
+		String oid = (String)subobj.get("_id");
+		cache(oid, subent);
+		
+		return subent;
+	}
+
+
 }

Modified: labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/TransactionPart.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/TransactionPart.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/TransactionPart.java (original)
+++ labs/magma/trunk/database-mongodb/src/main/java/org/apache/magma/database/mongo/TransactionPart.java Tue Jun  7 16:40:31 2011
@@ -1,5 +1,8 @@
 package org.apache.magma.database.mongo;
 
+import java.nio.channels.IllegalSelectorException;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -9,6 +12,7 @@ import org.apache.magma.beans.PropertyIn
 import org.bson.BSONObject;
 import org.junit.runner.manipulation.Sortable;
 
+import com.mongodb.BasicDBList;
 import com.mongodb.BasicDBObject;
 import com.mongodb.DBObject;
 
@@ -45,12 +49,19 @@ public class TransactionPart extends Bas
 	public String getTransactionId() {
 		return this.getString("__transactionId");
 	}
+	public String getObjectId() {
+		return this.getString("_id");
+	}
 	public void deleted() {
 		this.put("__deleted", true);
 	}
 	public boolean isDeleted() {
 		return this.getBoolean("__deleted", false);
 	}
+	public void init(MongoEntity ent) {
+		BSONObject bson = ent.checkGetBson();
+		this.put("_id", bson.get("_id"));
+	}
 	public void populateBasics(MongoEntity ent) {
 		BSONObject bson = ent.checkGetBson();
 		this.put("_jcl", bson.get("_jcl"));
@@ -64,16 +75,37 @@ public class TransactionPart extends Bas
 			if (pi.isJpaId() || pi.isJpaVersion()) continue;
 			Object val = handler.getValue(propname);
 			ent.dirtyModified(pi, val);
-		}
+		}	
 	}
 	public void reapply(BSONObject doc) {
 		for (String key : this.keySet()) {
 			if (key.startsWith("__")) continue;
-			Object object = this.get(key);
-			if (object == null) {
-				doc.removeField(key);
+			if (key.equals("_id") && doc.containsField("_id")) continue;
+			if (key.equals("_beans")) {
+				BasicDBList beans = (BasicDBList) this.get(key);
+				for (Object subobj : beans) {
+					DBObject sub = (DBObject) subobj;
+					TransactionPart subtr = new TransactionPart(sub);
+					// FIXME ignore it, remove it, but don't throw this exception
+					if (subtr.getObjectId() == null) throw new IllegalStateException("Found null id in a sub bean transaction update");
+					if (subtr.isDeleted()) {
+						MongoUtils.removeSub(subtr.getObjectId(), doc);
+					} else {
+						BSONObject beanpart = MongoUtils.findSub(subtr.getObjectId(), doc);
+						if (beanpart == null) {
+							beanpart = new BasicDBObject();
+							MongoUtils.addSub(doc, beanpart);
+						}
+						subtr.reapply(beanpart);
+					}
+				}
 			} else {
-				doc.put(key, object);
+				Object object = this.get(key);
+				if (object == null) {
+					doc.removeField(key);
+				} else {
+					doc.put(key, object);
+				}
 			}
 		}
 	}
@@ -81,4 +113,33 @@ public class TransactionPart extends Bas
 		return this.getTransactionId().compareTo(o.getTransactionId());
 	}
 	
+	public void joined(TransactionPart tp) {
+		BasicDBList beans = (BasicDBList) tp.get("_beans");
+		if (beans == null) {
+			beans = new BasicDBList();
+			tp.put("_beans", beans);
+		}
+		beans.add(this);
+	}
+	
+	public void disjoin(TransactionPart other) {
+		List<DBObject> beans = (List<DBObject>) get("_beans");
+		if (beans == null) return;
+		for (Iterator iterator = beans.iterator(); iterator.hasNext();) {
+			DBObject subobj = (DBObject) iterator.next();
+			if (subobj == other) {
+				iterator.remove();
+				break;
+			}
+		}
+		TransactionPart np = new TransactionPart();
+		np.put("_id", other.get("_id"));
+		np.deleted();
+		beans.add(np);
+	}
+
+	public void check() {
+		if (get("_id") == null) throw new IllegalStateException("Null id in " + this.toString());
+	}
+	
 }

Modified: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/BSONPieces.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/BSONPieces.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/BSONPieces.java (original)
+++ labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/BSONPieces.java Tue Jun  7 16:40:31 2011
@@ -1,14 +1,18 @@
 package org.apache.magma.database.mongo;
 
+import java.util.List;
+
 import org.apache.magma.database.mongo.test.domain.Address;
 import org.apache.magma.database.mongo.test.domain.Car;
 import org.apache.magma.database.mongo.test.domain.City;
 import org.apache.magma.database.mongo.test.domain.Person;
+import org.apache.magma.database.mongo.test.domain.Settings;
 import org.apache.magma.database.mongo.test.utils.MongoTestCursor;
 
 import static org.junit.Assert.*;
 import static org.hamcrest.CoreMatchers.*;
 
+import com.mongodb.BasicDBList;
 import com.mongodb.DBObject;
 import com.mongodb.util.JSON;
 
@@ -19,6 +23,7 @@ public class BSONPieces {
 	public static String cityId = "2296e47076130001";
 	public static String carId = "2296e47076130003";
 	public static String addressId = "2296e47076130005";
+	public static String emptyF1Id = "2296e47076130006";
 	
 	public static DBObject simplePerson = (DBObject) JSON.parse(
 			"{" + 
@@ -101,4 +106,60 @@ public class BSONPieces {
 		assertThat(a.getAddress(), equalTo("Via Tiburtina"));
 	}
 	
+	public static String createSettingsString(Settings s) {
+		String ret = "{";
+		ret += "\"_id\":";
+		ret += "\"" + Long.toHexString(LongObjectId.generate()) + "\"";
+		ret += ",";
+		if (s.getGreeting() != null) {
+			ret += "\"greeting\":";
+			ret += "\"" + s.getGreeting() + "\"";
+			ret += ",";
+		}
+		if (s.getOwner() != null) {
+			ret += "\"owner\":";
+			ret += "\"" + Long.toHexString(s.getOwner().getId()) + "\"";
+			ret += ",";			
+		}
+		if (s.getReferredTo() != null) {
+			ret += "\"referredTo\":";
+			ret += "\"" + Long.toHexString(s.getReferredTo().getId()) + "\"";
+			ret += ",";			
+		}
+		ret += "\"likesCoffee\":";
+		if (s.isLikesCoffee()) {
+			ret += "true";
+		} else {
+			ret += "false";
+		}
+		ret += "}";
+		return ret;
+	}
+	
+	public static DBObject createSettingsObject(Settings s) {
+		return (DBObject) JSON.parse(createSettingsString(s));
+	}
+	
+	
+	public static DBObject emptyF1 = (DBObject) JSON.parse(
+			"{" + 
+			"	\"_id\" : \"" + emptyF1Id + "\"," + 
+			"   \"_jcl\" : \"F1Team\"," +
+			"   \"version\": 1," +
+			"}" 
+		);
+	
+	public static void addBean(DBObject main, DBObject sub) {
+		List beans = (List) main.get("_beans");
+		if (beans == null) {
+			beans = new BasicDBList();
+			main.put("_beans", beans);
+		}
+		beans.add(sub);
+	}
+	
+	public static String getId(DBObject dbo) {
+		return (String)dbo.get("_id");
+	}
+	
 }

Added: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/SubEntitiesTest.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/SubEntitiesTest.java?rev=1133089&view=auto
==============================================================================
--- labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/SubEntitiesTest.java (added)
+++ labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/SubEntitiesTest.java Tue Jun  7 16:40:31 2011
@@ -0,0 +1,527 @@
+package org.apache.magma.database.mongo;
+
+import static org.apache.magma.database.mongo.test.utils.DBObjectMatcher.dbObject;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.magma.database.mongo.BSONPieces.*;
+
+import org.apache.magma.database.mongo.test.domain.F1Team;
+import org.apache.magma.database.mongo.test.domain.GraphNode;
+import org.apache.magma.database.mongo.test.domain.GraphRoot;
+import org.apache.magma.database.mongo.test.domain.Person;
+import org.apache.magma.database.mongo.test.domain.Settings;
+import org.apache.magma.database.mongo.test.utils.DBObjectMatcher;
+import org.apache.magma.database.mongo.test.utils.MongoTestCollection.Expect;
+import org.bson.BSONObject;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+import com.mongodb.DummyResultFactory;
+import com.mongodb.util.JSON;
+
+
+public class SubEntitiesTest extends MongoDbTestBase {
+
+	@Test
+	public void readASetting() throws Exception {
+		DBObject fdb = cloneDbo(simplePerson);
+		
+		DBObject sub = createSettingsObject(new Settings(true, "The great", null, null));
+		
+		fdb.put("settings", getId(sub));
+		addBean(fdb, sub);
+		
+		mdb.getCollection("test", "person")
+			.expectFindOne(dbObject("{'_id':'" + BSONPieces.simplePersonId + "'}"), fdb);
+		
+		Person p = db.load(Person.class, BSONPieces.simplePersonId);
+		
+		mdb.checkAll();
+		
+		assertThat(p, notNullValue());
+		Settings f1tset = p.getSettings();
+		assertThat(f1tset, notNullValue());
+		assertThat(f1tset.getGreeting(), equalTo("The great"));
+		assertThat(f1tset.isLikesCoffee(), equalTo(true));
+		assertThat(f1tset.isFromDb(), equalTo(true));
+	}
+	
+	@Test
+	public void readAList() throws Exception {
+		DBObject sp = cloneDbo(emptyF1);
+		
+		DBObject sub1 = createSettingsObject(new Settings(true, "Mr.", null, null));
+		DBObject sub2 = createSettingsObject(new Settings(true, "Master", null, null));
+		DBObject sub3 = createSettingsObject(new Settings(true, "Monster", null, null));
+		
+		BasicDBList list = new BasicDBList();
+		list.add(getId(sub1));
+		list.add(getId(sub2));
+		list.add(getId(sub3));
+		sp.put("settings", list);
+
+		addBean(sp, sub1);
+		addBean(sp, sub2);
+		addBean(sp, sub3);
+		
+		mdb.getCollection("test", "f1team")
+			.expectFindOne(dbObject("{'_id':'" + BSONPieces.emptyF1Id + "'}"), sp);
+		
+		F1Team f1t = db.load(F1Team.class, BSONPieces.emptyF1Id);
+		
+		mdb.checkAll();
+		
+		assertThat(f1t, notNullValue());
+		List<Settings> settings = f1t.getSettings();
+		
+		assertThat(settings, notNullValue());
+		assertThat(settings.size(), equalTo(3));
+		
+		assertThat(settings.get(0).getGreeting(), equalTo("Mr."));
+		assertThat(settings.get(0).isFromDb(), equalTo(true));
+		assertThat(settings.get(1).getGreeting(), equalTo("Master"));
+		assertThat(settings.get(2).getGreeting(), equalTo("Monster"));
+	}
+	
+	@Test
+	public void dirtySub() throws Exception {
+		Person p = new Person();
+		
+		p.clearDirty();
+		
+		Settings s = new Settings(false, "Mr.", null, null);
+		p.setSettings(s);
+		
+		assertThat(p.isDirty(), equalTo(true));
+
+		p.clearDirty();
+		s.clearDirty();
+		
+		s.setGreeting("Hello Mr.");
+
+		assertThat(s.isDirty(), equalTo(true));
+		assertThat(p.isDirty(), equalTo(true));		
+	}
+
+	@Test
+	public void dirtySubList() throws Exception {
+		F1Team f1t = new F1Team();
+		f1t.clearDirty();
+		
+		Settings s = new Settings(false, "Mr.", null, null);
+		f1t.getSettings().add(s);
+		
+		assertThat(f1t.isDirty(), equalTo(true));
+		
+		f1t.clearDirty();
+		s.clearDirty();
+		
+		s.setGreeting("Goodbye Mr.");
+		
+		assertThat(s.isDirty(), equalTo(true));
+		assertThat(f1t.isDirty(), equalTo(true));				
+	}
+	
+	@Test
+	public void checkTransactionPart() throws Exception {
+		Person p = new Person();
+		Settings s = new Settings(false, "Mr.", null, null);
+		p.setSettings(s);
+		
+		TransactionPart part = p.getPart();
+		part.populateBasics(p);
+		TransactionPart subpart = s.getPart();
+		subpart.populateBasics(s);
+		
+		Object beans = part.get("_beans");
+		assertThat(beans, notNullValue());
+		assertThat(beans, instanceOf(List.class));
+		List lb = (List) beans;
+		assertThat(lb.size(), equalTo(1));
+		Object sub = lb.get(0);
+		assertThat(sub, notNullValue());
+		assertThat(sub, instanceOf(BSONObject.class));
+		BSONObject subdb = (BSONObject) sub;
+		assertThat((String)subdb.get("greeting"), equalTo("Mr."));
+		
+		s.setGreeting("Hello Mr.");
+
+		assertThat((String)subdb.get("greeting"), equalTo("Hello Mr."));
+	}
+	
+	@Test
+	public void transactionPartApply() throws Exception {
+		Person p = new Person();
+		p.setName("Test");
+		Settings s = new Settings(false, "Mr.", null, null);
+		p.setSettings(s);
+		
+		TransactionPart part = p.getPart();
+		part.populateBasics(p);
+		TransactionPart subpart = s.getPart();
+		subpart.populateBasics(s);
+		
+
+		DBObject dbo = new BasicDBObject();
+		
+		part.reapply(dbo);
+		
+		assertThat((String)dbo.get("name"), equalTo("Test"));
+		Object beansobj = dbo.get("_beans");
+		assertThat(beansobj, notNullValue());
+		List beans = (List)beansobj;
+		assertThat(beans.size(), equalTo(1));
+		Object subobj = beans.get(0);
+		assertThat(subobj, notNullValue());
+		assertThat(subobj, instanceOf(DBObject.class));
+		DBObject subdbo = (DBObject) subobj;
+		assertThat((String)subdbo.get("greeting"), equalTo("Mr."));
+	}
+	
+	@Test
+	public void writeBasicSub() throws Exception {
+		Person p = new Person();
+		p.setName("Simone");
+		Settings s = new Settings(false, "Mr.", null, null);
+		p.setSettings(s);
+		
+		db.save(p);
+
+		mdb.checkAll();
+		
+		mdb.getCollection("test", "person")
+			.expectInsert(dbObject("{'version': 1, '__transactions': [{'__transactionId' : '" + tr.getId() + "', 'name' :'Simone', '_jcl':'Person', 'settings':'" + Long.toHexString(s.getId()) + "', '_beans' : [{'_jcl':'Settings','greeting':'Mr.'}]}]}"));
+	
+		mdb.getCollection("test", "transactions")
+			.clearExpectations()
+			.expectInsert(dbObject("{'_id' : '" + tr.getId() + "', 'state':'R', 'entities' : {'person' : ['" + Long.toHexString(p.getId()) + "'],'settings':'__NOTPRESENT__'} }"))
+			.expectUpdate(dbObject("{'_id' : '" + tr.getId() + "'}"),dbObject("{'$set': {'state':'D'}}"));
+			
+		db.commit();
+		mdb.checkAll();
+	}
+	
+	@Test
+	public void updateSimple() throws Exception {
+		DBObject fdb = cloneDbo(simplePerson);
+		
+		DBObject sub = createSettingsObject(new Settings(true, "The great", null, null));
+		
+		fdb.put("settings", getId(sub));
+		addBean(fdb, sub);
+		
+		mdb.getCollection("test", "person")
+			.expectFindOne(dbObject("{'_id':'" + BSONPieces.simplePersonId + "'}"), fdb);
+		
+		Person p = db.load(Person.class, BSONPieces.simplePersonId);
+		Settings s = p.getSettings();
+		s.setGreeting("Test");
+		db.save(p);
+
+		mdb.getCollection("test", "person")
+			.expectUpdate(
+					dbObject("{'_id':'" + Long.toHexString(p.getId()) + "'}"),
+					dbObject("{'$push': {'__transactions': {'__transactionId' : '" + tr.getId() + "', '_beans' : [{'greeting':'Test','_id':'" + Long.toHexString(s.getId()) + "'}]}}}"));
+	
+		mdb.getCollection("test", "transactions")
+			.clearExpectations()
+			.expectInsert(dbObject("{'_id' : '" + tr.getId() + "', 'state':'R', 'entities' : {'person' : ['" + Long.toHexString(p.getId()) + "'],'settings':'__NOTPRESENT__'} }"))
+			.expectUpdate(dbObject("{'_id' : '" + tr.getId() + "'}"),dbObject("{'$set': {'state':'D'}}"));
+			
+		db.commit();
+		mdb.checkAll();
+		
+		
+
+	}
+	
+	@Test
+	public void writeListSub() throws Exception {
+		F1Team f1t = new F1Team();
+		f1t.setCar(null);
+		Settings s = new Settings(false, "Mr.", null, null);
+		Settings s2 = new Settings(false, "Master", null, null);
+		List<Settings> settings = f1t.getSettings();
+		settings.add(s);
+		settings.add(s2);
+		
+		db.save(f1t);
+
+		mdb.checkAll();
+		
+		mdb.getCollection("test", "f1team")
+			.expectInsert(dbObject("{'version': 1, '__transactions': [{'__transactionId' : '" + tr.getId() + "', '_jcl':'F1Team', 'settings':['" + Long.toHexString(s.getId()) + "','" + Long.toHexString(s2.getId()) + "'], '_beans' : [{'_jcl':'Settings','greeting':'Mr.'},{'_jcl':'Settings','greeting':'Master'}]}]}"));
+	
+		mdb.getCollection("test", "transactions")
+			.clearExpectations()
+			.expectInsert(dbObject("{'_id' : '" + tr.getId() + "', 'state':'R', 'entities' : {'f1team' : ['" + Long.toHexString(f1t.getId()) + "'],'settings':'__NOTPRESENT__'} }"))
+			.expectUpdate(dbObject("{'_id' : '" + tr.getId() + "'}"),dbObject("{'$set': {'state':'D'}}"));
+			
+		db.commit();
+		mdb.checkAll();
+
+	}
+	
+	@Test
+	public void listUpdate() throws Exception {
+		DBObject sp = cloneDbo(emptyF1);
+		
+		DBObject sub1 = createSettingsObject(new Settings(true, "Mr.", null, null));
+		DBObject sub2 = createSettingsObject(new Settings(true, "Master", null, null));
+		DBObject sub3 = createSettingsObject(new Settings(true, "Monster", null, null));
+		
+		BasicDBList list = new BasicDBList();
+		list.add(getId(sub1));
+		list.add(getId(sub2));
+		list.add(getId(sub3));
+		sp.put("settings", list);
+
+		addBean(sp, sub1);
+		addBean(sp, sub2);
+		addBean(sp, sub3);
+		
+		mdb.getCollection("test", "f1team")
+			.expectFindOne(dbObject("{'_id':'" + BSONPieces.emptyF1Id + "'}"), sp);
+		
+		F1Team f1t = db.load(F1Team.class, BSONPieces.emptyF1Id);
+		
+		mdb.checkAll();
+		
+		Settings s = f1t.getSettings().get(0);
+		s.setGreeting("Test");
+		db.save(f1t);
+		
+		mdb.getCollection("test", "f1team")
+			.expectUpdate(
+					dbObject("{'_id':'" + Long.toHexString(f1t.getId()) + "'}"),
+					dbObject("{'$push': {'__transactions': {'__transactionId' : '" + tr.getId() + "', '_beans' : [{'greeting':'Test','_id':'" + Long.toHexString(s.getId()) + "'}]}}}"));
+	
+		mdb.getCollection("test", "transactions")
+			.clearExpectations()
+			.expectInsert(dbObject("{'_id' : '" + tr.getId() + "', 'state':'R', 'entities' : {'f1team' : ['" + Long.toHexString(f1t.getId()) + "'],'settings':'__NOTPRESENT__'} }"))
+			.expectUpdate(dbObject("{'_id' : '" + tr.getId() + "'}"),dbObject("{'$set': {'state':'D'}}"));
+			
+		db.commit();
+		mdb.checkAll();
+		
+
+	}
+	
+	@Test
+	public void subEntityRemove() throws Exception {
+		DBObject fdb = cloneDbo(simplePerson);
+		
+		DBObject sub = createSettingsObject(new Settings(true, "The great", null, null));
+		
+		fdb.put("settings", getId(sub));
+		addBean(fdb, sub);
+		
+		mdb.getCollection("test", "person")
+			.expectFindOne(dbObject("{'_id':'" + BSONPieces.simplePersonId + "'}"), fdb);
+		
+		Person p = db.load(Person.class, BSONPieces.simplePersonId);
+		Settings s = p.getSettings();
+		Settings s2 = new Settings(false,"Mr.", null, null);
+		p.setSettings(s2);
+		db.save(p);
+
+		DBObjectMatcher partmatch = dbObject("{'$push': {'__transactions': {'__transactionId' : '" + tr.getId() + "', '_beans' : [{'_id':'" + Long.toHexString(s.getId()) + "','__deleted':true},{'_id':'" + Long.toHexString(s2.getId()) + "','greeting':'Mr.'}]}}}");
+		mdb.getCollection("test", "person")
+			.expectUpdate(
+					dbObject("{'_id':'" + Long.toHexString(p.getId()) + "'}"),
+					partmatch);
+	
+		mdb.getCollection("test", "transactions")
+			.clearExpectations()
+			.expectInsert(dbObject("{'_id' : '" + tr.getId() + "', 'state':'R', 'entities' : {'person' : ['" + Long.toHexString(p.getId()) + "'],'settings':'__NOTPRESENT__'} }"))
+			.expectUpdate(dbObject("{'_id' : '" + tr.getId() + "'}"),dbObject("{'$set': {'state':'D'}}"));
+			
+		db.commit();
+		mdb.checkAll();		
+		
+		// Check applying the part
+		DBObject part = partmatch.getObtained();
+		part = (DBObject) part.get("$push");
+		part = (DBObject) part.get("__transactions");
+		
+		TransactionPart tp = new TransactionPart(part);
+		
+		tp.reapply(fdb);
+		
+		BSONObject sdbo = MongoUtils.findSub(Long.toHexString(s.getId()), fdb);
+		BSONObject s2dbo = MongoUtils.findSub(Long.toHexString(s2.getId()), fdb);
+
+		assertThat(((List)fdb.get("_beans")).size(), equalTo(1));
+		assertThat(sdbo, nullValue());
+		assertThat(s2dbo, notNullValue());
+		
+	}
+	
+	@Test
+	public void treeWriteTest() throws Exception {
+		GraphRoot gr = new GraphRoot();
+		
+		int cnt = 0;
+		// Create a tree
+		for (int i = 0; i < 10; i++) {
+			GraphNode branch = new GraphNode("Branch " + i);
+			gr.getRoots().add(branch);
+			cnt++;
+			for (int j = 0; j < 10; j++) {
+				GraphNode leaf = new GraphNode("Leaf " + i + "-" + j);
+				branch.addSub(leaf);
+				cnt++;
+			}
+		}
+		
+		db.save(gr);
+
+		mdb.checkAll();
+
+		DBObjectMatcher match = dbObject("{'version': 1, '__transactions': [{'__transactionId' : '" + tr.getId() + "'}]}");
+		
+		mdb.getCollection("test", "graphroot")
+			.expectInsert(match);
+
+		db.commit();
+		
+		DBObject part = match.getObtained();
+		
+		System.out.println(JSON.serialize(part));
+		List transactions = (List) part.get("__transactions");
+		part = (DBObject) transactions.get(0);
+		
+		Object beansobj = part.get("_beans");
+		assertThat(beansobj, notNullValue());
+		assertThat(beansobj, instanceOf(List.class));
+		List<DBObject> beans = (List<DBObject>) beansobj;
+		assertThat(beans.size(), equalTo(cnt));
+		
+		for (DBObject dbo : beans) {
+			Object subbeans = dbo.get("_beans");
+			if (subbeans != null) {
+				assertThat(subbeans, instanceOf(List.class));
+				assertThat(((List)subbeans).size(), equalTo(0));
+			}
+		}
+	}
+
+	// TODO this does not work at all
+	/*
+	@Test
+	public void graphWriteTest() throws Exception {
+		GraphRoot gr = new GraphRoot();
+		
+		int cnt = 0;
+		// Create some nodes
+		
+		List<GraphNode> nodes = new ArrayList<GraphNode>();
+		for (int i = 0; i < 20; i++) {
+			GraphNode branch = new GraphNode("Node " + i);
+			nodes.add(branch);
+			cnt++;
+		}
+		
+		gr.getRoots().addAll(nodes);		
+		
+		for (GraphNode node : nodes) {
+			node.getSubs().addAll(nodes);
+		}
+		
+		
+		db.save(gr);
+		mdb.checkAll();
+		DBObjectMatcher match = dbObject("{'version': 1, '__transactions': [{'__transactionId' : '" + tr.getId() + "'}]}");
+		mdb.getCollection("test", "graphroot")
+			.expectInsert(match);
+		db.commit();
+		
+		DBObject part = match.getObtained();
+		
+		System.out.println(JSON.serialize(part));
+		List transactions = (List) part.get("__transactions");
+		part = (DBObject) transactions.get(0);
+		
+		Object beansobj = part.get("_beans");
+		assertThat(beansobj, notNullValue());
+		assertThat(beansobj, instanceOf(List.class));
+		List<DBObject> beans = (List<DBObject>) beansobj;
+		assertThat(beans.size(), equalTo(cnt));
+		
+		for (DBObject dbo : beans) {
+			Object subbeans = dbo.get("_beans");
+			if (subbeans != null) {
+				assertThat(subbeans, instanceOf(List.class));
+				assertThat(((List)subbeans).size(), equalTo(0));
+			}
+		}
+		
+
+	}
+	*/
+	
+	@Test
+	public void subMove() throws Exception {
+		DBObject fdb = cloneDbo(simplePerson);
+		
+		DBObject sub = createSettingsObject(new Settings(true, "The great", null, null));
+		String subid = getId(sub);
+		fdb.put("settings", subid);
+		addBean(fdb, sub);
+		
+		mdb.getCollection("test", "person")
+			.expectFindOne(dbObject("{'_id':'" + BSONPieces.simplePersonId + "'}"), fdb);
+		
+		Person p = db.load(Person.class, BSONPieces.simplePersonId);
+		Settings s = p.getSettings();
+		p.setSettings(null);
+		
+		Person p2 = new Person();
+		p2.setSettings(s);
+		
+		db.save(p);
+		db.save(p2);
+
+		mdb.getCollection("test", "person")
+			.addExpectation(new Expect("update", new Matcher[] { 
+						dbObject("{'_id':'" + Long.toHexString(p.getId()) + "'}"),
+						dbObject("{'$push' : {'__transactions':{'settings':'__NULL__','_beans':[{'_id':'" + subid + "','__deleted':true}]}}}"),anything(), anything(), anything() 
+					}, DummyResultFactory.ok(1), true, false))
+			.addExpectation(new Expect("insert", new Matcher[] { 
+					dbObject("{'_id':'" + Long.toHexString(p2.getId()) + "','__transactions':[{'settings':'" + subid + "','_beans':[{'_id':'" + subid + "','greeting':'The great','__deleted':'__NOTPRESENT__'}]}]}"),anything(), anything(), anything() 
+					}, DummyResultFactory.ok(1), true, false));
+	
+		mdb.getCollection("test", "transactions")
+			.clearExpectations()
+			.expectInsert(dbObject("{'_id' : '" + tr.getId() + "', 'state':'R', 'entities' : {'person' : ['" + Long.toHexString(p.getId()) + "','" + Long.toHexString(p2.getId()) + "'],'settings':'__NOTPRESENT__'} }"))
+			.expectUpdate(dbObject("{'_id' : '" + tr.getId() + "'}"),dbObject("{'$set': {'state':'D'}}"));
+			
+		db.commit();
+		mdb.checkAll();
+		
+
+	}
+	
+	// TODO more graph tests
+	
+	
+	// TODO test passing a subobj between two mains
+	
+	// TODO test writing a map
+	
+	// TODO test updating a map subentity	
+
+	// TODO test list elements removal
+	
+	// TODO test map elements removal
+	
+	// TODO test persisting a graph of subentities
+	
+}

Propchange: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/SubEntitiesTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/TransactionPartWritingTest.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/TransactionPartWritingTest.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/TransactionPartWritingTest.java (original)
+++ labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/TransactionPartWritingTest.java Tue Jun  7 16:40:31 2011
@@ -11,7 +11,6 @@ import org.apache.magma.database.mongo.t
 import org.apache.magma.database.mongo.test.domain.F1Team;
 import org.apache.magma.database.mongo.test.domain.Person;
 import org.apache.magma.database.mongo.test.domain.Person.PersonType;
-import org.apache.magma.database.mongo.test.domain.Settings;
 import org.apache.magma.database.mongo.test.utils.MongoTestCollection.Expect;
 import org.hamcrest.Matcher;
 import org.junit.Test;

Modified: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/F1Team.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/F1Team.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/F1Team.java (original)
+++ labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/F1Team.java Tue Jun  7 16:40:31 2011
@@ -16,6 +16,7 @@ public class F1Team {
 
 	private Car car = new Car();
 	private List<Person> fans = new ArrayList<Person>();
+	private List<Settings> settings = new ArrayList<Settings>();
 	
 	public F1Team() {}
 	
@@ -44,5 +45,14 @@ public class F1Team {
 	public void setFans(List<Person> fans) {
 		this.fans = fans;
 	}
+
+	@OneToMany
+	public List<Settings> getSettings() {
+		return settings;
+	}
+	public void setSettings(List<Settings> settings) {
+		this.settings = settings;
+	}
+
 	
 }

Added: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphNode.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphNode.java?rev=1133089&view=auto
==============================================================================
--- labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphNode.java (added)
+++ labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphNode.java Tue Jun  7 16:40:31 2011
@@ -0,0 +1,43 @@
+package org.apache.magma.database.mongo.test.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+
+import org.apache.magma.beans.MagmaBean;
+import org.apache.magma.database.mongo.SubEntity;
+
+@Entity
+@SubEntity
+@MagmaBean
+public class GraphNode {
+
+	private String name;
+	private List<GraphNode> subs = new ArrayList<GraphNode>();
+	
+	public GraphNode(String name) {
+		this.name = name;
+	}
+	
+	
+	public List<GraphNode> getSubs() {
+		return subs;
+	}
+	public void setSubs(List<GraphNode> subs) {
+		this.subs = subs;
+	}
+	
+	public GraphNode addSub(GraphNode sub) {
+		this.getSubs().add(sub);
+		return this;
+	}
+	
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	
+}

Propchange: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphNode.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphRoot.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphRoot.java?rev=1133089&view=auto
==============================================================================
--- labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphRoot.java (added)
+++ labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphRoot.java Tue Jun  7 16:40:31 2011
@@ -0,0 +1,23 @@
+package org.apache.magma.database.mongo.test.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Entity;
+
+import org.apache.magma.beans.MagmaBean;
+
+@Entity
+@MagmaBean
+public class GraphRoot {
+
+	private List<GraphNode> roots = new ArrayList<GraphNode>();
+
+	public List<GraphNode> getRoots() {
+		return roots;
+	}
+	public void setRoots(List<GraphNode> roots) {
+		this.roots = roots;
+	}
+	
+}

Propchange: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/GraphRoot.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/Settings.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/Settings.java?rev=1133089&r1=1133088&r2=1133089&view=diff
==============================================================================
--- labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/Settings.java (original)
+++ labs/magma/trunk/database-mongodb/src/test/java/org/apache/magma/database/mongo/test/domain/Settings.java Tue Jun  7 16:40:31 2011
@@ -1,12 +1,31 @@
 package org.apache.magma.database.mongo.test.domain;
 
 import javax.persistence.Entity;
+import javax.persistence.OneToOne;
+
+import org.apache.magma.database.mongo.SubEntity;
 
 @Entity
+@SubEntity
 public class Settings {
 
 	private boolean likesCoffee;
 	private String greeting;
+	private Person owner;
+	private Car referredTo;
+	
+	public Settings(boolean likesCoffee, String greeting, Person owner, Car referredTo) {
+		this.likesCoffee = likesCoffee;
+		this.greeting = greeting;
+		this.owner = owner;
+		this.referredTo = referredTo;
+	}
+
+
+
+	public Settings() {}
+	
+	
 	
 	public boolean isLikesCoffee() {
 		return likesCoffee;
@@ -20,5 +39,20 @@ public class Settings {
 	public void setGreeting(String greeting) {
 		this.greeting = greeting;
 	}
+	@OneToOne
+	public Person getOwner() {
+		return owner;
+	}
+	public void setOwner(Person owner) {
+		this.owner = owner;
+	}
+	
+	@OneToOne
+	public Car getReferredTo() {
+		return referredTo;
+	}
+	public void setReferredTo(Car referredTo) {
+		this.referredTo = referredTo;
+	}
 	
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org