sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1831270 - in /sis/branches/JDK8: core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-feature/src/main/java/org/apache/sis/internal/feature/ core/sis-feature/src/test/java/org/apache/sis/feature/ storage/sis-netcdf/src/main/java...
Date Wed, 09 May 2018 17:10:32 GMT
Author: desruisseaux
Date: Wed May  9 17:10:31 2018
New Revision: 1831270

URL: http://svn.apache.org/viewvc?rev=1831270&view=rev
Log:
Move common getMetadata() default implementation in AbstractFeatureSet.
Allow FeatureOperations.compound(...) to work with FeatureAssociationRole. The intent is to
use it in JoinFeatureSet.

Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
    sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataSet.java
    sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Writer.java

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultAssociationRole.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -25,6 +25,7 @@ import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.apache.sis.internal.feature.Resources;
+import org.apache.sis.internal.feature.AttributeConvention;
 import org.apache.sis.util.Debug;
 
 import static org.apache.sis.util.ArgumentChecks.*;
@@ -56,7 +57,7 @@ import org.opengis.feature.PropertyNotFo
  * Such immutable instances can be shared by many objects and passed between threads without
synchronization.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  *
  * @see DefaultFeatureType
  * @see AbstractAssociation
@@ -425,7 +426,7 @@ public class DefaultAssociationRole exte
     private static String searchTitleProperty(final FeatureType ft) {
         String fallback = null;
         try {
-            return ft.getProperty("sis:identifier").getName().toString();
+            return ft.getProperty(AttributeConvention.IDENTIFIER).getName().toString();
         } catch (PropertyNotFoundException e) {
             // Ignore.
         }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -30,6 +30,7 @@ import org.apache.sis.util.resources.Err
 // Branch-dependent imports
 import org.opengis.feature.Operation;
 import org.opengis.feature.PropertyType;
+import org.opengis.feature.FeatureAssociationRole;
 
 
 /**
@@ -106,7 +107,7 @@ import org.opengis.feature.PropertyType;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  * @since   0.7
  * @module
  */
@@ -176,7 +177,7 @@ public final class FeatureOperations ext
      * <p><b>Restrictions:</b></p>
      * <ul>
      *   <li>The single properties can be either attributes or operations that produce
attributes;
-     *       feature associations are not allowed.</li>
+     *       feature associations are not allowed, unless they have an {@code "sis:identifier"}
property.</li>
      *   <li>Each attribute shall contain at most one value; multi-valued attributes
are not allowed.</li>
      *   <li>The delimiter can not contain the {@code '\'} escape character.</li>
      * </ul>
@@ -217,7 +218,10 @@ public final class FeatureOperations ext
             }
             case 1: {
                 if ((prefix == null || prefix.isEmpty()) && (suffix == null || suffix.isEmpty()))
{
-                    return link(identification, singleAttributes[0]);
+                    final PropertyType at = singleAttributes[0];
+                    if (!(at instanceof FeatureAssociationRole)) {
+                        return link(identification, at);
+                    }
                 }
                 break;
             }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -21,10 +21,13 @@ import java.util.Map;
 import java.util.Set;
 import java.util.Objects;
 import java.io.IOException;
+import java.io.Serializable;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.util.GenericName;
 import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.internal.converter.SurjectiveConverter;
+import org.apache.sis.internal.feature.AttributeConvention;
 import org.apache.sis.internal.feature.FeatureUtilities;
 import org.apache.sis.internal.feature.Resources;
 import org.apache.sis.util.ArgumentChecks;
@@ -38,11 +41,14 @@ import org.apache.sis.util.Classes;
 // Branch-dependent imports
 import org.opengis.feature.AttributeType;
 import org.opengis.feature.Feature;
+import org.opengis.feature.FeatureType;
+import org.opengis.feature.FeatureAssociationRole;
 import org.opengis.feature.IdentifiedType;
 import org.opengis.feature.InvalidPropertyValueException;
 import org.opengis.feature.Operation;
 import org.opengis.feature.Property;
 import org.opengis.feature.PropertyType;
+import org.opengis.feature.PropertyNotFoundException;
 
 
 /**
@@ -55,7 +61,7 @@ import org.opengis.feature.PropertyType;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  *
  * @see <a href="https://en.wikipedia.org/wiki/Compound_key">Compound key on Wikipedia</a>
  *
@@ -79,6 +85,52 @@ final class StringJoinOperation extends
     private static final ParameterDescriptorGroup EMPTY_PARAMS = FeatureUtilities.parameters("StringJoin");
 
     /**
+     * A pseudo-converter returning the identifier of a feature. This pseudo-converter is
used in place
+     * of "real" converters in the {@link StringJoinOperation#converters} array when the
property is an
+     * association to a feature instead than an attribute. This pseudo-converters is used
as below:
+     *
+     * <ul>
+     *   <li>{@link Result#getValue()} gets this converter by a call to {@code converters[i].inverse()}.
+     *       This works provided that {@link #inverse()} returns {@code this} (see comment
below).</li>
+     *   <li>{@link Result#setValue(String)} needs to perform a special case for this
class.</li>
+     * </ul>
+     *
+     * This is not a well-formed converter since its {@link #inverse()} method does not fulfill
the required
+     * semantic of {@link ObjectConverter#inverse()}, but this is okay for {@link StringJoinOperation}
needs.
+     * This converter should never be accessible to users however.
+     */
+    private static final class ForFeature extends SurjectiveConverter<Object,Object>
implements Serializable {
+        /** For cross-version compatibility. */
+        private static final long serialVersionUID = 2208230611402221572L;
+
+        /**
+         * The "real" converter which would have been stored in the {@link StringJoinOperation#converters}
+         * array if the property was an attribute instead than an association. For formatting
the feature
+         * identifier, we need to use the inverse of that converter.
+         */
+        final ObjectConverter<? super String, ?> converter;
+
+        /** Creates a new wrapper over the given converter. */
+        ForFeature(final ObjectConverter<? super String, ?> converter) {
+            this.converter = converter;
+        }
+
+        /**
+         * Returns {@code this} for allowing {@link Result#getValue()} to get this pseudo-converter.
+         * This is a violation of {@link ObjectConverter} contract since this pseudo-converter
is not
+         * an identity converter. Direct uses of this pseudo-converter will need a {@code
instanceof}
+         * check instead.
+         */
+        @Override public ObjectConverter<Object,Object> inverse()        {return this;}
+        @Override public Class<Object>                  getSourceClass() {return Object.class;}
+        @Override public Class<Object>                  getTargetClass() {return Object.class;}
+        @Override public Object apply(final Object f) {
+            return (f != null) ? format(converter.inverse(),
+                    ((Feature) f).getPropertyValue(AttributeConvention.IDENTIFIER)) : null;
+        }
+    }
+
+    /**
      * The name of the properties (attributes of operations producing attributes)
      * from which to get the values to concatenate.
      */
@@ -139,21 +191,42 @@ final class StringJoinOperation extends
             /*
              * Verify the following conditions:
              *   - property types are non-null.
-             *   - properties are either attributes, or operations producing attributes.
+             *   - properties are either attributes, or operations producing attributes,
+             *     or association to features having an "sis:identifier" property.
              *   - attributes contain at most one value (no collections).
+             *
+             * We test FeatureAssociationRole, Operation and AttributeType in that order
+             * because the "sis:identifier" property of FeatureType may be an Operation,
+             * which may in turn produce an AttributeType. We do not accept more complex
+             * combinations (e.g. operation producing an association).
              */
-            IdentifiedType attributeType = singleAttributes[i];
-            ArgumentChecks.ensureNonNullElement("singleAttributes", i, attributeType);
-            final GenericName name = attributeType.getName();
-            if (attributeType instanceof Operation) {
-                attributeType = ((Operation) attributeType).getResult();
+            IdentifiedType propertyType = singleAttributes[i];
+            ArgumentChecks.ensureNonNullElement("singleAttributes", i, propertyType);
+            final GenericName name = propertyType.getName();
+            int maximumOccurs = 0;                              // May be a bitwise combination;
need only to know if > 1.
+            PropertyNotFoundException cause = null;             // In case of failure to
find "sis:identifier" property.
+            final boolean isAssociation = (propertyType instanceof FeatureAssociationRole);
+            if (isAssociation) {
+                final FeatureAssociationRole role = (FeatureAssociationRole) propertyType;
+                final FeatureType ft = role.getValueType();
+                maximumOccurs = role.getMaximumOccurs();
+                try {
+                    propertyType = ft.getProperty(AttributeConvention.IDENTIFIER);
+                } catch (PropertyNotFoundException e) {
+                    cause = e;
+                }
             }
-            if (!(attributeType instanceof AttributeType)) {
-                final Class<?>[] inf = Classes.getLeafInterfaces(Classes.getClass(attributeType),
PropertyType.class);
+            if (propertyType instanceof Operation) {
+                propertyType = ((Operation) propertyType).getResult();
+            }
+            if (propertyType instanceof AttributeType) {
+                maximumOccurs |= ((AttributeType<?>) propertyType).getMaximumOccurs();
+            } else {
+                final Class<?>[] inf = Classes.getLeafInterfaces(Classes.getClass(propertyType),
PropertyType.class);
                 throw new IllegalArgumentException(Resources.forProperties(identification)
-                        .getString(Resources.Keys.IllegalPropertyType_2, name, (inf.length
!= 0) ? inf[0] : null));
+                        .getString(Resources.Keys.IllegalPropertyType_2, name, (inf.length
!= 0) ? inf[0] : null), cause);
             }
-            if (((AttributeType<?>) attributeType).getMaximumOccurs() > 1) {
+            if (maximumOccurs > 1) {
                 throw new IllegalArgumentException(Resources.forProperties(identification)
                         .getString(Resources.Keys.NotASingleton_1, name));
             }
@@ -162,7 +235,12 @@ final class StringJoinOperation extends
              * We need only their names and how to convert from String to their values.
              */
             attributeNames[i] = name.toString();
-            converters[i] = ObjectConverters.find(String.class, ((AttributeType<?>)
attributeType).getValueClass());
+            ObjectConverter<? super String, ?> converter = ObjectConverters.find(
+                    String.class, ((AttributeType<?>) propertyType).getValueClass());
+            if (isAssociation) {
+                converter = new ForFeature(converter);
+            }
+            converters[i] = converter;
         }
         resultType = FeatureOperations.POOL.unique(new DefaultAttributeType<>(
                 resultIdentification(identification), String.class, 1, 1, null));
@@ -208,7 +286,7 @@ final class StringJoinOperation extends
     /**
      * Formats the given value using the given converter. This method is a workaround for
the presence
      * of the first {@code ?} in {@code ObjectConverter<?,?>}: defining a separated
method allows us
-     * to replace that {@code <?>} by {@code <V>}, thus allowing the compiler
to verify consistency.
+     * to replace that {@code <?>} by {@code <S>}, thus allowing the compiler
to verify consistency.
      *
      * @param converter  the converter to use for formatting the given value.
      * @param value      the value to format, or {@code null}.
@@ -377,11 +455,17 @@ final class StringJoinOperation extends
                  * If we have more values than expected, continue the parsing but without
storing the values.
                  * The intent is to get the correct count of values for error reporting.
                  */
-                if (!element.isEmpty() && count < values.length) try {
-                    values[count] = converters[count].apply(element);
-                } catch (UnconvertibleObjectException e) {
-                    throw new InvalidPropertyValueException(Errors.format(
-                            Errors.Keys.CanNotAssign_2, attributeNames[count], element),
e);
+                if (!element.isEmpty() && count < values.length) {
+                    ObjectConverter<? super String, ?> converter = converters[count];
+                    if (converter instanceof ForFeature) {
+                        converter = ((ForFeature) converter).converter;
+                    }
+                    try {
+                        values[count] = converter.apply(element);
+                    } catch (UnconvertibleObjectException e) {
+                        throw new InvalidPropertyValueException(Errors.format(
+                                Errors.Keys.CanNotAssign_2, attributeNames[count], element),
e);
+                    }
                 }
                 count++;
                 upper += delimiter.length();
@@ -389,14 +473,21 @@ final class StringJoinOperation extends
             } while (!done);
             /*
              * Store the values in the properties only after we successfully converted all
of them,
-             * in order to have a "all or nothing" behavior.
+             * in order to have a "all or nothing" behavior (assuming that calls to Feature
methods
+             * below do not fail).
              */
             if (values.length != count) {
                 throw new InvalidPropertyValueException(Resources.format(
                         Resources.Keys.UnexpectedNumberOfComponents_4, getName(), value,
values.length, count));
             }
             for (int i=0; i < values.length; i++) {
-                feature.setPropertyValue(attributeNames[i], values[i]);
+                Feature f   = feature;
+                String name = attributeNames[i];
+                if (converters[i] instanceof ForFeature) {
+                    f = (Feature) f.getPropertyValue(name);
+                    name = AttributeConvention.IDENTIFIER;
+                }
+                f.setPropertyValue(name, values[i]);
             }
         }
     }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -93,7 +93,7 @@
  * @author  Travis L. Pinney
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.5
  * @module
  */

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -24,6 +24,7 @@ import org.apache.sis.util.iso.Names;
 import org.apache.sis.util.Static;
 
 // Branch-dependent imports
+import org.opengis.feature.Feature;
 import org.opengis.feature.Attribute;
 import org.opengis.feature.AttributeType;
 import org.opengis.feature.IdentifiedType;
@@ -31,6 +32,7 @@ import org.opengis.feature.Operation;
 import org.opengis.feature.Property;
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.FeatureType;
+import org.opengis.feature.PropertyNotFoundException;
 
 
 /**
@@ -65,7 +67,7 @@ import org.opengis.feature.FeatureType;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.7
  * @module
  */
@@ -173,6 +175,18 @@ public final class AttributeConvention e
     }
 
     /**
+     * String representation of the {@link #IDENTIFIER_PROPERTY} name.
+     * This can be used in calls to {@link Feature#getPropertyValue(String)}.
+     */
+    public static final String IDENTIFIER = "sis:identifier";
+
+    /**
+     * String representation of the {@link #GEOMETRY_PROPERTY} name.
+     * This can be used in calls to {@link Feature#getPropertyValue(String)}.
+     */
+    public static final String GEOMETRY = "sis:geometry";
+
+    /**
      * Do not allow instantiation of this class.
      */
     private AttributeConvention() {
@@ -200,6 +214,21 @@ public final class AttributeConvention e
         }
         return false;
     }
+
+    /**
+     * Returns {@code true} if the given feature type is non-null and has a {@value #IDENTIFIER}
property.
+     *
+     * @param  feature  the feature type to test, or {@code null}.
+     * @return whether the given feature type is non-null and has a {@value #IDENTIFIER}
property.
+     */
+    public static boolean hasIdentifier(final FeatureType feature) {
+        if (feature != null) try {
+            return feature.getProperty(IDENTIFIER) != null;
+        } catch (PropertyNotFoundException e) {
+            // Ignore
+        }
+        return false;
+    }
 
     /**
      * Returns {@code true} if the given type is an {@link AttributeType} or an {@link Operation}
computing

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -19,6 +19,7 @@ package org.apache.sis.feature;
 import java.util.Collections;
 import java.util.Map;
 import org.junit.Test;
+import org.apache.sis.internal.feature.AttributeConvention;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -26,6 +27,8 @@ import org.apache.sis.test.TestCase;
 import static org.junit.Assert.*;
 
 // Branch-dependent imports
+import org.opengis.feature.Feature;
+import org.opengis.feature.FeatureType;
 import org.opengis.feature.PropertyType;
 import org.opengis.feature.InvalidPropertyValueException;
 
@@ -35,7 +38,7 @@ import org.opengis.feature.InvalidProper
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.0
  * @since   0.7
  * @module
  */
@@ -67,7 +70,7 @@ public final strictfp class StringJoinOp
     /**
      * Creates the identification map to be given to attribute, operation and feature constructors.
      */
-    private static Map<String,?> name(final String name) {
+    private static Map<String,?> name(final Object name) {
         return Collections.singletonMap(AbstractIdentifiedType.NAME_KEY, name);
     }
 
@@ -172,4 +175,41 @@ public final strictfp class StringJoinOp
             assertTrue(message, message.contains("age"));
         }
     }
+
+    /**
+     * Tests the creation of an identifier when one property is a feature.
+     * This method tests both {@code getValue(…)} and {@code setValue(…)}.
+     */
+    @Test
+    public void testFeatureAssociation() {
+        final PropertyType id1 = new DefaultAttributeType<>(name(AttributeConvention.IDENTIFIER_PROPERTY),
String.class, 1, 1, null);
+        final FeatureType  ft1 = new DefaultFeatureType(name("Child feature"), false, null,
id1);
+        final PropertyType  p1 = new DefaultAssociationRole(name("first"), ft1, 1, 1);
+        final PropertyType  p2 = new DefaultAttributeType<>(name("second"), Integer.class,
1, 1, null);
+        final PropertyType idc = FeatureOperations.compound(name("concat"), "/", "<<:",
":>>", p1, p2);
+        final Feature  feature = new DefaultFeatureType(name("Parent feature"), false, null,
p1, p2, idc).newInstance();
+        /*
+         * For empty feature, should have only the prefix, delimiter and suffix.
+         */
+        assertEquals("<<:/:>>", feature.getPropertyValue("concat"));
+        /*
+         * Test with a value for the property (nothing in the association yet).
+         */
+        feature.setPropertyValue("second", 21);
+        assertEquals("<<:/21:>>", feature.getPropertyValue("concat"));
+        /*
+         * Create the associated feature and set its identifier.
+         * The compound identifier shall be updated accordingly.
+         */
+        final Feature f1 = ft1.newInstance();
+        feature.setPropertyValue("first", f1);
+        f1.setPropertyValue("sis:identifier", "SomeKey");
+        assertEquals("<<:SomeKey/21:>>", feature.getPropertyValue("concat"));
+        /*
+         * Setting a value should cascade to the child feature.
+         */
+        feature.setPropertyValue("concat", "<<:NewKey/38:>>");
+        assertEquals(38, feature.getPropertyValue("second"));
+        assertEquals("NewKey", f1.getPropertyValue("sis:identifier"));
+    }
 }

Modified: sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/DiscreteSampling.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.internal.netcdf;
 
-import org.opengis.metadata.Metadata;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.internal.feature.Geometries;
@@ -55,18 +54,6 @@ public abstract class DiscreteSampling e
     }
 
     /**
-     * Returns information about this resource.
-     *
-     * @return information about this resource, or {@code null} if none.
-     *
-     * @todo Not yet implemented.
-     */
-    @Override
-    public Metadata getMetadata() {
-        return null;
-    }
-
-    /**
      * Returns the error message for a file that can not be read.
      *
      * @return default error message to use in exceptions.

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/AbstractFeatureSet.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -22,7 +22,15 @@ import org.apache.sis.storage.FeatureSet
 import org.apache.sis.storage.Query;
 import org.apache.sis.storage.UnsupportedQueryException;
 import org.apache.sis.internal.storage.query.SimpleQuery;
+import org.apache.sis.metadata.iso.DefaultMetadata;
+import org.apache.sis.metadata.iso.citation.DefaultCitation;
+import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
 import org.apache.sis.util.logging.WarningListeners;
+import org.opengis.metadata.Metadata;
+import org.opengis.util.GenericName;
+
+// Branch-dependent imports
+import org.opengis.feature.FeatureType;
 
 
 /**
@@ -36,6 +44,13 @@ import org.apache.sis.util.logging.Warni
  */
 public abstract class AbstractFeatureSet extends AbstractResource implements FeatureSet {
     /**
+     * A description of this set of features, or {@code null} if not yet computed.
+     * Those metadata are created by {@link #getMetadata()} when first needed.
+     * Subclasses can set a value to this field directly.
+     */
+    protected Metadata metadata;
+
+    /**
      * Creates a new resource.
      *
      * @param listeners  the set of registered warning listeners for the data store, or {@code
null} if none.
@@ -55,6 +70,35 @@ public abstract class AbstractFeatureSet
     }
 
     /**
+     * Returns a description of this set of features.
+     * Current implementation sets only the resource name; this may change in any future
Apache SIS version.
+     *
+     * <div class="note"><b>Note:</b>
+     * we currently do not set the geographic extent from the envelope because default {@link
#getEnvelope()}
+     * implementation itself invokes {@code getMetadata()}. Consequently requesting the envelope
from this
+     * method could create a never-ending loop.</div>
+     */
+    @Override
+    public synchronized Metadata getMetadata() throws DataStoreException {
+        if (metadata == null) {
+            final DefaultMetadata metadata = new DefaultMetadata();
+            final FeatureType type = getType();
+            if (type != null) {
+                final GenericName name = type.getName();
+                if (name != null) {                         // Paranoiac check (should never
be null).
+                    final DefaultCitation citation = new DefaultCitation(name.toInternationalString());
+                    final DefaultDataIdentification identification = new DefaultDataIdentification();
+                    identification.setCitation(citation);
+                }
+            }
+            // No geographic extent - see above javadoc.
+            metadata.freeze();
+            this.metadata = metadata;
+        }
+        return metadata;
+    }
+
+    /**
      * Requests a subset of features and/or feature properties from this resource.
      * The default implementation try to execute the queries by filtering the
      * {@linkplain #features(boolean) stream of features}, which may be inefficient.

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MemoryFeatureSet.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -18,10 +18,6 @@ package org.apache.sis.internal.storage;
 
 import java.util.Collection;
 import java.util.stream.Stream;
-import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.metadata.iso.citation.DefaultCitation;
-import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
-import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.logging.WarningListeners;
@@ -42,11 +38,6 @@ import org.opengis.metadata.Metadata;
  */
 public final class MemoryFeatureSet extends AbstractFeatureSet {
     /**
-     * The metadata to be returned by {@link #getMetadata()}.
-     */
-    private final Metadata metadata;
-
-    /**
      * The type specified at construction time and returned by {@link #getType()}.
      */
     private final FeatureType type;
@@ -75,30 +66,10 @@ public final class MemoryFeatureSet exte
         ArgumentChecks.ensureNonNull("features", features);
         this.type     = type;
         this.features = features;
-        if (metadata == null) {
-            final DefaultDataIdentification identification = new DefaultDataIdentification();
-            final DefaultCitation citation = new DefaultCitation(type.getName().toString());
-            citation.getIdentifiers().add(new NamedIdentifier(type.getName()));
-            identification.setCitation(citation);
-
-            final DefaultMetadata md = new DefaultMetadata(null, null, identification);
-            md.freeze();
-            metadata = md;
-        }
         this.metadata = metadata;
     }
 
     /**
-     * Returns the metadata given or inferred at construction time.
-     *
-     * @return information about this resource.
-     */
-    @Override
-    public Metadata getMetadata() {
-        return metadata;
-    }
-
-    /**
      * Returns the type common to all feature instances in this set.
      *
      * @return a description of properties that are common to all features in this dataset.

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/package-info.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -24,8 +24,9 @@
  * may change in incompatible ways in any future version without notice.
  *
  * @author  Martin Desruisseaux (Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @version 1.0
- * @since   0.3
+ * @since   0.4
  * @module
  */
 package org.apache.sis.internal.storage;

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/FeatureSubset.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -19,12 +19,8 @@ package org.apache.sis.internal.storage.
 import java.util.List;
 import java.util.stream.Stream;
 import org.opengis.geometry.Envelope;
-import org.opengis.metadata.Metadata;
 import org.apache.sis.internal.feature.FeatureUtilities;
 import org.apache.sis.internal.storage.AbstractFeatureSet;
-import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.metadata.iso.citation.DefaultCitation;
-import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.FeatureSet;
 
@@ -66,11 +62,6 @@ final class FeatureSubset extends Abstra
     private FeatureType resultType;
 
     /**
-     * A description of this set of features, computed when first needed.
-     */
-    private DefaultMetadata metadata;
-
-    /**
      * Creates a new set of features by filtering the given set using the given query.
      */
     FeatureSubset(final FeatureSet source, final SimpleQuery query) {
@@ -88,26 +79,6 @@ final class FeatureSubset extends Abstra
     }
 
     /**
-     * Computes information about this resource.
-     * Current implementation sets only the resource name.
-     */
-    @Override
-    public synchronized Metadata getMetadata() throws DataStoreException {
-        if (metadata == null) {
-            final DefaultCitation citation = new DefaultCitation(getType().getName().toInternationalString());
-            final DefaultDataIdentification identification = new DefaultDataIdentification();
-            identification.setCitation(citation);
-
-            final DefaultMetadata metadata = new DefaultMetadata();
-            metadata.getIdentificationInfo().add(identification);
-            metadata.freeze();
-
-            this.metadata = metadata;
-        }
-        return metadata;
-    }
-
-    /**
      * Returns a description of properties that are common to all features in this dataset.
      */
     @Override

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataSet.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataSet.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataSet.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataSet.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -67,7 +67,7 @@ public interface DataSet extends Resourc
      * If this resource uses many different CRS with none of them covering all data, then
the envelope should use a
      * global system (typically a {@linkplain org.apache.sis.referencing.crs.DefaultGeocentricCRS
geographic CRS}).
      *
-     * @return the spatio-temporal resource extent. Should not be {@code null}.
+     * @return the spatio-temporal resource extent. Should not be {@code null} (but may happen
if too costly to compute).
      * @throws DataStoreException if an error occurred while reading or computing the envelope.
      */
     Envelope getEnvelope() throws DataStoreException;

Modified: sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -25,7 +25,7 @@ import org.junit.BeforeClass;
  * All tests from the {@code sis-storage} module, in approximative dependency order.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.3
  * @module
  */

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/GroupAsPolylineOperation.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -190,7 +190,7 @@ final class GroupAsPolylineOperation ext
                     }
 
                     @Override public Object next() {
-                        return ((Feature) it.next()).getPropertyValue("sis:geometry");
+                        return ((Feature) it.next()).getPropertyValue(AttributeConvention.GEOMETRY);
                     }
                 });
                 geometry = getType().getValueClass().cast(geom);

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Reader.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -30,6 +30,7 @@ import javax.xml.bind.JAXBException;
 import org.apache.sis.storage.gps.Fix;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.internal.feature.AttributeConvention;
 import org.apache.sis.internal.storage.xml.stream.StaxStreamReader;
 import org.apache.sis.util.collection.BackingStoreException;
 import org.apache.sis.util.resources.Errors;
@@ -55,7 +56,7 @@ import org.opengis.feature.Feature;
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.8
  * @module
  */
@@ -409,8 +410,8 @@ parse:  while (reader.hasNext()) {
         }
         final Types types = ((Store) owner).types;
         final Feature feature = types.wayPoint.newInstance();
-        feature.setPropertyValue("sis:identifier", index);
-        feature.setPropertyValue("sis:geometry", types.geometries.createPoint(parseDouble(lon),
parseDouble(lat)));
+        feature.setPropertyValue(AttributeConvention.IDENTIFIER, index);
+        feature.setPropertyValue(AttributeConvention.GEOMETRY, types.geometries.createPoint(parseDouble(lon),
parseDouble(lat)));
         List<Link> links = null;
         while (true) {
             /*
@@ -474,7 +475,7 @@ parse:  while (reader.hasNext()) {
     private Feature parseRoute(final int index) throws Exception {
         assert reader.isStartElement() && Tags.ROUTES.equals(reader.getLocalName());
         final Feature feature = ((Store) owner).types.route.newInstance();
-        feature.setPropertyValue("sis:identifier", index);
+        feature.setPropertyValue(AttributeConvention.IDENTIFIER, index);
         List<Feature> wayPoints = null;
         List<Link> links = null;
         while (true) {
@@ -530,7 +531,7 @@ parse:  while (reader.hasNext()) {
     private Feature parseTrackSegment(final int index) throws Exception {
         assert reader.isStartElement() && Tags.TRACK_SEGMENTS.equals(reader.getLocalName());
         final Feature feature = ((Store) owner).types.trackSegment.newInstance();
-        feature.setPropertyValue("sis:identifier", index);
+        feature.setPropertyValue(AttributeConvention.IDENTIFIER, index);
         List<Feature> wayPoints = null;
         while (true) {
             /*
@@ -573,7 +574,7 @@ parse:  while (reader.hasNext()) {
     private Feature parseTrack(final int index) throws Exception {
         assert reader.isStartElement() && Tags.TRACKS.equals(reader.getLocalName());
         final Feature feature = ((Store) owner).types.track.newInstance();
-        feature.setPropertyValue("sis:identifier", index);
+        feature.setPropertyValue(AttributeConvention.IDENTIFIER, index);
         List<Feature> segments = null;
         List<Link> links = null;
         while (true) {

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Writer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Writer.java?rev=1831270&r1=1831269&r2=1831270&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Writer.java
[UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Writer.java
[UTF-8] Wed May  9 17:10:31 2018
@@ -24,6 +24,7 @@ import org.apache.sis.storage.gps.Fix;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.IllegalFeatureTypeException;
 import org.apache.sis.internal.storage.xml.stream.StaxStreamWriter;
+import org.apache.sis.internal.feature.AttributeConvention;
 import org.apache.sis.internal.feature.Geometries;
 import org.apache.sis.util.Version;
 
@@ -191,7 +192,7 @@ final class Writer extends StaxStreamWri
      */
     private void writeWayPoint(final Feature feature, final String tagName) throws XMLStreamException,
JAXBException {
         if (feature != null) {
-            final double[] pt = Geometries.getCoordinate(feature.getPropertyValue("sis:geometry"));
+            final double[] pt = Geometries.getCoordinate(feature.getPropertyValue(AttributeConvention.GEOMETRY));
             if (pt != null && pt.length >= 2) {
                 writer.writeStartElement(tagName);
                 writer.writeAttribute(Attributes.LATITUDE,  Double.toString(pt[1]));



Mime
View raw message