Author: desruisseaux
Date: Tue Feb 13 18:02:12 2018
New Revision: 1824166
URL: http://svn.apache.org/viewvc?rev=1824166&view=rev
Log:
Replace the use of XMLStreamReader by XMLEventReader.
Added:
sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredXML.java (with props)
Modified:
sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilterVersion.java
sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredEvent.java
sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredReader.java
sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredWriter.java
sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/InputFactory.java
sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java
Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilterVersion.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilterVersion.java?rev=1824166&r1=1824165&r2=1824166&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilterVersion.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilterVersion.java [UTF-8] Tue Feb 13 18:02:12 2018
@@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Collections;
import javax.xml.namespace.QName;
+import org.apache.sis.util.Debug;
import org.apache.sis.internal.jaxb.LegacyNamespaces;
@@ -153,6 +154,14 @@ final class FilterVersion {
final String exportProperty(final String localPart) {
return exports.getOrDefault(localPart, localPart);
}
+
+ /**
+ * Returns the namespace for debugging purpose.
+ */
+ @Override @Debug
+ public String toString() {
+ return namespace;
+ }
}
/**
@@ -241,6 +250,10 @@ final class FilterVersion {
uri = r.namespace;
name = new QName(uri, r.exportProperty(name.getLocalPart()),
Namespaces.getPreferredPrefix(uri, name.getPrefix()));
+ /*
+ * Note: the call for 'getPreferredPrefix' above is required:
+ * JAXB seems to need the prefixes for recognizing namespaces.
+ */
}
}
return name;
Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredEvent.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredEvent.java?rev=1824166&r1=1824165&r2=1824166&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredEvent.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredEvent.java [UTF-8] Tue Feb 13 18:02:12 2018
@@ -207,7 +207,7 @@ abstract class FilteredEvent<E extends X
* This wrapper is used for changing the namespace and sometime the name of the element.
* The attributes may also be modified.
*/
- static final class Start extends FilteredEvent<StartElement> implements StartElement {
+ static class Start extends FilteredEvent<StartElement> implements StartElement {
/** The namespaces, may or may not be the same than the wrapped event. */
private final List<Namespace> namespaces;
@@ -215,7 +215,7 @@ abstract class FilteredEvent<E extends X
private final List<Attribute> attributes;
/** The version to export, used for wrapping namespace context. */
- private final FilterVersion version;
+ final FilterVersion version;
/** Wraps the given event with potentially different name, namespaces and attributes. */
Start(StartElement event, QName name, List<Namespace> namespaces, List<Attribute> attributes, FilterVersion version) {
@@ -225,18 +225,18 @@ abstract class FilteredEvent<E extends X
this.version = version;
}
- @Override public boolean isStartElement() {return true;}
- @Override public StartElement asStartElement() {return this;}
- @Override public int getEventType() {return START_ELEMENT;}
- @Override public Iterator<Namespace> getNamespaces() {return namespaces.iterator();}
- @Override public Iterator<Attribute> getAttributes() {return attributes.iterator();}
+ @Override public final boolean isStartElement() {return true;}
+ @Override public final StartElement asStartElement() {return this;}
+ @Override public final int getEventType() {return START_ELEMENT;}
+ @Override public final Iterator<Namespace> getNamespaces() {return namespaces.iterator();}
+ @Override public final Iterator<Attribute> getAttributes() {return attributes.iterator();}
/**
* Returns the attribute referred to by the given name, or {@code null} if none.
* Current implementation is okay on the assumption that there is few attributes.
*/
@Override
- public Attribute getAttributeByName(final QName name) {
+ public final Attribute getAttributeByName(final QName name) {
for (final Attribute attr : attributes) {
if (name.equals(attr.getName())) {
return attr;
@@ -246,7 +246,8 @@ abstract class FilteredEvent<E extends X
}
/**
- * Gets a read-only namespace context.
+ * Gets a read-only namespace context. Default implementation is suitable for exports
+ * (i.e. write operation). Needs to be overridden for imports (read operation).
*
* @see FilteredWriter#getNamespaceContext()
*/
@@ -257,6 +258,8 @@ abstract class FilteredEvent<E extends X
/**
* Gets the value that the prefix is bound to in the context of this element.
+ * Default implementation is suitable for export (i.e. write operation).
+ * Needs to be overridden for imports (read operation).
*/
@Override
public String getNamespaceURI(final String prefix) {
@@ -267,7 +270,7 @@ abstract class FilteredEvent<E extends X
* Writes the event as per the XML 1.0 without indentation or whitespace.
*/
@Override
- void write(final Appendable out) throws IOException {
+ final void write(final Appendable out) throws IOException {
name(out.append('<'));
final int n = attributes.size();
for (int i=0; i<n; i++) {
@@ -277,4 +280,30 @@ abstract class FilteredEvent<E extends X
out.append('>');
}
}
+
+ /**
+ * Wrapper over an element emitted during the reading of an XML document.
+ */
+ static final class Import extends Start {
+ /** Wraps the given event with potentially different name, namespaces and attributes. */
+ Import(StartElement event, QName name, List<Namespace> namespaces, List<Attribute> attributes, FilterVersion version) {
+ super(event, name, namespaces, attributes, version);
+ }
+
+ /**
+ * Gets a read-only namespace context.
+ */
+ @Override
+ public NamespaceContext getNamespaceContext() {
+ return FilteredNamespaces.importNS(event.getNamespaceContext(), version);
+ }
+
+ /**
+ * Gets the value that the prefix is bound to in the context of this element.
+ */
+ @Override
+ public String getNamespaceURI(final String prefix) {
+ return version.importNS(event.getNamespaceURI(prefix));
+ }
+ }
}
Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredReader.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredReader.java?rev=1824166&r1=1824165&r2=1824166&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredReader.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredReader.java [UTF-8] Tue Feb 13 18:02:12 2018
@@ -22,23 +22,30 @@ import java.util.List;
import java.util.HashSet;
import java.util.HashMap;
import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Collections;
+import java.util.InvalidPropertiesFormatException;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.InputStreamReader;
-import java.util.InvalidPropertiesFormatException;
import javax.xml.namespace.QName;
-import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-import javax.xml.stream.util.StreamReaderDelegate;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Namespace;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.internal.util.CollectionsExt;
+import static javax.xml.stream.XMLStreamConstants.*;
+
/**
* A filter replacing the namespaces found in XML documents by the namespaces expected by SIS at unmarshalling time.
- * This class forwards every method calls to the wrapped {@link XMLStreamReader}, but with some {@code namespaceURI}
+ * This class forwards every method calls to the wrapped {@link XMLEventReader}, but with some {@code namespaceURI}
* modified before being transfered. This class uses a dictionary for identifying the XML namespaces expected by JAXB
* implementation. This is needed when a single namespace in a legacy schema has been splitted into many namespaces
* in the newer schema. This happen for example in the upgrade from ISO 19139:2007 to ISO 19115-3.
@@ -50,7 +57,7 @@ import org.apache.sis.internal.util.Coll
* @since 1.0
* @module
*/
-final class FilteredReader extends StreamReaderDelegate {
+final class FilteredReader extends FilteredXML implements XMLEventReader {
/**
* Location of the file listing types and attributes contained in namespaces.
* The file location is relative to this {@code NamespaceContent} class.
@@ -164,6 +171,18 @@ final class FilteredReader extends Strea
}
/**
+ * Returns the namespace for the given ISO type, or {@code null} if unknown.
+ * This is the namespace used in JAXB annotations.
+ *
+ * @param type a class name defined by ISO 19115 or related standards (e.g. {@code "CI_Citation"}.
+ * @return a namespace for the given type, or {@code null} if unknown.
+ */
+ static String namespace(final String type) {
+ final Map<String,String> attributes = NAMESPACES.get(type);
+ return (attributes != null) ? attributes.get(TYPE_KEY) : null;
+ }
+
+ /**
* The mapping from attribute names to types where such attribute is declared.
* An attribute of the same name may be declared in many types.
*
@@ -194,105 +213,146 @@ final class FilteredReader extends Strea
}
/**
- * The external XML format version to unmarshal from.
+ * The reader from which to read events.
*/
- private final FilterVersion version;
+ private final XMLEventReader in;
/**
- * List of encountered XML tags, in order. Used for backtracking.
- * Elements are removed from this list when they are closed.
+ * List of encountered XML tags, in order. Used for backtracking. Elements are removed from this list
+ * when they are closed. Names should be the ones we get after conversion from namespaces used in XML
+ * document to namespaces used in JAXB annotations.
*/
- private final List<String> outerElements;
+ private final List<QName> outerElements;
/**
- * The {@code localPart} argument given to {@link #namespaceOf(String)}, potentially renamed.
- * For example given the {@code "DCP/distributedComputingPlatform"} entry in {@value #FILENAME} file,
- * a call to {@code namespaceOf("DCP")} will set this field to {@code "distributedComputingPlatform"}.
+ * Creates a new filter for the given version of the standards.
*/
- private String renamed;
+ FilteredReader(final XMLEventReader in, final FilterVersion version) {
+ super(version);
+ this.in = in;
+ outerElements = new ArrayList<>();
+ }
/**
- * Creates a new filter for the given version of the standards.
+ * Checks if there are more events.
*/
- FilteredReader(final XMLStreamReader in, final FilterVersion version) {
- super(in);
- this.version = version;
- outerElements = new ArrayList<>();
+ @Override
+ public boolean hasNext() {
+ return in.hasNext();
}
/**
- * Forwards the call and keep trace of the XML element opened up to this point.
+ * Check the next XMLEvent without reading it from the stream.
*/
@Override
- public int next() throws XMLStreamException {
- return traceElements(super.next());
+ public XMLEvent peek() throws XMLStreamException {
+ return convert(in.peek(), false);
}
/**
- * Forwards the call and keep trace of the XML element opened up to this point.
+ * Returns the next element. Use {@link #nextEvent()} instead.
*/
@Override
- public int nextTag() throws XMLStreamException {
- return traceElements(super.nextTag());
+ public Object next() {
+ return convert((XMLEvent) in.next(), true);
}
/**
- * Keeps trace of XML elements opened up to this point.
- *
- * @param type value of {@link #getEventType()}.
- * @return {@code type}, returned for convenience.
+ * Forwards the call and keep trace of the XML elements opened up to this point.
*/
- private int traceElements(final int type) {
- switch (type) {
+ @Override
+ public XMLEvent nextEvent() throws XMLStreamException {
+ return convert(in.nextEvent(), true);
+ }
+
+ /**
+ * Forwards the call and keep trace of the XML elements opened up to this point.
+ */
+ @Override
+ public XMLEvent nextTag() throws XMLStreamException {
+ return convert(in.nextTag(), true);
+ }
+
+ /**
+ * Keeps trace of XML elements opened up to this point and imports the given event.
+ * This method replaces the namespaces used in XML document by the namespace used by JAXB annotations.
+ *
+ * @param event the event read from the underlying event reader.
+ * @param next {@code true} for a {@code next} operation, or {@code false} for a {@code peek} operation.
+ * @return the converted event (may be the same instance).
+ */
+ @SuppressWarnings("unchecked") // TODO: remove on JDK9
+ private XMLEvent convert(XMLEvent event, final boolean next) {
+ switch (event.getEventType()) {
+ case ATTRIBUTE: {
+ event = convert((Attribute) event);
+ break;
+ }
+ case NAMESPACE: {
+ event = importNS((Namespace) event);
+ break;
+ }
case START_ELEMENT: {
- outerElements.add(getLocalName());
+ final StartElement e = event.asStartElement();
+ final QName originalName = e.getName();
+ final QName name = convert(originalName);
+ boolean changed = name != originalName;
+ for (final Iterator<Attribute> it = e.getAttributes(); it.hasNext();) {
+ final Attribute a = it.next();
+ final Attribute ae = convert(a);
+ changed |= (a != ae);
+ renamedAttributes.add(ae);
+ }
+ final List<Namespace> namespaces = importNS(e.getNamespaces(), changed);
+ if (namespaces != null) {
+ event = new FilteredEvent.Import(e, name, namespaces, attributes(), version);
+ } else {
+ renamedAttributes.clear();
+ }
+ if (next) {
+ outerElements.add(e.getName());
+ }
break;
}
case END_ELEMENT: {
+ final EndElement e = event.asEndElement();
+ final QName originalName = e.getName();
+ final QName name = convert(originalName);
+ final List<Namespace> namespaces = importNS(e.getNamespaces(), name != originalName);
+ if (namespaces != null) {
+ event = new FilteredEvent.End(e, name, namespaces);
+ }
/*
- * If this is an end element, close the last open one with a matching name.
- * It should be the last list element in a well-formed XML, but we loop in
- * the list anyway as a safety.
+ * Close the last start element with a matching name. It should be the last element
+ * on the list in a well-formed XML, but we loop in the list anyway as a safety.
*/
- final String name = getLocalName();
- for (int i = outerElements.size(); --i >= 0;) {
- if (name.equals(outerElements.get(i))) {
- outerElements.remove(i);
- break;
+ if (next) {
+ for (int i = outerElements.size(); --i >= 0;) {
+ if (name.equals(outerElements.get(i))) {
+ outerElements.remove(i);
+ break;
+ }
}
}
break;
}
}
- return type;
- }
-
- /**
- * Returns the namespace of the given ISO type, or {@code null} if unknown.
- * This is the namespace used in JAXB annotations.
- *
- * @param type a class name defined by ISO 19115 or related standards (e.g. {@code "CI_Citation"}.
- * @return a namespace for the given type, or {@code null} if unknown.
- */
- static String namespace(final String type) {
- /*
- * Same implementation than namespaceOf(type) but without DECLARING_TYPES.get(…)
- * since that value should alway be null for class names.
- */
- final Map<String,String> attributes = NAMESPACES.get(type);
- return (attributes != null) ? attributes.get(TYPE_KEY) : null;
+ return event;
}
/**
- * Return the namespace used by implementation (the SIS classes with JAXB annotations)
- * in the context of the current part of the XML document being read.
+ * Imports a name read from the XML document to the name to give to JAXB.
+ * The new namespace depends on both the old namespace and the element name.
+ * The prefix is left unchanged since it can be arbitrary (even if confusing for
+ * human reader used to ISO/TC211 prefixes, it is non-ambiguous to the computer).
*
- * @param localPart the local name of the element or attribute currently being read.
+ * @param name the name of the element or attribute currently being read.
* @return the namespace URI for the element or attribute in the current context (e.g. an ISO 19115-3 namespace),
* or {@code null} if the given name is unknown.
*/
- private String namespaceOf(final String localPart) {
- renamed = localPart;
+ private QName convert(QName name) {
+ String namespace = null; // In this method, null means no change to given name.
+ String localPart = name.getLocalPart();
final Set<String> declaringTypes = DECLARING_TYPES.get(localPart);
if (declaringTypes == null) {
/*
@@ -302,7 +362,7 @@ final class FilteredReader extends Strea
*/
final Map<String,String> attributes = NAMESPACES.get(localPart);
if (attributes != null) {
- return attributes.get(TYPE_KEY);
+ namespace = attributes.get(TYPE_KEY); // May be null.
}
} else {
/*
@@ -310,105 +370,117 @@ final class FilteredReader extends Strea
* possible parent element. Then, we use the namespace associated with that parent.
*/
for (int i = outerElements.size(); --i >= 0;) {
- final String parent = outerElements.get(i);
+ final String parent = outerElements.get(i).getLocalPart();
if (declaringTypes.contains(parent)) {
/*
* A NullPointerException below would be a bug in our algorithm because
* we constructed DECLARING_TYPES from NAMESPACES keys only.
*/
final Map<String,String> attributes = NAMESPACES.get(parent);
- String uri = attributes.get(localPart);
- if (!isNamespace(uri)) {
- renamed = uri;
- uri = attributes.get(uri);
+ namespace = attributes.get(localPart);
+ if (!isNamespace(namespace)) {
+ localPart = namespace;
+ namespace = attributes.get(namespace);
}
- return uri;
+ break;
}
}
}
- return null;
- }
-
- /**
- * Converts a name read from the XML document to the name to give to JAXB.
- * The new namespace depends on both the old namespace and the element name.
- */
- private QName importNS(QName name) {
- final String namespaceURI = name.getNamespaceURI();
- final String localPart = name.getLocalPart();
- String replacement = namespaceOf(localPart);
- if (replacement == null) {
- replacement = version.importNS(namespaceURI);
+ /*
+ * If above code found no namespace by looking in our dictionary of special cases,
+ * maybe there is a simple one-to-one relationship between the old and new namespaces.
+ * Otherwise we leave the namespace unchanged.
+ */
+ final String oldNS = name.getNamespaceURI();
+ if (namespace == null) {
+ namespace = version.importNS(oldNS);
}
- if (!replacement.equals(namespaceURI) || !localPart.equals(renamed)) {
- name = new QName(replacement, renamed, name.getPrefix());
+ /*
+ * Build a new name if any component (URI or local part) changed. Do not specify the prefix
+ * because the same URI in the XML document could map to many different prefixes after we
+ * converted to the namespaces used by JAXB. Having the same prefix for those different URI
+ * may be a source of confusion.
+ */
+ if (!namespace.equals(oldNS) || !localPart.equals(name.getLocalPart())) {
+ name = new QName(namespace, localPart);
}
return name;
}
- /** Replaces the given URI if needed, then forwards the call. */
- @Override
- public void require(final int type, final String namespaceURI, final String localName) throws XMLStreamException {
- super.require(type, version.exportNS(namespaceURI), localName);
- }
-
- /** Returns the context of the underlying reader wrapped in a filter that converts the namespaces on the fly. */
- @Override
- public NamespaceContext getNamespaceContext() {
- return FilteredNamespaces.importNS(super.getNamespaceContext(), version);
- }
-
- /** Forwards the call, then replaces the namespace URI if needed. */
- @Override
- public QName getName() {
- return importNS(super.getName());
- }
-
- /** Forwards the call, then replaces the namespace URI if needed. */
- @Override
- public QName getAttributeName(final int index) {
- return importNS(super.getAttributeName(index));
+ /**
+ * Imports an attribute read from the XML document.
+ * If there is no name change, then this method returns the given instance as-is.
+ */
+ private Attribute convert(Attribute attribute) {
+ final QName originalName = attribute.getName();
+ final QName name = convert(originalName);
+ if (name != originalName) {
+ attribute = new FilteredEvent.Attr(attribute, name);
+ }
+ return attribute;
}
/**
- * Returns the namespace of current element, after replacement by the URI used by SIS.
- * This replacement depends on the current local name in addition of current namespace.
+ * Imports a namespace read from the XML document. This may imply a prefix change.
+ * If there is no namespace change, then this method returns the given instance as-is.
+ *
+ * @param namespace the namespace to import.
*/
- @Override
- public String getNamespaceURI() {
- String namespace = namespaceOf(getLocalName());
- if (namespace == null) {
- namespace = version.importNS(super.getNamespaceURI());
+ private Namespace importNS(final Namespace namespace) {
+ String uri = namespace.getNamespaceURI();
+ if (uri != null && !uri.isEmpty()) {
+ uri = FilteredXML.removeTrailingSlash(uri);
+ final String imported = version.importNS(uri);
+ if (imported != uri) {
+ return new FilteredEvent.NS(namespace, Namespaces.getPreferredPrefix(imported, namespace.getPrefix()), imported);
+ }
}
return namespace;
}
/**
- * Forwards the call, then replaces the returned URI if needed.
+ * Imports the namespaces read from the XML document.
*
- * <b>Note:</b> the index passed to this method is the index of a namespace declaration on the root element.
- * This should not matter as long as each <em>element</em> has the proper namespace URI.
- */
- @Override
- public String getNamespaceURI(int index) {
- return version.importNS(super.getNamespaceURI(index));
+ * @param namespaces the namespaces to filter.
+ * @param changed whether to unconditionally pretend that there is a change.
+ * @return the updated namespaces, or {@code null} if there is no changes.
+ */
+ private List<Namespace> importNS(final Iterator<Namespace> namespaces, boolean changed) {
+ if (!namespaces.hasNext()) {
+ return changed ? Collections.emptyList() : null;
+ }
+ final List<Namespace> modified = new ArrayList<>();
+ do {
+ Namespace namespace = namespaces.next();
+ changed |= (namespace != (namespace = importNS(namespace)));
+ modified.add(namespace);
+ } while (namespaces.hasNext());
+ return changed ? modified : null;
}
- /** Forwards the call, then replaces the returned URI if needed. */
+ /**
+ * Reads the content of a text-only element. Forwards from the underlying reader as-is.
+ */
@Override
- public String getNamespaceURI(final String prefix) {
- return version.importNS(super.getNamespaceURI(prefix));
+ public String getElementText() throws XMLStreamException {
+ return in.getElementText();
}
- /** Forwards the call, then replaces the returned URI if needed. */
+ /**
+ * Get the value of a feature/property from the underlying implementation.
+ */
@Override
- public String getAttributeNamespace(final int index) {
- return version.importNS(super.getAttributeNamespace(index));
+ public Object getProperty(final String name) {
+ return in.getProperty(name);
}
- /** Replaces the given URI if needed, then forwards the call. */
+ /**
+ * Frees any resources associated with this reader.
+ * This method does not close the underlying input source.
+ */
@Override
- public String getAttributeValue(final String namespaceUri, final String localName) {
- return super.getAttributeValue(version.exportNS(namespaceUri), localName);
+ public void close() throws XMLStreamException {
+ outerElements.clear();
+ in.close();
}
}
Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredWriter.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredWriter.java?rev=1824166&r1=1824165&r2=1824166&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredWriter.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredWriter.java [UTF-8] Tue Feb 13 18:02:12 2018
@@ -19,7 +19,6 @@ package org.apache.sis.xml;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
@@ -51,18 +50,13 @@ import static javax.xml.stream.XMLStream
* @since 1.0
* @module
*/
-final class FilteredWriter implements XMLEventWriter {
+final class FilteredWriter extends FilteredXML implements XMLEventWriter {
/**
* Where events are sent.
*/
private final XMLEventWriter out;
/**
- * The other version to marshal to.
- */
- private final FilterVersion version;
-
- /**
* Keep track of namespace URIs that have already been declared so they don't get duplicated.
* This map is recycled in two different contexts:
*
@@ -74,19 +68,12 @@ final class FilteredWriter implements XM
private final Map<String, Namespace> uniqueNamespaces;
/**
- * Temporary list of attributes after their namespace change.
- * This list is recycled for each XML element to be read.
- */
- private final List<Attribute> exportedAttributes;
-
- /**
* Creates a new filter for the given version of the standards.
*/
FilteredWriter(final XMLEventWriter out, final FilterVersion version) {
+ super(version);
this.out = out;
- this.version = version;
uniqueNamespaces = new LinkedHashMap<>();
- exportedAttributes = new ArrayList<>();
}
/**
@@ -113,11 +100,7 @@ final class FilteredWriter implements XM
private Namespace exportIfNew(final Namespace namespace) {
String uri = namespace.getNamespaceURI();
if (uri != null && !uri.isEmpty()) {
- final int end = uri.length() - 1;
- if (uri.charAt(end) == '/') {
- uri = uri.substring(0, end); // Trim trailing '/' in URI.
- }
- final String exported = version.exportNS(uri);
+ final String exported = version.exportNS(removeTrailingSlash(uri));
if (exported != uri) {
return uniqueNamespaces.computeIfAbsent(exported, (k) -> {
return new FilteredEvent.NS(namespace, Namespaces.getPreferredPrefix(k, namespace.getPrefix()), k);
@@ -188,21 +171,13 @@ final class FilteredWriter implements XM
final Attribute a = it.next();
final Attribute ae = export(a);
changed |= (a != ae);
- exportedAttributes.add(ae);
+ renamedAttributes.add(ae);
}
final List<Namespace> namespaces = export(e.getNamespaces(), changed);
if (namespaces != null) {
- final List<Attribute> attributes;
- switch (exportedAttributes.size()) {
- case 0: attributes = Collections.emptyList(); break; // Avoid object creation for this common case.
- case 1: attributes = Collections.singletonList(exportedAttributes.remove(0)); break;
- default: attributes = Arrays.asList(exportedAttributes.toArray(new Attribute[exportedAttributes.size()]));
- exportedAttributes.clear();
- break;
- }
- event = new FilteredEvent.Start(e, name, namespaces, attributes, version);
+ event = new FilteredEvent.Start(e, name, namespaces, attributes(), version);
} else {
- exportedAttributes.clear();
+ renamedAttributes.clear();
}
break;
}
Added: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredXML.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredXML.java?rev=1824166&view=auto
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredXML.java (added)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredXML.java [UTF-8] Tue Feb 13 18:02:12 2018
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.xml;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import javax.xml.stream.events.Attribute;
+
+
+/**
+ * Base class of XML reader or writer replacing the namespaces used by JAXB by namespaces used in the XML document,
+ * or conversely (depending on the direction of the I/O operation).
+ *
+ * See {@link FilteredNamespaces} for more information.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @author Cullen Rombach (Image Matters)
+ * @version 1.0
+ * @since 1.0
+ * @module
+ */
+abstract class FilteredXML {
+ /**
+ * The external XML format version to (un)marshal from.
+ */
+ final FilterVersion version;
+
+ /**
+ * Temporary list of attributes after their namespace change.
+ * This list is recycled for each XML element to be read or written.
+ */
+ final List<Attribute> renamedAttributes;
+
+ /**
+ * Creates a new XML reader or writer.
+ */
+ FilteredXML(final FilterVersion version) {
+ this.version = version;
+ renamedAttributes = new ArrayList<>();
+ }
+
+ /**
+ * Removes the trailing slash in given URI, if any. It is caller's responsibility
+ * to ensure that the URI is not null and not empty before to invoke this method.
+ */
+ static String removeTrailingSlash(String uri) {
+ final int end = uri.length() - 1;
+ if (uri.charAt(end) == '/') {
+ uri = uri.substring(0, end);
+ }
+ return uri;
+ }
+
+ /**
+ * Returns a snapshot of {@link #renamedAttributes} list and clears the later.
+ */
+ final List<Attribute> attributes() {
+ final List<Attribute> attributes;
+ switch (renamedAttributes.size()) {
+ case 0: attributes = Collections.emptyList(); break; // Avoid object creation for this common case.
+ case 1: attributes = Collections.singletonList(renamedAttributes.remove(0)); break;
+ default: attributes = Arrays.asList(renamedAttributes.toArray(new Attribute[renamedAttributes.size()]));
+ renamedAttributes.clear();
+ break;
+ }
+ return attributes;
+ }
+}
Propchange: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredXML.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/FilteredXML.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/InputFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/InputFactory.java?rev=1824166&r1=1824165&r2=1824166&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/InputFactory.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/InputFactory.java [UTF-8] Tue Feb 13 18:02:12 2018
@@ -37,7 +37,7 @@ import org.apache.sis.util.Static;
* only when first needed, when initializing this class.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
* @since 0.4
* @module
*/
@@ -55,7 +55,7 @@ final class InputFactory extends Static
/*
* Do not provide convenience method for java.io.File, because the caller needs to close the created
- * input stream himself (this is not done by XMLStreamReader.close(), despite its method name).
+ * input stream himself (this is not done by XMLEventReader.close(), despite its method name).
*/
/**
@@ -65,8 +65,8 @@ final class InputFactory extends Static
* @return the reader.
* @throws XMLStreamException if the reader can not be created.
*/
- public static XMLStreamReader createXMLStreamReader(final InputStream in) throws XMLStreamException {
- return FACTORY.createXMLStreamReader(in);
+ public static XMLEventReader createXMLEventReader(final InputStream in) throws XMLStreamException {
+ return FACTORY.createXMLEventReader(in);
}
/**
@@ -76,8 +76,8 @@ final class InputFactory extends Static
* @return the reader.
* @throws XMLStreamException if the reader can not be created.
*/
- public static XMLStreamReader createXMLStreamReader(final Reader in) throws XMLStreamException {
- return FACTORY.createXMLStreamReader(in);
+ public static XMLEventReader createXMLEventReader(final Reader in) throws XMLStreamException {
+ return FACTORY.createXMLEventReader(in);
}
/**
@@ -87,8 +87,8 @@ final class InputFactory extends Static
* @return the reader.
* @throws XMLStreamException if the reader can not be created.
*/
- public static XMLStreamReader createXMLStreamReader(final InputSource in) throws XMLStreamException {
- return FACTORY.createXMLStreamReader(new SAXSource(in));
+ public static XMLEventReader createXMLEventReader(final InputSource in) throws XMLStreamException {
+ return FACTORY.createXMLEventReader(new SAXSource(in));
}
/**
@@ -98,8 +98,8 @@ final class InputFactory extends Static
* @return the reader.
* @throws XMLStreamException if the reader can not be created.
*/
- public static XMLStreamReader createXMLStreamReader(final XMLEventReader in) throws XMLStreamException {
- return FACTORY.createXMLStreamReader(new StAXSource(in));
+ public static XMLEventReader createXMLEventReader(final XMLStreamReader in) throws XMLStreamException {
+ return FACTORY.createXMLEventReader(new StAXSource(in));
}
/**
@@ -109,8 +109,8 @@ final class InputFactory extends Static
* @return the reader.
* @throws XMLStreamException if the reader can not be created.
*/
- public static XMLStreamReader createXMLStreamReader(final Node in) throws XMLStreamException {
- return FACTORY.createXMLStreamReader(new DOMSource(in));
+ public static XMLEventReader createXMLEventReader(final Node in) throws XMLStreamException {
+ return FACTORY.createXMLEventReader(new DOMSource(in));
}
/**
@@ -120,7 +120,7 @@ final class InputFactory extends Static
* @return the reader.
* @throws XMLStreamException if the reader can not be created.
*/
- public static XMLStreamReader createXMLStreamReader(final Source in) throws XMLStreamException {
- return FACTORY.createXMLStreamReader(in);
+ public static XMLEventReader createXMLEventReader(final Source in) throws XMLStreamException {
+ return FACTORY.createXMLEventReader(in);
}
}
Modified: sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java
URL: http://svn.apache.org/viewvc/sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java?rev=1824166&r1=1824165&r2=1824166&view=diff
==============================================================================
--- sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java [UTF-8] (original)
+++ sis/branches/ISO-19115-3/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java [UTF-8] Tue Feb 13 18:02:12 2018
@@ -55,7 +55,7 @@ import org.apache.sis.internal.jaxb.Cont
* </ul>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.4
+ * @version 1.0
* @since 0.3
* @module
*/
@@ -117,7 +117,7 @@ final class PooledUnmarshaller extends P
* @param version identify the namespace substitutions to perform.
* @return the unmarshalled object.
*/
- private Object unmarshal(XMLStreamReader input, final FilterVersion version)
+ private Object unmarshal(XMLEventReader input, final FilterVersion version)
throws XMLStreamException, JAXBException
{
input = new FilteredReader(input, version);
@@ -133,10 +133,10 @@ final class PooledUnmarshaller extends P
}
/**
- * Same as {@link #unmarshal(XMLStreamReader, FilterVersion)}, but delegating to the unmarshaller
+ * Same as {@link #unmarshal(XMLEventReader, FilterVersion)}, but delegating to the unmarshaller
* methods returning a JAXB element instead than the one returning the object.
*/
- private <T> JAXBElement<T> unmarshal(XMLStreamReader input, final FilterVersion version, final Class<T> declaredType)
+ private <T> JAXBElement<T> unmarshal(XMLEventReader input, final FilterVersion version, final Class<T> declaredType)
throws XMLStreamException, JAXBException
{
input = new FilteredReader(input, version);
@@ -158,7 +158,7 @@ final class PooledUnmarshaller extends P
public Object unmarshal(final InputStream input) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version);
+ return unmarshal(InputFactory.createXMLEventReader(input), version);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -179,7 +179,7 @@ final class PooledUnmarshaller extends P
final FilterVersion version = getFilterVersion();
if (version != null) try {
try (InputStream s = input.openStream()) {
- return unmarshal(InputFactory.createXMLStreamReader(s), version);
+ return unmarshal(InputFactory.createXMLEventReader(s), version);
}
} catch (IOException | XMLStreamException e) {
throw new JAXBException(e);
@@ -201,7 +201,7 @@ final class PooledUnmarshaller extends P
final FilterVersion version = getFilterVersion();
if (version != null) try {
try (InputStream s = new BufferedInputStream(new FileInputStream(input))) {
- return unmarshal(InputFactory.createXMLStreamReader(s), version);
+ return unmarshal(InputFactory.createXMLEventReader(s), version);
}
} catch (IOException | XMLStreamException e) {
throw new JAXBException(e);
@@ -222,7 +222,7 @@ final class PooledUnmarshaller extends P
public Object unmarshal(final Reader input) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version);
+ return unmarshal(InputFactory.createXMLEventReader(input), version);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -242,7 +242,7 @@ final class PooledUnmarshaller extends P
public Object unmarshal(final InputSource input) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version);
+ return unmarshal(InputFactory.createXMLEventReader(input), version);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -262,7 +262,7 @@ final class PooledUnmarshaller extends P
public Object unmarshal(final Node input) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version);
+ return unmarshal(InputFactory.createXMLEventReader(input), version);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -282,7 +282,7 @@ final class PooledUnmarshaller extends P
public <T> JAXBElement<T> unmarshal(final Node input, final Class<T> declaredType) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version, declaredType);
+ return unmarshal(InputFactory.createXMLEventReader(input), version, declaredType);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -302,7 +302,7 @@ final class PooledUnmarshaller extends P
public Object unmarshal(final Source input) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version);
+ return unmarshal(InputFactory.createXMLEventReader(input), version);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -322,7 +322,7 @@ final class PooledUnmarshaller extends P
public <T> JAXBElement<T> unmarshal(final Source input, final Class<T> declaredType) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version, declaredType);
+ return unmarshal(InputFactory.createXMLEventReader(input), version, declaredType);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -339,44 +339,10 @@ final class PooledUnmarshaller extends P
* Delegates the unmarshalling to the wrapped unmarshaller.
*/
@Override
- public Object unmarshal(XMLStreamReader input) throws JAXBException {
- final FilterVersion version = getFilterVersion();
- if (version != null) {
- input = new FilteredReader(input, version);
- }
- final Context context = begin();
- try {
- return unmarshaller.unmarshal(input);
- } finally {
- context.finish();
- }
- }
-
- /**
- * Delegates the unmarshalling to the wrapped unmarshaller.
- */
- @Override
- public <T> JAXBElement<T> unmarshal(XMLStreamReader input, final Class<T> declaredType) throws JAXBException {
- final FilterVersion version = getFilterVersion();
- if (version != null) {
- input = new FilteredReader(input, version);
- }
- final Context context = begin();
- try {
- return unmarshaller.unmarshal(input, declaredType);
- } finally {
- context.finish();
- }
- }
-
- /**
- * Delegates the unmarshalling to the wrapped unmarshaller.
- */
- @Override
- public Object unmarshal(final XMLEventReader input) throws JAXBException {
+ public Object unmarshal(final XMLStreamReader input) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version);
+ return unmarshal(InputFactory.createXMLEventReader(input), version);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -393,10 +359,10 @@ final class PooledUnmarshaller extends P
* Delegates the unmarshalling to the wrapped unmarshaller.
*/
@Override
- public <T> JAXBElement<T> unmarshal(final XMLEventReader input, final Class<T> declaredType) throws JAXBException {
+ public <T> JAXBElement<T> unmarshal(final XMLStreamReader input, final Class<T> declaredType) throws JAXBException {
final FilterVersion version = getFilterVersion();
if (version != null) try {
- return unmarshal(InputFactory.createXMLStreamReader(input), version, declaredType);
+ return unmarshal(InputFactory.createXMLEventReader(input), version, declaredType);
} catch (XMLStreamException e) {
throw new JAXBException(e);
} else {
@@ -409,6 +375,40 @@ final class PooledUnmarshaller extends P
}
}
+ /**
+ * Delegates the unmarshalling to the wrapped unmarshaller.
+ */
+ @Override
+ public Object unmarshal(XMLEventReader input) throws JAXBException {
+ final FilterVersion version = getFilterVersion();
+ if (version != null) {
+ input = new FilteredReader(input, version);
+ }
+ final Context context = begin();
+ try {
+ return unmarshaller.unmarshal(input);
+ } finally {
+ context.finish();
+ }
+ }
+
+ /**
+ * Delegates the unmarshalling to the wrapped unmarshaller.
+ */
+ @Override
+ public <T> JAXBElement<T> unmarshal(XMLEventReader input, final Class<T> declaredType) throws JAXBException {
+ final FilterVersion version = getFilterVersion();
+ if (version != null) {
+ input = new FilteredReader(input, version);
+ }
+ final Context context = begin();
+ try {
+ return unmarshaller.unmarshal(input, declaredType);
+ } finally {
+ context.finish();
+ }
+ }
+
/**
* Delegates to the wrapped unmarshaller.
*/
|