diff --git a/spring-data-mongodb-cross-store/pom.xml b/spring-data-mongodb-cross-store/pom.xml index f19aff501..e0db5fa7e 100644 --- a/spring-data-mongodb-cross-store/pom.xml +++ b/spring-data-mongodb-cross-store/pom.xml @@ -21,20 +21,30 @@ org.springframework spring-tx + + org.springframework + spring-aspects + ${org.springframework.version} + org.springframework spring-orm + + org.springframework + spring-test + test + org.springframework.data spring-data-commons-core - + org.springframework.data spring-data-mongodb @@ -197,10 +207,10 @@ org.springframework spring-aspects - + 1.6 1.6 diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/DocumentBacked.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/DocumentBacked.java new file mode 100644 index 000000000..5e29f6fab --- /dev/null +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/DocumentBacked.java @@ -0,0 +1,7 @@ +package org.springframework.data.persistence.document; + +import org.springframework.data.support.ChangeSetBacked; + +public interface DocumentBacked extends ChangeSetBacked { + +} diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/DocumentBackedTransactionSynchronization.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/DocumentBackedTransactionSynchronization.java new file mode 100644 index 000000000..7aa23ccfc --- /dev/null +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/DocumentBackedTransactionSynchronization.java @@ -0,0 +1,70 @@ +package org.springframework.data.persistence.document; + +//public class DocumentBackedTransactionSynchronization { + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.data.support.ChangeSetBacked; +import org.springframework.data.support.ChangeSetPersister; +import org.springframework.transaction.support.TransactionSynchronization; + +public class DocumentBackedTransactionSynchronization implements TransactionSynchronization { + + protected final Log log = LogFactory.getLog(getClass()); + + private ChangeSetPersister changeSetPersister; + + private ChangeSetBacked entity; + + private int changeSetTxStatus = -1; + + public DocumentBackedTransactionSynchronization(ChangeSetPersister changeSetPersister, ChangeSetBacked entity) { + this.changeSetPersister = changeSetPersister; + this.entity = entity; + } + + @Override + public void afterCommit() { + log.debug("After Commit called for " + entity); + changeSetPersister.persistState(entity.getClass(), entity.getChangeSet()); + changeSetTxStatus = 0; + } + + @Override + public void afterCompletion(int status) { + log.debug("After Completion called with status = " + status); + if (changeSetTxStatus == 0) { + if (status == STATUS_COMMITTED) { + // this is good + log.debug("ChangedSetBackedTransactionSynchronization completed successfully for " + this.entity); + } + else { + // this could be bad - TODO: compensate + log.error("ChangedSetBackedTransactionSynchronization failed for " + this.entity); + } + } + } + + @Override + public void beforeCommit(boolean readOnly) { + } + + @Override + public void beforeCompletion() { + } + + @Override + public void flush() { + } + + @Override + public void resume() { + throw new IllegalStateException("ChangedSetBackedTransactionSynchronization does not support transaction suspension currently."); + } + + @Override + public void suspend() { + throw new IllegalStateException("ChangedSetBackedTransactionSynchronization does not support transaction suspension currently."); + } + +} diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/mongo/MongoChangeSetPersister.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/mongo/MongoChangeSetPersister.java new file mode 100644 index 000000000..a67c3f289 --- /dev/null +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/mongo/MongoChangeSetPersister.java @@ -0,0 +1,138 @@ +package org.springframework.data.persistence.document.mongo; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBCollection; +import com.mongodb.DBObject; +import com.mongodb.MongoException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.document.mongodb.CollectionCallback; +import org.springframework.data.document.mongodb.MongoTemplate; +import org.springframework.data.support.ChangeSet; +import org.springframework.data.support.ChangeSetBacked; +import org.springframework.data.support.ChangeSetPersister; +import org.springframework.util.ClassUtils; + +public class MongoChangeSetPersister implements ChangeSetPersister { + + private static final String ENTITY_CLASS = "_entity_class"; + + private static final String ENTITY_ID = "_entity_id"; + + private static final String ENTITY_FIELD_NAME = "_entity_field_name"; + + private static final String ENTITY_FIELD_CLASS = "_entity_field_class"; + + protected final Log log = LogFactory.getLog(getClass()); + + private MongoTemplate mongoTemplate; + + public void setMongoTemplate(MongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + @Override + public void getPersistentState(Class entityClass, + Object id, final ChangeSet changeSet) throws DataAccessException, + NotFoundException { + String collName = getCollectionNameForEntity(entityClass); + + final DBObject dbk = new BasicDBObject(); + dbk.put(ENTITY_ID, id); + dbk.put(ENTITY_CLASS, entityClass.getName()); + mongoTemplate.execute(collName, new CollectionCallback() { + @Override + public Object doInCollection(DBCollection collection) + throws MongoException, DataAccessException { + for (DBObject dbo : collection.find(dbk)) { + String key = (String) dbo.get(ENTITY_FIELD_NAME); + String className = (String) dbo.get(ENTITY_FIELD_CLASS); + if (className == null) { + throw new DataIntegrityViolationException( + "Unble to convert property " + key + + ": Invalid metadata, " + ENTITY_FIELD_CLASS + " not available"); + } + Class clazz = null; + try { + clazz = Class.forName(className); + } catch (ClassNotFoundException e) { + throw new DataIntegrityViolationException( + "Unble to convert property " + key + " of type " + className, e); + } + Object value = mongoTemplate.getConverter().read(clazz, dbo); + changeSet.set(key, value); + } + return null; + } + }); + } + + @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.debug("Flush: changeset: " + cs.getValues().keySet()); + + String collName = getCollectionNameForEntity(entityClass); + DBCollection dbc = mongoTemplate.getCollection(collName); + if (dbc == null) { + dbc = mongoTemplate.createCollection(collName); + } + for (String key : cs.getValues().keySet()) { + if (key != null && !key.startsWith("_") && !key.equals(ChangeSetPersister.ID_KEY)) { + Object value = cs.getValues().get(key); + final DBObject dbQuery = new BasicDBObject(); + dbQuery.put(ENTITY_ID, cs.getValues().get(ChangeSetPersister.ID_KEY)); + dbQuery.put(ENTITY_CLASS, entityClass.getName()); + dbQuery.put(ENTITY_FIELD_NAME, key); + dbQuery.put(ENTITY_FIELD_CLASS, value.getClass().getName()); + DBObject dbId = mongoTemplate.execute(collName, + new CollectionCallback() { + @Override + public DBObject doInCollection(DBCollection collection) + throws MongoException, DataAccessException { + return collection.findOne(dbQuery); + } + }); + final DBObject dbDoc = new BasicDBObject(); + mongoTemplate.getConverter().write(value, dbDoc); + dbDoc.putAll(dbQuery); + if (dbId != null) { + dbDoc.put("_id", dbId.get("_id")); + } + mongoTemplate.execute(collName, new CollectionCallback() { + @Override + public Object doInCollection(DBCollection collection) + throws MongoException, DataAccessException { + collection.save(dbDoc); + return null; + } + }); + } + } + return 0L; + } + + private String getCollectionNameForEntity( + Class entityClass) { + return ClassUtils.getQualifiedName(entityClass); + } + +} diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/mongo/MongoDocumentBacking.aj b/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/mongo/MongoDocumentBacking.aj new file mode 100644 index 000000000..617277751 --- /dev/null +++ b/spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/mongo/MongoDocumentBacking.aj @@ -0,0 +1,179 @@ +package org.springframework.data.persistence.document.mongo; + +import java.lang.reflect.Field; + +import javax.persistence.Transient; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.reflect.FieldSignature; + +import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.data.document.mongodb.mapping.Document; + +import org.springframework.data.persistence.document.DocumentBacked; +import org.springframework.data.persistence.document.DocumentBackedTransactionSynchronization; +import org.springframework.data.support.ChangeSet; +import org.springframework.data.support.ChangeSetPersister; +import org.springframework.data.support.ChangeSetPersister.NotFoundException; +import org.springframework.data.support.HashMapChangeSet; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +/** + * Aspect to turn an object annotated with @Document into a persistent document + * using Mongo. + * + * @author Thomas Risberg + */ +public aspect MongoDocumentBacking { + + private static final Log LOGGER = LogFactory + .getLog(MongoDocumentBacking.class); + + // Aspect shared config + private ChangeSetPersister changeSetPersister; + + public void setChangeSetPersister( + ChangeSetPersister changeSetPersister) { + this.changeSetPersister = changeSetPersister; + } + + // ITD to introduce N state to Annotated objects + declare parents : (@Entity *) implements DocumentBacked; + +// declare @type: DocumentBacked+: @Configurable; + + declare @field: @Document * (@Entity+ *).*:@Transient; + declare @field: ChangeSet (DocumentBacked+).*:@Transient; + declare @field: ChangeSetPersister (DocumentBacked+).*:@Transient; + + // ------------------------------------------------------------------------- + // Advise user-defined constructors of ChangeSetBacked objects to create a new + // backing ChangeSet + // ------------------------------------------------------------------------- + pointcut arbitraryUserConstructorOfChangeSetBackedObject(DocumentBacked entity) : + execution((DocumentBacked+).new(..)) && + !execution((DocumentBacked+).new(ChangeSet)) && + this(entity); + + pointcut finderConstructorOfChangeSetBackedObject(DocumentBacked entity, + ChangeSet cs) : + execution((DocumentBacked+).new(ChangeSet)) && + this(entity) && + args(cs); + + protected pointcut entityFieldGet(DocumentBacked entity) : + get(@Document * DocumentBacked+.*) && + this(entity) && + !get(* DocumentBacked.*); + + protected pointcut entityFieldSet(DocumentBacked entity, Object newVal) : + set(@Document * DocumentBacked+.*) && + this(entity) && + args(newVal) && + !set(* DocumentBacked.*); + + protected pointcut entityIdSet(DocumentBacked entity, Object newVal) : + set(@Id * DocumentBacked+.*) && + this(entity) && + args(newVal) && + !set(* DocumentBacked.*); + + before(DocumentBacked entity) : arbitraryUserConstructorOfChangeSetBackedObject(entity) { + LOGGER + .debug("User-defined constructor called on DocumentBacked object of class " + + entity.getClass()); + entity.itdChangeSetPersister = changeSetPersister; + // Populate all properties + ChangeSet changeSet = new HashMapChangeSet(); + // changeSetManager.populateChangeSet(changeSet, entity); + entity.setChangeSet(changeSet); + if (!TransactionSynchronizationManager.isSynchronizationActive()) { + throw new InvalidDataAccessResourceUsageException( + "No transaction synchronization is active"); + } + TransactionSynchronizationManager + .registerSynchronization(new DocumentBackedTransactionSynchronization( + changeSetPersister, entity)); + } + + // ------------------------------------------------------------------------- + // ChangeSet-related mixins + // ------------------------------------------------------------------------- + // Introduced field + private ChangeSet DocumentBacked.changeSet; + + private ChangeSetPersister DocumentBacked.itdChangeSetPersister; + + public void DocumentBacked.setChangeSet(ChangeSet cs) { + this.changeSet = cs; + } + + public ChangeSet DocumentBacked.getChangeSet() { + return changeSet; + } + + // Flush the entity state to the persistent store + public void DocumentBacked.flush() { + itdChangeSetPersister.persistState(this.getClass(), this.changeSet); + } + + public Object DocumentBacked.get_persistent_id() { + return itdChangeSetPersister.getPersistentId(this.getClass(), + this.changeSet); + } + + /** + * delegates field reads to the state accessors instance + */ + Object around(DocumentBacked entity): entityFieldGet(entity) { + Field f = field(thisJoinPoint); + String propName = f.getName(); + LOGGER.trace("GET " + f + " -> ChangeSet value property [" + propName + + "] using: " + entity.getChangeSet()); + if (entity.getChangeSet().getValues().get(propName) == null) { + try { + this.changeSetPersister.getPersistentState(entity.getClass(), + entity.get_persistent_id(), entity.getChangeSet()); + } catch (NotFoundException e) { + } + } + Object fValue = entity.getChangeSet().getValues().get(propName); + if (fValue != null) { + return fValue; + } + return proceed(entity); + } + + /** + * delegates field writes to the state accessors instance + */ + Object around(DocumentBacked entity, Object newVal) : entityFieldSet(entity, newVal) { + Field f = field(thisJoinPoint); + String propName = f.getName(); + LOGGER.trace("SET " + f + " -> ChangeSet number value property [" + propName + + "] with value=[" + newVal + "]"); + entity.getChangeSet().set(propName, newVal); + return proceed(entity, newVal); + } + + /** + * delegates field writes to the state accessors instance + */ + Object around(DocumentBacked entity, Object newVal) : entityIdSet(entity, newVal) { + Field f = field(thisJoinPoint); + String propName = f.getName(); + LOGGER.trace("SET @Id -> ChangeSet @Id property [" + propName + + "] with value=[" + newVal + "]"); + entity.getChangeSet().set("_id", newVal); + return proceed(entity, newVal); + } + + Field field(JoinPoint joinPoint) { + FieldSignature fieldSignature = (FieldSignature) joinPoint.getSignature(); + return fieldSignature.getField(); + } +} diff --git a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/DocumentEntity.java b/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/DocumentEntity.java deleted file mode 100644 index 2b690df97..000000000 --- a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/DocumentEntity.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.springframework.persistence.document; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation to denote an object that should be transparently persisted - * using MongoDB - * - * @author Thomas Risberg - */ - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface DocumentEntity { - -} 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 deleted file mode 100644 index 6801b8b83..000000000 --- a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoChangeSetPersister.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.springframework.persistence.document; - -import com.mongodb.BasicDBObject; -import com.mongodb.DBCollection; -import com.mongodb.DBObject; -import com.mongodb.MongoException; -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.data.document.mongodb.MongoTemplate; -import org.springframework.persistence.support.ChangeSet; -import org.springframework.persistence.support.ChangeSetBacked; -import org.springframework.persistence.support.ChangeSetPersister; -import org.springframework.util.ClassUtils; - -//import edu.emory.mathcs.backport.java.util.Arrays; - -public class MongoChangeSetPersister implements ChangeSetPersister { - - protected final Log log = LogFactory.getLog(getClass()); - - @Autowired - private MongoTemplate mongoTemplate; - - @Autowired - private ConversionService conversionService; - - @Override - public void getPersistentState(Class entityClass, Object id, ChangeSet changeSet) - throws DataAccessException, NotFoundException { - String collection = ClassUtils.getShortName(entityClass).toLowerCase(); - DBObject q = new BasicDBObject(); - q.put("_id", id); - try { - DBObject dbo = mongoTemplate.getCollection(collection).findOne(q); - log.debug("Found DBObject: " + dbo); - 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(propertyKey, dbo.get(propertyKey)); - } else { - //throw new IllegalStateException("Unknown property [" + propertyName + "] found in MongoDB store"); - changeSet.set(propertyKey, 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.getSimpleName().toLowerCase(); - DBCollection dbc = mongoTemplate.getCollection(collection); - DBObject dbo = mapChangeSetToDbObject(cs); - if (dbc == null) { - dbc = mongoTemplate.createCollection(collection); - } - dbc.save(dbo); - id = dbo.get(ID_KEY); - log.info("Data store assigned id: " + id); - } else { - log.info("Flush: entity already persistent with id=" + id); - String collection = entityClass.getName(); - DBCollection dbc = mongoTemplate.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 deleted file mode 100644 index 133e482b7..000000000 --- a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoDocumentBacking.aj +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index b735456b7..000000000 --- a/spring-data-mongodb-cross-store/src/main/java/org/springframework/persistence/document/MongoEntityOperations.java +++ /dev/null @@ -1,78 +0,0 @@ -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.data.document.mongodb.MongoTemplate; -import org.springframework.persistence.OrderedEntityOperations; -import org.springframework.persistence.RelatedEntity; -import org.springframework.persistence.support.ChangeSet; -import org.springframework.persistence.support.ChangeSetBacked; -import org.springframework.persistence.support.ChangeSetPersister.NotFoundException; -import org.springframework.persistence.support.EntityInstantiator; -import org.springframework.persistence.support.HashMapChangeSet; - -public class MongoEntityOperations extends OrderedEntityOperations { - - @Autowired - private MongoTemplate mongoTemplate; - - private EntityInstantiator entityInstantiator; - - private MongoChangeSetPersister changeSetPersister; - - public void setEntityInstantiator(EntityInstantiator entityInstantiator) { - this.entityInstantiator = entityInstantiator; - } - - @Autowired - public void setChangeSetPersister(MongoChangeSetPersister changeSetPersister) { - this.changeSetPersister = changeSetPersister; - } - - - @Override - public boolean cacheInEntity() { - return true; - } - - @Override - public ChangeSetBacked findEntity(Class entityClass, Object key) throws DataAccessException { - try { - ChangeSet cs = new HashMapChangeSet(); - changeSetPersister.getPersistentState(entityClass, key, cs); - return entityInstantiator.createEntityFromState(cs, entityClass); - } catch (NotFoundException ex) { - return null; - } - } - - @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 215639511..c050d0afe 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 @@ -3,14 +3,11 @@ package org.springframework.data.document.persistence; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; -import com.mongodb.*; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.document.mongodb.MongoTemplate; -import org.springframework.persistence.document.test.Account; -import org.springframework.persistence.document.test.MongoPerson; import org.springframework.persistence.document.test.Person; import org.springframework.persistence.document.test.Resume; import org.springframework.test.annotation.Rollback; @@ -18,6 +15,9 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.annotation.Transactional; +import com.mongodb.DBCollection; +import com.mongodb.Mongo; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:/META-INF/spring/applicationContext.xml") public class CrossStoreMongoTests { @@ -30,8 +30,6 @@ public class CrossStoreMongoTests { private EntityManager entityManager; - private String colName = MongoPerson.class.getSimpleName().toLowerCase(); - @PersistenceContext public void setEntityManager(EntityManager entityManager) { @@ -45,65 +43,6 @@ public class CrossStoreMongoTests { } } - @Test - @Transactional - @Rollback(false) - public void testUserConstructor() { - clearData(colName); - int age = 33; - MongoPerson p = new MongoPerson("Thomas", age); - Assert.assertEquals(age, p.getAge()); - p.birthday(); - Assert.assertEquals(1 + age, p.getAge()); - } - - @Test - @Transactional - public void testInstantiatedFinder() throws MongoException { - DBCollection col = this.mongoTemplate.getCollection(colName); - DBObject dbo = col.findOne(); - Object _id = dbo.get("_id"); - MongoPerson found = MongoPerson.findPerson(_id); - Assert.assertNotNull(found); - Assert.assertEquals(_id, found.getId()); - System.out.println("Loaded MongoPerson data: " + found); - } - - @Test - @Transactional - @Rollback(false) - public void testCreateMongoToJpaEntityRelationship() { - clearData(colName); - Account a = new Account(); - a.setName("My Account"); - a.setFriendlyName("My Test Acct."); - a.setBalance(123.45F); - a.setId(2L); - MongoPerson p = new MongoPerson("Jack", 22); - entityManager.persist(a); - p.setAccount(a); - } - - @Test - @Transactional - public void testReadMongoToJpaEntityRelationship() { - DBCollection col = this.mongoTemplate.getCollection(colName); - DBCursor dbc = col.find(); - Object _id = null; - for (DBObject dbo : dbc) { - System.out.println(dbo); - if ("Jack".equals(dbo.get("name"))) { - _id = dbo.get("_id"); - break; - } - } - System.out.println(_id); - MongoPerson found = MongoPerson.findPerson(_id); - System.out.println(found); - if (found != null) - System.out.println(found.getAccount()); - } - @Test @Transactional @Rollback(false) @@ -122,12 +61,20 @@ public class CrossStoreMongoTests { @Test @Transactional + @Rollback(false) public void testReadJpaToMongoEntityRelationship() { Person found = entityManager.find(Person.class, 1L); - System.out.println(found); -// TODO: This part isn't working yet - there is no reference to the Momgo _id stored in the db -// if (found != null) -// System.out.println(found.getResume()); - } + Assert.assertNotNull(found); +// TODO: This part isn't quite working yet - need to intercept the id population from JPA EM + found.setId(found.getId()); + + Assert.assertEquals(Long.valueOf(1), found.getId()); + Assert.assertNotNull(found); + Assert.assertEquals(Long.valueOf(1), found.getId()); + Assert.assertNotNull(found.getResume()); + Assert.assertEquals("DiMark, DBA, 1990-2000" + "; " + "VMware, Developer, 2007-", + found.getResume().getJobs()); + found.getResume().addJob("Developer, SpringDeveloper.com, 2005-2006"); + } } diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson.java deleted file mode 100644 index 7b123a977..000000000 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.springframework.persistence.document.test; - -import org.springframework.persistence.RelatedEntity; -import org.springframework.persistence.document.DocumentEntity; - -@DocumentEntity -public class MongoPerson { - - // TODO only public because of AspectJ bug - public String name; - - public int age; - - public java.util.Date birthDate; - - // TODO only public to check weaving bug-- - // seems to work whereas private didn't - @RelatedEntity - public Account account; - - public MongoPerson(String name, int age) { - this.name = name; - this.age = age; - this.birthDate = new java.util.Date(); - } - - public void birthday() { - ++age; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - public java.util.Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(java.util.Date birthDate) { - this.birthDate = birthDate; - } - - public Account getAccount() { - return account; - } - - public void setAccount(Account account) { - this.account = account; - } - -} diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson_Roo_Mongo_Entity.aj b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson_Roo_Mongo_Entity.aj deleted file mode 100644 index cb7751aa7..000000000 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/MongoPerson_Roo_Mongo_Entity.aj +++ /dev/null @@ -1,54 +0,0 @@ -package org.springframework.persistence.document.test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Configurable; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.persistence.support.*; -import org.springframework.persistence.support.ChangeSetPersister.NotFoundException; - -/** - * EXAMPLE OF CODE THAT SHOULD BE GENERATED BY ROO BESIDES EACH MONGOENTITY CLASS - * - * Note: Combines X_Roo_Entity with X_Roo_Finder, as - * we need only a single aspect for entities. - * - * @author Thomas Risberg - * - */ -privileged aspect MongoPerson_Roo_Mongo_Entity { - - private static ChangeSetPersister changeSetPersister() { - return new MongoConfigurationHolder().changeSetConfig.getChangeSetPersister(); - } - - private static ChangeSetSynchronizer changeSetManager() { - return new MongoConfigurationHolder().changeSetConfig.getChangeSetManager(); - } - - @Configurable - public static class MongoConfigurationHolder { - @Autowired - @Qualifier("mongoChangeSetConfiguration") - public ChangeSetConfiguration changeSetConfig; - } - - /** - * Add constructor that takes ChangeSet. - * @param ChangeSet - */ - public MongoPerson.new(ChangeSet cs) { - super(); - setChangeSet(cs); - } - - public static MongoPerson MongoPerson.findPerson(Object id) { - ChangeSet rv = new HashMapChangeSet(); - try { - changeSetPersister().getPersistentState(MongoPerson.class, id, rv); - return new MongoPerson(rv); - } catch (NotFoundException ex) { - return null; - } - } - -} diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java index 71d323b91..9f4869241 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Person.java @@ -3,7 +3,7 @@ package org.springframework.persistence.document.test; import javax.persistence.Entity; import javax.persistence.Id; -import org.springframework.persistence.RelatedEntity; +import org.springframework.data.document.mongodb.mapping.Document; @Entity public class Person { @@ -17,8 +17,7 @@ public class Person { private java.util.Date birthDate; - // @Document // need to decide what the annotation here should be - @RelatedEntity + @Document public Resume resume; public Person() { diff --git a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java index f7eaa3fd5..adfdfef64 100644 --- a/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java +++ b/spring-data-mongodb-cross-store/src/test/java/org/springframework/persistence/document/test/Resume.java @@ -1,8 +1,6 @@ package org.springframework.persistence.document.test; -import org.springframework.persistence.document.DocumentEntity; - -@DocumentEntity +//@DocumentEntity public class Resume { private String education = ""; 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 807f56a55..ac3855ea8 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 @@ -12,41 +12,9 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -61,19 +29,14 @@ - - - - - - - - - + + + diff --git a/spring-data-mongodb-cross-store/src/test/resources/log4j.properties b/spring-data-mongodb-cross-store/src/test/resources/log4j.properties index 292bb1d4d..79159f674 100644 --- a/spring-data-mongodb-cross-store/src/test/resources/log4j.properties +++ b/spring-data-mongodb-cross-store/src/test/resources/log4j.properties @@ -5,8 +5,7 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n log4j.category.org.springframework=INFO -log4j.category.org.springframework.data=DEBUG -log4j.category.org.springframework.persistence=DEBUG +log4j.category.org.springframework.data=TRACE log4j.category.org.hibernate.SQL=DEBUG # for debugging datasource initialization diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 0d7fb7449..d144d88f2 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -13,7 +13,7 @@ Spring Data MongoDB Support - 2.3 + 2.3 @@ -49,89 +49,97 @@ ${data.commons.version} - - - org.mongodb + + + org.mongodb mongo-java-driver ${mongo.version} + + + javax.persistence + persistence-api + + - - - org.slf4j - slf4j-api - - - org.slf4j - jcl-over-slf4j - compile - - - org.slf4j - slf4j-log4j12 - runtime - - - log4j - log4j - - - javax.mail - mail - - - javax.jms - jms - - - com.sun.jdmk - jmxtools - - - com.sun.jmx - jmxri - - - runtime - - - - com.mysema.querydsl - querydsl-mongodb - 2.1.1 - true - - - com.google.code.morphia - morphia - - - - - - com.mysema.querydsl - querydsl-apt - 2.1.1 - provided - - - - javax.annotation - jsr250-api - true - - + + + org.slf4j + slf4j-api + + + org.slf4j + jcl-over-slf4j + compile + + + org.slf4j + slf4j-log4j12 + runtime + + + log4j + log4j + + + javax.mail + mail + + + javax.jms + jms + + + com.sun.jdmk + jmxtools + + + com.sun.jmx + jmxri + + + runtime + + + + com.mysema.querydsl + querydsl-mongodb + 2.1.1 + true + + + com.google.code.morphia + morphia + + + + + + com.mysema.querydsl + querydsl-apt + 2.1.1 + provided + + javax.annotation jsr250-api true + + javax.annotation + jsr250-api + true + + + @@ -153,42 +161,42 @@ test - - - - - com.springsource.bundlor - com.springsource.bundlor.maven - - - - com.mysema.maven - maven-apt-plugin - 1.0 - - - generate-test-sources - - test-process - - - target/generated-sources/test-annotations - org.springframework.data.document.mongodb.repository.MongoAnnotationProcessor - - - - - - - - - - querydsl - Mysema QueryDsl - http://source.mysema.com/maven2/releases - - false - - - + + + + + com.springsource.bundlor + com.springsource.bundlor.maven + + + + com.mysema.maven + maven-apt-plugin + 1.0 + + + generate-test-sources + + test-process + + + target/generated-sources/test-annotations + org.springframework.data.document.mongodb.repository.MongoAnnotationProcessor + + + + + + + + + + querydsl + Mysema QueryDsl + http://source.mysema.com/maven2/releases + + false + + +