Author: desruisseaux Date: Sat Jun 25 00:30:30 2016 New Revision: 1750175 URL: http://svn.apache.org/viewvc?rev=1750175&view=rev Log: Begin refactoring of GPX reader. The intend is to have it as a DataStore subclass. Added: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/XMLStoreProvider.java (with props) sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/package-info.java (with props) Removed: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/AbstractConfigurable.java Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/XMLInputFactory.java sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamWriter.java sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXReaderTest.java sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXWriterTest.java Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/XMLInputFactory.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/XMLInputFactory.java?rev=1750175&r1=1750174&r2=1750175&view=diff ============================================================================== --- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/XMLInputFactory.java [UTF-8] (original) +++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/XMLInputFactory.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -37,7 +37,7 @@ import org.apache.sis.util.Static; * * @author Martin Desruisseaux (Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.8 * @module */ public final class XMLInputFactory extends Static { @@ -52,6 +52,31 @@ public final class XMLInputFactory exten private XMLInputFactory() { } + /** + * Creates a new reader for the given object. The given object should be one of the types + * expected by a {@code createXMLStreamReader(…)} method defined in this class. + * + *

Note that this method does not open streams from files, paths or URLs. + * Creating input streams and closing them after usage are caller's responsibility.

+ * + * @param in where to read from. + * @return the reader, or {@code null} if the given file where not recognized. + * @throws XMLStreamException if the type of the given input is one recognized types, + * but despite that the reader can not be created. + * + * @since 0.8 + */ + public static XMLStreamReader createFromAny(final Object in) throws XMLStreamException { + if (in instanceof XMLStreamReader) return ((XMLStreamReader) in); + if (in instanceof XMLEventReader) return createXMLStreamReader((XMLEventReader) in); + if (in instanceof InputSource) return createXMLStreamReader((InputSource) in); + if (in instanceof InputStream) return createXMLStreamReader((InputStream) in); + if (in instanceof Reader) return createXMLStreamReader((Reader) in); + if (in instanceof Source) return createXMLStreamReader((Source) in); + if (in instanceof Node) return createXMLStreamReader((Node) in); + return null; + } + /* * 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 XMLInputFactory.close(), despite its method name). @@ -60,9 +85,9 @@ public final class XMLInputFactory exten /** * Creates a new reader for the given stream. * - * @param in Where to read from. - * @return The reader. - * @throws XMLStreamException If the reader can not be created. + * @param in where to read from. + * @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); @@ -71,9 +96,9 @@ public final class XMLInputFactory exten /** * Creates a new reader for the given stream. * - * @param in Where to read from. - * @return The reader. - * @throws XMLStreamException If the reader can not be created. + * @param in where to read from. + * @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); @@ -82,9 +107,9 @@ public final class XMLInputFactory exten /** * Creates a new reader for the given source. * - * @param in Where to read from. - * @return The reader. - * @throws XMLStreamException If the reader can not be created. + * @param in where to read from. + * @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)); @@ -93,9 +118,9 @@ public final class XMLInputFactory exten /** * Creates a new reader for the given source. * - * @param in Where to read from. - * @return The reader. - * @throws XMLStreamException If the reader can not be created. + * @param in where to read from. + * @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)); @@ -104,9 +129,9 @@ public final class XMLInputFactory exten /** * Creates a new reader for the given source. * - * @param in Where to read from. - * @return The reader. - * @throws XMLStreamException If the reader can not be created. + * @param in where to read from. + * @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)); @@ -115,9 +140,9 @@ public final class XMLInputFactory exten /** * Creates a new reader for the given source. * - * @param in Where to read from. - * @return The reader. - * @throws XMLStreamException If the reader can not be created. + * @param in where to read from. + * @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); Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java?rev=1750175&r1=1750174&r2=1750175&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/IOUtilities.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -442,7 +442,7 @@ public final class IOUtilities extends S */ final Set optionSet; if (options == null || options.length == 0) { - optionSet = Collections.emptySet(); + optionSet = Collections.singleton(StandardOpenOption.READ); } else { optionSet = new HashSet<>(Arrays.asList(options)); optionSet.add(StandardOpenOption.READ); Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java?rev=1750175&r1=1750174&r2=1750175&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -90,7 +90,7 @@ public abstract class DataStore implemen * or distributor, data quality, update frequency, usage constraints and more. * * @return Information about the dataset, or {@code null} if none. - * @throws DataStoreException If an error occurred while reading the data. + * @throws DataStoreException if an error occurred while reading the data. */ public abstract Metadata getMetadata() throws DataStoreException; @@ -118,7 +118,7 @@ public abstract class DataStore implemen * } * * @param listener The listener to add. - * @throws IllegalArgumentException If the given listener is already registered in this data store. + * @throws IllegalArgumentException if the given listener is already registered in this data store. */ public void addWarningListener(final WarningListener listener) throws IllegalArgumentException @@ -130,7 +130,7 @@ public abstract class DataStore implemen * Removes a previously registered listener. * * @param listener The listener to remove. - * @throws NoSuchElementException If the given listener is not registered in this data store. + * @throws NoSuchElementException if the given listener is not registered in this data store. */ public void removeWarningListener(final WarningListener listener) throws NoSuchElementException @@ -141,7 +141,7 @@ public abstract class DataStore implemen /** * Closes this data store and releases any underlying resources. * - * @throws DataStoreException If an error occurred while closing this data store. + * @throws DataStoreException if an error occurred while closing this data store. */ @Override public abstract void close() throws DataStoreException; Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java?rev=1750175&r1=1750174&r2=1750175&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -16,7 +16,6 @@ */ package org.apache.sis.internal.gpx; -import org.apache.sis.internal.xml.StaxStreamReader; import com.esri.core.geometry.Point; import java.io.IOException; import java.net.URI; @@ -34,11 +33,18 @@ import java.util.List; import javax.xml.stream.XMLStreamException; import org.opengis.geometry.Envelope; import org.opengis.feature.Feature; +import org.opengis.metadata.Metadata; -import static javax.xml.stream.XMLStreamReader.*; +import javax.xml.stream.XMLStreamReader; import org.apache.sis.geometry.ImmutableEnvelope; -import static org.apache.sis.internal.gpx.GPXConstants.*; import org.apache.sis.referencing.CommonCRS; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.StorageConnector; +import org.apache.sis.internal.xml.StaxStreamReader; + +import static javax.xml.stream.XMLStreamReader.*; +import static org.apache.sis.internal.gpx.GPXConstants.*; + /** * Stax reader class for GPX 1.0 and 1.1 files. @@ -66,7 +72,7 @@ import org.apache.sis.referencing.Common */ public class GPXReader extends StaxStreamReader { - private MetaData metadata; + MetaData metadata; // TODO private Feature current; private int wayPointInc = 0; private int routeInc = 0; @@ -81,9 +87,10 @@ public class GPXReader extends StaxStrea * @throws IOException if input failed to be opened for any IO reason * @throws XMLStreamException if input is not a valid XML stream */ - @Override - public void setInput(final Object input) throws IOException, XMLStreamException { - super.setInput(input); + public GPXReader(final StorageConnector storage) throws DataStoreException, IOException, XMLStreamException { + super(storage); + final Object input = storage.getStorage(); + final XMLStreamReader reader = getReader(); //search for the bound tag to generate the envelope searchLoop : @@ -147,16 +154,17 @@ public class GPXReader extends StaxStrea * * @return Metadata or null if input is not set. */ - public MetaData getMetadata() { - return metadata; + @Override + public Metadata getMetadata() { + return null; // TODO } /** * {@inheritDoc } */ @Override - public void reset() throws IOException, XMLStreamException { - super.reset(); + public void close() throws DataStoreException { + super.close(); metadata = null; current = null; wayPointInc = 0; @@ -171,7 +179,7 @@ public class GPXReader extends StaxStrea * @throws javax.xml.stream.XMLStreamException if xml parser encounter an invalid * element or underlying stream caused an exception */ - public boolean hasNext() throws XMLStreamException { + public boolean hasNext() throws DataStoreException, XMLStreamException { findNext(); return current != null; } @@ -183,7 +191,7 @@ public class GPXReader extends StaxStrea * @throws javax.xml.stream.XMLStreamException if xml parser encounter an invalid * element or underlying stream caused an exception */ - public Feature next() throws XMLStreamException { + public Feature next() throws DataStoreException, XMLStreamException { findNext(); final Feature ele = current; current = null; @@ -194,7 +202,8 @@ public class GPXReader extends StaxStrea * Search for the next feature in the stax stream. * This method will set the current local property if there is one. */ - private void findNext() throws XMLStreamException { + private void findNext() throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); if(current != null) return; boolean first = true; @@ -230,7 +239,8 @@ public class GPXReader extends StaxStrea * * @return MetaData */ - private MetaData parseMetaData100() throws XMLStreamException { + private MetaData parseMetaData100() throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final MetaData metadata = new MetaData(); @@ -284,8 +294,8 @@ public class GPXReader extends StaxStrea * * @return MetaData */ - private MetaData parseMetaData110() throws XMLStreamException { - + private MetaData parseMetaData110() throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final MetaData metadata = new MetaData(); while (reader.hasNext()) { @@ -330,8 +340,8 @@ public class GPXReader extends StaxStrea * * @return CopyRight */ - private CopyRight parseCopyRight() throws XMLStreamException { - + private CopyRight parseCopyRight() throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final CopyRight copyright = new CopyRight(); copyright.setAuthor(reader.getAttributeValue(null, ATT_COPYRIGHT_AUTHOR)); @@ -368,8 +378,8 @@ public class GPXReader extends StaxStrea * * @return URI */ - private URI parseLink() throws XMLStreamException { - + private URI parseLink() throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); String text = reader.getAttributeValue(null, ATT_LINK_HREF); String mime = null; @@ -407,8 +417,8 @@ public class GPXReader extends StaxStrea * * @return Person */ - private Person parsePerson() throws XMLStreamException { - + private Person parsePerson() throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final Person person = new Person(); while (reader.hasNext()) { @@ -443,7 +453,8 @@ public class GPXReader extends StaxStrea * * @return Envelope */ - private Envelope parseBound() throws XMLStreamException { + private Envelope parseBound() throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final String xmin = reader.getAttributeValue(null, ATT_BOUNDS_MINLON); final String xmax = reader.getAttributeValue(null, ATT_BOUNDS_MAXLON); final String ymin = reader.getAttributeValue(null, ATT_BOUNDS_MINLAT); @@ -453,7 +464,7 @@ public class GPXReader extends StaxStrea throw new XMLStreamException("Error in xml file, metadata bounds not defined correctly"); } - toTagEnd(TAG_BOUNDS); + skipUntilEnd(TAG_BOUNDS); return new ImmutableEnvelope(new double[] {Double.parseDouble(xmin), Double.parseDouble(ymin)}, new double[] {Double.parseDouble(xmax), Double.parseDouble(ymax)}, @@ -466,8 +477,8 @@ public class GPXReader extends StaxStrea * * @return Feature */ - private Feature parseWayPoint(final int index) throws XMLStreamException { - + private Feature parseWayPoint(final int index) throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final Feature feature = TYPE_WAYPOINT.newInstance(); feature.setPropertyValue("index", index); @@ -558,8 +569,8 @@ public class GPXReader extends StaxStrea * * @return Feature */ - private Feature parseRoute(final int index) throws XMLStreamException { - + private Feature parseRoute(final int index) throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final Feature feature = TYPE_ROUTE.newInstance(); feature.setPropertyValue("index", index); @@ -621,8 +632,8 @@ public class GPXReader extends StaxStrea * * @return Feature */ - private Feature parseTrackSegment(final int index) throws XMLStreamException { - + private Feature parseTrackSegment(final int index) throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final Feature feature = TYPE_TRACK_SEGMENT.newInstance(); feature.setPropertyValue("index", index); int ptInc = 0; @@ -658,8 +669,8 @@ public class GPXReader extends StaxStrea * * @return Feature */ - private Feature parseTrack(final int index) throws XMLStreamException { - + private Feature parseTrack(final int index) throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); final Feature feature = TYPE_TRACK.newInstance(); feature.setPropertyValue("index", index); int segInc = 0; Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java?rev=1750175&r1=1750174&r2=1750175&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -16,290 +16,216 @@ */ package org.apache.sis.internal.xml; -import java.io.*; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.Result; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.dom.DOMSource; -import org.w3c.dom.Node; - -import java.net.URI; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.stream.XMLInputFactory; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.util.NoSuchElementException; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; -import javax.xml.transform.Source; -import javax.xml.transform.TransformerException; - -import static javax.xml.stream.XMLStreamReader.*; import javax.xml.stream.util.StreamReaderDelegate; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.stax.StAXSource; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; +import org.apache.sis.storage.DataStore; +import org.apache.sis.storage.DataStoreException; +import org.apache.sis.storage.StorageConnector; +import org.apache.sis.internal.system.XMLInputFactory; +import org.apache.sis.util.resources.Errors; +import org.apache.sis.util.ArgumentChecks; +import org.apache.sis.util.Classes; + /** - * An abstract class for all stax parser.
- * Readers for a given specification should extend this class and - * provide appropriate read methods.
- *
- * Example :
- *
- * {@code
- * public class UserReader extends StaxStreamReader{
+ * Base class of Apache SIS readers of XML files using STAX parser.
+ * Readers for a given specification should extend this class and provide appropriate read methods.
  *
- *   public User read() throws XMLStreamException{
- *      //casual stax reading operations
- *      return user;
- *   }
- * }
- * }
- * 
- * And should be used like :
- *
- * {@code
- * final UserReader instance = new UserReader();
- * try{
- *     instance.setInput(stream);
- *     user = instance.read();
- * }finally{
- *     instance.dispose();
+ * 

Example:

+ * {@preformat + * public class UserObjectReader extends StaxStreamReader { + * public UserObject read() throws XMLStreamException { + * // Actual STAX reading operations. + * return userObject; + * } + * } * } + * + * And should be used like below: + * + * {@preformat + * UserObject obj; + * try (UserObjectReader reader = new UserObjectReader(input)) { + * obj = instance.read(); + * } * } - *
* - * @author Johann Sorel (Geomatys) - * @since 0.7 - * @version 0.7 + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @since 0.8 + * @version 0.8 * @module */ -public abstract class StaxStreamReader extends AbstractConfigurable implements AutoCloseable { - +public abstract class StaxStreamReader extends DataStore { /** - * Wrapped xml stream reader + * The XML stream reader. */ - protected XMLStreamReader reader; - + private XMLStreamReader reader; + /** - * Store the input stream if it was generated by the parser itself. - * It will closed on the dispose method or when a new input is set. + * The underlying reader or input stream to close when this {@code StaxStreamReader} is closed, + * or {@code null} if none. */ - private InputStream sourceStream; + private Closeable sourceStream; /** - * close potentiel previous stream and cache if there are some. - * This way the reader can be reused for a different input later. - * The underlying stax reader will be closed. - * - * @throws java.io.IOException if previous source stream caused an exception on close - * @throws javax.xml.stream.XMLStreamException if previous stax reader caused an exception on close + * Creates a new XML store from the given file, URL, stream or reader object. + * This constructor invokes {@link StorageConnector#closeAllExcept(Object)}, + * keeping open only the needed resource. + * + * @param storage information about the storage (URL, stream, etc). + * @throws DataStoreException if an error occurred while opening the XML file. */ - public void reset() throws IOException, XMLStreamException { - if(sourceStream != null){ - sourceStream.close(); - sourceStream = null; - } - if(reader != null){ - reader.close(); - reader = null; + protected StaxStreamReader(final StorageConnector storage) throws DataStoreException { + ArgumentChecks.ensureNonNull("storage", storage); + Object obj = storage.getStorage(); + try { + reader = XMLInputFactory.createFromAny(obj); + if (reader != null) { + if (obj instanceof Closeable) { + sourceStream = (Closeable) obj; + } + } else { + final InputStream in = storage.getStorageAs(InputStream.class); + if (in == null) { + throw new DataStoreException(Errors.format(Errors.Keys.IllegalInputTypeForReader_2, "XML", Classes.getClass(obj))); + } + reader = XMLInputFactory.createXMLStreamReader(in); + sourceStream = in; + obj = in; + } + } catch (XMLStreamException e) { + throw new DataStoreException(e); } + storage.closeAllExcept(obj); } /** - * Release potentiel locks or opened stream. - * Must be called when the reader is not needed anymore. - * It should not be used after this method has been called. + * Returns the error resources in the current locale. */ - @Override - public void close() throws Exception { - reset(); - } - - /** - * Set the input for this reader.
- * Handle types are :
- * - java.io.File
- * - java.io.Reader
- * - java.io.InputStream
- * - java.net.URL
- * - java.net.URI
- * - javax.xml.stream.XMLStreamReader
- * - javax.xml.transform.Source
- * - * @param input input object - * @throws IOException if input failed to be opened for any IO reason - * @throws XMLStreamException if input is not a valid XML stream - */ - public void setInput(Object input) throws IOException, XMLStreamException { - reset(); - - if(input instanceof XMLStreamReader){ - reader = (XMLStreamReader) input; - return; - } - - if(input instanceof File){ - sourceStream = new FileInputStream((File)input); - input = sourceStream; - }else if(input instanceof Path){ - sourceStream = Files.newInputStream((Path)input, StandardOpenOption.READ); - input = sourceStream; - }else if(input instanceof URL){ - sourceStream = ((URL)input).openStream(); - input = sourceStream; - }else if(input instanceof URI){ - sourceStream = ((URI)input).toURL().openStream(); - input = sourceStream; - }else if(input instanceof String){ - input = new StringReader((String) input); - } - - reader = toReader(input); + private Errors errors() { + return Errors.getResources(getLocale()); } /** - * Iterator on the reader until it reachs the end of the given tag name. - * @param tagName tag name to search - * @throws XMLStreamException if end tag could not be found - * or if there is error processing the xml stream + * Returns the XML stream reader. + * + * @return the XML stream reader (never null). + * @throws DataStoreException if this XML reader has been closed. */ - protected void toTagEnd(final String tagName) throws XMLStreamException { - while (reader.hasNext()) { - if(END_ELEMENT == reader.next() && - tagName.equalsIgnoreCase(reader.getLocalName())) - return; + protected final XMLStreamReader getReader() throws DataStoreException { + if (reader != null) { + return reader; } - throw new XMLStreamException("Error in xml file, Could not find end of tag "+tagName+" ."); + throw new DataStoreException(errors().getString(Errors.Keys.ClosedReader_1, "XML")); } /** - * Creates a new XMLStreamReader. - * @param input input to convert to stax stream - * @return XMLStreamReader - * @throws XMLStreamException if the input is not handled - */ - private static final XMLStreamReader toReader(final Object input) - throws XMLStreamException { - final XMLInputFactory XMLfactory = XMLInputFactory.newInstance(); - XMLfactory.setProperty("http://java.sun.com/xml/stream/properties/report-cdata-event", Boolean.TRUE); - XMLfactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.FALSE); - - if (input instanceof InputStream) { - return XMLfactory.createXMLStreamReader((InputStream) input); - } else if (input instanceof Source) { - return XMLfactory.createXMLStreamReader((Source) input); - } else if (input instanceof Node) { - - /* here we can think that we can use a DOMSource and pass it directly to the - * method XMLfactory.createXMLStreamReader(Source) but it lead to a NPE - * during the geometry unmarshall. - */ - try { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - Result outputTarget = new StreamResult(outputStream); - Transformer t = TransformerFactory.newInstance().newTransformer(); - t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - t.transform(new DOMSource((Node) input), outputTarget); - return XMLfactory.createXMLStreamReader(new ByteArrayInputStream(outputStream.toByteArray())); - } catch (TransformerException ex) { - throw new XMLStreamException(ex); + * Returns a XML stream reader over only a portion of the document, from given position inclusive + * until the end of the given element exclusive. Nested elements of the same name, if any; will be + * ignored. + * + * @param tagName name of the tag to close. + * @return a reader over a portion of the stream. + * @throws DataStoreException if this XML reader has been closed. + */ + protected final XMLStreamReader getSubReader(final String tagName) throws DataStoreException { + return new StreamReaderDelegate(getReader()) { + /** Increased every time a nested element of the same name is found. */ + private int nested; + + /** Returns {@code false} if we reached the end of the sub-region. */ + @Override public boolean hasNext() throws XMLStreamException { + return (nested >= 0) && super.hasNext(); } - } else if (input instanceof Reader) { - return XMLfactory.createXMLStreamReader((Reader) input); - } else { - throw new XMLStreamException("Input type is not supported : " + input); - } + + /** Reads the next element in the sub-region. */ + @Override public int next() throws XMLStreamException { + if (nested < 0) { + throw new NoSuchElementException(); + } + final int t = super.next(); + switch (t) { + case START_ELEMENT: if (tagName.equals(getLocalName())) nested++; break; + case END_ELEMENT: if (tagName.equals(getLocalName())) nested--; break; + } + return t; + } + }; } /** - *

XML language provides two notations for boolean type : - * "true" can be written "1" and "0" significates "false". - * This method considers all this values as CharSequences and return its boolean value.

+ * Skips all remaining elements until we reach the end of the given tag. + * Nested tags of the same name, if any, are also skipped. * - * @param candidate The String to parse - * @return true if bool is equal to "true" or "1". - */ - protected static boolean parseBoolean(final String candidate) { - if (candidate.length() == 1) { - return !candidate.equals("0"); + * @param tagName name of the tag to close. + * @throws DataStoreException if end tag could not be found. + * @throws XMLStreamException if an error occurred while reading the XML stream. + */ + protected final void skipUntilEnd(final String tagName) throws DataStoreException, XMLStreamException { + final XMLStreamReader reader = getReader(); + int nested = 0; + while (reader.hasNext()) { + switch (reader.next()) { + case XMLStreamReader.START_ELEMENT: { + if (tagName.equals(reader.getLocalName())) { + nested++; + } + break; + } + case XMLStreamReader.END_ELEMENT: { + if (tagName.equals(reader.getLocalName())) { + if (--nested < 0) return; + } + break; + } + } } - return Boolean.parseBoolean(candidate); + throw new DataStoreException(errors().getString(Errors.Keys.UnexpectedEndOfFile_1, tagName)); } /** - *

This method reads doubles with coma separated.

- * - * @param candidate Can not be null. - * @return parsed double value + * Parses the given string as a boolean value. This method performs the same parsing than + * {@link Boolean#parseBoolean(String)} with one extension: the "0" value is considered + * as {@code false} and the "1" value as {@code true}. + * + * @param value The string value to parse as a boolean. + * @return true if the boolean is equal to "true" or "1". */ - protected static double parseDouble(final String candidate) { - return Double.parseDouble(candidate.replace(',', '.')); + protected static boolean parseBoolean(final String value) { + if (value.length() == 1) { + switch (value.charAt(0)) { + case '0': return false; + case '1': return true; + } + } + return Boolean.parseBoolean(value); } /** - * Iterator on the reader until it reach the end of the given tag name. - * Return the read elements as dom. + * Closes the input stream and releases any resources used by this data store. + * This data store can not be used anymore after this method has been invoked. * - * @param tagName tag - * @return Document read elements as a dom document - * @throws javax.xml.stream.XMLStreamException if conversion to dom failed + * @throws DataStoreException if an error occurred while closing the stream or releasing the resources. */ - protected Document readAsDom(final String tagName) throws XMLStreamException { - - final XMLStreamReader limitedReader = new StreamReaderDelegate(reader){ - boolean finished = false; - - @Override - public boolean hasNext() throws XMLStreamException { - if(finished) return false; - return super.hasNext(); + @Override + public synchronized void close() throws DataStoreException { + try { + if (reader != null) { + reader.close(); + reader = null; } - - @Override - public int next() throws XMLStreamException { - int t = super.next(); - finished = END_ELEMENT == t && tagName.equalsIgnoreCase(reader.getLocalName()); - return t; + if (sourceStream != null) { + sourceStream.close(); + sourceStream = null; } - - }; - - final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(false); - - final TransformerFactory trsFactory = TransformerFactory.newInstance(); - try { - final DocumentBuilder builder = factory.newDocumentBuilder(); - final Transformer idTransform = trsFactory.newTransformer(); - final Source input = new StAXSource(limitedReader); - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final Result output = new StreamResult(out); - idTransform.transform(input, output); - final Document doc = builder.parse(new ByteArrayInputStream(out.toByteArray())); - return doc; - } catch (TransformerConfigurationException e) { - throw new XMLStreamException(e.getMessage()); - } catch (TransformerFactoryConfigurationError e) { - throw new XMLStreamException(e.getMessage()); - } catch (IOException e) { - throw new XMLStreamException(e.getMessage()); - } catch (TransformerException e) { - throw new XMLStreamException(e.getMessage()); - } catch (SAXException e) { - throw new XMLStreamException(e.getMessage()); - } catch (ParserConfigurationException e) { - throw new XMLStreamException(e.getMessage()); + } catch (IOException | XMLStreamException e) { + throw new DataStoreException(e); } - } - } Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamWriter.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamWriter.java?rev=1750175&r1=1750174&r2=1750175&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamWriter.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamWriter.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -64,12 +64,12 @@ import org.apache.sis.xml.Namespaces; * } * * - * @author Johann Sorel (Geomatys) - * @since 0.7 - * @version 0.7 + * @author Johann Sorel (Geomatys) + * @since 0.8 + * @version 0.8 * @module */ -public abstract class StaxStreamWriter extends AbstractConfigurable implements AutoCloseable { +public abstract class StaxStreamWriter implements AutoCloseable { /** * Underlying stax writer. Added: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/XMLStoreProvider.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/XMLStoreProvider.java?rev=1750175&view=auto ============================================================================== --- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/XMLStoreProvider.java (added) +++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/XMLStoreProvider.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -0,0 +1,37 @@ +/* + * 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.internal.xml; + +import org.apache.sis.storage.DataStoreProvider; + + +/** + * The provider of {@link StaxStreamReader} instances. + * + * @author Johann Sorel (Geomatys) + * @author Martin Desruisseaux (Geomatys) + * @since 0.8 + * @version 0.8 + * @module + */ +public abstract class XMLStoreProvider extends DataStoreProvider { + /** + * Creates a new provider. + */ + protected XMLStoreProvider() { + } +} Propchange: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/XMLStoreProvider.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/XMLStoreProvider.java ------------------------------------------------------------------------------ svn:mime-type = text/plain;charset=UTF-8 Added: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/package-info.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/package-info.java?rev=1750175&view=auto ============================================================================== --- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/package-info.java (added) +++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/package-info.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/** + * Helper classes for reading and writing XML documents using STAX. + * + * @author Johann Sorel (Geomatys) + * @since 0.8 + * @version 0.8 + * @module + */ +package org.apache.sis.internal.xml; Propchange: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/package-info.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/package-info.java ------------------------------------------------------------------------------ svn:mime-type = text/plain;charset=UTF-8 Modified: sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXReaderTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXReaderTest.java?rev=1750175&r1=1750174&r2=1750175&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXReaderTest.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXReaderTest.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -20,11 +20,15 @@ import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.io.IOException; +import javax.xml.stream.XMLStreamException; import com.esri.core.geometry.Point; import org.opengis.geometry.Envelope; import org.apache.sis.geometry.GeneralEnvelope; import org.apache.sis.geometry.ImmutableEnvelope; import org.apache.sis.referencing.CommonCRS; +import org.apache.sis.storage.StorageConnector; +import org.apache.sis.storage.DataStoreException; import org.junit.Test; import static org.junit.Assert.*; @@ -50,6 +54,10 @@ public class GPXReaderTest { private static final double DELTA = 0.000001; + private static GPXReader create(final String resource) throws DataStoreException, IOException, XMLStreamException { + return new GPXReader(new StorageConnector(GPXReaderTest.class.getResource(resource))); + } + /** * Tests GPX version 1.0.0 metadata tag parsing. * @@ -57,12 +65,8 @@ public class GPXReaderTest { */ @Test public void testMetadataRead100() throws Exception { - - try (final GPXReader reader = new GPXReader()) { - reader.setInput(GPXReaderTest.class.getResource( - "/org/apache/sis/gpx/sample_metadata100.xml")); - - final MetaData data = reader.getMetadata(); + try (final GPXReader reader = create("/org/apache/sis/gpx/sample_metadata100.xml")) { + final MetaData data = reader.metadata; assertEquals("sample", data.getName()); assertEquals("sample gpx test file", data.getDescription()); @@ -88,12 +92,8 @@ public class GPXReaderTest { */ @Test public void testMetadataRead110() throws Exception { - - try (final GPXReader reader = new GPXReader()) { - reader.setInput(GPXReaderTest.class.getResource( - "/org/apache/sis/gpx/sample_metadata110.xml")); - - final MetaData data = reader.getMetadata(); + try (final GPXReader reader = create("/org/apache/sis/gpx/sample_metadata110.xml")) { + final MetaData data = reader.metadata; assertEquals("sample", data.getName()); assertEquals("sample gpx test file", data.getDescription()); @@ -124,12 +124,8 @@ public class GPXReaderTest { */ @Test public void testWayPointRead100() throws Exception { - - try (final GPXReader reader = new GPXReader()) { - reader.setInput(GPXReaderTest.class.getResource( - "/org/apache/sis/gpx/sample_waypoint100.xml")); - - final MetaData data = reader.getMetadata(); + try (final GPXReader reader = create("/org/apache/sis/gpx/sample_waypoint100.xml")) { + final MetaData data = reader.metadata; assertNull(data.getName()); assertNull(data.getDescription()); @@ -157,12 +153,8 @@ public class GPXReaderTest { */ @Test public void testWayPointRead110() throws Exception { - - try (final GPXReader reader = new GPXReader()) { - reader.setInput(GPXReaderTest.class.getResource( - "/org/apache/sis/gpx/sample_waypoint110.xml")); - - final MetaData data = reader.getMetadata(); + try (final GPXReader reader = create("/org/apache/sis/gpx/sample_waypoint110.xml")) { + final MetaData data = reader.metadata; assertNull(data.getName()); assertNull(data.getDescription()); @@ -191,12 +183,8 @@ public class GPXReaderTest { */ @Test public void testRouteRead100() throws Exception { - - try (final GPXReader reader = new GPXReader()) { - reader.setInput(GPXReaderTest.class.getResource( - "/org/apache/sis/gpx/sample_route100.xml")); - - final MetaData data = reader.getMetadata(); + try (final GPXReader reader = create("/org/apache/sis/gpx/sample_route100.xml")) { + final MetaData data = reader.metadata; assertNull(data.getName()); assertNull(data.getDescription()); @@ -260,12 +248,8 @@ public class GPXReaderTest { */ @Test public void testRouteRead110() throws Exception { - - try (final GPXReader reader = new GPXReader()) { - reader.setInput(GPXReaderTest.class.getResource( - "/org/apache/sis/gpx/sample_route110.xml")); - - final MetaData data = reader.getMetadata(); + try (final GPXReader reader = create("/org/apache/sis/gpx/sample_route110.xml")) { + final MetaData data = reader.metadata; assertNull(data.getName()); assertNull(data.getDescription()); @@ -331,12 +315,8 @@ public class GPXReaderTest { */ @Test public void testTrackRead100() throws Exception { - - try (final GPXReader reader = new GPXReader()) { - reader.setInput(GPXReaderTest.class.getResource( - "/org/apache/sis/gpx/sample_track100.xml")); - - final MetaData data = reader.getMetadata(); + try (final GPXReader reader = create("/org/apache/sis/gpx/sample_track100.xml")) { + final MetaData data = reader.metadata; assertNull(data.getName()); assertNull(data.getDescription()); @@ -405,12 +385,8 @@ public class GPXReaderTest { */ @Test public void testTrackRead110() throws Exception { - - try (final GPXReader reader = new GPXReader()) { - reader.setInput(GPXReaderTest.class.getResource( - "/org/apache/sis/gpx/sample_track110.xml")); - - final MetaData data = reader.getMetadata(); + try (final GPXReader reader = create("/org/apache/sis/gpx/sample_track110.xml")) { + final MetaData data = reader.metadata; assertNull(data.getName()); assertNull(data.getDescription()); @@ -601,6 +577,5 @@ public class GPXReaderTest { envelope.setRange(0, d0, d1); envelope.setRange(1, d2, d3); return new ImmutableEnvelope(envelope); - } } Modified: sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXWriterTest.java URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXWriterTest.java?rev=1750175&r1=1750174&r2=1750175&view=diff ============================================================================== --- sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXWriterTest.java [UTF-8] (original) +++ sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/GPXWriterTest.java [UTF-8] Sat Jun 25 00:30:30 2016 @@ -29,6 +29,7 @@ import com.esri.core.geometry.Point; import org.apache.sis.geometry.GeneralEnvelope; import org.apache.sis.geometry.ImmutableEnvelope; import org.apache.sis.referencing.CommonCRS; +import org.apache.sis.storage.StorageConnector; import org.junit.Test; import static org.apache.sis.internal.gpx.GPXConstants.*; @@ -89,9 +90,8 @@ public final strictfp class GPXWriterTes writer.writeEndDocument(); writer.close(); - try (GPXReader reader = new GPXReader()) { - reader.setInput(f); - assertEquals(metaData, reader.getMetadata()); + try (GPXReader reader = new GPXReader(new StorageConnector(f))) { + assertEquals(metaData, reader.metadata); } if (f.exists()) f.delete(); @@ -250,8 +250,7 @@ public final strictfp class GPXWriterTes writer.writeEndDocument(); writer.close(); - final GPXReader reader = new GPXReader(); - reader.setInput(f); + final GPXReader reader = new GPXReader(new StorageConnector(f)); //testing on toString since JTS geometry always fail on equals method. assertEquals(point1.toString(), reader.next().toString());