diff --git a/src/org/exist/source/SourceFactory.java b/src/org/exist/source/SourceFactory.java index fbc8a93a2a2..239ac5f016c 100644 --- a/src/org/exist/source/SourceFactory.java +++ b/src/org/exist/source/SourceFactory.java @@ -77,14 +77,9 @@ public class SourceFactory { Source source = null; /* resource: */ - if (location.startsWith(ClassLoaderSource.PROTOCOL)) { - source = new ClassLoaderSource(location); - } else if (contextPath != null && contextPath.startsWith(ClassLoaderSource.PROTOCOL)) { - // Pretend it is a file on the local system so we can resolve it easily with URL() class. - final String conPathNoProtocol = contextPath.replace(ClassLoaderSource.PROTOCOL, "file://"); - String resolvedURL = new URL(new URL(conPathNoProtocol), location).toString(); - resolvedURL = resolvedURL.replaceFirst("file://", ClassLoaderSource.PROTOCOL); - source = new ClassLoaderSource(resolvedURL); + if (location.startsWith(ClassLoaderSource.PROTOCOL) + || (contextPath != null && contextPath.startsWith(ClassLoaderSource.PROTOCOL))) { + source = getSource_fromClasspath(contextPath, location); } /* xmldb */ @@ -154,6 +149,26 @@ private static String firstPathSegment(final String path) { .getRawCollectionPath(); } + private static Source getSource_fromClasspath(final String contextPath, final String location) throws IOException { + if (location.startsWith(ClassLoaderSource.PROTOCOL)) { + return new ClassLoaderSource(location); + } + + final Path rootPath = Paths.get(contextPath.substring(ClassLoaderSource.PROTOCOL.length())); + + // 1) try resolving location as child + final Path childLocation = rootPath.resolve(location); + try { + return new ClassLoaderSource(ClassLoaderSource.PROTOCOL + childLocation.toString().replace('\\', '/')); + } catch (final IOException e) { + // no-op, we will try again below + } + + // 2) try resolving location as sibling + final Path siblingLocation = rootPath.resolveSibling(location); + return new ClassLoaderSource(ClassLoaderSource.PROTOCOL + siblingLocation.toString().replace('\\', '/')); + } + /** * Get the resource source from the database. * diff --git a/test/src/org/exist/source/SourceFactoryTest.java b/test/src/org/exist/source/SourceFactoryTest.java index 6de6080391d..f0c3a9583aa 100644 --- a/test/src/org/exist/source/SourceFactoryTest.java +++ b/test/src/org/exist/source/SourceFactoryTest.java @@ -133,6 +133,53 @@ public void getSourceFromResource_contextAbsoluteFileUrl_locationRelativeUrl_bas assertEquals(getClass().getResource(location), relativeSource.getKey()); } + @Test + public void getSourceFromResource_contextFolderUrl_locationRelative() throws IOException, PermissionDeniedException { + final String contextPath = "resource:org/exist/source"; + final String location = "library.xqm"; + + final Source source = SourceFactory.getSource(null, contextPath, location, false); + + assertTrue(source instanceof ClassLoaderSource); + assertEquals(getClass().getResource("library.xqm"), source.getKey()); + } + + @Test + public void getSourceFromResource_contextFolderUrl_locationAbsoluteUrl() throws IOException, PermissionDeniedException { + final String contextPath = "resource:org/exist/source"; + final String location = "resource:org/exist/source/library.xqm"; + + final Source source = SourceFactory.getSource(null, contextPath, location, false); + + assertTrue(source instanceof ClassLoaderSource); + assertEquals(getClass().getResource("library.xqm"), source.getKey()); + } + + @Test + public void getSourceFromResource_contextFolderUrl_locationRelativeUrl() throws IOException, PermissionDeniedException { + final String contextPath = "resource:org/exist/source"; + final String location = "library.xqm"; + + final Source source = SourceFactory.getSource(null, contextPath, location, false); + + assertTrue(source instanceof ClassLoaderSource); + assertEquals(getClass().getResource("library.xqm"), source.getKey()); + } + + @Test + public void getSourceFromResource_contextFolderUrl_locationRelativeUrl_basedOnSource() throws IOException, PermissionDeniedException { + final String contextPath = "resource:org/exist/source"; + final String location = "library.xqm"; + + final Source mainSource = SourceFactory.getSource(null, "", contextPath, false); + assertTrue(mainSource instanceof ClassLoaderSource); + + final Source relativeSource = SourceFactory.getSource(null, ((ClassLoaderSource)mainSource).getSource(), location, false); + + assertTrue(relativeSource instanceof ClassLoaderSource); + assertEquals(getClass().getResource(location), relativeSource.getKey()); + } + @Test public void getSourceFromXmldb_noContext() throws IOException, PermissionDeniedException { final String contextPath = null;