diff --git a/spring-data-mongodb-cross-store/.classpath b/spring-data-mongodb-cross-store/.classpath index 399cc9b91..35f990ccf 100644 --- a/spring-data-mongodb-cross-store/.classpath +++ b/spring-data-mongodb-cross-store/.classpath @@ -4,7 +4,7 @@ - + diff --git a/spring-data-mongodb-cross-store/.settings/org.eclipse.jdt.core.prefs b/spring-data-mongodb-cross-store/.settings/org.eclipse.jdt.core.prefs index 2bafcc110..644302d5c 100644 --- a/spring-data-mongodb-cross-store/.settings/org.eclipse.jdt.core.prefs +++ b/spring-data-mongodb-cross-store/.settings/org.eclipse.jdt.core.prefs @@ -1,6 +1,9 @@ -#Mon Feb 28 16:26:01 EST 2011 +#Tue Mar 01 09:48:37 EST 2011 eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java new file mode 100644 index 000000000..7af1aed73 --- /dev/null +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java @@ -0,0 +1,120 @@ +package org.springframework.persistence.document; + +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.ConversionService; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.persistence.support.ChangeSet; +import org.springframework.persistence.support.ChangeSetBacked; +import org.springframework.persistence.support.ChangeSetPersister; +import org.springframework.util.ClassUtils; + +import com.mongodb.BasicDBObject; +import com.mongodb.DB; +import com.mongodb.DBCollection; +import com.mongodb.DBObject; +import com.mongodb.MongoException; + +//import edu.emory.mathcs.backport.java.util.Arrays; + +public class MongoChangeSetPersister implements ChangeSetPersister { + + protected final Log log = LogFactory.getLog(getClass()); + + @Autowired + private DB mongoDb; + + @Autowired + private ConversionService conversionService; + + @Override + public void getPersistentState(Class entityClass, Object id, ChangeSet changeSet) + throws DataAccessException, NotFoundException { + String collection = ClassUtils.getQualifiedName(entityClass); + DBObject q = new BasicDBObject(); + q.put("_id", id); + try { + DBObject dbo = mongoDb.getCollection(collection).findOne(q); + if (dbo == null) { + throw new NotFoundException(); + } + String classShortName = ClassUtils.getShortName(entityClass); + for (Object property : dbo.toMap().keySet()) { + String propertyKey = (String) property; + String propertyName = propertyKey.startsWith(classShortName) ? propertyKey.substring(propertyKey.indexOf(classShortName) + + classShortName.length() + 1) : propertyKey; + // System.err.println("Mongo persisted property [" + propertyName + "] :: " + propertyKey + " = " + dbo.get(propertyKey)); + if (propertyKey.startsWith("_")) { + // Id or class + changeSet.set(propertyName, dbo.get(propertyKey)); + } else { + //throw new IllegalStateException("Unknown property [" + propertyName + "] found in MongoDB store"); + changeSet.set(propertyName, dbo.get(propertyKey)); + } + } + } catch (MongoException ex) { + throw new DataAccessResourceFailureException("Can't read from Mongo", ex); + } + } + + @Override + public Object getPersistentId(Class entityClass, + ChangeSet cs) throws DataAccessException { + log.debug("getPersistentId called on " + entityClass); + if (cs == null) { + return null; + } + if (cs.getValues().get(ChangeSetPersister.ID_KEY) == null) { + // Not yet persistent + return null; + } + Object o = cs.getValues().get(ChangeSetPersister.ID_KEY); + return o; + } + + @Override + public Object persistState(Class entityClass, ChangeSet cs) throws DataAccessException { + log.info("PERSIST::"+cs); + cs.set(CLASS_KEY, entityClass.getName()); + String idstr = cs.get(ID_KEY, String.class, this.conversionService); + Object id = null; + if (idstr != null) { + id = idstr; + } + if (id == null) { + log.info("Flush: entity make persistent; data store will assign id"); + cs.set("_class", entityClass.getName()); + String collection = entityClass.getName(); + DBCollection dbc = mongoDb.getCollection(collection); + DBObject dbo = mapChangeSetToDbObject(cs); + if (dbc == null) { + dbc = mongoDb.createCollection(collection, dbo); + } + dbc.save(dbo); + id = dbo.get(ID_KEY); + } else { + log.info("Flush: entity already persistent with id=" + id); + String collection = entityClass.getName(); + DBCollection dbc = mongoDb.getCollection(collection); + DBObject dbo = mapChangeSetToDbObject(cs); + if (dbc == null) { + throw new DataAccessResourceFailureException("Expected to find a collection named '" + collection +"'. It was not found, so ChangeSet can't be persisted."); + } + dbc.save(dbo); + } + + return 0L; + } + + private DBObject mapChangeSetToDbObject(ChangeSet cs) { + BasicDBObject dbo = new BasicDBObject(); + for (String property : cs.getValues().keySet()) { + dbo.put(property, cs.getValues().get(property)); + } + return dbo; + } +} diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoDocumentBacking.aj b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoDocumentBacking.aj new file mode 100644 index 000000000..914c1efcf --- /dev/null +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoDocumentBacking.aj @@ -0,0 +1,12 @@ +package org.springframework.persistence.document; + +import org.springframework.persistence.support.AbstractDeferredUpdateMixinFields; + +/** + * Aspect to turn an object annotated with DocumentEntity into a document entity using Mongo. + * + * @author Thomas Risberg + */ +public aspect MongoDocumentBacking extends AbstractDeferredUpdateMixinFields { + +} diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java new file mode 100644 index 000000000..c812358da --- /dev/null +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java @@ -0,0 +1,58 @@ +package org.springframework.persistence.document; + +import java.lang.reflect.Field; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.persistence.OrderedEntityOperations; +import org.springframework.persistence.RelatedEntity; +import org.springframework.persistence.support.ChangeSetBacked; + +import com.mongodb.DB; + +public class MongoEntityOperations extends OrderedEntityOperations { + + @Autowired + private DB mongoDb; + + @Autowired + private MongoChangeSetPersister changeSetPersister; + + @Override + public boolean cacheInEntity() { + return true; + } + + @Override + public ChangeSetBacked findEntity(Class entityClass, Object pk) throws DataAccessException { + throw new UnsupportedOperationException(); + } + + @Override + public Object findUniqueKey(ChangeSetBacked entity) throws DataAccessException { + return entity.getId(); + } + + @Override + public boolean isTransactional() { + // TODO + return false; + } + + @Override + public boolean isTransient(ChangeSetBacked entity) throws DataAccessException { + return entity.getId() == null; + } + + @Override + public Object makePersistent(Object owner, ChangeSetBacked entity, Field f, RelatedEntity fs) throws DataAccessException { + changeSetPersister.persistState(entity.getClass(), entity.getChangeSet()); + return entity.getId(); + } + + @Override + public boolean supports(Class entityClass, RelatedEntity fs) { + return entityClass.isAnnotationPresent(DocumentEntity.class); + } + +} diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java index 6cc76521d..c9e863383 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java @@ -19,12 +19,11 @@ public class CrossStoreMongoTests { private Mongo mongo; @Test -// @Transactional -// @Rollback(false) + @Transactional + @Rollback(false) public void testUserConstructor() { int age = 33; MongoPerson p = new MongoPerson("Thomas", age); - //Assert.assertEquals(p.getRedisValue().getString("RedisPerson.name"), p.getName()); Assert.assertEquals(age, p.getAge()); p.birthday(); Assert.assertEquals(1 + age, p.getAge()); diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/MongoPerson.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/MongoPerson.java index c1a32ee02..d1ad5e3f8 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/MongoPerson.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/MongoPerson.java @@ -1,8 +1,11 @@ package org.springframework.data.document.persistence; +import javax.persistence.Entity; + import org.springframework.persistence.RelatedEntity; import org.springframework.persistence.document.DocumentEntity; +@Entity @DocumentEntity public class MongoPerson { diff --git a/spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml b/spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml index 0e0d85184..4ab9c2012 100644 --- a/spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml +++ b/spring-data-mongodb-cross-store/src/test/resources/META-INF/spring/applicationContext.xml @@ -1,7 +1,9 @@ + xmlns:tx="http://www.springframework.org/schema/tx" + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> @@ -16,4 +18,27 @@ + + + + + + + + + + + + + + + + + + + + + +