sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1777266 - in /sis/branches/JDK8: core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/ core/sis-metadata/src/test/java/org/apache/sis/test/suite/ core/sis-utilit...
Date Wed, 04 Jan 2017 08:43:15 GMT
Author: desruisseaux
Date: Wed Jan  4 08:43:14 2017
New Revision: 1777266

URL: http://svn.apache.org/viewvc?rev=1777266&view=rev
Log:
Test the merge operation and merge the hard-coded FeatureCatalogDescription metadata in the
GPX metadata.

Added:
    sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java
  (with props)
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java
    sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
    sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Types.java
    sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/ReaderTest.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java?rev=1777266&r1=1777265&r2=1777266&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java
[UTF-8] Wed Jan  4 08:43:14 2017
@@ -28,6 +28,7 @@ import org.apache.sis.metadata.InvalidMe
 import org.apache.sis.metadata.ModifiableMetadata;
 import org.apache.sis.metadata.KeyNamePolicy;
 import org.apache.sis.metadata.ValueExistencePolicy;
+import org.apache.sis.util.CorruptedObjectException;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.Classes;
 
@@ -38,14 +39,19 @@ import org.apache.sis.util.Classes;
  * value from the <var>source</var> metadata, the merge operation is defined
as below:
  *
  * <ul>
- *   <li>If the target metadata does not have a non-null and non-empty value for the
same property, then reference
- *       to the value from the source metadata is stored <cite>as-is</cite> in
the target metadata.</li>
+ *   <li>If the target metadata does not have a non-null and non-empty value for the
same property, then the
+ *     reference to the value from the source metadata is stored <cite>as-is</cite>
in the target metadata.</li>
  *   <li>Otherwise if the target value is a collection, then:
  *     <ul>
- *       <li>Each element of the source collection which is an instance of a
- *           {@linkplain MetadataStandard#getInterface(Class) standard type}
- *           assignable to the type of an element of the target collection, this {@code merge(…)}
- *           method will be invoked recursively for that pair of source and target elements.</li>
+ *       <li>For each element of the source collection, a corresponding element of
the target collection is searched.
+ *         A pair of source and target elements is established if the pair meet all of the
following conditions:
+ *         <ul>
+ *           <li>The {@linkplain MetadataStandard#getInterface(Class) standard type}
of the source element
+ *               is assignable to the type of the target element.</li>
+ *           <li>There is no conflict, i.e. no property value that are not collection
and not equal.</li>
+ *         </ul>
+ *         If such pair is found, then the merge operation if performed recursively
+ *         for that pair of source and target elements.</li>
  *       <li>All other source elements will be added as new elements in the target
collection.</li>
  *     </ul>
  *   </li>
@@ -100,18 +106,31 @@ public class Merger {
      * Merges the data from the given source into the given target.
      * See class javadoc for a description of the merge process.
      *
-     * <p>Note that this method will be invoked recursively for all child properties
to merge.</p>
-     *
-     * @param  source  the source metadata to merge into the target. This metadata will not
be modified.
-     * @param  target  the target metadata where to merge values.
-     * @return {@code true} if the merge has been performed, or {@code false} if the {@code
target} type
-     *         is not compatible with the {@code source} type.
+     * @param  source  the source metadata to merge into the target. Will never be modified.
+     * @param  target  the target metadata where to merge values. Will be modified as a result
of this call.
      * @throws ClassCastException if the source and target are not instances of the same
metadata standard.
-     * @throws InvalidMetadataException if a property of the {@code target} metadata is not
specialized
-     *         enough for holding a {@code source} property value.
-     * @throws IllegalArgumentException if this method detects a cross-reference between
source and target.
+     * @throws InvalidMetadataException if the {@code target} metadata can not hold all {@code
source} properties,
+     *         for example because the source class is a more specialized type than the target
class.
+     * @throws IllegalArgumentException if this method detects a cross-reference between
source and target metadata.
+     */
+    public final void merge(final Object source, final ModifiableMetadata target) {
+        if (!merge(source, target, false)) {
+            throw new InvalidMetadataException(errors().getString(Errors.Keys.IllegalArgumentClass_3,
"target",
+                    target.getStandard().getInterface(source.getClass()), Classes.getClass(target)));
+        }
+    }
+
+    /**
+     * Implementation of {@link #merge(Object, ModifiableMetadata)} method,
+     * to be invoked recursively for all child properties to merge.
+     *
+     * @param  dryRun  {@code true} for executing the merge operation in "dry run" mode
instead than performing the
+     *                 actual merge. This mode is used for verifying if there is a merge
conflict before to perform
+     *                 the actual operation.
+     * @return {@code true} if the merge operation is valid, or {@code false} if the given
arguments are valid
+     *         metadata but the merge operation can nevertheless not be executed because
it could cause data lost.
      */
-    public boolean merge(final Object source, final ModifiableMetadata target) {
+    private boolean merge(final Object source, final ModifiableMetadata target, final boolean
dryRun) {
         /*
          * Verify if the given source can be merged with the target. If this is not the case,
action
          * taken will depend on the caller: it may either skips the value or throws an exception.
@@ -125,24 +144,25 @@ public class Merger {
          * we are going to merge those two metadata and verify that we are not in an infinite
loop.
          * We will also verify that the target metadata does not contain a source, or vis-versa.
          */
-        final Boolean sourceDone = done.put(source, Boolean.FALSE);
-        final Boolean targetDone = done.put(target, Boolean.TRUE);
-        if (sourceDone != null || targetDone != null) {
-            if (Boolean.FALSE.equals(sourceDone) && Boolean.TRUE.equals(targetDone))
{
-                /*
-                 * At least, the 'source' and 'target' status are consistent. Pretend that
we have already
-                 * merged those metadata since actually the merge operation is probably underway
by the caller.
-                 */
-                return true;
-            } else {
-                throw new IllegalArgumentException(errors().getString(Errors.Keys.CrossReferencesNotSupported));
+        {   // For keeping 'sourceDone' and 'targetDone' more local.
+            final Boolean sourceDone = done.put(source, Boolean.FALSE);
+            final Boolean targetDone = done.put(target, Boolean.TRUE);
+            if (sourceDone != null || targetDone != null) {
+                if (Boolean.FALSE.equals(sourceDone) && Boolean.TRUE.equals(targetDone))
{
+                    /*
+                     * At least, the 'source' and 'target' status are consistent. Pretend
that we have already
+                     * merged those metadata since actually the merge operation is probably
underway by the caller.
+                     */
+                    return true;
+                } else {
+                    throw new IllegalArgumentException(errors().getString(Errors.Keys.CrossReferencesNotSupported));
+                }
             }
         }
         /*
          * Get views of metadata as maps. Those maps are live: write operations
          * on those maps will be reflected on the metadata objects and conversely.
          */
-        Map<String, Class<?>>    typeMap   = null;
         final Map<String,Object> targetMap = target.asMap();
         final Map<String,Object> sourceMap;
         if (source instanceof AbstractMetadata) {
@@ -154,13 +174,16 @@ public class Merger {
          * Iterate on source values in order to find the objects that need to be copied or
merged.
          * If the value does not exist in the target map, then it can be copied directly.
          */
+        boolean success = true;
         for (final Map.Entry<String,Object> entry : sourceMap.entrySet()) {
             final String propertyName = entry.getKey();
             final Object sourceValue  = entry.getValue();
-            final Object targetValue  = targetMap.putIfAbsent(propertyName, sourceValue);
+            final Object targetValue  = dryRun ? targetMap.get(propertyName)
+                                               : targetMap.putIfAbsent(propertyName, sourceValue);
             if (targetValue != null) {
                 if (targetValue instanceof ModifiableMetadata) {
-                    if (!merge(sourceValue, (ModifiableMetadata) targetValue)) {
+                    success = merge(sourceValue, (ModifiableMetadata) targetValue, dryRun);
+                    if (!success) {
                         /*
                          * This exception may happen if the source is a subclass of the target.
This is the converse
                          * of what we usually have in Java (we can assign a sub-type to a
more generic Java variable)
@@ -168,23 +191,34 @@ public class Merger {
                          * from the source to the target. We do not use ClassCastException
type in the hope to reduce
                          * confusion.
                          */
+                        if (dryRun) break;
                         throw new InvalidMetadataException(errors().getString(Errors.Keys.IllegalPropertyValueClass_3,
                                 name(target, propertyName), ((ModifiableMetadata) targetValue).getInterface(),
                                 Classes.getClass(sourceValue)));
                     }
                 } else if (targetValue instanceof Collection<?>) {
                     /*
+                     * If the merge is executed in dry run, there is no need to verify the
collection elements since
+                     * in case of conflict, it is always possible to append the source values
as new elements at the
+                     * end of the collection.
+                     */
+                    if (dryRun) continue;
+                    /*
                      * If the target value is a collection, then the source value should
be a collection too
                      * (otherwise the two objects would not be implementing the same standard,
in which case
                      * a ClassCastException is conform to this method contract). The loop
tries to merge the
                      * source elements to target elements that are specialized enough.
                      */
+                    final Collection<?> targetList = (Collection<?>) targetValue;
                     final Collection<?> sourceList = new LinkedList<>((Collection<?>)
sourceValue);
-                    for (final Object element : (Collection<?>) targetValue) {
+                    for (final Object element : targetList) {
                         if (element instanceof ModifiableMetadata) {
                             final Iterator<?> it = sourceList.iterator();
                             while (it.hasNext()) {
-                                if (merge(it.next(), (ModifiableMetadata) element)) {
+                                final Object value = it.next();
+                                if (merge(value, (ModifiableMetadata) element, true) &&
+                                    merge(value, (ModifiableMetadata) element, false))
+                                {
                                     it.remove();
                                     break;          // Merge at most one source element to
each target element.
                                 }
@@ -194,21 +228,38 @@ public class Merger {
                     /*
                      * Add remaining elements one-by-one. In such case, the Apache SIS metadata
implementation
                      * shall add the elements to the collection instead than replacing the
whole collection by
-                     * a singleton. As a partial safety check, we verify that the collection
instance does not
-                     * change.
+                     * a singleton. As a partial safety check, we verify that the collection
instance contains
+                     * all the previous values.
                      */
                     for (final Object element : sourceList) {
-                        if (targetMap.put(propertyName, element) != targetValue) {
-                            throw new InvalidMetadataException(errors().getString(
-                                    Errors.Keys.UnsupportedImplementation_1, Classes.getShortClassName(targetValue)));
+                        final Object old = targetMap.put(propertyName, element);
+                        if (old instanceof Collection<?>) {
+                            final Collection<?> oldList = (Collection<?>) old;
+                            if (oldList.size() <= targetList.size()) {
+                                // Above was only a cheap check based on collection size
only.
+                                // Below is a more expansive check if assertions are enabled.
+                                assert targetList.containsAll(oldList) : propertyName;
+                                continue;
+                            }
                         }
+                        throw new InvalidMetadataException(errors().getString(
+                                Errors.Keys.UnsupportedImplementation_1, Classes.getShortClassName(targetList)));
                     }
                 } else {
-                    unmerged(target, propertyName, sourceValue, targetValue);
+                    success = targetValue.equals(sourceValue);
+                    if (!success) {
+                        if (dryRun) break;
+                        unmerged(target, propertyName, sourceValue, targetValue);
+                    }
                 }
             }
         }
-        return true;
+        if (dryRun) {
+            if (!Boolean.FALSE.equals(done.remove(source)) || !Boolean.TRUE.equals(done.remove(target)))
{
+                throw new CorruptedObjectException();           // Should never happen.
+            }
+        }
+        return success;
     }
 
     /**

Added: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java?rev=1777266&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java
(added)
+++ sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java
[UTF-8] Wed Jan  4 08:43:14 2017
@@ -0,0 +1,125 @@
+/*
+ * 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.metadata;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Iterator;
+import java.util.Collections;
+import java.nio.charset.StandardCharsets;
+import org.opengis.metadata.content.ContentInformation;
+import org.opengis.metadata.content.CoverageDescription;
+import org.opengis.metadata.content.FeatureCatalogueDescription;
+import org.opengis.metadata.content.ImagingCondition;
+import org.opengis.metadata.content.ImageDescription;
+import org.apache.sis.metadata.iso.DefaultIdentifier;
+import org.apache.sis.metadata.iso.DefaultMetadata;
+import org.apache.sis.metadata.iso.citation.DefaultCitation;
+import org.apache.sis.metadata.iso.content.DefaultCoverageDescription;
+import org.apache.sis.metadata.iso.content.DefaultFeatureCatalogueDescription;
+import org.apache.sis.metadata.iso.content.DefaultImageDescription;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.apache.sis.test.Assert.*;
+import org.opengis.metadata.citation.Citation;
+
+
+/**
+ * Tests the {@link Merger} class.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+public final strictfp class MergerTest extends TestCase {
+    /**
+     * Creates a metadata sample with 3 content information of different kind.
+     */
+    private static DefaultMetadata createSample1() {
+        final DefaultFeatureCatalogueDescription features = new DefaultFeatureCatalogueDescription();
+        final DefaultCoverageDescription         coverage = new DefaultCoverageDescription();
+        final DefaultImageDescription            image    = new DefaultImageDescription();
+        final DefaultMetadata                    metadata = new DefaultMetadata();
+        features.setFeatureCatalogueCitations(Collections.singleton(new DefaultCitation("Shapefile")));
+        features.setIncludedWithDataset(Boolean.TRUE);
+        metadata.getContentInfo().add(features);
+
+        coverage.setProcessingLevelCode(new DefaultIdentifier("Level 1"));
+        metadata.getContentInfo().add(coverage);
+
+        image.setImagingCondition(ImagingCondition.CLOUD);
+        image.setCloudCoverPercentage(0.8);
+        metadata.getContentInfo().add(image);
+
+        metadata.getLanguages().add(Locale.JAPANESE);
+        metadata.getCharacterSets().add(StandardCharsets.UTF_16);
+        return metadata;
+    }
+
+    /**
+     * Creates a metadata sample with content information of different kind in a different
order
+     * than the one created by {@link #createSample1()}.
+     */
+    private static DefaultMetadata createSample2() {
+        final DefaultFeatureCatalogueDescription features = new DefaultFeatureCatalogueDescription();
+        final DefaultImageDescription            image    = new DefaultImageDescription();
+        final DefaultMetadata                    metadata = new DefaultMetadata();
+        image.setProcessingLevelCode(new DefaultIdentifier("Level 2"));
+        metadata.getContentInfo().add(image);
+
+        features.setFeatureCatalogueCitations(Collections.singleton(new DefaultCitation("GPX
file")));
+        features.setIncludedWithDataset(Boolean.TRUE);
+        metadata.getContentInfo().add(features);
+
+        metadata.getLanguages().add(Locale.FRENCH);
+        return metadata;
+    }
+
+    /**
+     * Tests a merge operation that merge also the collection elements. Such deep merge is
a
+     * little bit aggressive; it may be desired in some occasions, but may also be dangerous.
+     */
+    @Test
+    public void testDeepMerge() {
+        final DefaultMetadata source = createSample1();
+        final DefaultMetadata target = createSample2();
+        final Merger merger = new Merger(null);
+        merger.merge(source, target);
+
+        assertSetEquals(Arrays.asList(Locale.JAPANESE, Locale.FRENCH),  target.getLanguages());
+        assertSetEquals(Collections.singleton(StandardCharsets.UTF_16), target.getCharacterSets());
+
+        final Iterator<ContentInformation> it       = target.getContentInfo().iterator();
+        final ImageDescription             image    = (ImageDescription)            it.next();
+        final FeatureCatalogueDescription  features = (FeatureCatalogueDescription) it.next();
+        final CoverageDescription          coverage = (CoverageDescription)         it.next();
+        assertFalse(it.hasNext());
+
+        assertEquals("imagingCondition",     ImagingCondition.CLOUD, image   .getImagingCondition());
+        assertEquals("cloudCoverPercentage", Double.valueOf(0.8),    image   .getCloudCoverPercentage());
+        assertEquals("processingLevelCode",  "Level 2",              image   .getProcessingLevelCode().getCode());
+        assertEquals("processingLevelCode",  "Level 1",              coverage.getProcessingLevelCode().getCode());
+        assertEquals("includedWithDataset",  Boolean.TRUE,           features.isIncludedWithDataset());
+
+        final Iterator<? extends Citation> ci = features.getFeatureCatalogueCitations().iterator();
+        assertEquals("GPX file",  ci.next().getTitle().toString());
+        assertEquals("Shapefile", ci.next().getTitle().toString());
+        assertFalse(ci.hasNext());
+    }
+}

Propchange: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/MergerTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java?rev=1777266&r1=1777265&r2=1777266&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
[UTF-8] Wed Jan  4 08:43:14 2017
@@ -52,6 +52,7 @@ import org.junit.BeforeClass;
     org.apache.sis.metadata.MetadataStandardTest.class,
     org.apache.sis.metadata.PrunerTest.class,
     org.apache.sis.metadata.AbstractMetadataTest.class,
+    org.apache.sis.internal.metadata.MergerTest.class,
 
     // XML marshalling.
     org.apache.sis.internal.jaxb.code.EnumMarshallingTest.class,

Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java?rev=1777266&r1=1777265&r2=1777266&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java [UTF-8]
(original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/test/TestRunner.java [UTF-8]
Wed Jan  4 08:43:14 2017
@@ -177,8 +177,8 @@ public final class TestRunner extends Bl
     /**
      * Creates a new test runner for the given class.
      *
-     * @param  testClass The class to run.
-     * @throws InitializationError If the test class is malformed.
+     * @param  testClass  the class to run.
+     * @throws InitializationError if the test class is malformed.
      */
     public TestRunner(final Class<?> testClass) throws InitializationError {
         super(testClass);
@@ -189,7 +189,7 @@ public final class TestRunner extends Bl
      * verification documented in {@link BlockJUnit4ClassRunner#validateTestMethods(List)},
      * then ensures that all {@link DependsOnMethod} annotations refer to an existing method.
      *
-     * @param errors The list where to report any problem found.
+     * @param  errors  the list where to report any problem found.
      */
     @Override
     protected void validateTestMethods(final List<Throwable> errors) {
@@ -216,7 +216,7 @@ public final class TestRunner extends Bl
     /**
      * Returns the test methods to be executed, with dependencies sorted before dependant
tests.
      *
-     * @return The test method to be executed in dependencies order.
+     * @return the test methods to be executed in dependencies order.
      */
     @Override
     public List<FrameworkMethod> getChildren() {
@@ -226,7 +226,7 @@ public final class TestRunner extends Bl
     /**
      * Returns the test methods to be executed, with dependencies sorted before dependant
tests.
      *
-     * @return The test method to be executed in dependencies order.
+     * @return the test methods to be executed in dependencies order.
      */
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
     private FrameworkMethod[] getFilteredChildren() {
@@ -243,7 +243,7 @@ public final class TestRunner extends Bl
      * conform to the sorter specification, since this method will ensure that dependencies
      * are still sorted before dependant tests.
      *
-     * @param sorter The sorter to use for sorting tests.
+     * @param  sorter  the sorter to use for sorting tests.
      */
     @Override
     public void sort(final Sorter sorter) {
@@ -259,7 +259,7 @@ public final class TestRunner extends Bl
     /**
      * Sorts the given array of methods in dependencies order.
      *
-     * @param methods The methods to sort.
+     * @param  methods  the methods to sort.
      */
     private static void sortDependantTestsLast(final FrameworkMethod[] methods) {
         final Set<String> dependencies = new HashSet<>();
@@ -296,8 +296,8 @@ public final class TestRunner extends Bl
     /**
      * Removes tests that don't pass the parameter {@code filter}.
      *
-     * @param  filter The filter to apply.
-     * @throws NoTestsRemainException If all tests are filtered out.
+     * @param  filter  the filter to apply.
+     * @throws NoTestsRemainException if all tests are filtered out.
      */
     @Override
     public void filter(final Filter filter) throws NoTestsRemainException {
@@ -323,8 +323,8 @@ public final class TestRunner extends Bl
      * Returns the {@link Statement} which will execute all the tests in the class given
      * to the {@linkplain #TestRunner(Class) constructor}.
      *
-     * @param  notifier The object to notify about test results.
-     * @return The statement to execute for running the tests.
+     * @param  notifier  the object to notify about test results.
+     * @return the statement to execute for running the tests.
      */
     @Override
     protected Statement childrenInvoker(final RunNotifier notifier) {
@@ -347,8 +347,8 @@ public final class TestRunner extends Bl
      * Before to delegate to the {@linkplain BlockJUnit4ClassRunner#runChild default implementation},
      * check if a dependency of the given method failed. In such case, the test will be ignored.
      *
-     * @param method   The test method to execute.
-     * @param notifier The object to notify about test results.
+     * @param  method    the test method to execute.
+     * @param  notifier  the object to notify about test results.
      */
     @Override
     protected void runChild(final FrameworkMethod method, final RunNotifier notifier) {
@@ -375,7 +375,7 @@ public final class TestRunner extends Bl
      * Declares that the given method failed.
      * Other methods depending on this method will be ignored.
      *
-     * @param methodName The name of the method that failed.
+     * @param  methodName the name of the method that failed.
      */
     final void addDependencyFailure(final String methodName) {
         if (methodDependencyFailures == null) {

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java?rev=1777266&r1=1777265&r2=1777266&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java
[UTF-8] Wed Jan  4 08:43:14 2017
@@ -37,6 +37,7 @@ import org.opengis.metadata.constraint.L
 import org.opengis.metadata.extent.Extent;
 import org.opengis.metadata.identification.Keywords;
 import org.opengis.metadata.identification.Identification;
+import org.opengis.metadata.content.ContentInformation;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.iso.Types;
 
@@ -156,6 +157,15 @@ public final class Metadata extends Simp
     public Bounds bounds;
 
     /**
+     * Names of features types available for the GPX format, or null if none.
+     * This field is not part of metadata described in GPX file; it is rather a hard-coded
value shared by all
+     * GPX files. Users could however filter the list of features, for example with only
routes and no tracks.
+     *
+     * @see #getContentInfo()
+     */
+    public Collection<ContentInformation> features;
+
+    /**
      * Creates an initially empty metadata object.
      */
     public Metadata() {
@@ -354,6 +364,16 @@ public final class Metadata extends Simp
     }
 
     /**
+     * Information about the feature and coverage characteristics.
+     *
+     * @return information about the feature characteristics.
+     */
+    @Override
+    public Collection<ContentInformation> getContentInfo() {
+        return (features != null) ? features : Collections.emptyList();
+    }
+
+    /**
      * Compares this {@code Metadata} with the given object for equality.
      *
      * @param  obj  the object to compare with this {@code Metadata}.

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java?rev=1777266&r1=1777265&r2=1777266&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java
[UTF-8] Wed Jan  4 08:43:14 2017
@@ -233,14 +233,17 @@ parse:  while (reader.hasNext()) {
                     /*
                      * Reminder: END_ELEMENT events are skipped by getElementText(), getElementAsFoo()
                      * and unmarshal(…) methods. There is only the enclosing <gpx>
tag to check here.
+                     * If that end tag is found, we skip the metadata().features = … line
since there
+                     * is no feature in that file.
                      */
                     if (isEndGPX()) {
-                        break parse;
+                        return version;
                     }
                     break;
                 }
             }
         }
+        metadata().features = ((Store) owner).types.metadata;
         return version;
     }
 

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java?rev=1777266&r1=1777265&r2=1777266&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java
[UTF-8] Wed Jan  4 08:43:14 2017
@@ -145,9 +145,9 @@ public final class Store extends StaxDat
     public synchronized Metadata getMetadata() throws DataStoreException {
         if (!initialized) try {
             initialized = true;
-            reader = new Reader(this);
-            version = reader.initialize(true);
-            metadata = reader.getMetadata();
+            reader      = new Reader(this);
+            version     = reader.initialize(true);
+            metadata    = reader.getMetadata();
         } catch (XMLStreamException | IOException | JAXBException e) {
             throw new DataStoreException(e);
         } catch (URISyntaxException | RuntimeException e) {

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Types.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Types.java?rev=1777266&r1=1777265&r2=1777266&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Types.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Types.java
[UTF-8] Wed Jan  4 08:43:14 2017
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.gpx;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Locale;
 import java.util.Map;
@@ -23,8 +24,8 @@ import com.esri.core.geometry.Point;
 import org.opengis.util.LocalName;
 import org.opengis.util.NameFactory;
 import org.opengis.util.FactoryException;
-import org.opengis.metadata.Metadata;
 import org.opengis.metadata.citation.OnlineResource;
+import org.opengis.metadata.content.ContentInformation;
 import org.apache.sis.storage.gps.Fix;
 import org.apache.sis.storage.FeatureNaming;
 import org.apache.sis.referencing.CommonCRS;
@@ -76,9 +77,11 @@ final class Types extends Static {
     final FeatureType trackSegment;
 
     /**
-     * The metadata to use as a template, including the list of feature types.
+     * The list of feature types to be given to GPC metadata objects.
+     *
+     * @see Metadata#features
      */
-    private final Metadata metadata;
+    final Collection<ContentInformation> metadata;
 
     /**
      * Binding from names to feature type instances.
@@ -266,10 +269,10 @@ final class Types extends Static {
         track = builder.build();
 
         final FeatureCatalogBuilder fc = new FeatureCatalogBuilder(null);
-        fc.define(wayPoint);
         fc.define(route);
         fc.define(track);
-        metadata = fc.build(true);
+        fc.define(wayPoint);
+        metadata = fc.build(true).getContentInfo();
         names = fc.features;
     }
 }

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/ReaderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/ReaderTest.java?rev=1777266&r1=1777265&r2=1777266&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/ReaderTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/test/java/org/apache/sis/internal/gpx/ReaderTest.java
[UTF-8] Wed Jan  4 08:43:14 2017
@@ -23,6 +23,7 @@ import java.time.Instant;
 import com.esri.core.geometry.Point;
 import com.esri.core.geometry.Polyline;
 import org.opengis.geometry.Envelope;
+import org.opengis.metadata.content.FeatureCatalogueDescription;
 import org.apache.sis.storage.gps.Fix;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
@@ -35,9 +36,11 @@ import org.junit.Test;
 
 import static org.junit.Assert.*;
 import static org.apache.sis.test.TestUtilities.date;
+import static org.apache.sis.test.TestUtilities.getSingleton;
 
 // Branch-dependent imports
 import org.opengis.feature.Feature;
+import org.opengis.metadata.content.FeatureTypeInfo;
 
 
 /**
@@ -180,10 +183,16 @@ public final strictfp class ReaderTest e
                      assertStringEquals("first",                     md.links.get(0).text);
             case 0:  break;
         }
+        /*
+         * In the particular case of "metadata.xml" test files, there is no route, track
or way points
+         * after the metadata. Consequently the GPX reader should not declare any list of
features.
+         */
+        assertTrue("contentInfo", md.getContentInfo().isEmpty());
     }
 
     /**
-     * Verifies that the given metadata contains only bounds information.
+     * Verifies that the given metadata contains only bounds information
+     * and the hard-coded list of feature types.
      */
     private static void verifyAlmostEmptyMetadata(final Metadata md) {
         assertNull("name",                  md.name);
@@ -194,6 +203,17 @@ public final strictfp class ReaderTest e
         assertNull("author",                md.author);
         assertNull("copyright",             md.copyright);
         assertNull("links",                 md.links);
+        /*
+         * Verifies the list of feature types declared in the given metadata. Those features
+         * are not listed in GPX files; they are rather hard-coded in Types.metadata constant.
+         */
+        final FeatureCatalogueDescription content = (FeatureCatalogueDescription) getSingleton(md.getContentInfo());
+        assertTrue("isIncludedWithDataset", content.isIncludedWithDataset());
+        final Iterator<? extends FeatureTypeInfo> it = content.getFeatureTypeInfo().iterator();
+        assertStringEquals("Route",    it.next().getFeatureTypeName().tip());
+        assertStringEquals("Track",    it.next().getFeatureTypeName().tip());
+        assertStringEquals("WayPoint", it.next().getFeatureTypeName().tip());
+        assertFalse(it.hasNext());
     }
 
     /**



Mime
View raw message