Skip to content

Commit 057eeb1

Browse files
author
Thomas Risberg
committed
DATADOC-48 using the entity lifecycle for transaction synch registration
1 parent bfb3db5 commit 057eeb1

File tree

2 files changed

+82
-28
lines changed

2 files changed

+82
-28
lines changed

spring-data-mongodb-cross-store/src/main/java/org/springframework/data/persistence/document/mongo/MongoDocumentBacking.aj

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,8 @@ public aspect MongoDocumentBacking {
4444
// ITD to introduce N state to Annotated objects
4545
declare parents : (@Entity *) implements DocumentBacked;
4646

47-
// declare @type: DocumentBacked+: @Configurable;
48-
47+
// The annotated fields that will be persisted in MongoDB rather than with JPA
4948
declare @field: @Document * (@Entity+ *).*:@Transient;
50-
declare @field: ChangeSet (DocumentBacked+).*:@Transient;
51-
declare @field: ChangeSetPersister (DocumentBacked+).*:@Transient;
5249

5350
// -------------------------------------------------------------------------
5451
// Advise user-defined constructors of ChangeSetBacked objects to create a new
@@ -86,27 +83,44 @@ public aspect MongoDocumentBacking {
8683
LOGGER
8784
.debug("User-defined constructor called on DocumentBacked object of class "
8885
+ entity.getClass());
86+
// Populate all ITD fields
87+
entity.setChangeSet(new HashMapChangeSet());
8988
entity.itdChangeSetPersister = changeSetPersister;
90-
// Populate all properties
91-
ChangeSet changeSet = new HashMapChangeSet();
92-
// changeSetManager.populateChangeSet(changeSet, entity);
93-
entity.setChangeSet(changeSet);
94-
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
95-
throw new InvalidDataAccessResourceUsageException(
96-
"No transaction synchronization is active");
89+
entity.itdTransactionSynchronization =
90+
new DocumentBackedTransactionSynchronization(changeSetPersister, entity);
91+
registerTransactionSynchronization(entity);
92+
}
93+
94+
private static void registerTransactionSynchronization(DocumentBacked entity) {
95+
if (TransactionSynchronizationManager.isSynchronizationActive()) {
96+
if (!TransactionSynchronizationManager.getSynchronizations().contains(entity.itdTransactionSynchronization)) {
97+
if (LOGGER.isDebugEnabled()) {
98+
LOGGER.debug("Adding transaction synchronization for " + entity.getClass());
99+
}
100+
TransactionSynchronizationManager.registerSynchronization(entity.itdTransactionSynchronization);
101+
}
102+
else {
103+
if (LOGGER.isDebugEnabled()) {
104+
LOGGER.debug("Transaction synchronization already active for " + entity.getClass());
105+
}
106+
}
107+
}
108+
else {
109+
if (LOGGER.isDebugEnabled()) {
110+
LOGGER.debug("Transaction syncronization is not active for " + entity.getClass());
111+
}
97112
}
98-
TransactionSynchronizationManager
99-
.registerSynchronization(new DocumentBackedTransactionSynchronization(
100-
changeSetPersister, entity));
101113
}
102114

103115
// -------------------------------------------------------------------------
104116
// ChangeSet-related mixins
105117
// -------------------------------------------------------------------------
106118
// Introduced field
107-
private ChangeSet DocumentBacked.changeSet;
119+
@Transient private ChangeSet DocumentBacked.changeSet;
108120

109-
private ChangeSetPersister<?> DocumentBacked.itdChangeSetPersister;
121+
@Transient private ChangeSetPersister<?> DocumentBacked.itdChangeSetPersister;
122+
123+
@Transient private DocumentBackedTransactionSynchronization DocumentBacked.itdTransactionSynchronization;
110124

111125
public void DocumentBacked.setChangeSet(ChangeSet cs) {
112126
this.changeSet = cs;
@@ -126,6 +140,32 @@ public aspect MongoDocumentBacking {
126140
return itdChangeSetPersister.getPersistentId(this, this.changeSet);
127141
}
128142

143+
// lifecycle methods
144+
@javax.persistence.PrePersist public void DocumentBacked.prePersist() {
145+
if (LOGGER.isDebugEnabled()) {
146+
LOGGER.debug("JPA lifecycle called PrePersist: " + this.getClass().getName() + " :: " + this.get_persistent_id());
147+
}
148+
registerTransactionSynchronization(this);
149+
}
150+
@javax.persistence.PreUpdate public void DocumentBacked.preUpdate() {
151+
if (LOGGER.isDebugEnabled()) {
152+
LOGGER.debug("JPA lifecycle called PreUpdate: " + this.getClass().getName() + " :: " + this.get_persistent_id());
153+
}
154+
registerTransactionSynchronization(this);
155+
}
156+
@javax.persistence.PreRemove public void DocumentBacked.preRemove() {
157+
if (LOGGER.isDebugEnabled()) {
158+
LOGGER.debug("JPA lifecycle called PreRemove: " + this.getClass().getName() + " :: " + this.get_persistent_id());
159+
}
160+
registerTransactionSynchronization(this);
161+
}
162+
@javax.persistence.PostLoad public void DocumentBacked.postLoad() {
163+
if (LOGGER.isDebugEnabled()) {
164+
LOGGER.debug("JPA lifecycle called PostLoad: " + this.getClass().getName() + " :: " + this.get_persistent_id());
165+
}
166+
registerTransactionSynchronization(this);
167+
}
168+
129169
/**
130170
* delegates field reads to the state accessors instance
131171
*/
@@ -160,18 +200,6 @@ public aspect MongoDocumentBacking {
160200
return proceed(entity, newVal);
161201
}
162202

163-
// /**
164-
// * delegates field writes to the state accessors instance
165-
// */
166-
// Object around(DocumentBacked entity, Object newVal) : entityIdSet(entity, newVal) {
167-
// Field f = field(thisJoinPoint);
168-
// String propName = f.getName();
169-
// LOGGER.trace("SET @Id -> ChangeSet @Id property [" + propName
170-
// + "] with value=[" + newVal + "]");
171-
// entity.getChangeSet().set("_id", newVal);
172-
// return proceed(entity, newVal);
173-
// }
174-
175203
Field field(JoinPoint joinPoint) {
176204
FieldSignature fieldSignature = (FieldSignature) joinPoint.getSignature();
177205
return fieldSignature.getField();

spring-data-mongodb-cross-store/src/test/java/org/springframework/data/document/persistence/CrossStoreMongoTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
import org.springframework.test.annotation.Rollback;
1414
import org.springframework.test.context.ContextConfiguration;
1515
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
16+
import org.springframework.transaction.PlatformTransactionManager;
17+
import org.springframework.transaction.TransactionStatus;
1618
import org.springframework.transaction.annotation.Transactional;
19+
import org.springframework.transaction.support.TransactionCallback;
20+
import org.springframework.transaction.support.TransactionTemplate;
1721

1822
import com.mongodb.DBCollection;
1923
import com.mongodb.Mongo;
@@ -30,6 +34,9 @@ public class CrossStoreMongoTests {
3034

3135
private EntityManager entityManager;
3236

37+
@Autowired
38+
private PlatformTransactionManager transactionManager;
39+
3340
@PersistenceContext
3441
public void setEntityManager(EntityManager entityManager) {
3542
this.entityManager = entityManager;
@@ -71,6 +78,7 @@ public void testReadJpaToMongoEntityRelationship() {
7178
Assert.assertEquals("DiMark, DBA, 1990-2000" + "; "
7279
+ "VMware, Developer, 2007-", found.getResume().getJobs());
7380
found.getResume().addJob("SpringDeveloper.com, Consultant, 2005-2006");
81+
found.setAge(44);
7482
}
7583

7684
@Test
@@ -87,4 +95,22 @@ public void testUpdatedJpaToMongoEntityRelationship() {
8795
+ "VMware, Developer, 2007-" + "; "
8896
+ "SpringDeveloper.com, Consultant, 2005-2006", found.getResume().getJobs());
8997
}
98+
99+
@Test
100+
public void testMergeJpaEntityWithMongoDocument() {
101+
TransactionTemplate txTemplate = new TransactionTemplate(transactionManager);
102+
final Person found = entityManager.find(Person.class, 1L);
103+
found.setAge(77);
104+
found.getResume().addJob("TargetRx, Developer, 2000-2005");
105+
txTemplate.execute(new TransactionCallback<Object>() {
106+
public Object doInTransaction(TransactionStatus status) {
107+
entityManager.merge(found);
108+
return null;
109+
}
110+
});
111+
final Person updated = entityManager.find(Person.class, 1L);
112+
// assert that the new values are in respective DBs
113+
// TODO: during merge we lose the changeset since JPA creates a new persistent instance -
114+
// we need to move the existing changeset over somehow
115+
}
90116
}

0 commit comments

Comments
 (0)