Modified: 
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java?rev=1740177&r1=1740152&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/AttributeConvention.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -27,11 +27,10 @@ import org.apache.sis.internal.util.Cons
 import org.apache.sis.util.Static;
 
 // Branch-dependent imports
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Operation;
-import org.opengis.feature.Property;
+import org.apache.sis.feature.AbstractAttribute;
+import org.apache.sis.feature.AbstractIdentifiedType;
+import org.apache.sis.feature.AbstractOperation;
+import org.apache.sis.feature.DefaultAttributeType;
 
 
 /**
@@ -225,11 +224,11 @@ public final class AttributeConvention e
      *
      * @see #DEFAULT_GEOMETRY_PROPERTY
      */
-    public static boolean isGeometryAttribute(IdentifiedType type) {
-        while (type instanceof Operation) {
-            type = ((Operation) type).getResult();
+    public static boolean isGeometryAttribute(AbstractIdentifiedType type) {
+        while (type instanceof AbstractOperation) {
+            type = ((AbstractOperation) type).getResult();
         }
-        return (type instanceof AttributeType<?>) && 
Geometries.isKnownType(((AttributeType<?>) type).getValueClass());
+        return (type instanceof DefaultAttributeType<?>) && 
Geometries.isKnownType(((DefaultAttributeType<?>) type).getValueClass());
     }
 
     /**
@@ -240,7 +239,7 @@ public final class AttributeConvention e
      * @param  type  the operation or attribute type for which to get the CRS, 
or {@code null}.
      * @return {@code true} if a characteristic for Coordinate Reference 
System has been found.
      */
-    public static boolean characterizedByCRS(final IdentifiedType type) {
+    public static boolean characterizedByCRS(final AbstractIdentifiedType 
type) {
         return hasCharacteristic(type, CRS_CHARACTERISTIC.toString(), 
CoordinateReferenceSystem.class);
     }
 
@@ -255,7 +254,7 @@ public final class AttributeConvention e
      *
      * @see 
org.apache.sis.internal.feature.FeatureTypeBuilder.Property#setCRSCharacteristic(CoordinateReferenceSystem)
      */
-    public static CoordinateReferenceSystem getCRSCharacteristic(final 
Property attribute) {
+    public static CoordinateReferenceSystem getCRSCharacteristic(final Object 
attribute) {
         return (CoordinateReferenceSystem) getCharacteristic(attribute, 
CRS_CHARACTERISTIC.toString());
     }
 
@@ -267,7 +266,7 @@ public final class AttributeConvention e
      * @param  type  the operation or attribute type for which to get the 
maximal length, or {@code null}.
      * @return {@code true} if a characteristic for maximal length has been 
found.
      */
-    public static boolean characterizedByMaximalLength(final IdentifiedType 
type) {
+    public static boolean characterizedByMaximalLength(final 
AbstractIdentifiedType type) {
         return hasCharacteristic(type, 
MAXIMAL_LENGTH_CHARACTERISTIC.toString(), Integer.class);
     }
 
@@ -282,7 +281,7 @@ public final class AttributeConvention e
      *
      * @see 
org.apache.sis.internal.feature.FeatureTypeBuilder.Property#setMaximalLengthCharacteristic(Integer)
      */
-    public static Integer getMaximalLengthCharacteristic(final Property 
attribute) {
+    public static Integer getMaximalLengthCharacteristic(final Object 
attribute) {
         return (Integer) getCharacteristic(attribute, 
MAXIMAL_LENGTH_CHARACTERISTIC.toString());
     }
 
@@ -295,12 +294,12 @@ public final class AttributeConvention e
      * @param  valueClass  the expected characteristic values.
      * @return {@code true} if a characteristic of the given name exists and 
has values assignable to the given class.
      */
-    private static boolean hasCharacteristic(IdentifiedType type, final String 
name, final Class<?> valueClass) {
-        while (type instanceof Operation) {
-            type = ((Operation) type).getResult();
+    private static boolean hasCharacteristic(AbstractIdentifiedType type, 
final String name, final Class<?> valueClass) {
+        while (type instanceof AbstractOperation) {
+            type = ((AbstractOperation) type).getResult();
         }
-        if (type instanceof AttributeType<?>) {
-            final AttributeType<?> at = ((AttributeType<?>) 
type).characteristics().get(name);
+        if (type instanceof DefaultAttributeType<?>) {
+            final DefaultAttributeType<?> at = ((DefaultAttributeType<?>) 
type).characteristics().get(name);
             if (at != null) {
                 return valueClass.isAssignableFrom(at.getValueClass());
             }
@@ -317,16 +316,16 @@ public final class AttributeConvention e
      * @param  name       name of the characteristic to get.
      * @return the value or default value of the given characteristic in the 
given property, or {@code null} if none.
      */
-    private static Object getCharacteristic(final Property attribute, final 
String name) {
-        if (attribute instanceof Attribute<?>) {
-            final Attribute<?> at = ((Attribute<?>) 
attribute).characteristics().get(name);
+    private static Object getCharacteristic(final Object attribute, final 
String name) {
+        if (attribute instanceof AbstractAttribute<?>) {
+            final AbstractAttribute<?> at = ((AbstractAttribute<?>) 
attribute).characteristics().get(name);
             if (at != null) {
                 final Object value = at.getValue();
                 if (value != null) {
                     return value;
                 }
             }
-            final AttributeType<?> type = ((Attribute<?>) 
attribute).getType().characteristics().get(name);
+            final DefaultAttributeType<?> type = ((AbstractAttribute<?>) 
attribute).getType().characteristics().get(name);
             if (type != null) {
                 return type.getDefaultValue();
             }

Modified: 
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java?rev=1740177&r1=1740152&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -39,10 +39,8 @@ import org.apache.sis.util.ArgumentCheck
 import org.apache.sis.util.ArraysExt;
 
 // Branch-dependent imports
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
+import org.apache.sis.feature.AbstractFeature;
+import org.apache.sis.feature.AbstractIdentifiedType;
 
 
 /**
@@ -75,7 +73,7 @@ public class FeatureTypeBuilder extends
     /**
      * The parent of the feature to create. By default, new features have no 
parent.
      */
-    private final List<FeatureType> superTypes;
+    private final List<DefaultFeatureType> superTypes;
 
     /**
      * Whether the feature type is abstract. The default value is {@code 
false}.
@@ -144,7 +142,7 @@ public class FeatureTypeBuilder extends
     public FeatureTypeBuilder(final NameFactory factory) {
         nameFactory  = factory;
         properties   = new ArrayList<Property<?>>();
-        superTypes   = new ArrayList<FeatureType>();
+        superTypes   = new ArrayList<DefaultFeatureType>();
         idAttributes = new ArrayList<Property<?>>();
         idDelimiter  = ":";
         defaultMinimumOccurs = 1;
@@ -192,7 +190,7 @@ public class FeatureTypeBuilder extends
      * @param  parents  the parent types from which to inherit properties, or 
an empty array if none.
      * @return {@code this} for allowing method calls chaining.
      */
-    public FeatureTypeBuilder setSuperTypes(final FeatureType... parents) {
+    public FeatureTypeBuilder setSuperTypes(final DefaultFeatureType... 
parents) {
         ArgumentChecks.ensureNonNull("parents", parents);
         superTypes.clear();
         superTypes.addAll(Arrays.asList(parents));
@@ -339,7 +337,7 @@ public class FeatureTypeBuilder extends
         if (valueClass == null) {
             throw new 
NullArgumentException(errors().getString(Errors.Keys.NullArgument_1, 
"valueClass"));
         }
-        if (Feature.class.isAssignableFrom(valueClass)) {
+        if (AbstractFeature.class.isAssignableFrom(valueClass)) {
             throw new 
IllegalArgumentException(errors().getString(Errors.Keys.IllegalArgumentValue_2, 
"valueClass", valueClass));
         }
     }
@@ -352,9 +350,9 @@ public class FeatureTypeBuilder extends
      * @param  type  the type of feature values.
      * @return a builder for a {@code FeatureAssociationRole}.
      */
-    public Property<Feature> addAssociation(final FeatureType type) {
+    public Property<AbstractFeature> addAssociation(final DefaultFeatureType 
type) {
         ArgumentChecks.ensureNonNull("type", type);
-        final Property<Feature> property = new 
Property<Feature>(Feature.class, FeatureType.class, type);
+        final Property<AbstractFeature> property = new 
Property<AbstractFeature>(AbstractFeature.class, DefaultFeatureType.class, 
type);
         properties.add(property);
         return property;
     }
@@ -367,9 +365,9 @@ public class FeatureTypeBuilder extends
      * @param  type  the name of the type of feature values.
      * @return a builder for a {@code FeatureAssociationRole}.
      */
-    public Property<Feature> addAssociation(final GenericName type) {
+    public Property<AbstractFeature> addAssociation(final GenericName type) {
         ArgumentChecks.ensureNonNull("type", type);
-        final Property<Feature> property = new 
Property<Feature>(Feature.class, GenericName.class, type);
+        final Property<AbstractFeature> property = new 
Property<AbstractFeature>(AbstractFeature.class, GenericName.class, type);
         properties.add(property);
         return property;
     }
@@ -499,7 +497,6 @@ public class FeatureTypeBuilder extends
          *
          * @see AttributeConvention#VALID_VALUES_CHARACTERISTIC
          */
-        @SafeVarargs
         public final Property<V> setValidValues(final V... values) {
             return 
setCharacteristic(AttributeConvention.VALID_VALUES_CHARACTERISTIC,
                     Set.class, CollectionsExt.immutableSet(false, values));
@@ -575,7 +572,7 @@ public class FeatureTypeBuilder extends
          * @throws UnsupportedOperationException if this property does not 
support characteristics.
          */
         public <C> Characteristic<C> addCharacteristic(final Class<C> type) {
-            if (valueClass == Feature.class) {
+            if (valueClass == AbstractFeature.class) {
                 throw new 
UnsupportedOperationException(errors().getString(Errors.Keys.IllegalOperationForValueClass_1,
 valueClass));
             }
             ArgumentChecks.ensureNonNull("type", type);
@@ -587,17 +584,17 @@ public class FeatureTypeBuilder extends
         /**
          * Creates a new property type from the current setting.
          */
-        final PropertyType build() {
-            final PropertyType property;
-            if (valueClass == Feature.class) {
+        final AbstractIdentifiedType build() {
+            final AbstractIdentifiedType property;
+            if (valueClass == AbstractFeature.class) {
                 final Object type = 
CollectionsExt.first(characteristics).defaultValue;
-                if (type instanceof FeatureType) {
-                    property = new DefaultAssociationRole(identification, 
(FeatureType) type, minimumOccurs, maximumOccurs);
+                if (type instanceof DefaultFeatureType) {
+                    property = new DefaultAssociationRole(identification, 
(DefaultFeatureType) type, minimumOccurs, maximumOccurs);
                 } else {
                     property = new DefaultAssociationRole(identification, 
(GenericName) type, minimumOccurs, maximumOccurs);
                 }
             } else {
-                final AttributeType<?>[] chrts = new 
AttributeType<?>[characteristics.size()];
+                final DefaultAttributeType<?>[] chrts = new 
DefaultAttributeType<?>[characteristics.size()];
                 for (int i=0; i<chrts.length; i++) {
                     chrts[i] = characteristics.get(i).build();
                 }
@@ -668,7 +665,7 @@ public class FeatureTypeBuilder extends
         /**
          * Creates a new characteristic from the current setting.
          */
-        final AttributeType<V> build() {
+        final DefaultAttributeType<V> build() {
             return new DefaultAttributeType<V>(identification, valueClass, 0, 
1, defaultValue);
         }
     }
@@ -682,24 +679,24 @@ public class FeatureTypeBuilder extends
      * @throws IllegalStateException if the feature type contains incompatible
      *         {@linkplain Property#setCRSCharacteristic CRS characteristics}.
      */
-    public FeatureType build() throws IllegalStateException {
+    public DefaultFeatureType build() throws IllegalStateException {
         int numSynthetic;                                   // Number of 
synthetic properties to be generated.
         int numSpecified = properties.size();               // Number of 
explicitely specified properties.
-        final PropertyType[] identifierTypes;
+        final AbstractIdentifiedType[] identifierTypes;
         if (idAttributes.isEmpty()) {
             identifierTypes = null;
             numSynthetic = 0;
         } else {
-            identifierTypes = new PropertyType[idAttributes.size()];
+            identifierTypes = new AbstractIdentifiedType[idAttributes.size()];
             numSynthetic = 1;                               // Reserve one 
slot for the synthetic property "@id".
         }
         if (defaultGeometry != null) {
             numSynthetic += 2;                              // One slot for 
"@defaultGeometry" and one for "@envelope".
         }
-        PropertyType[] propertyTypes = new PropertyType[numSynthetic + 
numSpecified];
+        AbstractIdentifiedType[] propertyTypes = new 
AbstractIdentifiedType[numSynthetic + numSpecified];
         for (int i=0,j=numSynthetic; i<numSpecified; i++, j++) {
             final Property<?>  builder  = properties.get(i);
-            final PropertyType instance = builder.build();
+            final AbstractIdentifiedType instance = builder.build();
             propertyTypes[j] = instance;
             final int id = idAttributes.indexOf(builder);
             if (id >= 0) {
@@ -711,7 +708,7 @@ public class FeatureTypeBuilder extends
              * avoid to duplicate the property by removing the second 
occurrence.
              */
             if (builder == defaultGeometry) {
-                final PropertyType geom;
+                final AbstractIdentifiedType geom;
                 if 
(AttributeConvention.DEFAULT_GEOMETRY_PROPERTY.equals(instance.getName())) {
                     propertyTypes = ArraysExt.remove(propertyTypes, j--, 1);
                     geom = instance;
@@ -734,7 +731,7 @@ public class FeatureTypeBuilder extends
         if (identifierTypes != null) {
             propertyTypes[0] = 
FeatureOperations.compound(name(AttributeConvention.ID_PROPERTY), idDelimiter, 
idPrefix, idSuffix, identifierTypes);
         }
-        return new DefaultFeatureType(identification, isAbstract, 
superTypes.toArray(new FeatureType[superTypes.size()]), propertyTypes);
+        return new DefaultFeatureType(identification, isAbstract, 
superTypes.toArray(new DefaultFeatureType[superTypes.size()]), propertyTypes);
     }
 
     /**

Copied: 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java
 (from r1740152, 
sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java)
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java?p2=sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java&p1=sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java&r1=1740152&r2=1740177&rev=1740177&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -36,9 +36,6 @@ import org.junit.Test;
 
 import static org.apache.sis.test.ReferencingAssert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.PropertyType;
-
 
 /**
  * Tests {@link EnvelopeOperation}.
@@ -73,7 +70,7 @@ public final strictfp class EnvelopeOper
         final DefaultAttributeType<?> normalizedCRS = new 
DefaultAttributeType<CoordinateReferenceSystem>(
                 name(AttributeConvention.CRS_CHARACTERISTIC), 
CoordinateReferenceSystem.class, 1, 1, HardCodedCRS.WGS84);
 
-        final PropertyType[] attributes = {
+        final AbstractIdentifiedType[] attributes = {
             new DefaultAttributeType<String> (name("name"),          
String.class,  1, 1, null),
             new DefaultAttributeType<Polygon>(name("classes"),       
Polygon.class, 1, 1, null, standardCRS),
             new DefaultAttributeType<Point>  (name("climbing wall"), 
Point.class,   1, 1, null, standardCRS),
@@ -103,7 +100,7 @@ public final strictfp class EnvelopeOper
      */
     @Test
     public void testConstruction() throws FactoryException {
-        final PropertyType property = school(3).getProperty("bounds");
+        final AbstractIdentifiedType property = 
school(3).getProperty("bounds");
         assertInstanceOf("bounds", EnvelopeOperation.class, property);
         final EnvelopeOperation op = (EnvelopeOperation) property;
         assertSame("crs", HardCodedCRS.WGS84, op.crs);

Modified: 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeaturesTest.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -27,8 +27,9 @@ import static org.junit.Assert.*;
  * Tests {@link Features}.
  *
  * @author  Martin Desruisseaux (Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.7
  * @module
  */
 @DependsOn(SingletonAttributeTest.class)
@@ -68,4 +69,26 @@ public final strictfp class FeaturesTest
             assertTrue(message, message.contains("CharSequence"));
         }
     }
+
+    /**
+     * Tests {@link Features#validate(Feature)}.
+     */
+    @Test
+    public void testValidate() {
+        final AbstractFeature feature = 
DefaultFeatureTypeTest.city().newInstance();
+
+        // Should not pass validation.
+        try {
+            Features.validate(feature);
+            fail("Feature is invalid because of missing property “population”. 
Validation should have raised an exception.");
+        } catch (IllegalArgumentException ex) {
+            String message = ex.getMessage();
+            assertTrue(message, message.contains("city") || 
message.contains("population"));
+        }
+
+        // Should pass validation.
+        feature.setPropertyValue("city", "Utopia");
+        feature.setPropertyValue("population", 10);
+        Features.validate(feature);
+    }
 }

Modified: 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/LinkOperationTest.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/LinkOperationTest.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/LinkOperationTest.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/LinkOperationTest.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -42,8 +42,8 @@ public final strictfp class LinkOperatio
      * The feature contains the following properties:
      *
      * <ul>
-     *   <li>{@code city}       as a  {@link String}  (mandatory)</li>
-     *   <li>{@code population} as an {@link Integer} (mandatory)</li>
+     *   <li>{@code city}       as a  {@link String}  (mandatory).</li>
+     *   <li>{@code population} as an {@link Integer} (mandatory).</li>
      *   <li>{@code name} as a link to the {@code city} attribute.</li>
      * </ul>
      *
@@ -63,14 +63,14 @@ public final strictfp class LinkOperatio
     private static void run(final AbstractFeature feature) {
         assertEquals("Get directly",     "Utopia", 
feature.getPropertyValue("city"));
         assertEquals("Get through link", "Utopia", 
feature.getPropertyValue("name"));
-        feature.setPropertyValue("name", "Atlantide");  // Set through link.
+        feature.setPropertyValue("name", "Atlantide");                         
                 // Set through link.
         assertEquals("Get directly",     "Atlantide", 
feature.getPropertyValue("city"));
         assertEquals("Get through link", "Atlantide", 
feature.getPropertyValue("name"));
         assertSame(feature.getProperty("name"), feature.getProperty("name"));
     }
 
     /**
-     * Tests a dense type with operations.
+     * Tests a dense feature type with operations.
      */
     @Test
     public void testDenseFeature() {

Modified: 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/SingletonAttributeTest.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -105,7 +105,7 @@ public final strictfp class SingletonAtt
         ((AbstractAttribute) attribute).setValue(4.5f);
         quality = attribute.quality();
         assertEquals("scope.level", ScopeCode.ATTRIBUTE, 
quality.getScope().getLevel());
-        assertDomainConsistencyEquals("population", "Property “population” 
does not accept instances of ‘Float’.",
+        assertDomainConsistencyEquals("population", "Expected an instance of 
‘Integer’ for the “population” property, but got an instance of ‘Float’.",
                 (DomainConsistency) getSingleton(quality.getReports()));
     }
 

Copied: 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
 (from r1740152, 
sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java)
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java?p2=sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java&p1=sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java&r1=1740152&r2=1740177&rev=1740177&view=diff
==============================================================================
--- 
sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -25,10 +25,6 @@ import org.apache.sis.test.TestCase;
 
 import static org.junit.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.PropertyType;
-import org.opengis.feature.InvalidPropertyValueException;
-
 
 /**
  * Tests {@link StringJoinOperation}.
@@ -58,9 +54,9 @@ public final strictfp class StringJoinOp
      * @return The feature for a person.
      */
     private static DefaultFeatureType person() {
-        final PropertyType nameType = new DefaultAttributeType<String> 
(name("name"), String.class, 1, 1, null);
-        final PropertyType ageType  = new 
DefaultAttributeType<Integer>(name("age"), Integer.class, 1, 1, null);
-        final PropertyType cmpType  = 
FeatureOperations.compound(name("concat"), "/", "<<:", ":>>", nameType, 
ageType);
+        final AbstractIdentifiedType nameType = new 
DefaultAttributeType<String> (name("name"), String.class, 1, 1, null);
+        final AbstractIdentifiedType ageType  = new 
DefaultAttributeType<Integer>(name("age"), Integer.class, 1, 1, null);
+        final AbstractIdentifiedType cmpType  = 
FeatureOperations.compound(name("concat"), "/", "<<:", ":>>", nameType, 
ageType);
         return new DefaultFeatureType(name("person"), false, null, nameType, 
ageType, cmpType);
     }
 
@@ -143,7 +139,7 @@ public final strictfp class StringJoinOp
         try {
             feature.setPropertyValue("concat", "((:marc/21:>>");
             fail("Should fail because of mismatched prefix.");
-        } catch (InvalidPropertyValueException e) {
+        } catch (IllegalArgumentException e) {
             String message = e.getMessage();
             assertTrue(message, message.contains("<<:"));
             assertTrue(message, message.contains("(("));
@@ -151,7 +147,7 @@ public final strictfp class StringJoinOp
         try {
             feature.setPropertyValue("concat", "<<:marc/21:))");
             fail("Should fail because of mismatched suffix.");
-        } catch (InvalidPropertyValueException e) {
+        } catch (IllegalArgumentException e) {
             String message = e.getMessage();
             assertTrue(message, message.contains(":>>"));
             assertTrue(message, message.contains("))"));
@@ -159,14 +155,14 @@ public final strictfp class StringJoinOp
         try {
             feature.setPropertyValue("concat", "<<:marc/21/julie:>>");
             fail("Should fail because of too many components.");
-        } catch (InvalidPropertyValueException e) {
+        } catch (IllegalArgumentException e) {
             String message = e.getMessage();
             assertTrue(message, message.contains("<<:marc/21/julie:>>"));
         }
         try {
             feature.setPropertyValue("concat", "<<:marc/julie:>>");
             fail("Should fail because of unparsable number.");
-        } catch (InvalidPropertyValueException e) {
+        } catch (IllegalArgumentException e) {
             String message = e.getMessage();
             assertTrue(message, message.contains("julie"));
             assertTrue(message, message.contains("age"));

Modified: 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java?rev=1740177&r1=1740152&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeConventionTest.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -28,10 +28,6 @@ import org.junit.Test;
 
 import static org.junit.Assert.*;
 
-// Branch-dependent imports
-import org.opengis.feature.Property;
-import org.opengis.feature.IdentifiedType;
-
 
 /**
  * Tests {@link AttributeConvention}.

Modified: 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/FeatureTypeBuilderTest.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/FeatureTypeBuilderTest.java?rev=1740177&r1=1740152&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/FeatureTypeBuilderTest.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/internal/feature/FeatureTypeBuilderTest.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -27,9 +27,9 @@ import org.junit.Test;
 import static org.junit.Assert.*;
 
 // Branch-dependent imports
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.PropertyType;
+import org.apache.sis.feature.AbstractIdentifiedType;
+import org.apache.sis.feature.DefaultAttributeType;
+import org.apache.sis.feature.DefaultFeatureType;
 
 
 /**
@@ -56,7 +56,7 @@ public final strictfp class FeatureTypeB
             assertTrue(message, message.contains("name"));
         }
         builder.setName("myScope", "myName");
-        final AttributeType<?> att = (AttributeType<?>) builder.build();
+        final DefaultAttributeType<?> att = (DefaultAttributeType<?>) 
builder.build();
 
         assertEquals("name",       "myScope:myName", att.getName().toString());
         assertEquals("valueClass", String.class,     att.getValueClass());
@@ -90,7 +90,7 @@ public final strictfp class FeatureTypeB
      */
     private static void testEmptyFeature(final FeatureTypeBuilder builder) {
         builder.setName("scope", "test");
-        final FeatureType type = builder.build();
+        final DefaultFeatureType type = builder.build();
 
         assertEquals("name", "scope:test",   type.getName().toString());
         assertFalse ("isAbstract",           type.isAbstract());
@@ -112,7 +112,7 @@ public final strictfp class FeatureTypeB
         builder.setDefaultValue("test default value.");
         builder.setCardinality(10, 60);
         builder.setMaximalLengthCharacteristic(80);
-        final AttributeType<?> att = (AttributeType<?>) builder.build();
+        final DefaultAttributeType<?> att = (DefaultAttributeType<?>) 
builder.build();
 
         assertEquals("name",          "myScope:myName",      
att.getName().toString());
         assertEquals("definition",    "test definition",     
att.getDefinition().toString());
@@ -150,18 +150,18 @@ public final strictfp class FeatureTypeB
         builder.addAttribute(Point  
.class).setName("location").setCRSCharacteristic(HardCodedCRS.WGS84);
         builder.addAttribute(Double .class).setName("score").setCardinality(5, 
50).setDefaultValue(10.0);
 
-        final FeatureType type = builder.build();
+        final DefaultFeatureType type = builder.build();
         assertEquals("name",        "myScope:myName",   
type.getName().toString());
         assertEquals("definition",  "test definition",  
type.getDefinition().toString());
         assertEquals("description", "test description", 
type.getDescription().toString());
         assertEquals("designation", "test designation", 
type.getDesignation().toString());
         assertTrue  ("isAbstract",                      type.isAbstract());
 
-        final Iterator<? extends PropertyType> it = 
type.getProperties(true).iterator();
-        final AttributeType<?> a0 = (AttributeType<?>) it.next();
-        final AttributeType<?> a1 = (AttributeType<?>) it.next();
-        final AttributeType<?> a2 = (AttributeType<?>) it.next();
-        final AttributeType<?> a3 = (AttributeType<?>) it.next();
+        final Iterator<? extends AbstractIdentifiedType> it = 
type.getProperties(true).iterator();
+        final DefaultAttributeType<?> a0 = (DefaultAttributeType<?>) it.next();
+        final DefaultAttributeType<?> a1 = (DefaultAttributeType<?>) it.next();
+        final DefaultAttributeType<?> a2 = (DefaultAttributeType<?>) it.next();
+        final DefaultAttributeType<?> a3 = (DefaultAttributeType<?>) it.next();
         assertFalse("properties count", it.hasNext());
 
         assertEquals("name", "name",     a0.getName().toString());
@@ -219,16 +219,16 @@ public final strictfp class FeatureTypeB
         builder.addIdentifier(String.class).setName("name");
         
builder.addDefaultGeometry(Geometry.class).setName("shape").setCRSCharacteristic(HardCodedCRS.WGS84);
 
-        final FeatureType type = builder.build();
+        final DefaultFeatureType type = builder.build();
         assertEquals("name", "scope:test", type.getName().toString());
         assertFalse ("isAbstract", type.isAbstract());
 
-        final Iterator<? extends PropertyType> it = 
type.getProperties(true).iterator();
-        final PropertyType a0 = it.next();
-        final PropertyType a1 = it.next();
-        final PropertyType a2 = it.next();
-        final PropertyType a3 = it.next();
-        final PropertyType a4 = it.next();
+        final Iterator<? extends AbstractIdentifiedType> it = 
type.getProperties(true).iterator();
+        final AbstractIdentifiedType a0 = it.next();
+        final AbstractIdentifiedType a1 = it.next();
+        final AbstractIdentifiedType a2 = it.next();
+        final AbstractIdentifiedType a3 = it.next();
+        final AbstractIdentifiedType a4 = it.next();
         assertFalse("properties count", it.hasNext());
 
         assertEquals("name", AttributeConvention.ID_PROPERTY,                
a0.getName());

Modified: 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -25,8 +25,9 @@ import org.junit.BeforeClass;
  * All tests from the {@code sis-feature} module, in approximative dependency 
order.
  *
  * @author  Martin Desruisseaux (Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.7
  * @module
  */
 @Suite.SuiteClasses({
@@ -43,8 +44,12 @@ import org.junit.BeforeClass;
     org.apache.sis.feature.SingletonAssociationTest.class,
     org.apache.sis.feature.AbstractOperationTest.class,
     org.apache.sis.feature.LinkOperationTest.class,
+    org.apache.sis.feature.StringJoinOperationTest.class,
+    org.apache.sis.feature.EnvelopeOperationTest.class,
     org.apache.sis.feature.FeatureFormatTest.class,
-    org.apache.sis.feature.FeaturesTest.class
+    org.apache.sis.feature.FeaturesTest.class,
+    org.apache.sis.internal.feature.AttributeConventionTest.class,
+    org.apache.sis.internal.feature.FeatureTypeBuilderTest.class
 })
 public final strictfp class FeatureTestSuite extends TestSuite {
     /**

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/AxisDirections.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -417,7 +417,7 @@ public final class AxisDirections extend
      *
      * @param  cs The coordinate system from which to get the angular unit, or 
{@code null}.
      * @param  unit The default unit to return if no angular unit is found.
-     * @return The angular unit, of {@code null} if no angular unit was found.
+     * @return The angular unit, of {@code unit} if no angular unit was found.
      *
      * @since 0.6
      *

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ReferencingServices.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -60,6 +60,8 @@ import org.apache.sis.util.Deprecable;
 import org.apache.sis.util.resources.Errors;
 
 // Branch-specific imports
+import org.opengis.referencing.datum.Datum;
+import org.opengis.referencing.datum.DatumFactory;
 import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.util.NoSuchIdentifierException;
 
@@ -115,13 +117,23 @@ public class ReferencingServices extends
     public static final String OPERATION_TYPE_KEY = "operationType";
 
     /**
-     * The key for specifying a {@linkplain 
org.opengis.referencing.operation.MathTransformFactory}
-     * instance to use for the construction of a geodetic object. This is 
usually not needed for CRS
-     * construction, except in the special case of a derived CRS created from 
a defining conversion.
+     * The key for specifying a {@link MathTransformFactory} instance to use 
for geodetic object constructions.
+     * This is usually not needed for CRS construction, except in the special 
case of a derived CRS created
+     * from a defining conversion.
      */
     public static final String MT_FACTORY = "mtFactory";
 
     /**
+     * The key for specifying a {@link CRSFactory} instance to use for 
geodetic object constructions.
+     */
+    public static final String CRS_FACTORY = "crsFactory";
+
+    /**
+     * The key for specifying a {@link CSFactory} instance to use for geodetic 
object constructions.
+     */
+    public static final String CS_FACTORY = "csFactory";
+
+    /**
      * The separator character between an identifier and its namespace in the 
argument given to
      * {@link #getOperationMethod(String)}. For example this is the separator 
in {@code "EPSG:9807"}.
      *
@@ -394,6 +406,60 @@ public class ReferencingServices extends
     }
 
     /**
+     * Creates a parametric CS. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the coordinate system name, and optionally other 
properties.
+     * @param  axis        the axis of the parametric coordinate system.
+     * @param  factory     the factory to use for creating the coordinate 
system.
+     * @return a parametric coordinate system using the given axes.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    public CoordinateSystem createParametricCS(final Map<String,?> properties, 
final CoordinateSystemAxis axis,
+            final CSFactory factory) throws FactoryException
+    {
+        throw moduleNotFound();
+    }
+
+    /**
+     * Creates a parametric datum. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the datum name, and optionally other properties.
+     * @param  factory     the factory to use for creating the datum.
+     * @return a parametric datum using the given name.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    public Datum createParametricDatum(final Map<String,?> properties, final 
DatumFactory factory)
+            throws FactoryException
+    {
+        throw moduleNotFound();
+    }
+
+    /**
+     * Creates a parametric CRS. This method requires the SIS factory
+     * since parametric CRS were not available in GeoAPI 3.0.
+     *
+     * @param  properties  the coordinate reference system name, and 
optionally other properties.
+     * @param  datum       the parametric datum.
+     * @param  cs          the parametric coordinate system.
+     * @param  factory     the factory to use for creating the coordinate 
reference system.
+     * @return a parametric coordinate system using the given axes.
+     * @throws FactoryException if the parametric object creation failed.
+     *
+     * @since 0.7
+     */
+    public SingleCRS createParametricCRS(final Map<String,?> properties, final 
Datum datum,
+            final CoordinateSystem cs, final CRSFactory factory) throws 
FactoryException
+    {
+        throw moduleNotFound();
+    }
+
+    /**
      * Creates a derived CRS from the information found in a WKT 1 {@code 
FITTED_CS} element.
      * This coordinate system can not be easily constructed from the 
information provided by the WKT 1 format.
      * Note that this method is needed only for WKT 1 parsing, since WKT 
provides enough information for using
@@ -557,11 +623,15 @@ public class ReferencingServices extends
      *
      * @param  properties The default properties.
      * @param  mtFactory  The math transform factory to use.
+     * @param  crsFactory The factory to use if the operation factory needs to 
create CRS for intermediate steps.
+     * @param  csFactory  The factory to use if the operation factory needs to 
create CS for intermediate steps.
      * @return The coordinate operation factory to use.
      *
-     * @since 0.6
+     * @since 0.7
      */
-    public CoordinateOperationFactory 
getCoordinateOperationFactory(Map<String,?> properties, MathTransformFactory 
mtFactory) {
+    public CoordinateOperationFactory 
getCoordinateOperationFactory(Map<String,?> properties,
+            final MathTransformFactory mtFactory, final CRSFactory crsFactory, 
final CSFactory csFactory)
+    {
         /*
          * The check for 'properties' and 'mtFactory' is performed by the 
ServicesForMetadata subclass. If this code is
          * executed, this means that the "sis-referencing" module is not on 
the classpath, in which case we do not know

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/WKTKeywords.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -34,8 +34,9 @@ import org.apache.sis.util.Static;
  * This class is intended to be used only at compile-time and could be omitted 
from the JAR file.</div>
  *
  * @author  Martin Desruisseaux (Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @since   0.6
- * @version 0.6
+ * @version 0.7
  * @module
  *
  * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html";>WKT 
2 specification</a>
@@ -127,6 +128,15 @@ public final class WKTKeywords extends S
             BaseTimeCRS = "BaseTimeCRS";
 
     /**
+     * Related to {@link org.apache.sis.referencing.crs.DefaultParametricCRS}.
+     */
+    public static final String
+            ParametricDatum = "ParametricDatum",
+            PDatum          = "PDatum",
+            ParametricCRS   = "ParametricCRS",
+            BaseParamCRS    = "BaseParamCRS";
+
+    /**
      * Related to {@link org.apache.sis.referencing.crs.DefaultImageCRS}
      * and {@link org.apache.sis.referencing.crs.DefaultEngineeringCRS}.
      * Former can be seen as a special case of the later.

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -413,7 +413,7 @@ public abstract class Initializer {
             try {
                 ds.getConnection().close();     // Does the actual shutdown.
             } catch (SQLException e) {          // This is the expected 
exception.
-                final LogRecord record = new LogRecord(Level.CONFIG, 
e.getLocalizedMessage());
+                final LogRecord record = new LogRecord(Level.FINE, 
e.getLocalizedMessage());
                 if (!isSuccessfulShutdown(e)) {
                     record.setLevel(Level.WARNING);
                     record.setThrown(e);

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -353,11 +353,23 @@ abstract class AbstractParser implements
      * @param ex      The non-fatal exception that occurred while parsing the 
element, or {@code null}.
      */
     final void warning(final Element parent, final Element element, final 
InternationalString message, final Exception ex) {
+        warning(parent, (element != null) ? element.keyword : null, message, 
ex);
+    }
+
+    /**
+     * Reports a non-fatal warning that occurred while parsing a WKT.
+     *
+     * @param parent  The parent element, or {@code null} if unknown.
+     * @param element The name of the element that we can not parse, or {@code 
null} if unknown.
+     * @param message The message. Can be {@code null} only if {@code ex} is 
non-null.
+     * @param ex      The non-fatal exception that occurred while parsing the 
element, or {@code null}.
+     */
+    final void warning(final Element parent, final String element, final 
InternationalString message, final Exception ex) {
         if (warnings == null) {
             warnings = new Warnings(errorLocale, true, ignoredElements);
         }
         warnings.add(message, ex, (parent != null && element != null)
-                ? new String[] {parent.keyword, element.keyword} : null);
+                ? new String[] {parent.keyword, element} : null);
     }
 
     /**

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java 
[UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java 
[UTF-8] Wed Apr 20 17:40:11 2016
@@ -54,6 +54,7 @@ import org.opengis.referencing.crs.Compo
 import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.ConcatenatedOperation;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.util.CodeList;
 
@@ -768,8 +769,8 @@ public class Formatter implements Locali
             } else {
                 filterID = (parent != null);
                 if (object instanceof CoordinateOperation) {
-                    showOthers  = true;
-                    showRemarks = true;
+                    showOthers  = !(parent instanceof ConcatenatedOperation);
+                    showRemarks = showOthers;
                 } else if (object instanceof ReferenceSystem) {
                     showOthers  = (parent == null);
                     showRemarks = (parent == null) || (getEnclosingElement(2) 
instanceof CoordinateOperation);

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -87,6 +87,7 @@ import static java.util.Collections.sing
  *
  * @author  Rémi Eve (IRD)
  * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @since   0.6
  * @version 0.7
  * @module
@@ -203,7 +204,7 @@ final class GeodeticObjectParser extends
         csFactory       = (CSFactory)    factories;
         datumFactory    = (DatumFactory) factories;
         referencing     = ReferencingServices.getInstance();
-        opFactory       = 
referencing.getCoordinateOperationFactory(defaultProperties, mtFactory);
+        opFactory       = 
referencing.getCoordinateOperationFactory(defaultProperties, mtFactory, 
crsFactory, csFactory);
         transliterator  = Transliterator.DEFAULT;
         usesCommonUnits = false;
         ignoreAxes      = false;
@@ -240,7 +241,7 @@ final class GeodeticObjectParser extends
         if (f != null) {
             opFactory = (CoordinateOperationFactory) f;
         } else {
-            opFactory = referencing.getCoordinateOperationFactory(null, 
mtFactory);
+            opFactory = referencing.getCoordinateOperationFactory(null, 
mtFactory, crsFactory, csFactory);
             factories.put(CoordinateOperationFactory.class, opFactory);
         }
     }
@@ -299,7 +300,7 @@ final class GeodeticObjectParser extends
                     if (ex == null) ex = e;
                 }
                 if (verticalElements != null) {
-                    warning(null, null, 
Errors.formatInternational(Errors.Keys.CanNotAssignUnitToDimension_2,
+                    warning(null, (String) null, 
Errors.formatInternational(Errors.Keys.CanNotAssignUnitToDimension_2,
                             WKTKeywords.VerticalExtent, 
verticalElements.unit), ex);
                 }
             }
@@ -307,7 +308,7 @@ final class GeodeticObjectParser extends
             verticalElements = null;
             verticalCRS = null;
             axisOrder.clear();
-            properties.clear();     // for letting the garbage collector do 
its work.
+            properties.clear();                             // for letting the 
garbage collector do its work.
         }
         return object;
     }
@@ -337,6 +338,7 @@ final class GeodeticObjectParser extends
             (object = parseToWGS84          (FIRST, element       )) == null &&
             (object = parseVerticalDatum    (FIRST, element, false)) == null &&
             (object = parseTimeDatum        (FIRST, element       )) == null &&
+            (object = parseParametricDatum  (FIRST, element       )) == null &&
             (object = parseEngineeringDatum (FIRST, element, false)) == null &&
             (object = parseImageDatum       (FIRST, element       )) == null &&
             (object = parseOperation        (FIRST, element))        == null)
@@ -362,6 +364,7 @@ final class GeodeticObjectParser extends
             (crs = parseProjectedCRS   (FIRST, element, false))   == null &&
             (crs = parseVerticalCRS    (FIRST, element, false))   == null &&
             (crs = parseTimeCRS        (FIRST, element, false))   == null &&
+            (crs = parseParametricCRS  (FIRST, element, false))   == null &&
             (crs = parseEngineeringCRS (FIRST, element, false))   == null &&
             (crs = parseImageCRS       (FIRST, element))          == null &&
             (crs = parseCompoundCRS    (FIRST, element))          == null &&
@@ -704,7 +707,7 @@ final class GeodeticObjectParser extends
                                 new String[] {WKTKeywords.CS, type}, 
element.offset);
                     }
                 }
-                if (dimension <= 0 || dimension > 1000) {  // Arbitrary upper 
limit against badly formed CS.
+                if (dimension <= 0 || dimension > 1000) {       // Arbitrary 
upper limit against badly formed CS.
                     final short key;
                     final Object[] args;
                     if (dimension <= 0) {
@@ -739,7 +742,7 @@ final class GeodeticObjectParser extends
             } while (axis != null);
             if (!isWKT1 || !ignoreAxes) {
                 axes = list.toArray(new CoordinateSystemAxis[list.size()]);
-                Arrays.sort(axes, this);  // Take ORDER[n] elements in account.
+                Arrays.sort(axes, this);                    // Take ORDER[n] 
elements in account.
             }
         }
         /*
@@ -751,13 +754,13 @@ final class GeodeticObjectParser extends
             if (type == null) {
                 throw parent.missingComponent(WKTKeywords.Axis);
             }
-            String nx = null, x = null;             // Easting or Longitude 
axis name and abbreviation.
-            String ny = null, y = null;             // Northing or latitude 
axis name and abbreviation.
-            String nz = null, z = null;             // Depth, height or time 
axis name and abbreviation.
+            String nx = null, x = null;                     // Easting or 
Longitude axis name and abbreviation.
+            String ny = null, y = null;                     // Northing or 
latitude axis name and abbreviation.
+            String nz = null, z = null;                     // Depth, height 
or time axis name and abbreviation.
             AxisDirection dx = AxisDirection.EAST;
             AxisDirection dy = AxisDirection.NORTH;
-            AxisDirection direction = null;         // Depth, height or time 
axis direction.
-            Unit<?> unit = defaultUnit;             // Depth, height or time 
axis unit.
+            AxisDirection direction = null;                 // Depth, height 
or time axis direction.
+            Unit<?> unit = defaultUnit;                     // Depth, height 
or time axis unit.
             /*switch (type)*/ {
                 /*
                  * Cartesian — we can create axes only for geodetic datum, in 
which case the axes are for
@@ -845,6 +848,17 @@ final class GeodeticObjectParser extends
                     z = "t";
                 }
                 /*
+                 * Parametric — axis name and abbreviation not yet specified 
by ISO 19111_2.
+                 */
+                else if (type.equals(WKTKeywords.parametric)) {
+                    if (defaultUnit == null) {
+                        throw 
parent.missingComponent(WKTKeywords.ParametricUnit);
+                    }
+                    direction = AxisDirection.OTHER;
+                    nz = "Parametric";
+                    z = "p";
+                }
+                /*
                  * Unknown CS type — we can not guess which axes to create.
                  */
                 else {
@@ -889,21 +903,21 @@ final class GeodeticObjectParser extends
                     case 2: return csFactory.createEllipsoidalCS(csProperties, 
axes[0], axes[1]);
                     case 3: return csFactory.createEllipsoidalCS(csProperties, 
axes[0], axes[1], axes[2]);
                 }
-                dimension = (axes.length < 2) ? 2 : 3;  // For error message.
+                dimension = (axes.length < 2) ? 2 : 3;                      // 
For error message.
             }
             else if (type.equals(WKTKeywords.Cartesian)) {
                 switch (axes.length) {
                     case 2: return csFactory.createCartesianCS(csProperties, 
axes[0], axes[1]);
                     case 3: return csFactory.createCartesianCS(csProperties, 
axes[0], axes[1], axes[2]);
                 }
-                dimension = (axes.length < 2) ? 2 : 3;  // For error message.
+                dimension = (axes.length < 2) ? 2 : 3;                      // 
For error message.
             }
             else if (type.equals(WKTKeywords.affine)) {
                 switch (axes.length) {
                     case 2: return csFactory.createAffineCS(csProperties, 
axes[0], axes[1]);
                     case 3: return csFactory.createAffineCS(csProperties, 
axes[0], axes[1], axes[2]);
                 }
-                dimension = (axes.length < 2) ? 2 : 3;  // For error message.
+                dimension = (axes.length < 2) ? 2 : 3;                      // 
For error message.
             }
             else if (type.equals(WKTKeywords.vertical)) {
                 if (axes.length == (dimension = 1)) {
@@ -935,11 +949,13 @@ final class GeodeticObjectParser extends
                     return csFactory.createSphericalCS(csProperties, axes[0], 
axes[1], axes[2]);
                 }
             }
-            else if (type.equals(WKTKeywords.parametric)) {  // TODO: not yet 
supported.
-                return referencing.createAbstractCS(csProperties, axes);
+            else if (type.equals(WKTKeywords.parametric)) {
+                if (axes.length == (dimension = 1)) {
+                    return referencing.createParametricCS(csProperties, 
axes[0], csFactory);
+                }
             }
             else {
-                warning(parent, null, 
Errors.formatInternational(Errors.Keys.UnknownType_1, type), null);
+                warning(parent, WKTKeywords.CS, 
Errors.formatInternational(Errors.Keys.UnknownType_1, type), null);
                 return referencing.createAbstractCS(csProperties, axes);
             }
         }
@@ -1082,9 +1098,9 @@ final class GeodeticObjectParser extends
             if (n2 != null) {
                 return n1 - n2;
             }
-            return -1;  // Axis 1 before Axis 2 since the later has no 'ORDER' 
element.
+            return -1;                      // Axis 1 before Axis 2 since the 
later has no 'ORDER' element.
         } else if (n2 != null) {
-            return +1;  // Axis 2 before Axis 1 since the later has no 'ORDER' 
element.
+            return +1;                      // Axis 2 before Axis 1 since the 
later has no 'ORDER' element.
         }
         return 0;
     }
@@ -1156,7 +1172,7 @@ final class GeodeticObjectParser extends
         for (int i=0; i<values.length;) {
             values[i] = element.pullDouble(ToWGS84[i]);
             if ((++i % 3) == 0 && element.isEmpty()) {
-                break;  // It is legal to have only 3 or 6 elements.
+                break;                                              // It is 
legal to have only 3 or 6 elements.
             }
         }
         element.close(ignoredElements);
@@ -1194,7 +1210,7 @@ final class GeodeticObjectParser extends
         }
         final Map<String,?> properties = parseMetadataAndClose(element, name, 
null);
         try {
-            if (inverseFlattening == 0) {   // OGC convention for a sphere.
+            if (inverseFlattening == 0) {                           // OGC 
convention for a sphere.
                 return datumFactory.createEllipsoid(properties, semiMajorAxis, 
semiMajorAxis, unit);
             } else {
                 return datumFactory.createFlattenedSphere(properties, 
semiMajorAxis, inverseFlattening, unit);
@@ -1439,6 +1455,31 @@ final class GeodeticObjectParser extends
     }
 
     /**
+     * Parses a {@code "ParametricDatum"} element. This element has the 
following pattern:
+     *
+     * {@preformat wkt
+     *     ParametricDatum["<name>", Anchor[...] {,<authority>}]
+     * }
+     *
+     * @param  mode {@link #FIRST}, {@link #OPTIONAL} or {@link #MANDATORY}.
+     * @param  parent The parent element.
+     * @return The {@code "ParametricDatum"} element as a {@link 
ParametricDatum} object.
+     * @throws ParseException if the {@code "ParametricDatum"} element can not 
be parsed.
+     */
+    private Datum parseParametricDatum(final int mode, final Element parent) 
throws ParseException {
+        final Element element = parent.pullElement(mode, 
WKTKeywords.ParametricDatum, WKTKeywords.PDatum);
+        if (element == null) {
+            return null;
+        }
+        final String name = element.pullString("name");
+        try {
+            return 
referencing.createParametricDatum(parseAnchorAndClose(element, name), 
datumFactory);
+        } catch (FactoryException exception) {
+            throw element.parseFailed(exception);
+        }
+    }
+
+    /**
      * Parses a {@code "EngineeringDatum"} (WKT 2) element. The syntax is 
given by
      * <a 
href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#76";>WKT 2 
specification §11.2</a>.
      *
@@ -1464,9 +1505,9 @@ final class GeodeticObjectParser extends
         if (element == null) {
             return null;
         }
-        final String name  = element.pullString ("name");
+        final String name = element.pullString("name");
         if (isWKT1) {
-            element.pullInteger("datum");   // Ignored for now.
+            element.pullInteger("datum");                                      
 // Ignored for now.
         }
         try {
             return 
datumFactory.createEngineeringDatum(parseAnchorAndClose(element, name));
@@ -1519,14 +1560,14 @@ final class GeodeticObjectParser extends
             throws ParseException
     {
         final Element element = parent.pullElement(mode,
-                isBaseCRS ? new String[] {WKTKeywords.BaseEngCRS}       // WKT 
2 in DerivedCRS
-                          : new String[] {WKTKeywords.EngineeringCRS,   // [0] 
 WKT 2
-                                          WKTKeywords.EngCRS,           // [1] 
 WKT 2
-                                          WKTKeywords.Local_CS});       // [2] 
 WKT 1
+                isBaseCRS ? new String[] {WKTKeywords.BaseEngCRS}              
 // WKT 2 in DerivedCRS
+                          : new String[] {WKTKeywords.EngineeringCRS,          
 // [0]  WKT 2
+                                          WKTKeywords.EngCRS,                  
 // [1]  WKT 2
+                                          WKTKeywords.Local_CS});              
 // [2]  WKT 1
         if (element == null) {
             return null;
         }
-        final boolean isWKT1 = element.getKeywordIndex() == 2;  // Index of 
"Local_CS" above.
+        final boolean isWKT1 = element.getKeywordIndex() == 2;                 
 // Index of "Local_CS" above.
         final String  name   = element.pullString("name");
         final Unit<?> unit   = parseUnit(element);
         /*
@@ -1563,7 +1604,7 @@ final class GeodeticObjectParser extends
                 }
             }
         }
-        if (baseCRS == null) {  // The most usual case.
+        if (baseCRS == null) {                                                 
 // The most usual case.
             datum = parseEngineeringDatum(MANDATORY, element, isWKT1);
         }
         try {
@@ -1639,18 +1680,18 @@ final class GeodeticObjectParser extends
             throws ParseException
     {
         final Element element = parent.pullElement(mode,
-                (csType != null) ? new String[] {WKTKeywords.BaseGeodCRS,    
// [0]  WKT 2 in ProjectedCRS or DerivedCRS
-                                                 WKTKeywords.GeogCS}         
// [1]  WKT 1 in ProjectedCRS
-                                 : new String[] {WKTKeywords.GeodeticCRS,    
// [0]  WKT 2
-                                                 WKTKeywords.GeogCS,         
// [1]  WKT 1
-                                                 WKTKeywords.GeodCRS,        
// [2]  WKT 2
-                                                 WKTKeywords.GeocCS});       
// [3]  WKT 1
+                (csType != null) ? new String[] {WKTKeywords.BaseGeodCRS,      
 // [0]  WKT 2 in ProjectedCRS or DerivedCRS
+                                                 WKTKeywords.GeogCS}           
 // [1]  WKT 1 in ProjectedCRS
+                                 : new String[] {WKTKeywords.GeodeticCRS,      
 // [0]  WKT 2
+                                                 WKTKeywords.GeogCS,           
 // [1]  WKT 1
+                                                 WKTKeywords.GeodCRS,          
 // [2]  WKT 2
+                                                 WKTKeywords.GeocCS});         
 // [3]  WKT 1
         if (element == null) {
             return null;
         }
         final boolean isWKT1;
-        Unit<?>     csUnit;
-        Unit<Angle> angularUnit;
+        Unit<?> csUnit;
+        final Unit<Angle> angularUnit;
         switch (element.getKeywordIndex()) {
             default: {
                 /*
@@ -1683,7 +1724,7 @@ final class GeodeticObjectParser extends
                          * We recognize those cases by a non-null 'csType' 
given in argument to this method.
                          */
                         if (WKTKeywords.ellipsoidal.equals(csType)) {
-                            csUnit = NonSI.DEGREE_ANGLE;   // For BaseGeodCRS 
in ProjectedCRS.
+                            csUnit = NonSI.DEGREE_ANGLE;                       
 // For BaseGeodCRS in ProjectedCRS.
                         }
                     }
                 }
@@ -1747,7 +1788,7 @@ final class GeodeticObjectParser extends
                 return crsFactory.createDerivedCRS(properties, baseCRS, 
fromBase, cs);
             }
             /*
-             * The specifiation in §8.2.2 (ii) said:
+             * The specification in §8.2.2 (ii) said:
              *
              *     "(snip) the prime meridian’s <irm longitude> value shall be 
given in the
              *     same angular units as those for the horizontal axes of the 
geographic CRS."
@@ -1757,18 +1798,22 @@ final class GeodeticObjectParser extends
              * So we re-fetch the angular unit. Normally, we will get the same 
value (unless
              * the previous value was null).
              */
-            angularUnit = AxisDirections.getAngularUnit(cs, angularUnit);
-            final PrimeMeridian meridian = parsePrimeMeridian(OPTIONAL, 
element, isWKT1, angularUnit);
+            final Unit<Angle> longitudeUnit = 
AxisDirections.getAngularUnit(cs, angularUnit);
+            if (angularUnit != null && !angularUnit.equals(longitudeUnit)) {
+                warning(element, WKTKeywords.AngleUnit, 
Errors.formatInternational(
+                        Errors.Keys.InconsistentUnitsForCS_1, angularUnit), 
null);
+            }
+            final PrimeMeridian meridian = parsePrimeMeridian(OPTIONAL, 
element, isWKT1, longitudeUnit);
             final GeodeticDatum datum = parseDatum(MANDATORY, element, 
meridian);
             final Map<String,?> properties = parseMetadataAndClose(element, 
name, datum);
             if (cs instanceof EllipsoidalCS) {  // By far the most frequent 
case.
                 return crsFactory.createGeographicCRS(properties, datum, 
(EllipsoidalCS) cs);
             }
-            if (cs instanceof CartesianCS) {    // The second most frequent 
case.
+            if (cs instanceof CartesianCS) {                                   
 // The second most frequent case.
                 return crsFactory.createGeocentricCRS(properties, datum,
                         referencing.upgradeGeocentricCS((CartesianCS) cs));
             }
-            if (cs instanceof SphericalCS) {    // Not very common case.
+            if (cs instanceof SphericalCS) {                                   
 // Not very common case.
                 return crsFactory.createGeocentricCRS(properties, datum, 
(SphericalCS) cs);
             }
         } catch (FactoryException exception) {
@@ -1793,18 +1838,19 @@ final class GeodeticObjectParser extends
      * @return The {@code "VerticalCRS"} element as a {@link VerticalCRS} 
object.
      * @throws ParseException if the {@code "VerticalCRS"} element can not be 
parsed.
      */
+    @SuppressWarnings("null")
     private SingleCRS parseVerticalCRS(final int mode, final Element parent, 
final boolean isBaseCRS)
             throws ParseException
     {
         final Element element = parent.pullElement(mode,
-                isBaseCRS ? new String[] {WKTKeywords.BaseVertCRS}    // WKT 2 
in DerivedCRS
-                          : new String[] {WKTKeywords.VerticalCRS,    // [0]  
WKT 2
-                                          WKTKeywords.VertCRS,        // [1]  
WKT 2
-                                          WKTKeywords.Vert_CS});      // [2]  
WKT 1
+                isBaseCRS ? new String[] {WKTKeywords.BaseVertCRS}             
 // WKT 2 in DerivedCRS
+                          : new String[] {WKTKeywords.VerticalCRS,             
 // [0]  WKT 2
+                                          WKTKeywords.VertCRS,                 
 // [1]  WKT 2
+                                          WKTKeywords.Vert_CS});               
 // [2]  WKT 1
         if (element == null) {
             return null;
         }
-        final boolean isWKT1 = element.getKeywordIndex() == 2;  // Index of 
"Vert_CS" above.
+        final boolean isWKT1 = element.getKeywordIndex() == 2;                 
 // Index of "Vert_CS" above.
         final String  name   = element.pullString("name");
         final Unit<?> unit   = parseUnit(element);
         /*
@@ -1830,7 +1876,7 @@ final class GeodeticObjectParser extends
                 baseCRS = parseVerticalCRS(MANDATORY, element, true);
             }
         }
-        if (baseCRS == null) {                                                 
             // The most usual case.
+        if (baseCRS == null) {                                                 
 // The most usual case.
             datum = parseVerticalDatum(MANDATORY, element, isWKT1);
         }
         final CoordinateSystem cs;
@@ -1909,7 +1955,7 @@ final class GeodeticObjectParser extends
                 baseCRS = parseTimeCRS(MANDATORY, element, true);
             }
         }
-        if (baseCRS == null) {  // The most usual case.
+        if (baseCRS == null) {                                                 
 // The most usual case.
             datum = parseTimeDatum(MANDATORY, element);
         }
         final CoordinateSystem cs;
@@ -1929,6 +1975,66 @@ final class GeodeticObjectParser extends
     }
 
     /**
+     * Parses {@code "ParametricCRS"} element.
+     *
+     * @param  mode      {@link #FIRST}, {@link #OPTIONAL} or {@link 
#MANDATORY}.
+     * @param  parent    The parent element.
+     * @param  isBaseCRS {@code true} if parsing the CRS inside a {@code 
DerivedCRS}.
+     * @return The {@code "ParametricCRS"} object.
+     * @throws ParseException if the {@code "ParametricCRS"} element can not 
be parsed.
+     */
+    private SingleCRS parseParametricCRS(final int mode, final Element parent, 
final boolean isBaseCRS)
+            throws ParseException
+    {
+        final Element element = parent.pullElement(mode, isBaseCRS ? 
WKTKeywords.BaseParamCRS : WKTKeywords.ParametricCRS);
+        if (element == null) {
+            return null;
+        }
+        final String  name = element.pullString("name");
+        final Unit<?> unit = parseUnit(element);
+        /*
+         * A ParametricCRS can be either a "normal" one (with a non-null 
datum), or a DerivedCRS of kind ParametricCRS.
+         * In the later case, the datum is null and we have instead 
DerivingConversion element from a BaseParametricCRS.
+         */
+        Datum           datum    = null;
+        SingleCRS       baseCRS  = null;
+        Conversion      fromBase = null;
+        if (!isBaseCRS) {
+            /*
+             * UNIT[…] in DerivedCRS parameters are mandatory according ISO 
19162 and the specification does not said
+             * what to do if they are missing.  In this code, we default to 
the contextual units in the same way than
+             * what we do for ProjectedCRS parameters, in the hope to be 
consistent.
+             *
+             * An alternative would be to specify null units, in which case 
MathTransformParser.parseParameters(…)
+             * defaults to the units specified in the parameter descriptor. 
But this would make the CRS parser more
+             * implementation-dependent, because the parameter descriptors are 
provided by the MathTransformFactory
+             * instead than inferred from the WKT.
+             */
+            fromBase = parseDerivingConversion(OPTIONAL, element, 
WKTKeywords.DerivingConversion, unit, null);
+            if (fromBase != null) {
+                baseCRS = parseParametricCRS(MANDATORY, element, true);
+            }
+        }
+        if (baseCRS == null) {                                                 
 // The most usual case.
+            datum = parseParametricDatum(MANDATORY, element);
+        }
+        final CoordinateSystem cs;
+        try {
+            cs = parseCoordinateSystem(element, WKTKeywords.parametric, 1, 
false, unit, datum);
+            final Map<String,?> properties = parseMetadataAndClose(element, 
name, datum);
+            if (cs != null) {
+                if (baseCRS != null) {
+                    return crsFactory.createDerivedCRS(properties, baseCRS, 
fromBase, cs);
+                }
+                return referencing.createParametricCRS(properties, datum, cs, 
crsFactory);
+            }
+        } catch (FactoryException exception) {
+            throw element.parseFailed(exception);
+        }
+        throw element.illegalCS(cs);
+    }
+
+    /**
      * Parses a {@code "ProjectedCRS"} (WKT 2) element. The syntax is given by
      * <a 
href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#57";>WKT 2 
specification §9</a>.
      *
@@ -1949,15 +2055,15 @@ final class GeodeticObjectParser extends
             throws ParseException
     {
         final Element element = parent.pullElement(mode,
-                isBaseCRS ? new String[] {WKTKeywords.BaseProjCRS}    // WKT 2 
in DerivedCRS
-                          : new String[] {WKTKeywords.ProjectedCRS,   // [0]  
WKT 2
-                                          WKTKeywords.ProjCRS,        // [1]  
WKT 2
-                                          WKTKeywords.ProjCS});       // [2]  
WKT 1
+                isBaseCRS ? new String[] {WKTKeywords.BaseProjCRS}             
 // WKT 2 in DerivedCRS
+                          : new String[] {WKTKeywords.ProjectedCRS,            
 // [0]  WKT 2
+                                          WKTKeywords.ProjCRS,                 
 // [1]  WKT 2
+                                          WKTKeywords.ProjCS});                
 // [2]  WKT 1
 
         if (element == null) {
             return null;
         }
-        final boolean   isWKT1 = element.getKeywordIndex() == 2;  // Index of 
"ProjCS" above.
+        final boolean   isWKT1 = element.getKeywordIndex() == 2;               
 // Index of "ProjCS" above.
         final String    name   = element.pullString("name");
         final SingleCRS geoCRS = parseGeodeticCRS(MANDATORY, element, 2, 
WKTKeywords.ellipsoidal);
         if (!(geoCRS instanceof GeographicCRS)) {

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -358,7 +358,7 @@ public class ImmutableIdentifier extends
             final Map<String,?> properties, final String key, final Object 
value)
     {
         return new IllegalArgumentException(Errors.getResources(properties)
-                .getString(Errors.Keys.IllegalPropertyClass_2, key, 
value.getClass()));
+                .getString(Errors.Keys.IllegalPropertyValueClass_2, key, 
value.getClass()));
     }
 
     /**

Modified: 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1740177&r1=1740176&r2=1740177&view=diff
==============================================================================
--- 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
 [UTF-8] Wed Apr 20 17:40:11 2016
@@ -195,7 +195,7 @@ public abstract class AbstractEnvelope i
     static CoordinateSystemAxis getAxis(final CoordinateReferenceSystem crs, 
final int dimension) {
         if (crs != null) {
             final CoordinateSystem cs = crs.getCoordinateSystem();
-            if (cs != null) {   // Paranoiac check (should never be null).
+            if (cs != null) {                                       // 
Paranoiac check (should never be null).
                 return cs.getAxis(dimension);
             }
         }
@@ -348,7 +348,7 @@ public abstract class AbstractEnvelope i
     @Override
     public double getMinimum(final int dimension) throws 
IndexOutOfBoundsException {
         double lower = getLower(dimension);
-        if (isNegative(getUpper(dimension) - lower)) { // Special handling for 
-0.0
+        if (isNegative(getUpper(dimension) - lower)) {              // Special 
handling for -0.0
             final CoordinateSystemAxis axis = 
getAxis(getCoordinateReferenceSystem(), dimension);
             lower = (axis != null) ? axis.getMinimumValue() : 
Double.NEGATIVE_INFINITY;
         }
@@ -369,7 +369,7 @@ public abstract class AbstractEnvelope i
     @Override
     public double getMaximum(final int dimension) throws 
IndexOutOfBoundsException {
         double upper = getUpper(dimension);
-        if (isNegative(upper - getLower(dimension))) { // Special handling for 
-0.0
+        if (isNegative(upper - getLower(dimension))) {              // Special 
handling for -0.0
             final CoordinateSystemAxis axis = 
getAxis(getCoordinateReferenceSystem(), dimension);
             upper = (axis != null) ? axis.getMaximumValue() : 
Double.POSITIVE_INFINITY;
         }
@@ -404,7 +404,7 @@ public abstract class AbstractEnvelope i
         final double lower = getLower(dimension);
         final double upper = getUpper(dimension);
         double median = 0.5 * (lower + upper);
-        if (isNegative(upper - lower)) { // Special handling for -0.0
+        if (isNegative(upper - lower)) {                            // Special 
handling for -0.0
             median = fixMedian(getAxis(getCoordinateReferenceSystem(), 
dimension), median);
         }
         return median;
@@ -451,7 +451,7 @@ public abstract class AbstractEnvelope i
     @Override
     public double getSpan(final int dimension) {
         double span = getUpper(dimension) - getLower(dimension);
-        if (isNegative(span)) { // Special handling for -0.0
+        if (isNegative(span)) {                                     // Special 
handling for -0.0
             span = fixSpan(getAxis(getCoordinateReferenceSystem(), dimension), 
span);
         }
         return span;
@@ -532,14 +532,14 @@ public abstract class AbstractEnvelope i
      */
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
     public Envelope[] toSimpleEnvelopes() {
-        long isWrapAround = 0; // A bitmask of the dimensions having a "wrap 
around" behavior.
+        long isWrapAround = 0;                              // A bitmask of 
the dimensions having a "wrap around" behavior.
         CoordinateReferenceSystem crs = null;
         final int dimension = getDimension();
         for (int i=0; i!=dimension; i++) {
-            final double span = getUpper(i) - getLower(i); // Do not use 
getSpan(i).
-            if (!(span > 0)) { // Use '!' for catching NaN.
+            final double span = getUpper(i) - getLower(i);  // Do not use 
getSpan(i).
+            if (!(span > 0)) {                              // Use '!' for 
catching NaN.
                 if (!isNegative(span)) {
-                    return EMPTY; // Span is positive zero.
+                    return EMPTY;                           // Span is 
positive zero.
                 }
                 if (crs == null) {
                     crs = getCoordinateReferenceSystem();
@@ -589,9 +589,9 @@ public abstract class AbstractEnvelope i
              * Assign the minimum and maximum ordinate values in the dimension 
where a wraparound has been found.
              * The 'for' loop below iterates only over the 'i' values for 
which the 'isWrapAround' bit is set to 1.
              */
-            int mask = 1; // For identifying whether we need to set the lower 
or the upper ordinate.
+            int mask = 1;               // For identifying whether we need to 
set the lower or the upper ordinate.
             @SuppressWarnings("null")
-            final CoordinateSystem cs = crs.getCoordinateSystem(); // Should 
not be null at this point.
+            final CoordinateSystem cs = crs.getCoordinateSystem();            
// Should not be null at this point.
             for (int i; (i = Long.numberOfTrailingZeros(isWrapAround)) != 
Long.SIZE; isWrapAround &= ~(1L << i)) {
                 final CoordinateSystemAxis axis = cs.getAxis(i);
                 final double min = axis.getMinimumValue();
@@ -635,7 +635,7 @@ public abstract class AbstractEnvelope i
             return true;
         }
         for (int i=0; i<dimension; i++) {
-            if (!(getSpan(i) > 0)) { // Use '!' in order to catch NaN
+            if (!(getSpan(i) > 0)) {                            // Use '!' in 
order to catch NaN
                 return true;
             }
         }
@@ -708,7 +708,7 @@ public abstract class AbstractEnvelope i
             final boolean c1   = (value >= lower);
             final boolean c2   = (value <= upper);
             if (c1 & c2) {
-                continue; // Point inside the range, check other dimensions.
+                continue;               // Point inside the range, check other 
dimensions.
             }
             if (c1 | c2) {
                 if (isNegative(upper - lower)) {
@@ -1134,7 +1134,7 @@ public abstract class AbstractEnvelope i
             final DirectPosition lowerCorner = envelope.getLowerCorner();
             final DirectPosition upperCorner = envelope.getUpperCorner();
             boolean isUpper = false;
-            do { // Executed exactly twice.
+            do {                                                        // 
Executed exactly twice.
                 for (int i=0; i<dimension; i++) {
                     buffer.append(i == 0 && !isUpper ? '(' : ' ');
                     final double ordinate = (isUpper ? upperCorner : 
lowerCorner).getOrdinate(i);


Reply via email to