Skip to content

Commit 0ec448d

Browse files
author
Nico Verwer
committed
Merge branch 'develop-6.x.x' into JB-current
2 parents e0ea2bc + b28dbaf commit 0ec448d

File tree

12 files changed

+1411
-173
lines changed

12 files changed

+1411
-173
lines changed

.github/workflows/ci-deploy.yml

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ jobs:
55
name: Build and Test Images
66
runs-on: ubuntu-latest
77
# NOTE (DP): Publish on develop and master, test on PRs against these
8-
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || github.base_ref == 'develop' || github.base_ref == 'master'
8+
# TODO(DP) Reinstate CRONed release builds to update stock apps regularly
9+
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/develop-6.x.x' || github.ref == 'refs/heads/master'|| github.base_ref == 'develop' || github.base_ref == 'develop-6.x.x' || github.base_ref == 'master'
910
steps:
1011
- uses: actions/checkout@v4
1112
with:
@@ -15,6 +16,10 @@ jobs:
1516
with:
1617
distribution: liberica
1718
java-version: '8'
19+
- name: Set up QEMU
20+
uses: docker/setup-qemu-action@v3
21+
with:
22+
platforms: linux/amd64,linux/arm64
1823
- name: Make buildkit default
1924
uses: docker/setup-buildx-action@v3
2025
id: buildx
@@ -51,6 +56,14 @@ jobs:
5156
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
5257
run: mvn -q -Ddocker.tag=latest -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
5358
working-directory: ./exist-docker
59+
- name: Publish dev6 images
60+
if: github.ref == 'refs/heads/develop-6.x.x'
61+
env:
62+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63+
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
64+
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
65+
run: mvn -q -Ddocker.tag=dev6 -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
66+
working-directory: ./exist-docker
5467
- name: Publish release images
5568
if: github.ref == 'refs/heads/master'
5669
env:
@@ -61,11 +74,11 @@ jobs:
6174
working-directory: ./exist-docker
6275
# NOTE (DP): This is for debugging, publishes an experimental image from inside PRs against develop
6376
# - name: Publish experimental images
64-
# if: github.base_ref == 'develop'
77+
# if: github.base_ref == 'develop-6.x.x'
6578
# env:
6679
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6780
# DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
6881
# DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
69-
# run: mvn -q -Ddocker.tag=experimental -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
82+
# run: mvn -q -Ddocker.tag=experimental6 -Ddocker.username=$DOCKER_USERNAME -Ddocker.password=$DOCKER_PASSWORD docker:build docker:push
7083
# working-directory: ./exist-docker
7184

exist-core/src/main/java/org/exist/source/SourceFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public class SourceFactory {
111111
&& ((location.startsWith("/db") && !Files.exists(Paths.get(firstPathSegment(location))))
112112
|| (contextPath != null && contextPath.startsWith("/db") && !Files.exists(Paths.get(firstPathSegment(contextPath)))))) {
113113
final XmldbURI pathUri;
114-
if (contextPath == null) {
114+
if (contextPath == null || ".".equals(contextPath)) {
115115
pathUri = XmldbURI.create(location);
116116
} else {
117117
pathUri = XmldbURI.create(contextPath).append(location);

exist-core/src/main/java/org/exist/webstart/JnlpJarFiles.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class JnlpJarFiles {
6060
"commons-logging-%latest%",
6161
"commons-pool-%latest%",
6262
"jargo-%latest%",
63-
"bcprov-jdk15on-%latest%",
63+
"bcprov-jdk18on-%latest%",
6464
"fastutil-%latest%-min",
6565
"j8fu-%latest%",
6666
"jackson-core-%latest%",

exist-core/src/main/java/org/exist/xquery/XQueryContext.java

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -574,46 +574,50 @@ public Optional<ExistRepository> getRepository() {
574574
// the repo and its eXist handler
575575
final Optional<ExistRepository> repo = getRepository();
576576

577+
if (!repo.isPresent()) {
578+
return null;
579+
}
577580
// try an internal module
578-
if (repo.isPresent()) {
579-
final Module jMod = repo.get().resolveJavaModule(namespace, this);
580-
if (jMod != null) {
581-
return jMod;
582-
}
581+
final Module jMod = repo.get().resolveJavaModule(namespace, this);
582+
if (jMod != null) {
583+
return jMod;
583584
}
584585

585586
// try an eXist-specific module
586-
if (repo.isPresent()) {
587-
final Path resolved = repo.get().resolveXQueryModule(namespace);
588-
589-
// use the resolved file or return null
590-
if (resolved != null) {
591-
592-
String location = "";
593-
594-
try {
595-
596-
// see if the src exists in the database and if so, use that instead
597-
Source src = repo.get().resolveStoredXQueryModuleFromDb(getBroker(), resolved);
598-
if (src != null) {
599-
// NOTE(AR) set the location of the module to import relative to this module's load path - so that transient imports of the imported module will resolve correctly!
600-
location = Paths.get(XmldbURI.create(moduleLoadPath).getCollectionPath()).relativize(Paths.get(((DBSource)src).getDocumentPath().getCollectionPath())).toString();
601-
} else {
602-
// else, fallback to the one from the filesystem
603-
src = new FileSource(resolved, false);
604-
}
587+
final Path resolved = repo.get().resolveXQueryModule(namespace);
605588

606-
// build a module object from the source
607-
final ExternalModule module = compileOrBorrowModule(prefix, namespace, location, src);
608-
return module;
589+
if (resolved == null) {
590+
return null;
591+
}
609592

610-
} catch (final PermissionDeniedException e) {
611-
throw new XPathException(e.getMessage(), e);
593+
// use the resolved file
594+
try {
595+
// see if the src exists in the database and if so, use that instead
596+
Source src = repo.get().resolveStoredXQueryModuleFromDb(getBroker(), resolved);
597+
String location = "";
598+
if (src == null) {
599+
// fallback to load the source from the filesystem
600+
src = new FileSource(resolved, false);
601+
} else {
602+
final String sourceCollection = ((DBSource)src).getDocumentPath().getCollectionPath();
603+
if (".".equals(moduleLoadPath)) {
604+
// module is a string passed to the xquery context, has therefore no location of its own
605+
location = sourceCollection;
606+
} else {
607+
// NOTE(AR) set the location of the module to import relative to this module's load path
608+
// - so that transient imports of the imported module will resolve correctly!
609+
final Path collectionPath = Paths.get(XmldbURI.create(moduleLoadPath).getCollectionPath());
610+
final Path sourcePath = Paths.get(sourceCollection);
611+
location = collectionPath.relativize(sourcePath).toString();
612612
}
613613
}
614-
}
615614

616-
return null;
615+
// build a module object from the source
616+
return compileOrBorrowModule(prefix, namespace, location, src);
617+
618+
} catch (final PermissionDeniedException | IllegalArgumentException e) {
619+
throw new XPathException(e.getMessage(), e);
620+
}
617621
}
618622

619623
/**

exist-core/src/main/java/org/exist/xslt/XsltURIResolverHelper.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,16 @@ public class XsltURIResolverHelper {
5252
@Nullable final URIResolver defaultResolver, @Nullable final String base, final boolean avoidSelf) {
5353
final List<URIResolver> resolvers = new ArrayList<>();
5454

55+
// EXpath Pkg resolver
56+
// This resolver needs to be the first one to prevent
57+
// HTTP requests for registered package names (e.g. http://www.functx.com/functx.xsl)
58+
brokerPool.getExpathRepo().map(repo -> resolvers.add(new PkgXsltModuleURIResolver(repo)));
59+
5560
if (base != null) {
5661
// database resolver
5762
resolvers.add(new EXistURISchemeURIResolver(new EXistURIResolver(brokerPool, base)));
5863
}
5964

60-
// EXpath Pkg resolver
61-
brokerPool.getExpathRepo().map(repo -> resolvers.add(new PkgXsltModuleURIResolver(repo)));
62-
6365
// default resolver
6466
if (defaultResolver != null) {
6567
if (avoidSelf) {
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
6+
* http://www.exist-db.org
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; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
package org.exist.xquery;
23+
24+
import com.evolvedbinary.j8fu.Either;
25+
26+
import org.exist.EXistException;
27+
import org.exist.security.PermissionDeniedException;
28+
import org.exist.storage.BrokerPool;
29+
import org.exist.storage.DBBroker;
30+
import org.exist.test.ExistEmbeddedServer;
31+
import org.exist.xquery.value.Sequence;
32+
import org.exist.xquery.value.StringValue;
33+
34+
import org.junit.ClassRule;
35+
import org.junit.Test;
36+
37+
import java.net.URISyntaxException;
38+
import java.nio.file.Path;
39+
import java.nio.file.Paths;
40+
41+
import static com.evolvedbinary.j8fu.Either.Left;
42+
import static com.evolvedbinary.j8fu.Either.Right;
43+
import static com.ibm.icu.impl.Assert.fail;
44+
import static org.exist.test.XQueryAssertions.assertThatXQResult;
45+
import static org.exist.test.XQueryAssertions.assertXQStaticError;
46+
import static org.hamcrest.Matchers.equalTo;
47+
48+
/**
49+
* Ensure library module imports work in one-off queries
50+
* needs functx to be installed => conf.xml => triggers => autodeploy
51+
*
52+
* @author <a href="mailto:[email protected]">Juri Leino</a>
53+
*/
54+
public class ModuleImportTest {
55+
@ClassRule
56+
public static final ExistEmbeddedServer server = new ExistEmbeddedServer(null, getConfigFile(), null, false, true);
57+
58+
protected static Either<XPathException, CompiledXQuery> compileQuery(final String string) throws EXistException, PermissionDeniedException {
59+
final BrokerPool pool = server.getBrokerPool();
60+
final XQuery xqueryService = pool.getXQueryService();
61+
try (final DBBroker broker = pool.getBroker()) {
62+
try {
63+
return Right(xqueryService.compile(new XQueryContext(broker.getDatabase()), string));
64+
} catch (final XPathException e) {
65+
return Left(e);
66+
}
67+
}
68+
}
69+
70+
protected static Either<XPathException, Sequence> executeQuery(final String string) throws EXistException, PermissionDeniedException {
71+
final BrokerPool pool = server.getBrokerPool();
72+
final XQuery xqueryService = pool.getXQueryService();
73+
try (final DBBroker broker = pool.getBroker()) {
74+
try {
75+
return Right(xqueryService.execute(broker, string, null));
76+
} catch (final XPathException e) {
77+
return Left(e);
78+
}
79+
}
80+
}
81+
82+
private static Path getConfigFile() {
83+
final ClassLoader loader = ModuleImportTest.class.getClassLoader();
84+
final char separator = System.getProperty("file.separator").charAt(0);
85+
final String packagePath = ModuleImportTest.class.getPackage().getName().replace('.', separator);
86+
87+
try {
88+
return Paths.get(loader.getResource(packagePath + separator + "conf.xml").toURI());
89+
} catch (final URISyntaxException e) {
90+
fail(e);
91+
return null;
92+
}
93+
}
94+
95+
@Test
96+
public void importLibraryWithoutLocation() throws EXistException, PermissionDeniedException {
97+
final Sequence expected = new StringValue("xs:integer");
98+
99+
final String query = "import module namespace functx='http://www.functx.com';" +
100+
"functx:atomic-type(4)";
101+
final Either<XPathException, Sequence> actual = executeQuery(query);
102+
103+
assertThatXQResult(actual, equalTo(expected));
104+
}
105+
@Test
106+
public void importLibraryFromDbLocation() throws EXistException, PermissionDeniedException {
107+
final Sequence expected = new StringValue("xs:integer");
108+
109+
final String query = "import module namespace functx='http://www.functx.com'" +
110+
" at '/db/system/repo/functx-1.0.1/functx/functx.xq';" +
111+
"functx:atomic-type(4)";
112+
final Either<XPathException, Sequence> actual = executeQuery(query);
113+
114+
assertThatXQResult(actual, equalTo(expected));
115+
}
116+
117+
@Test
118+
public void importLibraryFromXMLDBLocation() throws EXistException, PermissionDeniedException {
119+
final Sequence expected = new StringValue("xs:integer");
120+
121+
final String query = "import module namespace functx='http://www.functx.com'" +
122+
" at 'xmldb:/db/system/repo/functx-1.0.1/functx/functx.xq';" +
123+
"functx:atomic-type(4)";
124+
final Either<XPathException, Sequence> actual = executeQuery(query);
125+
126+
assertThatXQResult(actual, equalTo(expected));
127+
}
128+
129+
@Test
130+
public void importLibraryFromXMLDBLocationDoubleSlash() throws EXistException, PermissionDeniedException {
131+
final Sequence expected = new StringValue("xs:integer");
132+
133+
final String query = "import module namespace functx='http://www.functx.com'" +
134+
" at 'xmldb:///db/system/repo/functx-1.0.1/functx/functx.xq';" +
135+
"functx:atomic-type(4)";
136+
final Either<XPathException, Sequence> actual = executeQuery(query);
137+
138+
assertThatXQResult(actual, equalTo(expected));
139+
}
140+
141+
@Test
142+
public void importLibraryFromExistXMLDBLocation() throws EXistException, PermissionDeniedException {
143+
final Sequence expected = new StringValue("xs:integer");
144+
145+
final String query = "import module namespace functx='http://www.functx.com'" +
146+
" at 'xmldb:exist:///db/system/repo/functx-1.0.1/functx/functx.xq';" +
147+
"functx:atomic-type(4)";
148+
final Either<XPathException, Sequence> actual = executeQuery(query);
149+
150+
assertThatXQResult(actual, equalTo(expected));
151+
}
152+
153+
@Test
154+
public void importLibraryFromUnknownLocation() throws EXistException, PermissionDeniedException {
155+
156+
final String query = "import module namespace functx='http://www.functx.com'" +
157+
" at 'unknown:///db/system/repo/functx-1.0.1/functx/functx.xq';" +
158+
"functx:atomic-type(4)";
159+
final String expectedMessage = "error found while loading module functx: Source for module 'http://www.functx.com' not found module location hint URI 'unknown:///db/system/repo/functx-1.0.1/functx/functx.xq'.";
160+
161+
assertXQStaticError(ErrorCodes.XQST0059, -1,-1, expectedMessage, compileQuery(query));
162+
}
163+
164+
@Test
165+
public void importLibraryFromRelativeLocation() throws EXistException, PermissionDeniedException {
166+
final String query = "import module namespace functx='http://www.functx.com'" +
167+
" at './functx.xq';" +
168+
"functx:atomic-type(4)";
169+
final String expectedMessage = "error found while loading module functx: Source for module 'http://www.functx.com' not found module location hint URI './functx.xq'.";
170+
171+
assertXQStaticError(ErrorCodes.XQST0059, -1,-1, expectedMessage, compileQuery(query));
172+
}
173+
174+
}

0 commit comments

Comments
 (0)