Skip to content

Commit 15b3909

Browse files
authored
Merge pull request #631 from stariy95/4.2-FIX-CAY-2899-commit-log
CAY-2899 CommitLog: missing lifecycle-induced changes in `excludeFromTransaction` mode
2 parents b052080 + ebfcb32 commit 15b3909

10 files changed

Lines changed: 545 additions & 4 deletions

File tree

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
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.commitlog.meta.IncludeAllCommitLogEntityFactory;
2526
import org.apache.cayenne.configuration.server.ServerModule;
2627
import org.apache.cayenne.di.ListBuilder;
2728
import org.apache.cayenne.di.Module;
29+
import org.apache.cayenne.graph.GraphChangeHandler;
2830
import org.apache.cayenne.tx.TransactionFilter;
2931
import org.slf4j.Logger;
3032
import org.slf4j.LoggerFactory;
@@ -115,10 +117,26 @@ public Module module() {
115117
}
116118

117119
if (excludeFromTransaction) {
118-
ServerModule.contributeDomainSyncFilters(binder).addAfter(CommitLogFilter.class, TransactionFilter.class);
120+
ServerModule.contributeDomainSyncFilters(binder)
121+
.insertBefore(createDiffInitFilter(), TransactionFilter.class)
122+
.addAfter(CommitLogFilter.class, TransactionFilter.class);
119123
} else {
120-
ServerModule.contributeDomainSyncFilters(binder).insertBefore(CommitLogFilter.class, TransactionFilter.class);
124+
ServerModule.contributeDomainSyncFilters(binder)
125+
.insertBefore(CommitLogFilter.class, TransactionFilter.class);
121126
}
122127
};
123128
}
129+
130+
/**
131+
* @return the filter that just initializes incoming Diff
132+
*/
133+
private static DataChannelSyncFilter createDiffInitFilter() {
134+
GraphChangeHandler noopHandler = new GraphChangeHandler() {};
135+
return (originatingContext, changes, syncType, filterChain)
136+
-> {
137+
// see ObjectStoreGraphDiff.resolveDiff()
138+
changes.apply(noopHandler);
139+
return filterChain.onSync(originatingContext, changes, syncType);
140+
};
141+
}
124142
}

cayenne-commitlog/src/test/java/org/apache/cayenne/commitlog/CommitLogFilter_OutsideTxIT.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,14 @@ protected ServerRuntimeBuilder configureCayenne() {
5252
log.getObjectContext().commitChanges();
5353
}
5454
};
55+
5556
return super.configureCayenne().addModule(
56-
CommitLogModule.extend().commitLogAnnotationEntitiesOnly().excludeFromTransaction().addListener(listener)
57-
.module());
57+
CommitLogModule.extend()
58+
.commitLogAnnotationEntitiesOnly()
59+
.excludeFromTransaction()
60+
.addListener(listener)
61+
.module()
62+
);
5863
}
5964

6065
@Before
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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.AuditableServerCase;
27+
import org.apache.cayenne.configuration.server.ServerModule;
28+
import org.apache.cayenne.configuration.server.ServerRuntimeBuilder;
29+
import org.apache.cayenne.query.ObjectSelect;
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 AuditableServerCase {
41+
42+
protected ObjectContext context;
43+
protected CommitLogListener listener;
44+
45+
@Override
46+
protected ServerRuntimeBuilder 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+
ServerModule.contributeDomainListeners(binder)
61+
.add(MyPreUpdateListener.class)
62+
)
63+
.addModule(
64+
CommitLogModule.extend()
65+
.commitLogAnnotationEntitiesOnly()
66+
.addListener(listener)
67+
.module()
68+
);
69+
}
70+
71+
@Before
72+
public void before() throws Exception {
73+
context = runtime.newContext();
74+
auditable5.insert(1, "yy");
75+
auditableChild5.insert(1, 1, "zz");
76+
}
77+
78+
@Test
79+
public void testCommitLog() throws SQLException {
80+
81+
AuditableChild5 auditableChild = ObjectSelect.query(AuditableChild5.class)
82+
.selectOne(context);
83+
assertEquals("zz", auditableChild.getCharProperty1());
84+
85+
auditableChild.setCharProperty1("xx");
86+
87+
context.commitChanges();
88+
89+
List<Object[]> logs = auditLog.selectAll();
90+
assertEquals(2, logs.size());
91+
}
92+
93+
public static class MyPreUpdateListener {
94+
95+
@PreUpdate({ AuditableChild5.class })
96+
public void preUpdate( AuditableChild5 child ) {
97+
child.getParent().setCharProperty1("zz");
98+
}
99+
}
100+
101+
102+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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.AuditableServerCase;
27+
import org.apache.cayenne.configuration.server.ServerModule;
28+
import org.apache.cayenne.configuration.server.ServerRuntimeBuilder;
29+
import org.apache.cayenne.query.ObjectSelect;
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 AuditableServerCase {
40+
41+
protected ObjectContext context;
42+
protected CommitLogListener listener;
43+
44+
@Override
45+
protected ServerRuntimeBuilder 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+
ServerModule.contributeDomainListeners(binder)
60+
.add(MyPreUpdateListener.class)
61+
)
62+
.addModule(
63+
CommitLogModule.extend()
64+
.commitLogAnnotationEntitiesOnly()
65+
.excludeFromTransaction()
66+
.addListener(listener)
67+
.module()
68+
);
69+
}
70+
71+
@Before
72+
public void before() throws Exception {
73+
context = runtime.newContext();
74+
auditable5.insert(1, "yy");
75+
auditableChild5.insert(1, 1, "zz");
76+
}
77+
78+
@Test
79+
public void testCommitLog() throws SQLException {
80+
81+
AuditableChild5 auditableChild = ObjectSelect.query(AuditableChild5.class)
82+
.selectOne(context);
83+
assertEquals("zz", auditableChild.getCharProperty1());
84+
85+
auditableChild.setCharProperty1("xx");
86+
87+
context.commitChanges();
88+
89+
List<Object[]> logs = auditLog.selectAll();
90+
assertEquals(2, logs.size());
91+
}
92+
93+
public static class MyPreUpdateListener {
94+
95+
@PreUpdate({ AuditableChild5.class })
96+
public void preUpdate( AuditableChild5 child ) {
97+
child.getParent().setCharProperty1("zz");
98+
}
99+
}
100+
101+
102+
}
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)