Skip to content

Commit 0f77d21

Browse files
committed
CAY-2899 CommitLog: missing lifecycle-induced changes in excludeFromTransaction mode
1 parent bc712f5 commit 0f77d21

9 files changed

Lines changed: 540 additions & 0 deletions

File tree

cayenne-commitlog/src/main/java/org/apache/cayenne/commitlog/CommitLogModuleExtender.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
****************************************************************/
1919
package org.apache.cayenne.commitlog;
2020

21+
import org.apache.cayenne.DataChannelSyncFilter;
2122
import org.apache.cayenne.commitlog.meta.AnnotationCommitLogEntityFactory;
2223
import org.apache.cayenne.commitlog.meta.CommitLogEntity;
2324
import org.apache.cayenne.commitlog.meta.CommitLogEntityFactory;
2425
import org.apache.cayenne.configuration.runtime.CoreModule;
2526
import org.apache.cayenne.di.Binder;
2627
import org.apache.cayenne.di.ListBuilder;
28+
import org.apache.cayenne.graph.GraphChangeHandler;
2729

2830
/**
2931
* A builder of a custom extensions module for {@link CommitLogModule} that customizes its services and installs
@@ -60,6 +62,7 @@ public CommitLogModuleExtender addListener(CommitLogListener instance) {
6062
* within the transaction, so listeners can commit their code together with the main commit.
6163
*/
6264
public CommitLogModuleExtender excludeFromTransaction() {
65+
CoreModule.extend(binder).addSyncFilter(createDiffInitFilter(), true);
6366
return registerFilter(false);
6467
}
6568

@@ -100,4 +103,17 @@ private ListBuilder<CommitLogListener> contributeCommitLogListeners() {
100103
}
101104
return commitLogListeners;
102105
}
106+
107+
/**
108+
* @return the filter that just initializes incoming Diff
109+
*/
110+
private static DataChannelSyncFilter createDiffInitFilter() {
111+
GraphChangeHandler noopHandler = new GraphChangeHandler() {};
112+
return (originatingContext, changes, syncType, filterChain)
113+
-> {
114+
// see ObjectStoreGraphDiff.resolveDiff()
115+
changes.apply(noopHandler);
116+
return filterChain.onSync(originatingContext, changes, syncType);
117+
};
118+
}
103119
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
****************************************************************/
19+
package org.apache.cayenne.commitlog;
20+
21+
import org.apache.cayenne.ObjectContext;
22+
import org.apache.cayenne.annotation.PreUpdate;
23+
import org.apache.cayenne.commitlog.db.AuditLog;
24+
import org.apache.cayenne.commitlog.db.AuditableChild5;
25+
import org.apache.cayenne.commitlog.model.ObjectChange;
26+
import org.apache.cayenne.commitlog.unit.AuditableRuntimeCase;
27+
import org.apache.cayenne.configuration.runtime.CoreModule;
28+
import org.apache.cayenne.query.ObjectSelect;
29+
import org.apache.cayenne.runtime.CayenneRuntimeBuilder;
30+
import org.apache.cayenne.tx.BaseTransaction;
31+
import org.junit.Before;
32+
import org.junit.Test;
33+
34+
import java.sql.SQLException;
35+
import java.util.List;
36+
37+
import static org.junit.Assert.assertEquals;
38+
import static org.junit.Assert.assertNotNull;
39+
40+
public class CommitLogFilter_PreUpdate_IT extends AuditableRuntimeCase {
41+
42+
protected ObjectContext context;
43+
protected CommitLogListener listener;
44+
45+
@Override
46+
protected CayenneRuntimeBuilder configureCayenne() {
47+
this.listener = (originatingContext, changes) -> {
48+
// assert we are not inside a transaction
49+
assertNotNull(BaseTransaction.getThreadTransaction());
50+
51+
for (ObjectChange c : changes.getUniqueChanges()) {
52+
AuditLog log = runtime.newContext().newObject(AuditLog.class);
53+
log.setLog("DONE: " + c.getPostCommitId());
54+
log.getObjectContext().commitChanges();
55+
}
56+
};
57+
58+
return super.configureCayenne()
59+
.addModule(binder ->
60+
CoreModule.extend(binder)
61+
.addListenerType(MyPreUpdateListener.class)
62+
)
63+
.addModule(binder ->
64+
CommitLogModule.extend(binder)
65+
.commitLogAnnotationEntitiesOnly()
66+
.addListener(listener)
67+
);
68+
}
69+
70+
@Before
71+
public void before() throws Exception {
72+
context = runtime.newContext();
73+
auditable5.insert(1, "yy");
74+
auditableChild5.insert(1, 1, "zz");
75+
}
76+
77+
@Test
78+
public void testCommitLog() throws SQLException {
79+
80+
AuditableChild5 auditableChild = ObjectSelect.query(AuditableChild5.class)
81+
.selectOne(context);
82+
assertEquals("zz", auditableChild.getCharProperty1());
83+
84+
auditableChild.setCharProperty1("xx");
85+
86+
context.commitChanges();
87+
88+
List<Object[]> logs = auditLog.selectAll();
89+
assertEquals(2, logs.size());
90+
}
91+
92+
public static class MyPreUpdateListener {
93+
94+
@PreUpdate({ AuditableChild5.class })
95+
public void preUpdate( AuditableChild5 child ) {
96+
child.getParent().setCharProperty1("zz");
97+
}
98+
}
99+
100+
101+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
****************************************************************/
19+
package org.apache.cayenne.commitlog;
20+
21+
import org.apache.cayenne.ObjectContext;
22+
import org.apache.cayenne.annotation.PreUpdate;
23+
import org.apache.cayenne.commitlog.db.AuditLog;
24+
import org.apache.cayenne.commitlog.db.AuditableChild5;
25+
import org.apache.cayenne.commitlog.model.ObjectChange;
26+
import org.apache.cayenne.commitlog.unit.AuditableRuntimeCase;
27+
import org.apache.cayenne.configuration.runtime.CoreModule;
28+
import org.apache.cayenne.query.ObjectSelect;
29+
import org.apache.cayenne.runtime.CayenneRuntimeBuilder;
30+
import org.apache.cayenne.tx.BaseTransaction;
31+
import org.junit.Before;
32+
import org.junit.Test;
33+
34+
import java.sql.SQLException;
35+
import java.util.List;
36+
37+
import static org.junit.Assert.*;
38+
39+
public class CommitLogFilter_PreUpdate_OutsideTxIT extends AuditableRuntimeCase {
40+
41+
protected ObjectContext context;
42+
protected CommitLogListener listener;
43+
44+
@Override
45+
protected CayenneRuntimeBuilder configureCayenne() {
46+
this.listener = (originatingContext, changes) -> {
47+
// assert we are not inside a transaction
48+
assertNull(BaseTransaction.getThreadTransaction());
49+
50+
for (ObjectChange c : changes.getUniqueChanges()) {
51+
AuditLog log = runtime.newContext().newObject(AuditLog.class);
52+
log.setLog("DONE: " + c.getPostCommitId());
53+
log.getObjectContext().commitChanges();
54+
}
55+
};
56+
57+
return super.configureCayenne()
58+
.addModule(binder ->
59+
CoreModule.extend(binder)
60+
.addListenerType(MyPreUpdateListener.class)
61+
)
62+
.addModule(
63+
b -> CommitLogModule.extend(b)
64+
.commitLogAnnotationEntitiesOnly()
65+
.excludeFromTransaction()
66+
.addListener(listener)
67+
);
68+
}
69+
70+
@Before
71+
public void before() throws Exception {
72+
context = runtime.newContext();
73+
auditable5.insert(1, "yy");
74+
auditableChild5.insert(1, 1, "zz");
75+
}
76+
77+
@Test
78+
public void testCommitLog() throws SQLException {
79+
80+
AuditableChild5 auditableChild = ObjectSelect.query(AuditableChild5.class)
81+
.selectOne(context);
82+
assertEquals("zz", auditableChild.getCharProperty1());
83+
84+
auditableChild.setCharProperty1("xx");
85+
86+
context.commitChanges();
87+
88+
List<Object[]> logs = auditLog.selectAll();
89+
assertEquals(2, logs.size());
90+
}
91+
92+
public static class MyPreUpdateListener {
93+
94+
@PreUpdate({ AuditableChild5.class })
95+
public void preUpdate( AuditableChild5 child ) {
96+
child.getParent().setCharProperty1("zz");
97+
}
98+
}
99+
100+
101+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
****************************************************************/
19+
20+
package org.apache.cayenne.commitlog.db;
21+
22+
import org.apache.cayenne.commitlog.CommitLog;
23+
import org.apache.cayenne.commitlog.db.auto._Auditable5;
24+
25+
@CommitLog
26+
public class Auditable5 extends _Auditable5 {
27+
28+
private static final long serialVersionUID = 1L;
29+
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
****************************************************************/
19+
20+
package org.apache.cayenne.commitlog.db;
21+
22+
import org.apache.cayenne.commitlog.CommitLog;
23+
import org.apache.cayenne.commitlog.db.auto._AuditableChild5;
24+
25+
@CommitLog
26+
public class AuditableChild5 extends _AuditableChild5 {
27+
28+
private static final long serialVersionUID = 1L;
29+
30+
}

0 commit comments

Comments
 (0)