This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 8818503612 During XML unmarshalling, if a `xlink:href` is not local
(i.e. starts with `#`), resolve only if explicitely authorized by the user.
Otherwise leave the element empty.
8818503612 is described below
commit 881850361234403ddbbaa5faa8456a114ce2903f
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue Sep 15 19:39:24 2026 +0900
During XML unmarshalling, if a `xlink:href` is not local (i.e. starts with
`#`),
resolve only if explicitely authorized by the user. Otherwise leave the
element empty.
---
.../apache/sis/metadata/internal/Resources.java | 5 ++
.../sis/metadata/internal/Resources.properties | 1 +
.../sis/metadata/internal/Resources_fr.properties | 1 +
.../main/org/apache/sis/xml/IdentifierSpace.java | 4 +-
.../main/org/apache/sis/xml/ReferenceResolver.java | 74 ++++++++++++++++++----
.../main/org/apache/sis/xml/XML.java | 28 ++++----
.../apache/sis/xml/internal/shared/URISource.java | 12 ++--
.../main/org/apache/sis/xml/package-info.java | 2 +-
.../org/apache/sis/metadata/xml/TestUsingFile.java | 14 ++++
.../org/apache/sis/xml/ReferenceResolverMock.java | 1 +
.../org/apache/sis/xml/ReferenceResolverTest.java | 68 ++++++++++++++++++--
.../org/apache/sis/xml/bind/referencing/Code.java | 2 +-
12 files changed, 173 insertions(+), 39 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources.java
index b9cd253db8..ef63d47380 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources.java
@@ -67,6 +67,11 @@ public class Resources extends IndexedResourceBundle {
throw new IllegalAccessException();
}
+ /**
+ * References to external documents are not followed without explicit
authorization.
+ */
+ public static final short AuthorizationRequired = 10;
+
/**
* Cannot handle `{1}` as a type derived from the {0} standard.
*/
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources.properties
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources.properties
index b20abf46fc..00772d8d87 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources.properties
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources.properties
@@ -19,6 +19,7 @@
# Resources in this file are for `org.apache.sis.metadata` usage only and
should not be used by any other module.
# For resources shared by all modules in the Apache SIS project, see
"org.apache.sis.util.resources" package.
#
+AuthorizationRequired = References to external documents are not
followed without explicit authorization.
CannotHandleAsStandardType_2 = Cannot handle `{1}` as a type derived from
the {0} standard.
ConnectionAlreadyInitialized_1 = Connection to \u201c{0}\u201d database is
already initialized.
ElementAlreadyInitialized_1 = This metadata element is already
initialized with value \u201c{0}\u201d.
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources_fr.properties
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources_fr.properties
index 12e98cbee0..5cbbad614a 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources_fr.properties
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/Resources_fr.properties
@@ -24,6 +24,7 @@
# U+202F NARROW NO-BREAK SPACE before ; ! and ?
# U+00A0 NO-BREAK SPACE before :
#
+AuthorizationRequired = Les r\u00e9f\u00e9rences vers des
documents externes ne sont pas suivit sans autorisation explicite.
CannotHandleAsStandardType_2 = Ne peut pas g\u00e9rer `{1}` comme un type
d\u00e9riv\u00e9 du standard {0}.
ConnectionAlreadyInitialized_1 = La connexion \u00e0 la base de
donn\u00e9es \u00ab\u202f{0}\u202f\u00bb est d\u00e9j\u00e0 initialis\u00e9e.
ElementAlreadyInitialized_1 = Cet \u00e9l\u00e9ment de
m\u00e9ta-donn\u00e9e est d\u00e9j\u00e0 initialis\u00e9 avec la valeur
\u00ab\u202f{0}\u202f\u00bb.
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/IdentifierSpace.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/IdentifierSpace.java
index 69a865a7cf..4c192cd239 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/IdentifierSpace.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/IdentifierSpace.java
@@ -82,8 +82,8 @@ public interface IdentifierSpace<T> extends Citation {
* is <i>unqualified</i>).</p>
*
* <p>Elements with {@code gco:uuid} attribute can be referenced from
other XML elements using the
- * {@code gco:uuidref} attribute. However, this is not done automatically
by Apache SIS. Users need
- * to manage their set of UUIDs in their own {@link ReferenceResolver}
subclass.</p>
+ * {@code gco:uuidref} attribute. However, this is not done automatically
by Apache <abbr>SIS</abbr>.
+ * Users need to manage their set of UUIDs in their own {@link
ReferenceResolver} subclass.</p>
*
* @see UUID
*/
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/ReferenceResolver.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/ReferenceResolver.java
index 47f2b26da1..2ca93e5608 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/ReferenceResolver.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/ReferenceResolver.java
@@ -18,6 +18,7 @@ package org.apache.sis.xml;
import java.net.URI;
import java.util.UUID;
+import java.nio.file.AccessDeniedException;
import java.lang.reflect.Proxy;
import javax.xml.transform.Source;
import javax.xml.transform.URIResolver;
@@ -46,20 +47,39 @@ import org.apache.sis.xml.internal.shared.XmlUtilities;
* to a unmarshaller.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.7
* @since 0.3
*/
public class ReferenceResolver {
/**
- * The default and thread-safe instance. This instance is used at
unmarshalling time when
- * no {@code ReferenceResolver} was explicitly set by the {@link
XML#RESOLVER} property.
+ * The default resolved used at unmarshalling time when no resolver was
explicitly set.
+ * This instance resolves {@code xlink:href} which are <abbr>URI</abbr>
fragments relative
+ * to the current document, but does not accept to open references to
external documents.
+ *
+ * @see XML#RESOLVER
*/
public static final ReferenceResolver DEFAULT = new ReferenceResolver();
+ /**
+ * A resolver which accepts to open all external documents referenced by
{@code xlink:href}.
+ * By {@linkplain #DEFAULT default}, only <abbr>URI</abbr> fragments
relative to the current document are opened.
+ * But if this resolver is specified as a {@link XML#RESOLVER} property,
all <abbr>URI</abbr>s will be accepted.
+ *
+ * <p><b>Historical note:</b> this was the default behavior in Apache
<abbr>SIS</abbr> 1.5 and 1.6, but
+ * <abbr>SIS</abbr> 1.7 reverted to not opening external document by
default for security reasons.</p>
+ *
+ * @see XML#RESOLVER
+ * @see #canOpenExternal(URI)
+ *
+ * @since 1.7
+ */
+ public static final ReferenceResolver OPEN_EXTERNAL_DOCUMENTS = new
ReferenceResolver();
+
/**
* Provider of sources to use for unmarshalling objects referenced by
links to another document.
* It provides the {@code source} argument in {@link
#resolveExternal(MarshalContext, Source)}.
- * If {@code null}, a default resolution is done.
+ * If {@code null}, relative <abbr>URI</abbr>s will be {@linkplain
URI#resolve(URI) resolved}
+ * against the <abbr>URI</abbr> of the document which contains the
reference.
*
* @since 1.5
*/
@@ -255,7 +275,13 @@ public class ReferenceResolver {
* </ul>
* The resolved URL, if known, should be available in {@link
Source#getSystemId()}.
*
- * <h4>Error handling</h4>
+ * <h4>Authorization to resolve {@code xlink:href}</h4>
+ * If the given {@code source} argument wraps an {@link URI}, then this
method asks to
+ * {@link #canOpenExternal(URI)} whether this {@code ReferenceResolver}
can open that <abbr>URI</abbr>.
+ * If {@code canOpenExternal(…)} returns {@code false}, then an {@link
AccessDeniedException} is thrown.
+ * For security reasons, the default {@code canOpenExternal(…)}
implementation returns always {@code false}.
+ *
+ * <h4>Error handling on failure to resolve {@code xlink:href}</h4>
* The default implementation keeps a cache during the execution of an
{@code XML.unmarshall(…)} method
* (or actually, during a {@linkplain MarshallerPool pooled unmarshaller}
method).
* If an exception is thrown during the document unmarshalling, this
failure is also recorded in the cache.
@@ -271,12 +297,16 @@ public class ReferenceResolver {
*
* @since 1.5
*/
+ @SuppressWarnings("UseSpecificCatch")
protected Object resolveExternal(final MarshalContext context, final
Source source) throws Exception {
final Object document;
final String fragment;
final URI uri;
if (source instanceof URISource) {
final var s = (URISource) source;
+ if (!canOpenExternal(s.document)) {
+ throw new AccessDeniedException(s.document.toString());
+ }
uri = s.getReadableURI();
document = s.document;
fragment = s.fragment;
@@ -347,9 +377,26 @@ public class ReferenceResolver {
return object;
}
+ /**
+ * Returns whether the given external document referenced in a {@code
xlink:href} can be opened.
+ * If this method returns {@code false}, then {@link
#resolveExternal(MarshalContext, Source)}
+ * while throw an {@link AccessDeniedException}.
+ * The {@linkplain #DEFAULT default} implementation returns {@code false}.
+ *
+ * @param document the external document referenced in a {@code
xlink:href}.
+ * @return whether the given document can be opened.
+ *
+ * @see #OPEN_EXTERNAL_DOCUMENTS
+ *
+ * @since 1.7
+ */
+ public boolean canOpenExternal(URI document) {
+ return this == OPEN_EXTERNAL_DOCUMENTS;
+ }
+
/**
* Returns {@code true} if the marshaller can use a {@code
xlink:href="#id"} reference to the given object
- * instead of writing the full XML element. This method is invoked by the
marshaller when:
+ * instead of writing the full <abbr>XML</abbr> element. This method is
invoked by the marshaller when:
*
* <ul>
* <li>The given object has already been marshalled in the same XML
document.</li>
@@ -380,15 +427,16 @@ public class ReferenceResolver {
*
* @since 0.7
*/
- public <T> boolean canSubstituteByReference(final MarshalContext context,
final Class<T> type, final T object, final String id) {
+ public <T> boolean canSubstituteByReference(MarshalContext context,
Class<T> type, T object, String id) {
return true;
}
/**
* Returns {@code true} if the marshaller can use a reference to the given
object
- * instead of writing the full XML element. This method is invoked when an
object to
- * be marshalled has a UUID identifier. Because those object may be
defined externally,
- * SIS cannot know if the object shall be fully marshalled or not.
+ * instead of writing the full <abbr>XML</abbr> element.
+ * This method is invoked when an object to be marshalled has a
<abbr>UUID</abbr> identifier.
+ * Because those object may be defined externally,
+ * <abbr>SIS</abbr> cannot know if the object shall be fully marshalled or
not.
* Such information needs to be provided by the application.
*
* <p>The default implementation returns {@code true} in the following
cases:</p>
@@ -407,7 +455,7 @@ public class ReferenceResolver {
* @return {@code true} if the marshaller can use the {@code uuidref}
attribute
* instead of marshalling the given object.
*/
- public <T> boolean canSubstituteByReference(final MarshalContext context,
final Class<T> type, final T object, final UUID uuid) {
+ public <T> boolean canSubstituteByReference(MarshalContext context,
Class<T> type, T object, UUID uuid) {
return (object instanceof NilObject) || (object instanceof Emptiable
&& ((Emptiable) object).isEmpty());
}
@@ -434,7 +482,7 @@ public class ReferenceResolver {
* @return {@code true} if the marshaller can use the {@code xlink:href}
attribute
* instead of marshalling the given object.
*/
- public <T> boolean canSubstituteByReference(final MarshalContext context,
final Class<T> type, final T object, final XLink link) {
+ public <T> boolean canSubstituteByReference(MarshalContext context,
Class<T> type, T object, XLink link) {
return (object instanceof NilObject) || (object instanceof Emptiable
&& ((Emptiable) object).isEmpty());
}
@@ -469,7 +517,7 @@ public class ReferenceResolver {
* @param text the textual representation of the value for which to
get the anchor.
* @return the anchor for the given text, or {@code null} if none.
*/
- public XLink anchor(final MarshalContext context, final Object value,
final CharSequence text) {
+ public XLink anchor(MarshalContext context, Object value, CharSequence
text) {
return (text instanceof Anchor) ? (Anchor) text : null;
}
}
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XML.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XML.java
index e196954ddb..a63e299a53 100644
--- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XML.java
+++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XML.java
@@ -251,28 +251,32 @@ public final class XML {
public static final String LENIENT_UNMARSHAL =
"org.apache.sis.xml.lenient";
/**
- * Allows client code to replace {@code xlink} or {@code uuidref}
attributes by the actual objects to use.
+ * Allows client code to replace {@code xlink} or {@code uuidref}
attributes by the actual data.
* The value for this property shall be an instance of {@link
ReferenceResolver}.
- *
- * <p>If a property in a XML document is defined only by {@code xlink} or
{@code uuidref} attributes,
- * without any concrete definition, then the default behavior is as
below:</p>
+ * The specified reference resolver (of if none, the {@linkplain
ReferenceResolver#DEFAULT default} one)
+ * is used when a <abbr>XML</abbr> element is defined only by {@code
xlink} or {@code uuidref} attributes,
+ * without any concrete definition. The typical choices are:
*
* <ul>
* <li>If the reference is of the form {@code xlink:href="#foo"} and an
object with the {@code gml:id="foo"}
- * attribute was previously found in the same XML document, then
that object will be used.</li>
- * <li>Otherwise, if {@code xlink:href} references an external document,
that document is unmarshalled.
- * The URI resolution can be controlled with an {@link
javax.xml.transform.URIResolver} specified
- * at construction time.</li>
+ * attribute was previously found in the same <abbr>XML</abbr>
document, then that object will be used.</li>
+ * <li>Otherwise, if {@code xlink:href} references an external document
and the resolver is
+ * {@linkplain ReferenceResolver#canOpenExternal(java.net.URI)
authorized to open external documents},
+ * then that document is unmarshalled.</li>
* <li>Otherwise, an empty element containing only the values of the
above-cited attributes is created.</li>
* </ul>
*
- * Applications can sometimes do better by using some domain-specific
knowledge, for example by searching in a
- * database. Users can define their search algorithm by subclassing {@link
ReferenceResolver} and configuring
+ * A custom {@code ReferenceResolver} can be specified for controlling
{@code xlink:href} handling.
+ * For example, the resolution of <abbr>URI</abbr>s relatively to the base
document can be controlled
+ * with an {@link javax.xml.transform.URIResolver} specified to the {@link
ReferenceResolver} constructor.
+ * Other methods can also be overridden for using some domain-specific
knowledge,
+ * for example by searching in a database the value associated to specific
{@code xlink:href} values.
+ * Users can define their search algorithm by subclassing {@link
ReferenceResolver} and configuring
* a unmarshaller as below:
*
* {@snippet lang="java" :
- * ReferenceResolver myResolver = ...;
- * Map<String,Object> properties = new HashMap<>();
+ * var myResolver = new ReferenceResolver(...);
+ * var properties = new HashMap<String, Object>();
* properties.put(XML.RESOLVER, myResolver);
* Object obj = XML.unmarshal(source, properties);
* }
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/internal/shared/URISource.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/internal/shared/URISource.java
index 9928d89dfa..51cc351f2a 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/internal/shared/URISource.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/internal/shared/URISource.java
@@ -54,9 +54,10 @@ public final class URISource extends StreamSource {
*/
URISource(URI source) throws URISyntaxException {
source = source.normalize();
+ fragment = Strings.trimOrNull(source.getFragment());
// Build a new URI unconditionally because it also decodes escaped
characters.
- URI c = new URI(source.getScheme(), source.getSchemeSpecificPart(),
null);
- if (c.isOpaque() && "file".equalsIgnoreCase(c.getScheme())) {
+ source = new URI(source.getScheme(), source.getSchemeSpecificPart(),
null);
+ if (source.isOpaque() && "file".equalsIgnoreCase(source.getScheme())) {
/*
* If the URI is "file:something" without "/" or "///" characters,
resolve as an absolute path.
* This special case happens if `IOUtilities.toFileOrURI(String)`
did not converted a string to
@@ -64,10 +65,9 @@ public final class URISource extends StreamSource {
* we can now attempt this conversion again. The result will be an
absolute path. This is needed
* for `URI.resolve(URI)` to work.
*/
- c = new File(c.getSchemeSpecificPart()).toURI();
+ source = new File(source.getSchemeSpecificPart()).toURI();
}
- document = source.equals(c) ? source : c; // Share the existing
instance if applicable.
- fragment = Strings.trimOrNull(source.getFragment());
+ document = source;
}
/**
@@ -116,6 +116,8 @@ public final class URISource extends StreamSource {
/**
* Returns a string representation of this source for debugging purposes.
+ *
+ * @return string representation for debugging purposes.
*/
@Override
public String toString() {
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/package-info.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/package-info.java
index eae744a91e..683eaf3014 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/package-info.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/package-info.java
@@ -59,7 +59,7 @@
* @author Guilhem Legal (Geomatys)
* @author Martin Desruisseaux (Geomatys)
* @author Cullen Rombach (Image Matters)
- * @version 1.5
+ * @version 1.7
* @since 0.3
*/
package org.apache.sis.xml;
diff --git
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/xml/TestUsingFile.java
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/xml/TestUsingFile.java
index ee49ef3c34..c20081f7b9 100644
---
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/xml/TestUsingFile.java
+++
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/xml/TestUsingFile.java
@@ -18,7 +18,10 @@ package org.apache.sis.metadata.xml;
import java.net.URL;
import java.io.InputStream;
+import java.net.URISyntaxException;
+import javax.xml.transform.Source;
import org.apache.sis.util.Version;
+import org.apache.sis.xml.internal.shared.URISource;
// Test dependencies
import org.apache.sis.xml.test.TestCase;
@@ -54,6 +57,17 @@ public abstract class TestUsingFile extends TestCase {
this.directory = directory;
}
+ /**
+ * Returns the source to the specified XML file.
+ *
+ * @param filename the XML file in the directory represented by this
enumeration.
+ * @return source for the specified file.
+ * @throws URISyntaxException if the URL to the file is not valid.
+ */
+ public final Source getSource(final String filename) throws
URISyntaxException {
+ return URISource.create(null, getURL(filename).toURI());
+ }
+
/**
* Returns the URL to the specified XML file.
*
diff --git
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverMock.java
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverMock.java
index 90bd05afa8..281bd34db8 100644
---
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverMock.java
+++
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverMock.java
@@ -53,6 +53,7 @@ public final class ReferenceResolverMock extends
ReferenceResolver {
* @param marshalling {@code true} for marshalling, or {@code false} for
unmarshalling.
* @return the (un)marshalling context.
*/
+ @SuppressWarnings("exports")
public static Context begin(final boolean marshalling) {
return new Context(marshalling ? Context.MARSHALLING : 0, null, null,
null, null, null, null,
null, new ReferenceResolverMock(), null, null);
diff --git
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverTest.java
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverTest.java
index 5fc6ef730b..99e672df7f 100644
---
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverTest.java
+++
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverTest.java
@@ -16,7 +16,13 @@
*/
package org.apache.sis.xml;
+import java.util.HashMap;
+import java.util.logging.Filter;
+import java.util.logging.LogRecord;
import java.io.IOException;
+import java.nio.file.AccessDeniedException;
+import java.net.URISyntaxException;
+import javax.xml.transform.Source;
import jakarta.xml.bind.JAXBException;
import org.opengis.metadata.citation.Citation;
import org.opengis.metadata.identification.DataIdentification;
@@ -35,23 +41,76 @@ import static
org.apache.sis.test.Assertions.assertSingleton;
* @author Martin Desruisseaux (Geomatys)
*/
@SuppressWarnings("exports")
-public final class ReferenceResolverTest extends TestUsingFile {
+public final class ReferenceResolverTest extends TestUsingFile implements
Filter {
+ /**
+ * Number of times that an "access denied" warning is expected.
+ */
+ private int expectAccessDenied;
+
/**
* Creates a new test case.
*/
public ReferenceResolverTest() {
}
+ /**
+ * Invoked when a warning occurred during the XML unmarshalling.
+ *
+ * @param record the warning.
+ * @return always {@code false} for keeping the output console quieter.
+ */
+ @Override
+ public boolean isLoggable(final LogRecord record) {
+ assertNotEquals(0, expectAccessDenied);
+ String file = assertInstanceOf(AccessDeniedException.class,
record.getThrown()).getFile();
+ assertTrue(file.endsWith("Citation.xml"), file);
+ expectAccessDenied--;
+ return false;
+ }
+
+ /**
+ * Reads the test <abbr>XML</abbr> document.
+ *
+ * @param readExternal whether to allow the reading of external
documents.
+ */
+ private DataIdentification data(final boolean readExternal) throws
URISyntaxException, JAXBException {
+ final Source source =
Format.XML2016.getSource("UsingExternalXLink.xml");
+ final var properties = new HashMap<String, Object>(4);
+ assertNull(properties.put(XML.WARNING_FILTER, this));
+ if (readExternal) {
+ assertNull(properties.put(XML.RESOLVER,
ReferenceResolver.OPEN_EXTERNAL_DOCUMENTS));
+ }
+ final var data = assertInstanceOf(DataIdentification.class,
XML.unmarshal(source, properties));
+ assertEquals("Test the use of XLink to an external document.",
data.getAbstract().toString());
+ return data;
+ }
+
+ /**
+ * Tests that the attempt to read a fragment in an external document is
denied by default.
+ *
+ * @throws URISyntaxException if an error occurred while getting the URL
to the test file.
+ * @throws IOException if an error occurred while opening the test file.
+ * @throws JAXBException if an error occurred while parsing the test file.
+ */
+ @Test
+ public void testAccessDenied() throws URISyntaxException, IOException,
JAXBException {
+ expectAccessDenied = 2;
+ final DataIdentification data = data(false);
+ final Citation citation = data.getCitation();
+ assertNull(citation.getTitle());
+ assertEquals(0, expectAccessDenied, "Expected a warning.");
+ }
+
/**
* Tests loading a document with a {@code xlink:href} to an external
document.
*
+ * @throws URISyntaxException if an error occurred while getting the URL
to the test file.
* @throws IOException if an error occurred while opening the test file.
* @throws JAXBException if an error occurred while parsing the test file.
*/
@Test
- public void testUsingExternalXLink() throws IOException, JAXBException {
- final var data = (DataIdentification)
XML.unmarshal(Format.XML2016.getURL("UsingExternalXLink.xml"));
- assertEquals("Test the use of XLink to an external document.",
data.getAbstract().toString());
+ public void testUsingExternalXLink() throws URISyntaxException,
IOException, JAXBException {
+ final DataIdentification data = data(true);
final Citation citation = data.getCitation();
DefaultCitationTest.verifyUnmarshalledCitation(citation);
/*
@@ -62,6 +121,5 @@ public final class ReferenceResolverTest extends
TestUsingFile {
assertEquals("Little John", reusing.getName().toString());
assertSame(assertSingleton(parent .getContactInfo()),
assertSingleton(reusing.getContactInfo()));
-
}
}
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/Code.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/Code.java
index 4e08c1bfc3..8aee2eb65e 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/Code.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/xml/bind/referencing/Code.java
@@ -19,9 +19,9 @@ package org.apache.sis.xml.bind.referencing;
import jakarta.xml.bind.annotation.XmlType;
import jakarta.xml.bind.annotation.XmlValue;
import jakarta.xml.bind.annotation.XmlAttribute;
-import org.apache.sis.util.collection.Containers;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.citation.Citation;
+import org.apache.sis.util.collection.Containers;
import org.apache.sis.util.internal.shared.Constants;
import org.apache.sis.util.internal.shared.DefinitionURI;
import org.apache.sis.metadata.internal.shared.NameMeaning;