Skip to content

Commit 99e557b

Browse files
committed
[bugfix] Correctly handle the lifetime of remote XML:DB objects
1 parent a423437 commit 99e557b

File tree

1 file changed

+62
-42
lines changed

1 file changed

+62
-42
lines changed

exist-core/src/test/java/org/exist/xmldb/XMLDBExternalVariableTest.java

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,52 +1642,66 @@ private void queryPostWithExternalVariable(@Nullable final ErrorCodes.ErrorCode
16421642
private void queryPostWithExternalVariable(final Tuple2<ErrorCodes.ErrorCode, String> expectedResponse, final ExternalVariableValueRep[] expectedResult, @Nullable final String xqExternalVariableType, final ExternalVariableValueRep... externalVariableSequence) throws XMLDBException {
16431643
@Nullable final Object[] externalVariableValue = buildExternalVariableValue(externalVariableSequence);
16441644
final String query = buildQueryExternalVariable(xqExternalVariableType);
1645-
final Either<XMLDBException, ResourceSet> response = doPostWithAuth(externalVariableValue, query);
1645+
final Either<XMLDBException, Tuple2<Collection, ResourceSet>> response = doPostWithAuth(externalVariableValue, query);
1646+
@Nullable final Collection dbCollection = response.map(r -> r._1).getOrElse((Collection) null);
1647+
@Nullable final ResourceSet actualResultSet = response.map(r -> r._2).getOrElse((ResourceSet) null);
16461648

1647-
if (expectedResponse._1 == null) {
1648-
// We expect success
1649-
assertTrue(response.isRight());
1650-
final ResourceSet actualResultSet = response.right().get();
1651-
1652-
final List<Tuple2<String, Object>> expectedResults = buildExistVariableResultSequence(expectedResult);
1653-
1654-
assertEquals(expectedResults.size(), actualResultSet.getSize());
1655-
for (int i = 0; i < expectedResults.size(); i++) {
1656-
final Tuple2<String, Object> expected = expectedResults.get(i);
1657-
final EXistResource actual = (EXistResource) actualResultSet.getResource(i);
1649+
try {
1650+
if (expectedResponse._1 == null) {
1651+
// We expect success
1652+
assertTrue(response.isRight());
1653+
final List<Tuple2<String, Object>> expectedResults = buildExistVariableResultSequence(expectedResult);
1654+
1655+
assertEquals(expectedResults.size(), actualResultSet.getSize());
1656+
for (int i = 0; i < expectedResults.size(); i++) {
1657+
final Tuple2<String, Object> expected = expectedResults.get(i);
1658+
try (final EXistResource actual = (EXistResource) actualResultSet.getResource(i)) {
1659+
1660+
if (expected._1 != null) {
1661+
assertEquals(expected._1, actual.getTypeName());
1662+
}
1663+
final Object actualValue = actual.getContent();
1664+
assertTrue(actualValue instanceof String);
1665+
final String actualString = actualValue.toString();
16581666

1659-
if (expected._1 != null) {
1660-
assertEquals(expected._1, actual.getTypeName());
1667+
try {
1668+
if (expected._1 != null && Type.getType(expected._1) == Type.MAP_ITEM || expectedResult[i] instanceof MapRep) {
1669+
// NOTE(AR) XDM Map type does not have order, so we cannot compare as strings
1670+
final Map<Object, Object> expectedMap = MapUtil.parseXdmMapStringToJavaMap(expected._2.toString());
1671+
final Map<Object, Object> actualMap = MapUtil.parseXdmMapStringToJavaMap(actualString);
1672+
assertThat(actualMap).containsExactlyInAnyOrderEntriesOf(expectedMap);
1673+
} else {
1674+
assertEquals(expected._2, actualString);
1675+
}
1676+
} catch (final XPathException e) {
1677+
fail(e.getMessage());
1678+
}
1679+
}
16611680
}
1662-
final Object actualValue = actual.getContent();
1663-
assertTrue(actualValue instanceof String);
1664-
final String actualString = actualValue.toString();
16651681

1682+
} else {
1683+
// We expect an error, so check the error is the expected one
1684+
assertTrue(response.isLeft());
1685+
final XMLDBException errorResponse = response.left().get();
1686+
assertTrue(errorResponse.getCause() instanceof XPathException);
1687+
final XPathException errorResponseXPathException = (XPathException) errorResponse.getCause();
1688+
assertEquals(expectedResponse._1, errorResponseXPathException.getErrorCode());
1689+
1690+
if (expectedResponse._2 != null) {
1691+
String expectedResponseMessage = expectedResponse._2;
1692+
assertEquals(expectedResponseMessage, errorResponseXPathException.getDetailMessage());
1693+
}
1694+
}
1695+
} finally {
1696+
if (actualResultSet instanceof AutoCloseable) {
16661697
try {
1667-
if (expected._1 != null && Type.getType(expected._1) == Type.MAP_ITEM || expectedResult[i] instanceof MapRep) {
1668-
// NOTE(AR) XDM Map type does not have order, so we cannot compare as strings
1669-
final Map<Object, Object> expectedMap = MapUtil.parseXdmMapStringToJavaMap(expected._2.toString());
1670-
final Map<Object, Object> actualMap = MapUtil.parseXdmMapStringToJavaMap(actualString);
1671-
assertThat(actualMap).containsExactlyInAnyOrderEntriesOf(expectedMap);
1672-
} else {
1673-
assertEquals(expected._2, actualString);
1674-
}
1675-
} catch (final XPathException e) {
1676-
fail(e.getMessage());
1698+
((AutoCloseable) actualResultSet).close();
1699+
} catch (final Exception e) {
1700+
// no-op
16771701
}
16781702
}
1679-
1680-
} else {
1681-
// We expect an error, so check the error is the expected one
1682-
assertTrue(response.isLeft());
1683-
final XMLDBException errorResponse = response.left().get();
1684-
assertTrue(errorResponse.getCause() instanceof XPathException);
1685-
final XPathException errorResponseXPathException = (XPathException) errorResponse.getCause();
1686-
assertEquals(expectedResponse._1, errorResponseXPathException.getErrorCode());
1687-
1688-
if (expectedResponse._2 != null) {
1689-
String expectedResponseMessage = expectedResponse._2;
1690-
assertEquals(expectedResponseMessage, errorResponseXPathException.getDetailMessage());
1703+
if (dbCollection != null) {
1704+
dbCollection.close();
16911705
}
16921706
}
16931707
}
@@ -1816,8 +1830,10 @@ private static List<Tuple2<String, Object>> buildExistVariableResultSequence(fin
18161830
return results;
18171831
}
18181832

1819-
private Either<XMLDBException, ResourceSet> doPostWithAuth(@Nullable final Object[] externalVariableValue, final String query) throws XMLDBException {
1820-
try (final Collection dbCollection = DatabaseManager.getCollection(getBaseUri() + "/db", TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)) {
1833+
private Either<XMLDBException, Tuple2<Collection, ResourceSet>> doPostWithAuth(@Nullable final Object[] externalVariableValue, final String query) throws XMLDBException {
1834+
// NOTE(AR) dbCollection will be closed either when XMLDBException is captured, or the ResourceSet is closed
1835+
final Collection dbCollection = DatabaseManager.getCollection(getBaseUri() + "/db", TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD);
1836+
try {
18211837
final XQueryService xqueryService = dbCollection.getService(XQueryService.class);
18221838

18231839
if (externalVariableValue != null) {
@@ -1831,10 +1847,14 @@ private Either<XMLDBException, ResourceSet> doPostWithAuth(@Nullable final Objec
18311847

18321848
final CompiledExpression compiled = xqueryService.compile(query);
18331849
try {
1834-
return Either.Right(xqueryService.execute(compiled));
1850+
return Either.Right(Tuple(dbCollection, xqueryService.execute(compiled)));
18351851
} catch (final XMLDBException e) {
1852+
dbCollection.close();
18361853
return Either.Left(e);
18371854
}
1855+
} catch (final XMLDBException e) {
1856+
dbCollection.close();
1857+
throw e;
18381858
}
18391859
}
18401860

0 commit comments

Comments
 (0)