Skip to content

Commit 234c7ee

Browse files
committed
[bugfix] Make sure the Error Code for an XPathException is transferred correctly over the XML:DB Remote API
1 parent b31c4a9 commit 234c7ee

File tree

4 files changed

+116
-23
lines changed

4 files changed

+116
-23
lines changed

exist-core/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,7 @@
10621062
<include>src/main/java/org/exist/xmldb/RemoteResourceSet.java</include>
10631063
<include>src/main/java/org/exist/xmldb/RemoteRestoreService.java</include>
10641064
<include>src/main/java/org/exist/xmldb/RemoteXMLResource.java</include>
1065+
<include>src/main/java/org/exist/xmldb/RemoteXPathQueryService.java</include>
10651066
<include>src/test/java/org/exist/xmldb/ResourceTest.java</include>
10661067
<include>src/test/java/org/exist/xmldb/SerializationTest.java</include>
10671068
<include>src/test/java/org/exist/xmldb/TestEXistXMLSerialize.java</include>
@@ -1081,6 +1082,7 @@
10811082
<include>src/test/java/org/exist/xmldb/concurrent/XMLGenerator.java</include>
10821083
<include>src/test/java/org/exist/xmldb/concurrent/action/MultiResourcesAction.java</include>
10831084
<include>src/main/java/org/exist/xmlrpc/ExistRpcTypeFactory.java</include>
1085+
<include>src/main/java/org/exist/xmlrpc/RpcAPI.java</include>
10841086
<include>src/main/java/org/exist/xmlrpc/RpcConnection.java</include>
10851087
<include>src/main/java/org/exist/xqj/Marshaller.java</include>
10861088
<include>src/test/java/org/exist/xqj/MarshallerTest.java</include>
@@ -1691,6 +1693,7 @@
16911693
<exclude>src/main/java/org/exist/xmldb/RemoteResourceSet.java</exclude>
16921694
<exclude>src/main/java/org/exist/xmldb/RemoteRestoreService.java</exclude>
16931695
<exclude>src/main/java/org/exist/xmldb/RemoteXMLResource.java</exclude>
1696+
<exclude>src/main/java/org/exist/xmldb/RemoteXPathQueryService.java</exclude>
16941697
<exclude>src/test/java/org/exist/xmldb/ResourceTest.java</exclude>
16951698
<exclude>src/test/java/org/exist/xmldb/SerializationTest.java</exclude>
16961699
<exclude>src/test/java/org/exist/xmldb/TestEXistXMLSerialize.java</exclude>
@@ -1712,6 +1715,7 @@
17121715
<exclude>src/main/java/org/exist/xmlrpc/ACEAiderParser.java</exclude>
17131716
<exclude>src/main/java/org/exist/xmlrpc/ACEAiderSerializer.java</exclude>
17141717
<exclude>src/main/java/org/exist/xmlrpc/ExistRpcTypeFactory.java</exclude>
1718+
<exclude>src/main/java/org/exist/xmlrpc/RpcAPI.java</exclude>
17151719
<exclude>src/main/java/org/exist/xmlrpc/RpcConnection.java</exclude>
17161720
<exclude>src/main/java/org/exist/xqj/Marshaller.java</exclude>
17171721
<exclude>src/test/java/org/exist/xqj/MarshallerTest.java</exclude>

exist-core/src/main/java/org/exist/xmldb/RemoteXPathQueryService.java

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -26,6 +50,7 @@
2650
import java.util.*;
2751

2852
import org.apache.xmlrpc.client.XmlRpcClient;
53+
import org.exist.dom.QName;
2954
import org.exist.source.Source;
3055
import org.exist.storage.serializers.EXistOutputKeys;
3156
import org.exist.util.Leasable;
@@ -34,6 +59,7 @@
3459
import org.xmldb.api.base.*;
3560
import org.xmldb.api.modules.XMLResource;
3661

62+
import javax.annotation.Nullable;
3763
import javax.xml.XMLConstants;
3864

3965
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -152,22 +178,35 @@ public CompiledExpression compileAndCheck(final String query) throws XMLDBExcept
152178
}
153179

154180
private void throwException(final Map result) throws XMLDBException {
155-
final String message = (String) result.get(RpcAPI.ERROR);
156-
final Integer lineInt = (Integer) result.get(RpcAPI.LINE);
157-
final Integer columnInt = (Integer) result.get(RpcAPI.COLUMN);
158-
final int line = lineInt == null ? 0 : lineInt;
159-
final int column = columnInt == null ? 0 : columnInt;
160-
final XPathException cause = new XPathException(line, column, message);
161-
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, message, cause);
181+
final XPathException cause = errorToXPathException(result);
182+
throw new XMLDBException(ErrorCodes.VENDOR_ERROR, cause.getMessage(), cause);
162183
}
163184

164185
private void throwXPathException(final Map result) throws XPathException {
186+
throw errorToXPathException(result);
187+
}
188+
189+
private XPathException errorToXPathException(final Map result) {
165190
final String message = (String) result.get(RpcAPI.ERROR);
191+
166192
final Integer lineInt = (Integer) result.get(RpcAPI.LINE);
167193
final Integer columnInt = (Integer) result.get(RpcAPI.COLUMN);
168194
final int line = lineInt == null ? 0 : lineInt;
169195
final int column = columnInt == null ? 0 : columnInt;
170-
throw new XPathException(line, column, message);
196+
197+
final org.exist.xquery.ErrorCodes.ErrorCode errorCode;
198+
@Nullable final Map<String, Object> code = (Map<String, Object>) result.get(RpcAPI.CODE);
199+
if (code != null) {
200+
final String namespaceUri = (String) code.get(RpcAPI.QNAME_NAMESPACE_URI);
201+
final String prefix = (String) code.get(RpcAPI.QNAME_PREFIX);
202+
final String localPart = (String) code.get(RpcAPI.QNAME_LOCAL_PART);
203+
final QName qname = new QName(localPart, namespaceUri, prefix);
204+
errorCode = org.exist.xquery.ErrorCodes.fromQName(qname);
205+
} else {
206+
errorCode = org.exist.xquery.ErrorCodes.EXistErrorCode.ERROR;
207+
}
208+
209+
return new XPathException(line, column, errorCode, message);
171210
}
172211

173212
@Override

exist-core/src/main/java/org/exist/xmlrpc/RpcAPI.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
11
/*
2+
* Elemental
3+
* Copyright (C) 2024, Evolved Binary Ltd
4+
*
5+
6+
* https://www.evolvedbinary.com | https://www.elemental.xyz
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; version 2.1.
11+
*
12+
* This library is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* Lesser General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Lesser General Public
18+
* License along with this library; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*
21+
* NOTE: Parts of this file contain code from 'The eXist-db Authors'.
22+
* The original license header is included below.
23+
*
24+
* =====================================================================
25+
*
226
* eXist-db Open Source Native XML Database
327
* Copyright (C) 2001 The eXist-db Authors
428
*
@@ -53,6 +77,11 @@ public interface RpcAPI {
5377
String ERROR = "error";
5478
String LINE = "line";
5579
String COLUMN = "column";
80+
String CODE = "code";
81+
String DESCRIPTION = "code";
82+
String QNAME_NAMESPACE_URI = "namespace-uri";
83+
String QNAME_PREFIX = "prefix";
84+
String QNAME_LOCAL_PART = "local-part";
5685
String MODULE_LOAD_PATH = "module-load-path";
5786

5887
/**

exist-core/src/main/java/org/exist/xmlrpc/RpcConnection.java

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
import org.exist.xmlrpc.function.XmlRpcDocumentFunction;
111111
import org.exist.xmlrpc.function.XmlRpcFunction;
112112
import org.exist.xquery.*;
113+
import org.exist.xquery.ErrorCodes;
113114
import org.exist.xquery.util.HTTPUtils;
114115
import org.exist.xquery.value.*;
115116
import org.exist.xupdate.Modification;
@@ -137,6 +138,7 @@
137138
import java.util.zip.DeflaterOutputStream;
138139
import javax.annotation.Nullable;
139140
import javax.annotation.concurrent.GuardedBy;
141+
import javax.xml.XMLConstants;
140142
import javax.xml.parsers.ParserConfigurationException;
141143
import javax.xml.transform.OutputKeys;
142144

@@ -1691,16 +1693,43 @@ public Map<String, Object> compile(final String query, final Map<String, Object>
16911693
try {
16921694
compileQuery(broker, transaction, source, parameters).apply(compiledQuery -> null);
16931695
} catch (final XPathException e) {
1694-
ret.put(RpcAPI.ERROR, e.getMessage());
1695-
if (e.getLine() != 0) {
1696-
ret.put(RpcAPI.LINE, e.getLine());
1697-
ret.put(RpcAPI.COLUMN, e.getColumn());
1698-
}
1696+
setErrorInformation(ret, e);
16991697
}
17001698
return ret;
17011699
});
17021700
}
17031701

1702+
private static void setErrorInformation(Map<String, Object> rpcResult, final XPathException e) {
1703+
if (e.getDetailMessage() != null) {
1704+
rpcResult.put(RpcAPI.ERROR, e.getDetailMessage());
1705+
} else {
1706+
rpcResult.put(RpcAPI.ERROR, e.getMessage());
1707+
}
1708+
final Map<String, Object> errorCode = errorCodeToMap(new HashMap(), e.getErrorCode());
1709+
rpcResult.put(RpcAPI.CODE, errorCode);
1710+
if (e.getLine() != 0) {
1711+
rpcResult.put(RpcAPI.LINE, e.getLine());
1712+
rpcResult.put(RpcAPI.COLUMN, e.getColumn());
1713+
}
1714+
}
1715+
1716+
private static Map<String, Object> errorCodeToMap(Map<String, Object> map, final ErrorCodes.ErrorCode errorCode) {
1717+
map = qnameToMap(map, errorCode.getErrorQName());
1718+
// map.put(RpcAPI.DESCRIPTION, errorCode.getDescription()); // NOTE(AR) unneeded as it can be reconstructed via {@link ErrorCodes#fromQName(QName)}
1719+
return map;
1720+
}
1721+
1722+
private static Map<String, Object> qnameToMap(final Map<String, Object> map, final QName qname) {
1723+
if (qname.getNamespaceURI() != null && !qname.getNamespaceURI().equals(XMLConstants.NULL_NS_URI)) {
1724+
map.put(RpcAPI.QNAME_NAMESPACE_URI, qname.getNamespaceURI());
1725+
}
1726+
if (qname.getPrefix() != null && !qname.getPrefix().equals(XMLConstants.DEFAULT_NS_PREFIX)) {
1727+
map.put(RpcAPI.QNAME_PREFIX, qname.getPrefix());
1728+
}
1729+
map.put(RpcAPI.QNAME_LOCAL_PART, qname.getLocalPart());
1730+
return map;
1731+
}
1732+
17041733
public String query(final String xpath, final int howmany, final int start,
17051734
final Map<String, Object> parameters) throws EXistException, PermissionDeniedException {
17061735

@@ -1809,11 +1838,7 @@ private Map<String, Object> queryResultToRpcResponse(final long startTime, final
18091838
if (queryResult.hasErrors()) {
18101839
// return an error description
18111840
final XPathException e = queryResult.getException();
1812-
ret.put(RpcAPI.ERROR, e.getMessage());
1813-
if (e.getLine() != 0) {
1814-
ret.put(RpcAPI.LINE, e.getLine());
1815-
ret.put(RpcAPI.COLUMN, e.getColumn());
1816-
}
1841+
setErrorInformation(ret, e);
18171842
return ret;
18181843
}
18191844

@@ -1930,11 +1955,7 @@ private Map<String, Object> queryResultToTypedRpcResponse(final long startTime,
19301955
if (queryResult.hasErrors()) {
19311956
// return an error description
19321957
final XPathException e = queryResult.getException();
1933-
ret.put(RpcAPI.ERROR, e.getMessage());
1934-
if (e.getLine() != 0) {
1935-
ret.put(RpcAPI.LINE, e.getLine());
1936-
ret.put(RpcAPI.COLUMN, e.getColumn());
1937-
}
1958+
setErrorInformation(ret, e);
19381959
return ret;
19391960
}
19401961

0 commit comments

Comments
 (0)