sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1686268 [1/4] - in /sis/branches/JDK7: ./ core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-feature/src/test/java/org/apache/sis/feature/ core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-metadata/src...
Date Thu, 18 Jun 2015 16:49:27 GMT
Author: desruisseaux
Date: Thu Jun 18 16:49:25 2015
New Revision: 1686268

URL: http://svn.apache.org/r1686268
Log:
Merge from the JDK8 branch Feature bug fixes and partial WKT 2 work.

Added:
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
      - copied unchanged from r1686266, sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java
      - copied unchanged from r1686266, sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Parser.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java
      - copied unchanged from r1686266, sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/VerticalInfo.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Warnings.java
      - copied, changed from r1686266, sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Warnings.java
Removed:
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTParser.java
Modified:
    sis/branches/JDK7/   (props changed)
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
    sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
    sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
    sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/package-info.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/ElementTest.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/extent/ExtentsTest.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/mock/VerticalCRSMock.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ServicesForMetadata.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AxesConvention.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractReferenceSystemTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultCompoundCRSTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultTemporalCRSTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultGeodeticDatumTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/DefaultPrimeMeridianTest.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/Characters.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
    sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java

Propchange: sis/branches/JDK7/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Jun 18 16:49:25 2015
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
 /sis/branches/JDK6:1394913-1508480
-/sis/branches/JDK8:1584960-1684685
+/sis/branches/JDK8:1584960-1686266
 /sis/trunk:1394364-1508466,1519089-1519674

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAssociation.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -30,6 +30,8 @@ import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.FeatureAssociation;
 import org.opengis.feature.FeatureAssociationRole;
+import org.opengis.feature.InvalidPropertyValueException;
+import org.opengis.feature.MultiValuedPropertyException;
 
 
 /**
@@ -47,7 +49,7 @@ import org.opengis.feature.FeatureAssoci
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see DefaultAssociationRole#newInstance()
@@ -130,12 +132,12 @@ public abstract class AbstractAssociatio
      * features is restricted to 1 or 0.
      *
      * @return The associated feature (may be {@code null}).
-     * @throws IllegalStateException if this association contains more than one value.
+     * @throws MultiValuedPropertyException if this association contains more than one value.
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
     @Override
-    public abstract Feature getValue();
+    public abstract Feature getValue() throws MultiValuedPropertyException;
 
     /**
      * Returns all features, or an empty collection if none.
@@ -162,12 +164,12 @@ public abstract class AbstractAssociatio
      * A more exhaustive verification can be performed by invoking the {@link #quality()} method.
      *
      * @param  value The new value, or {@code null}.
-     * @throws IllegalArgumentException If the given feature is not valid for this association.
+     * @throws InvalidPropertyValueException If the given feature is not valid for this association.
      *
      * @see AbstractFeature#setPropertyValue(String, Object)
      */
     @Override
-    public abstract void setValue(final Feature value) throws IllegalArgumentException;
+    public abstract void setValue(final Feature value) throws InvalidPropertyValueException;
 
     /**
      * Sets the features. All previous values are replaced by the given collection.
@@ -176,10 +178,10 @@ public abstract class AbstractAssociatio
      * then delegates to {@link #setValue(Feature)}.</p>
      *
      * @param  values The new values.
-     * @throws IllegalArgumentException if the given collection contains too many elements.
+     * @throws InvalidPropertyValueException if the given collection contains too many elements.
      */
     @Override
-    public void setValues(final Collection<? extends Feature> values) throws IllegalArgumentException {
+    public void setValues(final Collection<? extends Feature> values) throws InvalidPropertyValueException {
         super.setValues(values);
     }
 
@@ -189,7 +191,7 @@ public abstract class AbstractAssociatio
      */
     final void ensureValid(final FeatureType base, final FeatureType type) {
         if (base != type && !DefaultFeatureType.maybeAssignableFrom(base, type)) {
-            throw new IllegalArgumentException(
+            throw new InvalidPropertyValueException(
                     Errors.format(Errors.Keys.IllegalArgumentClass_3, getName(), base.getName(), type.getName()));
         }
     }

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractAttribute.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -35,6 +35,8 @@ import org.apache.sis.util.ArgumentCheck
 // Branch-dependent imports
 import org.opengis.feature.Attribute;
 import org.opengis.feature.AttributeType;
+import org.opengis.feature.InvalidPropertyValueException;
+import org.opengis.feature.MultiValuedPropertyException;
 
 
 /**
@@ -67,7 +69,7 @@ import org.opengis.feature.AttributeType
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see DefaultAttributeType#newInstance()
@@ -206,12 +208,12 @@ public abstract class AbstractAttribute<
      * of attribute values is restricted to 1 or 0.
      *
      * @return The attribute value (may be {@code null}).
-     * @throws IllegalStateException if this attribute contains more than one value.
+     * @throws MultiValuedPropertyException if this attribute contains more than one value.
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
     @Override
-    public abstract V getValue() throws IllegalStateException;
+    public abstract V getValue() throws MultiValuedPropertyException;
 
     /**
      * Returns all attribute values, or an empty collection if none.
@@ -251,10 +253,10 @@ public abstract class AbstractAttribute<
      * then delegates to {@link #setValue(Object)}.</p>
      *
      * @param  values The new values.
-     * @throws IllegalArgumentException if the given collection contains too many elements.
+     * @throws InvalidPropertyValueException if the given collection contains too many elements.
      */
     @Override
-    public void setValues(final Collection<? extends V> values) throws IllegalArgumentException {
+    public void setValues(final Collection<? extends V> values) throws InvalidPropertyValueException {
         super.setValues(values);
     }
 

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -31,6 +31,8 @@ import org.apache.sis.internal.util.Chec
 // Branch-dependent imports
 import org.opengis.feature.Property;
 import org.opengis.feature.PropertyType;
+import org.opengis.feature.PropertyNotFoundException;
+import org.opengis.feature.InvalidPropertyValueException;
 import org.opengis.feature.Attribute;
 import org.opengis.feature.AttributeType;
 import org.opengis.feature.Feature;
@@ -130,13 +132,13 @@ public abstract class AbstractFeature im
      *
      * @param  name The property name.
      * @return The property of the given name (never {@code null}).
-     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
+     * @throws PropertyNotFoundException if the given argument is not a property name of this feature.
      *
      * @see #getPropertyValue(String)
      * @see DefaultFeatureType#getProperty(String)
      */
     @Override
-    public abstract Property getProperty(final String name) throws IllegalArgumentException;
+    public abstract Property getProperty(final String name) throws PropertyNotFoundException;
 
     /**
      * Sets the property (attribute or feature association).
@@ -159,8 +161,9 @@ public abstract class AbstractFeature im
      * the {@link #setPropertyValue(String, Object)} method is preferred.</div>
      *
      * @param  property The property to set.
-     * @throws IllegalArgumentException if the type of the given property is not one of the types
-     *         known to this feature, or if the property can not be set of an other reason.
+     * @throws PropertyNotFoundException if the name of the given property is not a property name of this feature.
+     * @throws InvalidPropertyValueException if the value of the given property is not valid.
+     * @throws IllegalArgumentException if the property can not be set for another reason.
      *
      * @see #setPropertyValue(String, Object)
      */
@@ -192,10 +195,10 @@ public abstract class AbstractFeature im
      *
      * @param  name The name of the property to create.
      * @return A {@code Property} of the given name.
-     * @throws IllegalArgumentException If the given argument is not the name of an attribute or
+     * @throws PropertyNotFoundException if the given argument is not the name of an attribute or
      *         feature association of this feature.
      */
-    final Property createProperty(final String name) throws IllegalArgumentException {
+    final Property createProperty(final String name) throws PropertyNotFoundException {
         final PropertyType pt = type.getProperty(name);
         if (pt instanceof AttributeType<?>) {
             return ((AttributeType<?>) pt).newInstance();
@@ -260,9 +263,9 @@ public abstract class AbstractFeature im
      *
      * @param  name The name of the property for which to get the default value.
      * @return The default value for the {@code Property} of the given name.
-     * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
+     * @throws PropertyNotFoundException if the given argument is not an attribute or association name of this feature.
      */
-    final Object getDefaultValue(final String name) throws IllegalArgumentException {
+    final Object getDefaultValue(final String name) throws PropertyNotFoundException {
         final PropertyType pt = type.getProperty(name);
         if (pt instanceof AttributeType<?>) {
             return getDefaultValue((AttributeType<?>) pt);
@@ -306,12 +309,12 @@ public abstract class AbstractFeature im
      *
      * @param  name The property name.
      * @return The value for the given property, or {@code null} if none.
-     * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
+     * @throws PropertyNotFoundException if the given argument is not an attribute or association name of this feature.
      *
      * @see AbstractAttribute#getValue()
      */
     @Override
-    public abstract Object getPropertyValue(final String name) throws IllegalArgumentException;
+    public abstract Object getPropertyValue(final String name) throws PropertyNotFoundException;
 
     /**
      * Sets the value for the property of the given name.
@@ -324,8 +327,9 @@ public abstract class AbstractFeature im
      *
      * @param  name  The attribute name.
      * @param  value The new value for the given attribute (may be {@code null}).
-     * @throws ClassCastException If the value is not assignable to the expected value class.
-     * @throws IllegalArgumentException If the given value can not be assigned for an other reason.
+     * @throws PropertyNotFoundException if the given name is not an attribute or association name of this feature.
+     * @throws ClassCastException if the value is not assignable to the expected value class.
+     * @throws InvalidPropertyValueException if the given value is not valid for a reason other than its type.
      *
      * @see AbstractAttribute#setValue(Object)
      */
@@ -454,9 +458,11 @@ public abstract class AbstractFeature im
             throw illegalPropertyType(base.getName(), property.getClass());
         }
         if (pt != base) {
-            throw new IllegalArgumentException(base == null
-                    ? Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name)
-                    : Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
+            if (base == null) {
+                throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+            } else {
+                throw new InvalidPropertyValueException(Errors.format(Errors.Keys.MismatchedPropertyType_1, name));
+            }
         }
     }
 
@@ -565,9 +571,9 @@ public abstract class AbstractFeature im
     }
 
     /**
-     * Returns the exception for a property type which neither an attribute or an association.
+     * Returns the exception for a property type which is neither an attribute or an association.
      * This method is invoked after a {@link PropertyType} has been found for the user-supplied name,
-     * but that property can not be stored in a {@link Property} instance.
+     * but that property can not be stored in or extracted from a {@link Property} instance.
      */
     static IllegalArgumentException unsupportedPropertyType(final GenericName name) {
         return new IllegalArgumentException(Errors.format(Errors.Keys.CanNotInstantiate_1, name));
@@ -585,8 +591,8 @@ public abstract class AbstractFeature im
     /**
      * Returns the exception for a property value (usually a feature) of wrong type.
      */
-    private static IllegalArgumentException illegalPropertyType(final GenericName name, final Object value) {
-        return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyClass_2, name, value));
+    private static InvalidPropertyValueException illegalPropertyType(final GenericName name, final Object value) {
+        return new InvalidPropertyValueException(Errors.format(Errors.Keys.IllegalPropertyClass_2, name, value));
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractIdentifiedType.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -38,7 +38,7 @@ import org.opengis.feature.IdentifiedTyp
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public class AbstractIdentifiedType implements IdentifiedType, Serializable {
@@ -165,9 +165,7 @@ public class AbstractIdentifiedType impl
      * @param  identification The name and other information to be given to this identified type.
      * @throws IllegalArgumentException if a property has an invalid value.
      */
-    protected AbstractIdentifiedType(final Map<String,?> identification)
-            throws IllegalArgumentException
-    {
+    protected AbstractIdentifiedType(final Map<String,?> identification) throws IllegalArgumentException {
         ensureNonNull("identification", identification);
         Object value = identification.get(NAME_KEY);
         if (value == null) {

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/CharacteristicMap.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -27,6 +27,8 @@ import org.apache.sis.internal.util.Abst
 // Branch-dependent imports
 import org.opengis.feature.Attribute;
 import org.opengis.feature.AttributeType;
+import org.opengis.feature.InvalidPropertyValueException;
+import org.opengis.feature.PropertyNotFoundException;
 
 
 /**
@@ -35,7 +37,7 @@ import org.opengis.feature.AttributeType
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 final class CharacteristicMap extends AbstractMap<String,Attribute<?>> implements Cloneable {
@@ -166,13 +168,13 @@ final class CharacteristicMap extends Ab
      *
      * @param  key The name for which to get the characteristic index.
      * @return The index for the characteristic of the given name.
-     * @throws IllegalArgumentException if the given key is not the name of a characteristic in this map.
+     * @throws PropertyNotFoundException if the given key is not the name of a characteristic in this map.
      */
     private int indexOf(final String key) {
         ArgumentChecks.ensureNonNull("key", key);
         final Integer index = types.indices.get(key);
         if (index == null) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, source.getName(), key));
+            throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, source.getName(), key));
         }
         return index;
     }
@@ -190,7 +192,7 @@ final class CharacteristicMap extends Ab
         if (!expected.equals(type)) {
             final GenericName en = expected.getName();
             final GenericName an = type.getName();
-            throw new IllegalArgumentException(String.valueOf(en).equals(String.valueOf(an))
+            throw new InvalidPropertyValueException(String.valueOf(en).equals(String.valueOf(an))
                     ? Errors.format(Errors.Keys.MismatchedPropertyType_1, en)
                     : Errors.format(Errors.Keys.CanNotAssign_2, en.push(source.getName()), an));
         }

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -47,6 +47,8 @@ import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.FeatureAssociationRole;
 import org.opengis.feature.Operation;
+import org.opengis.feature.FeatureInstantiationException;
+import org.opengis.feature.PropertyNotFoundException;
 
 
 /**
@@ -607,7 +609,7 @@ public class DefaultFeatureType extends
             final PropertyType other;
             try {
                 other = type.getProperty(entry.getKey());
-            } catch (IllegalArgumentException e) {
+            } catch (PropertyNotFoundException e) {
                 /*
                  * A property in this FeatureType does not exist in the given FeatureType.
                  * Catching exceptions is not an efficient way to perform this check, but
@@ -713,17 +715,17 @@ public class DefaultFeatureType extends
      *
      * @param  name The name of the property to search.
      * @return The property for the given name, or {@code null} if none.
-     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
+     * @throws PropertyNotFoundException If the given argument is not a property name of this feature.
      *
      * @see AbstractFeature#getProperty(String)
      */
     @Override
-    public PropertyType getProperty(final String name) throws IllegalArgumentException {
+    public PropertyType getProperty(final String name) throws PropertyNotFoundException {
         final PropertyType pt = byName.get(name);
         if (pt != null) {
             return pt;
         }
-        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+        throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
     }
 
     /**
@@ -742,12 +744,12 @@ public class DefaultFeatureType extends
      * then this method is equivalent to {@link Class#newInstance()}.</div>
      *
      * @return A new feature instance.
-     * @throws IllegalStateException if this feature type {@linkplain #isAbstract() is abstract}.
+     * @throws FeatureInstantiationException if this feature type {@linkplain #isAbstract() is abstract}.
      */
     @Override
-    public Feature newInstance() throws IllegalStateException {
+    public Feature newInstance() throws FeatureInstantiationException {
         if (isAbstract) {
-            throw new IllegalStateException(Errors.format(Errors.Keys.AbstractType_1, getName()));
+            throw new FeatureInstantiationException(Errors.format(Errors.Keys.AbstractType_1, getName()));
         }
         return isSparse ? new SparseFeature(this) : new DenseFeature(this);
     }

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -28,6 +28,7 @@ import org.apache.sis.util.resources.Err
 import org.opengis.feature.Property;
 import org.opengis.feature.Attribute;
 import org.opengis.feature.FeatureAssociation;
+import org.opengis.feature.PropertyNotFoundException;
 
 
 /**
@@ -84,14 +85,14 @@ final class DenseFeature extends Abstrac
      * @param  name The property name.
      * @return The index for the property of the given name,
      *         or a negative value if the property is a parameterless operation.
-     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
+     * @throws PropertyNotFoundException if the given argument is not a property name of this feature.
      */
-    private int getIndex(final String name) throws IllegalArgumentException {
+    private int getIndex(final String name) throws PropertyNotFoundException {
         final Integer index = indices.get(name);
         if (index != null) {
             return index;
         }
-        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+        throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
     }
 
     /**
@@ -99,10 +100,10 @@ final class DenseFeature extends Abstrac
      *
      * @param  name The property name.
      * @return The property of the given name.
-     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
+     * @throws PropertyNotFoundException If the given argument is not a property name of this feature.
      */
     @Override
-    public Property getProperty(final String name) throws IllegalArgumentException {
+    public Property getProperty(final String name) throws PropertyNotFoundException {
         ArgumentChecks.ensureNonNull("name", name);
         final int index = getIndex(name);
         if (index < 0) {
@@ -132,7 +133,7 @@ final class DenseFeature extends Abstrac
      *
      * @param  property The property to set.
      * @throws IllegalArgumentException if the type of the given property is not one of the types
-     *         known to this feature.
+     *         known to this feature, or if the property can not be set or another reason.
      */
     @Override
     public void setProperty(final Property property) throws IllegalArgumentException {
@@ -175,10 +176,10 @@ final class DenseFeature extends Abstrac
      *
      * @param  name The property name.
      * @return The value for the given property, or {@code null} if none.
-     * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
+     * @throws PropertyNotFoundException If the given argument is not an attribute or association name of this feature.
      */
     @Override
-    public Object getPropertyValue(final String name) throws IllegalArgumentException {
+    public Object getPropertyValue(final String name) throws PropertyNotFoundException {
         ArgumentChecks.ensureNonNull("name", name);
         final int index = getIndex(name);
         if (index < 0) {
@@ -207,7 +208,7 @@ final class DenseFeature extends Abstrac
      * @param  name  The attribute name.
      * @param  value The new value for the given attribute (may be {@code null}).
      * @throws ClassCastException If the value is not assignable to the expected value class.
-     * @throws IllegalArgumentException If the given value can not be assigned for an other reason.
+     * @throws IllegalArgumentException If the given value can not be assigned for another reason.
      */
     @Override
     public void setPropertyValue(final String name, Object value) throws IllegalArgumentException {
@@ -290,12 +291,36 @@ final class DenseFeature extends Abstrac
 
     /**
      * Returns a hash code value for this feature.
+     * This implementation computes the hash code using only the property values, not the {@code Property} instances,
+     * in order to keep the hash code value stable before and after the {@code properties} array is promoted from the
+     * {@code Object[]} type to the {@code Property[]} type.
      *
      * @return A hash code value.
      */
     @Override
     public int hashCode() {
-        return type.hashCode() + 37 * Arrays.hashCode(properties);
+        int code = 1;
+        if (properties != null) {
+            if (properties instanceof Property[]) {
+                for (final Property p : (Property[]) properties) {
+                    code = 31 * code;
+                    final Object value;
+                    if (p instanceof Attribute<?>) {
+                        value = getAttributeValue((Attribute<?>) p);
+                    } else if (p instanceof FeatureAssociation) {
+                        value = getAssociationValue((FeatureAssociation) p);
+                    } else {
+                        continue;
+                    }
+                    if (value != null) {
+                        code += value.hashCode();
+                    }
+                }
+            } else {
+                code = Arrays.hashCode(properties);
+            }
+        }
+        return type.hashCode() + code;
     }
 
     /**
@@ -310,7 +335,17 @@ final class DenseFeature extends Abstrac
         }
         if (obj instanceof DenseFeature) {
             final DenseFeature that = (DenseFeature) obj;
-            return type.equals(that.type) && Arrays.equals(properties, that.properties);
+            if (type.equals(that.type)) {
+                final boolean asProperties = (properties instanceof Property[]);
+                if (asProperties != (that.properties instanceof Property[])) {
+                    if (asProperties) {
+                        that.wrapValuesInProperties();
+                    } else {
+                        wrapValuesInProperties();
+                    }
+                }
+                return Arrays.equals(properties, that.properties);
+            }
         }
         return false;
     }

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -16,6 +16,9 @@
  */
 package org.apache.sis.feature;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.Locale;
 import java.util.TimeZone;
 import java.io.IOException;
@@ -71,7 +74,7 @@ import org.opengis.feature.Operation;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public class FeatureFormat extends TabularFormat<Object> {
@@ -301,19 +304,28 @@ header: for (int i=0; ; i++) {
              * Column 3 - Value or default value.
              */
             if (value != null) {
-                final Format format = getFormat(valueClass);
-                if (format != null) {
-                    value = format.format(value, buffer, dummyFP);
-                } else if (value instanceof Feature && propertyType instanceof FeatureAssociationRole) {
-                    final String p = DefaultAssociationRole.getTitleProperty((FeatureAssociationRole) propertyType);
-                    if (p != null) {
-                        value = ((Feature) value).getPropertyValue(p);
+                final boolean isInstance = valueClass != null && valueClass.isInstance(value);
+                final Format format = isInstance ? getFormat(valueClass) : null;
+                final Iterator<?> it = (!isInstance && (value instanceof Collection<?>)
+                        ? (Collection<?>) value : Collections.singleton(value)).iterator();
+                String separator = "";
+                while (it.hasNext()) {
+                    value = it.next();
+                    if (value != null) {
+                        if (format != null) {
+                            value = format.format(value, buffer, dummyFP);
+                        } else if (value instanceof Feature && propertyType instanceof FeatureAssociationRole) {
+                            final String p = DefaultAssociationRole.getTitleProperty((FeatureAssociationRole) propertyType);
+                            if (p != null) {
+                                value = ((Feature) value).getPropertyValue(p);
+                                if (value == null) continue;
+                            }
+                        }
+                        table.append(separator).append(formatValue(value));
+                        buffer.setLength(0);
+                        separator = ", ";
                     }
                 }
-                if (value != null) {
-                    table.append(formatValue(value));
-                }
-                buffer.setLength(0);
             }
             /*
              * Column 4 - Characteristics.

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/Field.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -23,6 +23,9 @@ import org.apache.sis.util.resources.Err
 
 // Branch-dependent imports
 import org.opengis.feature.Property;
+import org.opengis.feature.MultiValuedPropertyException;
+import org.opengis.feature.InvalidPropertyValueException;
+
 
 /**
  * Base class of property that can be stored in a {@link AbstractFeature} instance.
@@ -30,7 +33,7 @@ import org.opengis.feature.Property;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 abstract class Field<V> implements Property {
@@ -55,12 +58,12 @@ abstract class Field<V> implements Prope
      * Returns the field feature or attribute value, or {@code null} if none.
      *
      * @return The feature or attribute value (may be {@code null}).
-     * @throws IllegalStateException if this field contains more than one value.
+     * @throws MultiValuedPropertyException if this field contains more than one value.
      *
      * @see AbstractFeature#getPropertyValue(String)
      */
     @Override
-    public abstract V getValue() throws IllegalStateException;
+    public abstract V getValue() throws MultiValuedPropertyException;
 
     /**
      * Returns all features or attribute values, or an empty collection if none.
@@ -89,16 +92,16 @@ abstract class Field<V> implements Prope
      * then delegates to {@link #setValue(Object)}.</p>
      *
      * @param values The new values.
-     * @throws IllegalArgumentException if the given collection contains too many elements.
+     * @throws InvalidPropertyValueException if the given collection contains too many elements.
      */
-    public void setValues(final Collection<? extends V> values) throws IllegalArgumentException {
+    public void setValues(final Collection<? extends V> values) throws InvalidPropertyValueException {
         V value = null;
         ArgumentChecks.ensureNonNull("values", values);
         final Iterator<? extends V> it = values.iterator();
         if (it.hasNext()) {
             value = it.next();
             if (it.hasNext()) {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.TooManyOccurrences_2, 1, getName()));
+                throw new InvalidPropertyValueException(Errors.format(Errors.Keys.TooManyOccurrences_2, 1, getName()));
             }
         }
         setValue(value);

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -25,6 +25,7 @@ import org.apache.sis.util.resources.Err
 import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.FeatureAssociationRole;
+import org.opengis.feature.MultiValuedPropertyException;
 
 
 /**
@@ -44,7 +45,7 @@ import org.opengis.feature.FeatureAssoci
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see DefaultAssociationRole
@@ -89,14 +90,14 @@ final class MultiValuedAssociation exten
      * Returns the feature, or {@code null} if none.
      *
      * @return The feature (may be {@code null}).
-     * @throws IllegalStateException if this association contains more than one value.
+     * @throws MultiValuedPropertyException if this association contains more than one value.
      */
     @Override
     public Feature getValue() {
         switch (values.size()) {
             case 0:  return null;
             case 1:  return values.get(0);
-            default: throw new IllegalStateException(Errors.format(Errors.Keys.NotASingleton_1, getName()));
+            default: throw new MultiValuedPropertyException(Errors.format(Errors.Keys.NotASingleton_1, getName()));
         }
     }
 

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -23,6 +23,7 @@ import org.apache.sis.util.resources.Err
 
 // Branch-dependent imports
 import org.opengis.feature.AttributeType;
+import org.opengis.feature.MultiValuedPropertyException;
 
 
 /**
@@ -45,7 +46,7 @@ import org.opengis.feature.AttributeType
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see DefaultAttributeType
@@ -89,10 +90,13 @@ final class MultiValuedAttribute<V> exte
         final Class<V> valueClass = type.getValueClass();
         if (values == null) {
             this.values = new CheckedArrayList<>(valueClass);
-        } else if (((CheckedArrayList<?>) values).getElementType() == valueClass) {
-            this.values = (CheckedArrayList<V>) values;
         } else {
-            throw new ClassCastException();
+            final Class<?> actual = ((CheckedArrayList<?>) values).getElementType();
+            if (actual == valueClass) {
+                this.values = (CheckedArrayList<V>) values;
+            } else {
+                throw new ClassCastException(Errors.format(Errors.Keys.IllegalArgumentClass_3, "values", valueClass, actual));
+            }
         }
     }
 
@@ -100,14 +104,14 @@ final class MultiValuedAttribute<V> exte
      * Returns the attribute value, or {@code null} if none.
      *
      * @return The attribute value (may be {@code null}).
-     * @throws IllegalStateException if this attribute contains more than one value.
+     * @throws MultiValuedPropertyException if this attribute contains more than one value.
      */
     @Override
     public V getValue() {
         switch (values.size()) {
             case 0:  return null;
             case 1:  return values.get(0);
-            default: throw new IllegalStateException(Errors.format(Errors.Keys.NotASingleton_1, getName()));
+            default: throw new MultiValuedPropertyException(Errors.format(Errors.Keys.NotASingleton_1, getName()));
         }
     }
 

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/NamedFeatureType.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -23,6 +23,8 @@ import java.io.Serializable;
 import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
 import org.opengis.feature.PropertyType;
+import org.opengis.feature.PropertyNotFoundException;
+import org.opengis.feature.FeatureInstantiationException;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.resources.Errors;
@@ -35,7 +37,7 @@ import org.apache.sis.util.resources.Err
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 final class NamedFeatureType implements FeatureType, Serializable {
@@ -86,11 +88,11 @@ final class NamedFeatureType implements
     }
 
     /**
-     * Always throws {@link IllegalArgumentException} since this feature type has no declared property yet.
+     * Always throws {@link PropertyNotFoundException} since this feature type has no declared property yet.
      */
     @Override
-    public PropertyType getProperty(final String name) throws IllegalArgumentException {
-        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+    public PropertyType getProperty(final String name) throws PropertyNotFoundException {
+        throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
     }
 
     /**
@@ -121,8 +123,8 @@ final class NamedFeatureType implements
      * Unsupported operation, since the feature has not yet been resolved.
      */
     @Override
-    public Feature newInstance() throws IllegalStateException {
-        throw new IllegalStateException(Errors.format(Errors.Keys.UnresolvedFeatureName_1, getName()));
+    public Feature newInstance() throws FeatureInstantiationException {
+        throw new FeatureInstantiationException(Errors.format(Errors.Keys.UnresolvedFeatureName_1, getName()));
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SingletonAssociation.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -20,6 +20,7 @@ package org.apache.sis.feature;
 import java.util.Objects;
 import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureAssociationRole;
+import org.opengis.feature.InvalidPropertyValueException;
 
 
 /**
@@ -36,7 +37,7 @@ import org.opengis.feature.FeatureAssoci
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see DefaultAssociationRole
@@ -91,10 +92,10 @@ final class SingletonAssociation extends
      * Sets the associated feature.
      *
      * @param  value The new value, or {@code null}.
-     * @throws IllegalArgumentException If the given feature is not valid for this association.
+     * @throws InvalidPropertyValueException If the given feature is not valid for this association.
      */
     @Override
-    public void setValue(final Feature value) {
+    public void setValue(final Feature value) throws InvalidPropertyValueException {
         if (value != null) {
             ensureValid(role.getValueType(), value.getType());
         }

Modified: sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -27,9 +27,11 @@ import org.apache.sis.util.CorruptedObje
 import org.apache.sis.util.resources.Errors;
 
 // Branch-dependent imports
+import java.util.Objects;
 import org.opengis.feature.Property;
 import org.opengis.feature.Attribute;
 import org.opengis.feature.FeatureAssociation;
+import org.opengis.feature.PropertyNotFoundException;
 
 
 /**
@@ -118,14 +120,14 @@ final class SparseFeature extends Abstra
      * @param  name The property name.
      * @return The index for the property of the given name,
      *         or a negative value if the property is a parameterless operation.
-     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
+     * @throws PropertyNotFoundException If the given argument is not a property name of this feature.
      */
-    private int getIndex(final String name) throws IllegalArgumentException {
+    private int getIndex(final String name) throws PropertyNotFoundException {
         final Integer index = indices.get(name);
         if (index != null) {
             return index;
         }
-        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+        throw new PropertyNotFoundException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
     }
 
     /**
@@ -170,10 +172,10 @@ final class SparseFeature extends Abstra
      *
      * @param  name The property name.
      * @return The property of the given name.
-     * @throws IllegalArgumentException If the given argument is not a property name of this feature.
+     * @throws PropertyNotFoundException If the given argument is not a property name of this feature.
      */
     @Override
-    public Property getProperty(final String name) throws IllegalArgumentException {
+    public Property getProperty(final String name) throws PropertyNotFoundException {
         ArgumentChecks.ensureNonNull("name", name);
         requireMapOfProperties();
         return getPropertyInstance(name);
@@ -183,7 +185,7 @@ final class SparseFeature extends Abstra
      * Implementation of {@link #getProperty(String)} invoked when we know that the {@link #properties}
      * map contains {@code Property} instances (as opposed to their value).
      */
-    private Property getPropertyInstance(final String name) throws IllegalArgumentException {
+    private Property getPropertyInstance(final String name) throws PropertyNotFoundException {
         assert valuesKind == PROPERTIES : valuesKind;
         final Integer index = getIndex(name);
         if (index < 0) {
@@ -202,7 +204,7 @@ final class SparseFeature extends Abstra
      *
      * @param  property The property to set.
      * @throws IllegalArgumentException if the type of the given property is not one of the types
-     *         known to this feature.
+     *         known to this feature, or if the property can not be set for another reason.
      */
     @Override
     public void setProperty(final Property property) throws IllegalArgumentException {
@@ -222,10 +224,10 @@ final class SparseFeature extends Abstra
      *
      * @param  name The property name.
      * @return The value for the given property, or {@code null} if none.
-     * @throws IllegalArgumentException If the given argument is not an attribute or association name of this feature.
+     * @throws PropertyNotFoundException If the given argument is not an attribute or association name of this feature.
      */
     @Override
-    public Object getPropertyValue(final String name) throws IllegalArgumentException {
+    public Object getPropertyValue(final String name) throws PropertyNotFoundException {
         ArgumentChecks.ensureNonNull("name", name);
         final Integer index = getIndex(name);
         if (index < 0) {
@@ -257,7 +259,7 @@ final class SparseFeature extends Abstra
      * @param  name  The attribute name.
      * @param  value The new value for the given attribute (may be {@code null}).
      * @throws ClassCastException If the value is not assignable to the expected value class.
-     * @throws IllegalArgumentException If the given value can not be assigned for an other reason.
+     * @throws IllegalArgumentException If the given value can not be assigned for another reason.
      */
     @Override
     public void setPropertyValue(final String name, final Object value) throws IllegalArgumentException {
@@ -360,12 +362,32 @@ final class SparseFeature extends Abstra
 
     /**
      * Returns a hash code value for this feature.
+     * This implementation computes the hash code using only the property values, not the {@code Property} instances,
+     * in order to keep the hash code value stable before and after the {@code properties} map is (conceptually)
+     * promoted from the {@code Map<Integer,Object>} type to the {@code Map<Integer,Property>} type.
      *
      * @return A hash code value.
      */
     @Override
     public int hashCode() {
-        return type.hashCode() + 37 * properties.hashCode();
+        int code = type.hashCode() * 37;
+        if (valuesKind == PROPERTIES) {
+            for (final Map.Entry<Integer,Object> entry : properties.entrySet()) {
+                final Object p = entry.getValue();
+                final Object value;
+                if (p instanceof Attribute<?>) {
+                    value = getAttributeValue((Attribute<?>) p);
+                } else if (p instanceof FeatureAssociation) {
+                    value = getAssociationValue((FeatureAssociation) p);
+                } else {
+                    value = null;
+                }
+                code += Objects.hashCode(entry.getKey()) ^ Objects.hashCode(value);
+            }
+        } else {
+            code += properties.hashCode();
+        }
+        return code;
     }
 
     /**
@@ -380,7 +402,17 @@ final class SparseFeature extends Abstra
         }
         if (obj instanceof SparseFeature) {
             final SparseFeature that = (SparseFeature) obj;
-            return type.equals(that.type) && properties.equals(that.properties);
+            if (type.equals(that.type)) {
+                final boolean asProperties = (valuesKind == PROPERTIES);
+                if (asProperties != (that.valuesKind == PROPERTIES)) {
+                    if (asProperties) {
+                        that.requireMapOfProperties();
+                    } else {
+                        requireMapOfProperties();
+                    }
+                }
+                return properties.equals(that.properties);
+            }
         }
         return false;
     }

Modified: sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.feature;
 
+import java.util.Arrays;
 import java.util.Locale;
 import java.util.Random;
 import org.apache.sis.test.DependsOn;
@@ -31,7 +32,7 @@ import static org.apache.sis.test.Assert
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 @DependsOn({
@@ -66,7 +67,47 @@ public final strictfp class FeatureForma
     @Test
     public void testFeature() {
         final Random random = TestUtilities.createRandomNumberGenerator();
-        final AbstractFeature feature = FeatureTestCase.twinTown(random.nextBoolean());
+        final boolean isSparse = random.nextBoolean();
+
+        final DefaultFeatureType type = DefaultFeatureTypeTest.worldMetropolis();
+        final AbstractFeature feature = isSparse ? new SparseFeature(type) : new DenseFeature(type);
+        feature.setPropertyValue("city", "Tokyo");
+        feature.setPropertyValue("population", 13185502); // In 2011.
+        feature.setPropertyValue("universities", Arrays.asList("Waseda", "Keio"));
+
+        final FeatureFormat format = new FeatureFormat(Locale.US, null);
+        final String text = format.format(feature);
+        assertMultilinesEquals("World metropolis\n" +
+                "┌──────────────┬─────────────────────┬─────────────┬──────────────┬─────────────────┐\n" +
+                "│ Name         │ Type                │ Cardinality │ Value        │ Characteristics │\n" +
+                "├──────────────┼─────────────────────┼─────────────┼──────────────┼─────────────────┤\n" +
+                "│ city         │ String              │ [1 … 1]     │ Tokyo        │                 │\n" +
+                "│ population   │ Integer             │ [1 … 1]     │ 13,185,502   │                 │\n" +
+                "│ region       │ InternationalString │ [1 … 1]     │              │                 │\n" +
+                "│ isGlobal     │ Boolean             │ [1 … 1]     │              │                 │\n" +
+                "│ universities │ String              │ [0 … ∞]     │ Waseda, Keio │                 │\n" +
+                "│ temperature  │ Float               │ [1 … 1]     │              │ accuracy, units │\n" +
+                "└──────────────┴─────────────────────┴─────────────┴──────────────┴─────────────────┘\n", text);
+    }
+
+    /**
+     * Tests the formatting of an {@link AbstractFeature} with an association to another feature of the same type.
+     */
+    @Test
+    public void testFeatureWithAssociation() {
+        final Random random = TestUtilities.createRandomNumberGenerator();
+        final boolean isSparse = random.nextBoolean();
+
+        final DefaultFeatureType type = DefaultAssociationRoleTest.twinTownCity(false);
+        final AbstractFeature twinTown = isSparse ? new SparseFeature(type) : new DenseFeature(type);
+        twinTown.setPropertyValue("city", "Le Mans");
+        twinTown.setPropertyValue("population", 143240); // In 2011.
+
+        final AbstractFeature feature = isSparse ? new SparseFeature(type) : new DenseFeature(type);
+        feature.setPropertyValue("city", "Paderborn");
+        feature.setPropertyValue("population", 143174); // December 31th, 2011
+        feature.setPropertyValue("twin town", twinTown);
+
         final FeatureFormat format = new FeatureFormat(Locale.US, null);
         final String text = format.format(feature);
         assertMultilinesEquals("Twin town\n" +

Modified: sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -38,7 +38,7 @@ import static org.apache.sis.test.Assert
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Marc le Bihan
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public abstract strictfp class FeatureTestCase extends TestCase {
@@ -60,23 +60,6 @@ public abstract strictfp class FeatureTe
     }
 
     /**
-     * Creates a feature for twin towns.
-     */
-    static AbstractFeature twinTown(final boolean isSparse) {
-        final DefaultFeatureType twinTown = DefaultAssociationRoleTest.twinTownCity(false);
-
-        final AbstractFeature leMans = isSparse ? new SparseFeature(twinTown) : new DenseFeature(twinTown);
-        leMans.setPropertyValue("city", "Le Mans");
-        leMans.setPropertyValue("population", 143240); // In 2011.
-
-        final AbstractFeature paderborn = isSparse ? new SparseFeature(twinTown) : new DenseFeature(twinTown);
-        paderborn.setPropertyValue("city", "Paderborn");
-        paderborn.setPropertyValue("population", 143174); // December 31th, 2011
-        paderborn.setPropertyValue("twin town", leMans);
-        return paderborn;
-    }
-
-    /**
      * Creates a new feature for the given type.
      */
     abstract AbstractFeature createFeature(final DefaultFeatureType type);
@@ -370,4 +353,31 @@ public abstract strictfp class FeatureTe
     private void testSerialization() {
         assertNotSame(feature, assertSerializedEquals(feature));
     }
+
+    /**
+     * Tests {@code equals(Object)}.
+     *
+     * @throws CloneNotSupportedException Should never happen.
+     */
+    @Test
+    @DependsOnMethod("testSimpleProperties")
+    public void testEquals() throws CloneNotSupportedException {
+        feature = createFeature(DefaultFeatureTypeTest.city());
+        feature.setPropertyValue("city", "Tokyo");
+        final AbstractFeature clone = cloneFeature();
+        assertEquals(feature, clone);
+        /*
+         * Force the conversion of a property value into a full Property object on one and only one of
+         * the Features to be compared. The implementation shall be able to wrap or unwrap the values.
+         */
+        assertEquals("Tokyo", clone.getProperty("city").getValue());
+        assertEquals("hashCode", feature.hashCode(), clone.hashCode());
+        assertEquals("equals", feature, clone);
+        /*
+         * For the other Feature instance to contain full Property object and test again.
+         */
+        assertEquals("Tokyo", feature.getProperty("city").getValue());
+        assertEquals("hashCode", feature.hashCode(), clone.hashCode());
+        assertEquals("equals", feature, clone);
+    }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -25,6 +25,7 @@ import org.opengis.parameter.ParameterDe
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.crs.DerivedCRS;
+import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.cs.AxisDirection;
 import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.cs.CoordinateSystem;
@@ -306,6 +307,17 @@ public class ReferencingServices extends
     ///////////////////////////////////////////////////////////////////////////////////////
 
     /**
+     * Returns a coordinate reference system for heights above the mean seal level.
+     *
+     * @return The "Mean Seal Level (MSL) height" coordinate reference system, or {@code null}.
+     *
+     * @since 0.6
+     */
+    public VerticalCRS getMSLH() {
+        throw moduleNotFound();
+    }
+
+    /**
      * Returns the Greenwich prime meridian.
      *
      * @return The Greenwich prime meridian.

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -60,7 +60,18 @@ public final class WKTKeywords extends S
             Anchor    = "Anchor",
             Scope     = "Scope",
             Area      = "Area",
-            Remarks   = "Remarks";
+            Remark    = "Remark";
+
+    /**
+     * Related to unit of measurements.
+     */
+    public static final String
+            Unit           = "Unit",
+            LengthUnit     = "LengthUnit",
+            AngleUnit      = "AngleUnit",
+            ScaleUnit      = "ScaleUnit",
+            TimeUnit       = "TimeUnit",
+            ParametricUnit = "ParametricUnit";
 
     /**
      * Related to {@link org.apache.sis.referencing.cs.AbstractCS}
@@ -86,6 +97,7 @@ public final class WKTKeywords extends S
             Datum       = "Datum",
             GeodeticCRS = "GeodeticCRS",
             BaseGeodCRS = "BaseGeodCRS",
+            GeodCRS     = "GeodCRS",
             GeogCS      = "GeogCS",
             GeocCS      = "GeocCS";
 

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -38,15 +38,19 @@ import org.apache.sis.metadata.iso.citat
  *       according the OGC 01-009 (<cite>Coordinate transformation services</cite>) specification.</li>
  *   <li>An older specification — <cite>Simple Features</cite> — was unclear on this matter and has been
  *       interpreted by many softwares as fixing the unit to decimal degrees.</li>
+ *   <li>Some softwares support only (<var>longitude</var>, <var>latitude</var>) axis order
+ *       and ignore completely all {@code AXIS[…]} elements in the WKT.</li>
  * </ul>
  *
  * Despite the first interpretation being specified by both OGC 01-009 and ISO 19162 standards, the second
  * interpretation appears to be in wide use for WKT 1. Apache SIS uses the standard interpretation by default,
  * but the {@link #WKT1_COMMON_UNITS} enumeration allows parsing and formatting using the older interpretation.
+ * The {@link #WKT1_IGNORE_AXES} enumeration mimics the most minimalist WKT 1 parsers,
+ * but should be avoided when not imposed by compatibility reasons.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  *
  * @see WKTFormat#getConvention()
@@ -66,7 +70,7 @@ public enum Convention {
      *
      * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
      */
-    WKT2(false),
+    WKT2(false, false),
 
     /**
      * The ISO 19162 format with omission of some optional elements. This convention is identical
@@ -91,7 +95,7 @@ public enum Convention {
      *
      * <p>This is the default convention used by {@link FormattableObject#toString()}.</p>
      */
-    WKT2_SIMPLIFIED(false),
+    WKT2_SIMPLIFIED(false, false),
 
     /**
      * The OGC 01-009 format, also known as “WKT 1”.
@@ -103,12 +107,14 @@ public enum Convention {
      * names when available.</p>
      *
      * <div class="section">Differences compared to WKT 2</div>
-     * WKT 1 and WKT 2 differ in their keywords and syntax, but also in more subtle ways regarding parameter
-     * and code list values. For {@link GeocentricCRS}, WKT 1 uses a legacy set of Cartesian axes which were
-     * defined in OGC 01-009. Those axes use the <var>Other</var>, <var>Easting</var> and <var>Northing</var>
-     * {@linkplain org.opengis.referencing.cs.AxisDirection axis directions} instead than the geocentric ones,
-     * as shown in the following table:
+     * WKT 1 and WKT 2 differ in their keywords and syntax, but also in more subtle ways regarding axis names,
+     * parameter and code list values. For example in  {@link GeocentricCRS}, WKT 1 uses a legacy set of Cartesian axes
+     * which were defined in OGC 01-009. Those axes use the <var>Other</var>, <var>Easting</var> and <var>Northing</var>
+     * {@linkplain org.opengis.referencing.cs.AxisDirection axis directions} instead than the geocentric ones.
+     * For more uniform handling of CRS objects in client code, SIS parser replaces some WKT 1 conventions by
+     * the ISO ones when possible.
      *
+     * <table class="compact" summary="Differences between current and legacy specifications"><tr><td>
      * <table class="sis">
      *   <caption>Geocentric axis directions</caption>
      *   <tr><th>ISO 19111</th>    <th>OGC 01-009</th> <th>Description</th></tr>
@@ -116,10 +122,20 @@ public enum Convention {
      *   <tr><td>Geocentric Y</td> <td>Easting</td>    <td>Toward 90°E longitude</td></tr>
      *   <tr><td>Geocentric Z</td> <td>Northing</td>   <td>Toward north pole</td></tr>
      * </table>
+     * </td><td>
+     * <table class="sis">
+     *   <caption>Coordinate system axis names</caption>
+     *   <tr><th>CRS type</th>   <th>WKT1 names</th>                               <th>ISO abbreviations</th></tr>
+     *   <tr><td>Geographic</td> <td>Lon, Lat</td>                                 <td>λ, φ</td></tr>
+     *   <tr><td>Vertical</td>   <td><var>H</var></td>                             <td><var>H</var> or <var>h</var></td></tr>
+     *   <tr><td>Projected</td>  <td><var>X</var>, <var>Y</var></td>               <td><var>E</var>, <var>N</var></td></tr>
+     *   <tr><td>Geocentric</td> <td><var>X</var>, <var>Y</var>, <var>Z</var></td> <td><var>X</var>, <var>Y</var>, <var>Z</var></td></tr>
+     * </table>
+     * </td></tr></table>
      *
      * @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
      */
-    WKT1(true),
+    WKT1(true, false),
 
     /**
      * The <cite>Simple Feature</cite> format, also known as “WKT 1”.
@@ -136,7 +152,24 @@ public enum Convention {
      *       (e.g. <cite>"meter"</cite> instead than <cite>"metre"</cite>).</li>
      * </ul>
      */
-    WKT1_COMMON_UNITS(true),
+    WKT1_COMMON_UNITS(true, true),
+
+    /**
+     * The <cite>Simple Feature</cite> format without parsing of axis elements.
+     * This convention is identical to {@link #WKT1_COMMON_UNITS} except that all {@code AXIS[…]} elements are ignored.
+     * Since the WKT 1 specification said that the default axis order shall be (<var>x</var>,<var>y</var>) or
+     * (<var>longitude</var>, <var>latitude</var>), ignoring {@code AXIS[…]} elements is equivalent to forcing
+     * the coordinate systems to that default order.
+     *
+     * <p>Note that {@code AXIS[…]} elements still need to be well formed even when parsing a text with this convention.
+     * Malformed axis elements will continue to cause a {@link java.text.ParseException} despite their content being ignored.</p>
+     *
+     * <p>This convention may be useful for compatibility with some other softwares that do not handle axis order correctly.
+     * But except when imposed by such compatibility reasons, this convention should be avoided as much as possible.</p>
+     *
+     * @since 0.6
+     */
+    WKT1_IGNORE_AXES(true, true),
 
     /**
      * A special convention for formatting objects as stored internally by Apache SIS.
@@ -167,7 +200,7 @@ public enum Convention {
      * @see org.apache.sis.referencing.operation.projection.NormalizedProjection#getParameterValues()
      */
     @Debug
-    INTERNAL(false);
+    INTERNAL(false, false);
 
     /**
      * The default conventions.
@@ -180,10 +213,24 @@ public enum Convention {
     private final boolean isWKT1;
 
     /**
+     * {@code true} for a frequently-used convention about units instead than the standard one.
+     * <ul>
+     *   <li>If {@code true}, forces {@code PRIMEM} and {@code PARAMETER} angular units to degrees
+     *       instead than inferring the unit from the context. The standard value is {@code false},
+     *       which means that the angular units are inferred from the context as required by the
+     *       WKT 1 specification.</li>
+     *   <li>If {@code true}, uses US unit names instead of the international names.
+     *       For example Americans said {@code "meter"} instead of {@code "metre"}.</li>
+     * </ul>
+     */
+    final boolean usesCommonUnits;
+
+    /**
      * Creates a new enumeration value.
      */
-    private Convention(final boolean isWKT1) {
+    private Convention(final boolean isWKT1, final boolean usesCommonUnits) {
         this.isWKT1 = isWKT1;
+        this.usesCommonUnits = usesCommonUnits;
     }
 
     /**
@@ -217,21 +264,6 @@ public enum Convention {
     }
 
     /**
-     * {@code true} for a frequently-used convention about units instead than the standard one.
-     * <ul>
-     *   <li>If {@code true}, forces {@code PRIMEM} and {@code PARAMETER} angular units to degrees
-     *       instead than inferring the unit from the context. The standard value is {@code false},
-     *       which means that the angular units are inferred from the context as required by the
-     *       WKT 1 specification.</li>
-     *   <li>If {@code true}, uses US unit names instead of the international names.
-     *       For example Americans said {@code "meter"} instead of {@code "metre"}.</li>
-     * </ul>
-     */
-    final boolean usesCommonUnits() {
-        return this == WKT1_COMMON_UNITS;
-    }
-
-    /**
      * Returns the default authority to look for when fetching identified object names and identifiers.
      * The difference between various authorities are most easily seen in projection and parameter names.
      * The value returned by this method can be overwritten by {@link WKTFormat#setNameAuthority(Citation)}.

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java?rev=1686268&r1=1686267&r2=1686268&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Element.java [UTF-8] Thu Jun 18 16:49:25 2015
@@ -77,6 +77,14 @@ final class Element {
     final int offset;
 
     /**
+     * Index of the keyword in the array given to the {@link #pullElement(String...)}
+     * or {@link #pullOptionalElement(String...)} method.
+     *
+     * @see #getKeywordIndex()
+     */
+    private byte keywordIndex;
+
+    /**
      * Keyword of this entity. For example: {@code "PrimeMeridian"}.
      */
     public final String keyword;
@@ -113,7 +121,7 @@ final class Element {
      * @param position On input, the position where to start parsing from.
      *                 On output, the first character after the separator.
      */
-    Element(final Parser parser, final String text, final ParsePosition position) throws ParseException {
+    Element(final AbstractParser parser, final String text, final ParsePosition position) throws ParseException {
         /*
          * Find the first keyword in the specified string. If a keyword is found, then
          * the position is set to the index of the first character after the keyword.
@@ -281,20 +289,6 @@ final class Element {
     ////////////////////////////////////////////////////////////////////////////////////////
 
     /**
-     * Returns a {@link ParseException} for a child keyword which is either missing or unknown.
-     *
-     * @param  child The missing or unknown child keyword.
-     * @return {@code true} if the given keyword is missing, or {@code false} if it is unknown.
-     * @return The exception to be thrown.
-     */
-    final ParseException keywordNotFound(final String child, final boolean missing) {
-        return new LocalizedParseException(locale,
-                missing ? Errors.Keys.MissingComponentInElement_2
-                        : Errors.Keys.UnknownKeywordInElement_2,
-                new String[] {keyword, child}, offset);
-    }
-
-    /**
      * Returns a {@link ParseException} with the specified cause. A localized string
      * <code>"Error in &lt;{@link #keyword}&gt;"</code> will be prepend to the message.
      * The error index will be the starting index of this {@code Element}.
@@ -345,11 +339,11 @@ final class Element {
     }
 
     /**
-     * Returns an exception saying that a component is missing.
+     * Returns an exception saying that a sub-element is missing.
      *
-     * @param key The name of the missing component.
+     * @param key The name of the missing sub-element.
      */
-    private ParseException missingParameter(final String key) {
+    final ParseException missingComponent(final String key) {
         int error = offset;
         if (keyword != null) {
             error += keyword.length();
@@ -358,6 +352,34 @@ final class Element {
                 new String[] {keyword, key}, error);
     }
 
+    /**
+     * Returns a {@link ParseException} for a child keyword which is unknown.
+     *
+     * @param  expected Keyword of a typical element. Used only if this element contains no child element.
+     * @return The exception to be thrown.
+     */
+    final ParseException missingOrUnknownComponent(final String expected) {
+        String name = null;
+        for (final Object child : list) {
+            if (child instanceof Element) {
+                name = ((Element) child).keyword;
+                if (name != null) {
+                    break;
+                }
+            }
+        }
+        final short res;
+        final String[] args;
+        if (name != null) {
+            res  = Errors.Keys.UnknownKeyword_1;
+            args = new String[] {name};
+        } else {
+            res  = Errors.Keys.MissingComponentInElement_2;
+            args = new String[] {keyword, expected};
+        }
+        return new LocalizedParseException(locale, res, args, offset);
+    }
+
 
 
 
@@ -383,7 +405,7 @@ final class Element {
                 return (Date) object;
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -402,7 +424,7 @@ final class Element {
                 return ((Number) object).doubleValue();
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -426,7 +448,7 @@ final class Element {
                 return number.intValue();
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -445,7 +467,7 @@ final class Element {
                 return (Boolean) object;
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -464,7 +486,7 @@ final class Element {
                 return (String) object;
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
@@ -483,43 +505,51 @@ final class Element {
                 return object;
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
-     * Removes the next {@link Element} from the list and returns it.
+     * Removes the next {@link Element} of the given name from the list and returns it.
+     * If the element was mandatory but is missing, then the first entry in the given {@code keys}
+     * array will be taken as the name of the missing element to report in the exception message.
      *
-     * @param  key The element name (e.g. {@code "PrimeMeridian"}).
-     * @return The next {@link Element} on the list.
-     * @throws ParseException if no more element is available.
-     */
-    public Element pullElement(final String key) throws ParseException {
-        final Element element = pullOptionalElement(key);
-        if (element != null) {
-            return element;
-        }
-        throw missingParameter(key);
-    }
-
-    /**
-     * Removes the next {@link Element} from the list and returns it.
+     * <p>The given {@code mode} argument can be one of the following constants:</p>
+     * <ul>
+     *   <li>{@link AbstractParser#MANDATORY} throw an exception if no matching element is found.</li>
+     *   <li>{@link AbstractParser#OPTIONAL} return {@code null} if no matching element is found.</li>
+     *   <li>{@link AbstractParser#FIRST} return {@code null} if the first element (ignoring all others)
+     *       does not match.</li>
+     * </ul>
      *
-     * @param  key The element name (e.g. {@code "PrimeMeridian"}).
-     * @return The next {@link Element} on the list, or {@code null} if no more element is available.
+     * @param  mode {@link AbstractParser#FIRST}, {@link AbstractParser#OPTIONAL} or {@link AbstractParser#MANDATORY}.
+     * @param  keys The element names (e.g. {@code "PrimeMeridian"}).
+     * @return The next {@link Element} of the given names found on the list, or {@code null} if none.
+     * @throws ParseException if {@code mode} is {@code MANDATORY} and no element of the given names was found.
      */
-    public Element pullOptionalElement(final String key) {
+    public Element pullElement(final int mode, final String... keys) throws ParseException {
         final Iterator<Object> iterator = list.iterator();
         while (iterator.hasNext()) {
             final Object object = iterator.next();
             if (object instanceof Element) {
                 final Element element = (Element) object;
-                if (element.list != null && key.equalsIgnoreCase(element.keyword)) {
-                    iterator.remove();
-                    return element;
+                if (element.list != null) {
+                    for (int i=0; i<keys.length; i++) {
+                        if (element.keyword.equalsIgnoreCase(keys[i])) {
+                            keywordIndex = (byte) i;
+                            iterator.remove();
+                            return element;
+                        }
+                    }
+                    if (mode == AbstractParser.FIRST) {
+                        return null;
+                    }
                 }
             }
         }
-        return null;
+        if (mode != AbstractParser.MANDATORY) {
+            return null;
+        }
+        throw missingComponent(keys[0]);
     }
 
     /**
@@ -542,17 +572,43 @@ final class Element {
                 }
             }
         }
-        throw missingParameter(key);
+        throw missingComponent(key);
     }
 
     /**
-     * Returns the next element, or {@code null} if there is no more element.
-     * The element is <strong>not</strong> removed from the list.
+     * Removes the next object of the given type from the list and returns it, if presents.
      *
-     * @return The next element, or {@code null} if there is no more elements.
+     * @param  type The object type.
+     * @return The next object on the list, or {@code null} if none.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T pullOptional(final Class<T> type) {
+        final Iterator<Object> iterator = list.iterator();
+        while (iterator.hasNext()) {
+            final Object object = iterator.next();
+            if (type.isInstance(object)) {
+                iterator.remove();
+                return (T) object;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns {@code true} if this element does not contains any remaining child.
+     *
+     * @return {@code true} if there is no child remaining.
+     */
+    public boolean isEmpty() {
+        return list.isEmpty();
+    }
+
+    /**
+     * Returns the index of the keyword in the array given to the {@link #pullElement(String...)}
+     * or {@link #pullOptionalElement(String...)} method.
      */
-    public Object peek() {
-        return list.isEmpty() ? null : list.getFirst();
+    final int getKeywordIndex() {
+        return keywordIndex;
     }
 
     /**
@@ -562,8 +618,9 @@ final class Element {
      * If the given {@code ignored} map is non-null, then this method will add the keywords
      * of ignored elements in that map as below:
      * <ul>
-     *   <li>Keyword of ignored elements are the keys. Note that a key may be null.</li>
-     *   <li>Keywords of the elements that contained ignored elements are the values.</li>
+     *   <li><b>Keys</b>: keyword of ignored elements. Note that a key may be null.</li>
+     *   <li><b>Values</b>: keywords of all elements containing an element identified by the above-cited key.
+     *       This list is used for helping the users to locate the ignored elements.</li>
      * </ul>
      *
      * @param  ignoredElements The collection where to declare ignored elements, or {@code null}.



Mime
View raw message