Skip to content

Commit 19e717a

Browse files
duncdrumclaude
andcommitted
[bugfix] Fix broker/transaction ordering race in 14 more try-with-resources blocks
Same root cause as DomEnhancingNodeProxyAdapterTest.withTestDocument: BrokerPool.get() is thread-local, so beginTransaction() must find an active broker already on the thread or it draws a fresh one from the pool. When the try-with-resources unwinds in reverse order, that pool broker may have been returned before Txn.close() fires, causing removeCurrentTransaction to hit a different instance and throw IllegalStateException. Fix: declare DBBroker before Txn in all affected try-with-resources blocks so the thread holds a reference throughout the transaction lifecycle. Files affected: exist-core: DeepEmbeddedBackupRestoreTest, XQueryTriggerChainTest, XQueryTriggerSetGidTest, XQueryTriggerSetUidTest extensions: DomEnhancingNodeProxyAdapterTest (@BeforeClass setup), SendEmailIT Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent baaebc0 commit 19e717a

6 files changed

Lines changed: 28 additions & 28 deletions

File tree

exist-core/src/test/java/org/exist/backup/DeepEmbeddedBackupRestoreTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ private CollectionsAndDocuments createHierarchy(final XmldbURI baseCollectionUri
123123
final List<ResourceInfo> documentInfos = new ArrayList<>();
124124

125125
final BrokerPool brokerPool = existEmbeddedServer.getBrokerPool();
126-
try (final Txn transaction = brokerPool.getTransactionManager().beginTransaction();
127-
final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()))) {
126+
try (final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()));
127+
final Txn transaction = brokerPool.getTransactionManager().beginTransaction()) {
128128

129129
try (final Collection baseCollection = broker.getOrCreateCollection(transaction, baseCollectionUri)) {
130130

exist-core/src/test/java/org/exist/collections/triggers/XQueryTriggerChainTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ public class XQueryTriggerChainTest {
133133
@BeforeClass
134134
public static void setup() throws EXistException, PermissionDeniedException, IOException, SAXException, LockException {
135135
final BrokerPool pool = EXIST_EMBEDDED_SERVER.getBrokerPool();
136-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
137-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
136+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
137+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
138138

139139
// store the trigger modules
140140
try (final Collection collection = broker.getOrCreateCollection(transaction, TEST_COLLECTION_URI)) {
@@ -172,8 +172,8 @@ public void xqueryTriggerChain() throws EXistException, PermissionDeniedExceptio
172172
final String documentContent = "<id>" + uuid + "</id>";
173173

174174
final BrokerPool pool = EXIST_EMBEDDED_SERVER.getBrokerPool();
175-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
176-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
175+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
176+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
177177

178178
// store a document into the /db/testXQueryTriggerChain/collection1/input, this should cause the first trigger to fire
179179
try (final Collection collection = broker.getOrCreateCollection(transaction, COLLECTION_1_INPUT_URI)) {
@@ -186,8 +186,8 @@ public void xqueryTriggerChain() throws EXistException, PermissionDeniedExceptio
186186

187187
// trigger 1 should have completed by this stage... which will have also caused trigger 2 to fire and complete by this stage... so now check the content of the collections/documents produced by the triggers
188188

189-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
190-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
189+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
190+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
191191

192192
// 1) assert that trigger1 moved the document from its input collection
193193
try (final Collection collection = broker.getOrCreateCollection(transaction, COLLECTION_1_INPUT_URI)) {

exist-core/src/test/java/org/exist/collections/triggers/XQueryTriggerSetGidTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ public class XQueryTriggerSetGidTest {
104104
@BeforeClass
105105
public static void setup() throws EXistException, PermissionDeniedException, IOException, SAXException, LockException {
106106
final BrokerPool pool = EXIST_EMBEDDED_SERVER.getBrokerPool();
107-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
108-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
107+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
108+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
109109

110110
// store the trigger module
111111
try (final Collection collection = broker.getOrCreateCollection(transaction, TEST_COLLECTION_URI)) {
@@ -150,8 +150,8 @@ public static void setup() throws EXistException, PermissionDeniedException, IOE
150150
@Test
151151
public void triggerSetGid() throws EXistException, PermissionDeniedException, IOException, SAXException, LockException, XPathException {
152152
final BrokerPool pool = EXIST_EMBEDDED_SERVER.getBrokerPool();
153-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
154-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getGuestSubject()))) { // NOTE: "guest" user
153+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getGuestSubject())); // NOTE: "guest" user
154+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
155155

156156
// store a document into the "triggered" collection as the guest user, should cause the trigger to fire
157157
try (final Collection collection = broker.getOrCreateCollection(transaction, TEST_TRIGGER_COLLECTION_URI)) {
@@ -172,8 +172,8 @@ public void triggerSetGid() throws EXistException, PermissionDeniedException, IO
172172
"import module namespace sm = 'http://exist-db.org/xquery/securitymanager';\n" +
173173
"doc('" + TEST_OUTPUT_BEFORE_DOC_URI + "')/sm:id/sm:effective/sm:groups/sm:group/string(.)";
174174

175-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
176-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
175+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
176+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
177177

178178
final String beforeRealGroup = withCompiledQuery(broker, new StringSource(queryBeforeRealGroup), compiledQuery -> {
179179
final Sequence result = executeQuery(broker, compiledQuery);
@@ -203,8 +203,8 @@ public void triggerSetGid() throws EXistException, PermissionDeniedException, IO
203203
"import module namespace sm = 'http://exist-db.org/xquery/securitymanager';\n" +
204204
"doc('" + TEST_OUTPUT_AFTER_DOC_URI + "')/sm:id/sm:effective/sm:groups/sm:group/string(.)";
205205

206-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
207-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
206+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
207+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
208208

209209
final String afterRealGroup = withCompiledQuery(broker, new StringSource(queryAfterRealGroup), compiledQuery -> {
210210
final Sequence result = executeQuery(broker, compiledQuery);

exist-core/src/test/java/org/exist/collections/triggers/XQueryTriggerSetUidTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ public class XQueryTriggerSetUidTest {
104104
@BeforeClass
105105
public static void setup() throws EXistException, PermissionDeniedException, IOException, SAXException, LockException {
106106
final BrokerPool pool = EXIST_EMBEDDED_SERVER.getBrokerPool();
107-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
108-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
107+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
108+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
109109

110110
// store the trigger module
111111
try (final Collection collection = broker.getOrCreateCollection(transaction, TEST_COLLECTION_URI)) {
@@ -150,8 +150,8 @@ public static void setup() throws EXistException, PermissionDeniedException, IOE
150150
@Test
151151
public void triggerSetUid() throws EXistException, PermissionDeniedException, IOException, SAXException, LockException, XPathException {
152152
final BrokerPool pool = EXIST_EMBEDDED_SERVER.getBrokerPool();
153-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
154-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getGuestSubject()))) { // NOTE: "guest" user
153+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getGuestSubject())); // NOTE: "guest" user
154+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
155155

156156
// store a document into the "triggered" collection as the guest user, should cause the trigger to fire
157157
try (final Collection collection = broker.getOrCreateCollection(transaction, TEST_TRIGGER_COLLECTION_URI)) {
@@ -172,8 +172,8 @@ public void triggerSetUid() throws EXistException, PermissionDeniedException, IO
172172
"import module namespace sm = 'http://exist-db.org/xquery/securitymanager';\n" +
173173
"doc('" + TEST_OUTPUT_BEFORE_DOC_URI + "')/sm:id/sm:effective/sm:username";
174174

175-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
176-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
175+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
176+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
177177

178178
final String beforeRealUser = withCompiledQuery(broker, new StringSource(queryBeforeRealUser), compiledQuery -> {
179179
final Sequence result = executeQuery(broker, compiledQuery);
@@ -204,8 +204,8 @@ public void triggerSetUid() throws EXistException, PermissionDeniedException, IO
204204
"import module namespace sm = 'http://exist-db.org/xquery/securitymanager';\n" +
205205
"doc('" + TEST_OUTPUT_AFTER_DOC_URI + "')/sm:id/sm:effective/sm:username";
206206

207-
try (final Txn transaction = pool.getTransactionManager().beginTransaction();
208-
final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
207+
try (final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
208+
final Txn transaction = pool.getTransactionManager().beginTransaction()) {
209209

210210
final String afterRealUser = withCompiledQuery(broker, new StringSource(queryAfterRealUser), compiledQuery -> {
211211
final Sequence result = executeQuery(broker, compiledQuery);

extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/adapters/DomEnhancingNodeProxyAdapterTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ public class DomEnhancingNodeProxyAdapterTest {
7575
@BeforeClass
7676
public static void setup() throws EXistException, PermissionDeniedException, IOException, SAXException, LockException {
7777
final BrokerPool brokerPool = existEmbeddedServer.getBrokerPool();
78-
try (final Txn transaction = brokerPool.getTransactionManager().beginTransaction();
79-
final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()));
78+
try (final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()));
79+
final Txn transaction = brokerPool.getTransactionManager().beginTransaction();
8080
final Collection collection = broker.getOrCreateCollection(transaction, TEST_COLLECTION_URI)) {
8181

8282
collection.storeDocument(transaction, broker, TEST_DOC_URI, new StringInputSource(TEST_DOC), MimeType.XML_TYPE);

extensions/modules/mail/src/test/java/org/exist/xquery/modules/mail/SendEmailIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ public static java.util.Collection<Object[]> data() {
128128
@BeforeClass
129129
public static void setup() throws PermissionDeniedException, IOException, SAXException, EXistException, LockException {
130130
final BrokerPool brokerPool = existEmbeddedServer.getBrokerPool();
131-
try (final Txn transaction = brokerPool.getTransactionManager().beginTransaction();
132-
final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()))) {
131+
try (final DBBroker broker = brokerPool.get(Optional.of(brokerPool.getSecurityManager().getSystemSubject()));
132+
final Txn transaction = brokerPool.getTransactionManager().beginTransaction()) {
133133

134134
try (final Collection collection = broker.getOrCreateCollection(transaction, TEST_COLLECTION)) {
135135
broker.storeDocument(transaction, XML_DOC1_NAME, new StringInputSource(XML_DOC1_CONTENT), MimeType.XML_TYPE, collection);

0 commit comments

Comments
 (0)