sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1677850 [1/4] - in /sis/trunk: ./ core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-feature/src/test/java/org/apache/sis/feature/ core/sis-feature/src/test/java/org/apache/sis/test/suite/ core/sis-metadata/src/main/java/org/a...
Date Tue, 05 May 2015 16:09:07 GMT
Author: desruisseaux
Date: Tue May  5 16:09:05 2015
New Revision: 1677850

URL: http://svn.apache.org/r1677850
Log:
Merge from the JDK6 branch.

Added:
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
      - copied, changed from r1677828, sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
      - copied, changed from r1677828, sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/AbstractOperationTest.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/AbstractOperationTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/LinkOperationTest.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/LinkOperationTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/NoOperation.java
      - copied, changed from r1677828, sis/branches/JDK6/core/sis-feature/src/test/java/org/apache/sis/feature/NoOperation.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/DQ_PositionalAccuracy.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/DQ_PositionalAccuracy.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/CharEncoding.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/CharEncoding.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/CharEncodingTest.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/CharEncodingTest.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/test/mock/CoordinateSystemAxisMock.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-metadata/src/test/java/org/apache/sis/test/mock/CoordinateSystemAxisMock.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_Conversion.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_Conversion.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SC_GeographicCRS.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SC_GeographicCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConicProjection.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConicProjection.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCylindricalProjection.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCylindricalProjection.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPlanarProjection.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPlanarProjection.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultProjection.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultProjection.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultTransformation.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultTransformation.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticObjectBuilder.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/GeodeticObjectBuilder.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultProjectedCRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/AbstractSingleOperationTest.java
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/AbstractSingleOperationTest.java
    sis/trunk/core/sis-referencing/src/test/resources/org/apache/sis/referencing/crs/NTF.xml
      - copied unchanged from r1677828, sis/branches/JDK6/core/sis-referencing/src/test/resources/org/apache/sis/referencing/crs/NTF.xml
Removed:
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultOperationTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/OperationMethodsTest.java
Modified:
    sis/trunk/   (props changed)
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultOperation.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
    sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureTestCase.java
    sis/trunk/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gts/TM_PeriodDuration.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Convention.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
    sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/io/wkt/FormatterTest.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/OperationMethods.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/PositionalAccuracyConstant.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/j2d/ParameterizedAffine.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/SubTypes.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeocentricCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/BursaWolfParameters.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultPrimeMeridian.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultTemporalDatum.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultFormula.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/package-info.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractReferenceSystemTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultCompoundCRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeocentricCRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeodeticCRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultGeographicCRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultTemporalCRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/DefaultVerticalCRSTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/crs/HardCodedCRS.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxisTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/cs/HardCodedAxes.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/datum/HardCodedDatum.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    sis/trunk/core/sis-referencing/src/test/resources/org/apache/sis/referencing/crs/WGS 84.xml
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/TM_Primitive.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Citations.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/CollectionsExt.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/TemporalUtilities.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/StringBuilders.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationsTest.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/StringBuildersTest.java

Propchange: sis/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue May  5 16:09:05 2015
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
-/sis/branches/JDK6:1394364-1675090
-/sis/branches/JDK7:1394913-1675087
-/sis/branches/JDK8:1584960-1675086
+/sis/branches/JDK6:1394364-1677828
+/sis/branches/JDK7:1394913-1677827
+/sis/branches/JDK8:1584960-1677787

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractFeature.java [UTF-8] Tue May  5 16:09:05 2015
@@ -36,7 +36,7 @@ import org.apache.sis.internal.util.Chec
  * <ul>
  *   <li>{@linkplain AbstractAttribute   Attributes}</li>
  *   <li>{@linkplain AbstractAssociation Associations to other features}</li>
- *   <li>{@linkplain DefaultOperation    Operations}</li>
+ *   <li>{@linkplain AbstractOperation   Operations}</li>
  * </ul>
  *
  * {@code AbstractFeature} can be instantiated by calls to {@link DefaultFeatureType#newInstance()}.
@@ -61,7 +61,7 @@ import org.apache.sis.internal.util.Chec
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see DefaultFeatureType#newInstance()
@@ -110,7 +110,10 @@ public abstract class AbstractFeature im
     }
 
     /**
-     * Returns the property (attribute, operation or association) of the given name.
+     * Returns the property (attribute, feature association or operation result) of the given name.
+     * If the property type is a parameterless {@linkplain AbstractOperation operation}, then this
+     * method may return the result of {@linkplain AbstractOperation#apply executing} the operation
+     * on this feature, at implementation choice.
      *
      * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
      * to {@code org.opengis.feature.Property}. This change is pending GeoAPI revision.</div>
@@ -129,7 +132,7 @@ public abstract class AbstractFeature im
     public abstract Object getProperty(final String name) throws IllegalArgumentException;
 
     /**
-     * Sets the property (attribute, operation or association).
+     * Sets the property (attribute or feature association).
      * The given property shall comply to the following conditions:
      *
      * <ul>
@@ -185,7 +188,8 @@ 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 an attribute or association name of this feature.
+     * @throws IllegalArgumentException If the given argument is not the name of an attribute or
+     *         feature association of this feature.
      */
     @SuppressWarnings({"unchecked","rawtypes"})
     final Property createProperty(final String name) throws IllegalArgumentException {
@@ -199,6 +203,54 @@ public abstract class AbstractFeature im
         }
     }
 
+    /**
+     * Executes the parameterless operation of the given name and returns its result.
+     */
+    final Object getOperationResult(final String name) {
+        /*
+         * The (Operation) cast below should never fail (unless the DefaultFeatureType in not really immutable,
+         * which would be a contract violation) because all callers shall ensure that this method is invoked in
+         * a context where the following assertion holds.
+         */
+        assert DefaultFeatureType.OPERATION_INDEX.equals(type.indices().get(name)) : name;
+        return ((AbstractOperation) type.getProperty(name)).apply(this, null);
+    }
+
+    /**
+     * Executes the parameterless operation of the given name and returns the value of its result.
+     */
+    final Object getOperationValue(final String name) {
+        final AbstractOperation operation = (AbstractOperation) type.getProperty(name);
+        if (operation instanceof LinkOperation) {
+            return getPropertyValue(((LinkOperation) operation).propertyName);
+        }
+        final Object result = operation.apply(this, null);
+        if (result instanceof AbstractAttribute<?>) {
+            return getAttributeValue((AbstractAttribute<?>) result);
+        } else if (result instanceof AbstractAssociation) {
+            return getAssociationValue((AbstractAssociation) result);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Executes the parameterless operation of the given name and sets the value of its result.
+     */
+    final void setOperationValue(final String name, final Object value) {
+        final AbstractOperation operation = (AbstractOperation) type.getProperty(name);
+        if (operation instanceof LinkOperation) {
+            setPropertyValue(((LinkOperation) operation).propertyName, value);
+        } else {
+            final Object result = operation.apply(this, null);
+            if (result instanceof Property) {
+                setPropertyValue((Property) result, value);
+            } else {
+                throw new IllegalStateException(Errors.format(Errors.Keys.CanNotSetPropertyValue_1, name));
+            }
+        }
+    }
+
     /**
      * Returns the default value to be returned by {@link #getPropertyValue(String)}
      * for the property of the given name.

Copied: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java (from r1677828, sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java?p2=sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java&p1=sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java&r1=1677828&r2=1677850&rev=1677850&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/AbstractOperation.java [UTF-8] Tue May  5 16:09:05 2015
@@ -28,12 +28,6 @@ import org.apache.sis.util.Debug;
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
-import org.opengis.feature.Attribute;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureAssociation;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Operation;
-import org.opengis.feature.Property;
 
 
 /**
@@ -59,7 +53,7 @@ import org.opengis.feature.Property;
  * @version 0.6
  * @module
  */
-public abstract class AbstractOperation extends AbstractIdentifiedType implements Operation {
+public abstract class AbstractOperation extends AbstractIdentifiedType {
     /**
      * For cross-version compatibility.
      */
@@ -80,16 +74,17 @@ public abstract class AbstractOperation
      *
      * @return Description of the input parameters.
      */
-    @Override
     public abstract ParameterDescriptorGroup getParameters();
 
     /**
      * Returns the expected result type, or {@code null} if none.
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the return type may be changed
+     * to {@code org.opengis.feature.IdentifiedType}. This change is pending GeoAPI revision.</div>
+     *
      * @return The type of the result, or {@code null} if none.
      */
-    @Override
-    public abstract IdentifiedType getResult();
+    public abstract AbstractIdentifiedType getResult();
 
     /**
      * Executes the operation on the specified feature with the specified parameters.
@@ -112,14 +107,17 @@ public abstract class AbstractOperation
      * in the Java language, and may be {@code null} if the operation does not need a feature instance
      * (like static methods in the Java language).</div>
      *
+     * <div class="warning"><b>Warning:</b> In a future SIS version, the parameter type and return value may
+     * be changed to {@code org.opengis.feature.Feature} and {@code org.opengis.feature.Property} respectively.
+     * This change is pending GeoAPI revision.</div>
+     *
      * @param  feature    The feature on which to execute the operation.
      *                    Can be {@code null} if the operation does not need feature instance.
      * @param  parameters The parameters to use for executing the operation.
      *                    Can be {@code null} if the operation does not take any parameters.
      * @return The operation result, or {@code null} if this operation does not produce any result.
      */
-    @Override
-    public abstract Property apply(Feature feature, ParameterValueGroup parameters);
+    public abstract Object apply(AbstractFeature feature, ParameterValueGroup parameters);
 
     /**
      * Returns the names of feature properties that this operation needs for performing its task.
@@ -196,7 +194,7 @@ public abstract class AbstractOperation
         if (separator == ", ") { // Identity comparaison is okay here.
             buffer.append(')');
         }
-        final IdentifiedType result = getResult();
+        final AbstractIdentifiedType result = getResult();
         if (result != null) {
             buffer.append(" : ").append(result.getName());
         }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultFeatureType.java [UTF-8] Tue May  5 16:09:05 2015
@@ -21,7 +21,6 @@ import java.util.List;
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Map;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.IdentityHashMap;
 import java.util.Collection;
@@ -29,14 +28,19 @@ import java.util.Collections;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import org.opengis.util.NameFactory;
+import org.opengis.util.LocalName;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
+import org.opengis.parameter.ParameterDescriptorGroup;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.collection.Containers;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk8.JDK8;
+
 
 /**
  * Abstraction of a real-world phenomena. A {@code FeatureType} instance describes the class of all
@@ -62,7 +66,7 @@ import org.apache.sis.internal.util.Unmo
  * <ul>
  *   <li>{@linkplain DefaultAttributeType    Attributes}</li>
  *   <li>{@linkplain DefaultAssociationRole  Associations to other features}</li>
- *   <li>{@linkplain DefaultOperation        Operations}</li>
+ *   <li>{@linkplain AbstractOperation       Operations}</li>
  * </ul>
  *
  * In addition, a feature type can inherit the properties of one or more other feature types.
@@ -83,7 +87,7 @@ import org.apache.sis.internal.util.Unmo
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see AbstractFeature
@@ -174,6 +178,7 @@ public class DefaultFeatureType extends
     /**
      * Indices of properties in an array of properties similar to {@link #properties},
      * but excluding operations. This map includes the properties from the super-types.
+     * Parameterless operations (to be handled in a special way) are identified by index -1.
      *
      * The size of this map may be smaller than the {@link #byName} size.
      * This map shall not be modified after construction.
@@ -181,6 +186,12 @@ public class DefaultFeatureType extends
     private transient Map<String, Integer> indices;
 
     /**
+     * Value in {@link #indices} map for parameterless operations. Those operations are not stored
+     * in feature instances, but can be handled as virtual attributes computed on-the-fly.
+     */
+    static final Integer OPERATION_INDEX = -1;
+
+    /**
      * Constructs a feature type from the given properties. The identification map is given unchanged to
      * the {@linkplain AbstractIdentifiedType#AbstractIdentifiedType(Map) super-class constructor}.
      * The following table is a reminder of main (not all) recognized map entries:
@@ -288,18 +299,14 @@ public class DefaultFeatureType extends
         assignableTo = new HashSet<GenericName>(4);
         assignableTo.add(super.getName());
         scanPropertiesFrom(this);
-        byName        = CollectionsExt.compact(byName);
-        assignableTo  = CollectionsExt.unmodifiableOrCopy(assignableTo);
-        allProperties = byName.values();
-        if (byName instanceof HashMap<?,?>) {
-            allProperties = Collections.unmodifiableCollection(allProperties);
-        }
+        allProperties = UnmodifiableArrayList.wrap(byName.values().toArray(new AbstractIdentifiedType[byName.size()]));
         /*
          * Now check if the feature is simple/complex or dense/sparse. We perform this check after we finished
          * to create the list of all properties, because some properties may be overridden and we want to take
          * in account only the most specific ones.
          */
         isSimple = true;
+        int index = 0;
         int mandatory = 0; // Count of mandatory properties.
         for (final Map.Entry<String,AbstractIdentifiedType> entry : byName.entrySet()) {
             final int minimumOccurs, maximumOccurs;
@@ -313,17 +320,57 @@ public class DefaultFeatureType extends
                 maximumOccurs = ((FieldType) property).getMaximumOccurs();
                 isSimple = false;
             } else {
+                if (isParameterlessOperation(property)) {
+                    indices.put(entry.getKey(), OPERATION_INDEX);
+                }
                 continue; // For feature operations, maximumOccurs is implicitly 0.
             }
             if (maximumOccurs != 0) {
                 isSimple &= (maximumOccurs == 1);
-                indices.put(entry.getKey(), indices.size());
+                indices.put(entry.getKey(), index++);
                 if (minimumOccurs != 0) {
                     mandatory++;
                 }
             }
         }
-        indices = CollectionsExt.compact(indices);
+        /*
+         * If some properties use long name of the form "head:tip", creates short aliases containing only the "tip"
+         * name for convenience, provided that it does not create ambiguity. If an short alias could map to two or
+         * more properties, then this alias is not added.
+         *
+         * In the 'aliases' map below, null values will be assigned to ambiguous short names.
+         */
+        final Map<String, AbstractIdentifiedType> aliases = new LinkedHashMap<String, AbstractIdentifiedType>();
+        for (final AbstractIdentifiedType property : allProperties) {
+            final GenericName name = property.getName();
+            final LocalName tip = name.tip();
+            if (tip != name) {  // Slight optimization for a common case.
+                final String key = tip.toString();
+                if (key != null && !key.isEmpty() && !key.equals(name.toString())) {
+                    aliases.put(key, aliases.containsKey(key) ? null : property);
+                }
+            }
+        }
+        for (final Map.Entry<String,AbstractIdentifiedType> entry : aliases.entrySet()) {
+            final AbstractIdentifiedType property = entry.getValue();
+            if (property != null) {
+                final String tip = entry.getKey();
+                if (JDK8.putIfAbsent(byName, tip, property) == null) {
+                    // This block is skipped if there is properties named "tip" and "head:tip".
+                    // The 'indices' value may be null if the property is an operation.
+                    final Integer value = indices.get(property.getName().toString());
+                    if (value != null && indices.put(tip, value) != null) {
+                        throw new AssertionError(tip);  // Should never happen.
+                    }
+                }
+            }
+        }
+        /*
+         * Trim the collections. Especially useful when the collections have less that 2 elements.
+         */
+        byName       = CollectionsExt.compact(byName);
+        indices      = CollectionsExt.compact(indices);
+        assignableTo = CollectionsExt.unmodifiableOrCopy(assignableTo);
         /*
          * Rational for choosing whether the feature is sparse: By default, java.util.HashMap implementation creates
          * an internal array of length 16 (see HashMap.DEFAULT_INITIAL_CAPACITY).  In addition, the HashMap instance
@@ -458,6 +505,20 @@ public class DefaultFeatureType extends
         return resolved;
     }
 
+    /**
+     * Returns {@code true} if the given property type stands for a parameterless operation which return a result.
+     *
+     * @see #OPERATION_INDEX
+     */
+    private static boolean isParameterlessOperation(final AbstractIdentifiedType type) {
+        if (type instanceof AbstractOperation) {
+            final ParameterDescriptorGroup parameters = ((AbstractOperation) type).getParameters();
+            return ((parameters == null) || parameters.descriptors().isEmpty())
+                   && ((AbstractOperation) type).getResult() != null;
+        }
+        return false;
+    }
+
 
     // -------- END OF CONSTRUCTORS ------------------------------------------------------------------------------
 

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultOperation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultOperation.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultOperation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DefaultOperation.java [UTF-8] Tue May  5 16:09:05 2015
@@ -17,38 +17,21 @@
 package org.apache.sis.feature;
 
 import java.util.Map;
-import org.opengis.util.GenericName;
-import org.opengis.parameter.GeneralParameterDescriptor;
+import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
-import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.Debug;
-
-// Branch-dependent imports
-import org.apache.sis.internal.jdk7.Objects;
 
 
 /**
- * Describes the behaviour of a feature type as a function or a method.
- * Operations can:
- *
- * <ul>
- *   <li>Compute values from the attributes.</li>
- *   <li>Perform actions that change the attribute values.</li>
- * </ul>
- *
- * <div class="note"><b>Example:</b> a mutator operation may raise the height of a dam. This changes
- * may affect other properties like the watercourse and the reservoir associated with the dam.</div>
- *
- * <div class="warning"><b>Warning:</b> this class is experimental and may change after we gained more
- * experience on this aspect of ISO 19109.</div>
+ * @deprecated Replaced by {@link AbstractOperation}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
-public class DefaultOperation extends AbstractIdentifiedType {
+@Deprecated
+public class DefaultOperation extends AbstractOperation {
     /**
      * For cross-version compatibility.
      */
@@ -86,6 +69,7 @@ public class DefaultOperation extends Ab
      *
      * @return Description of the input parameters.
      */
+    @Override
     public ParameterDescriptorGroup getParameters() {
         return parameters;
     }
@@ -95,67 +79,19 @@ public class DefaultOperation extends Ab
      *
      * @return The type of the result, or {@code null} if none.
      */
+    @Override
     public AbstractIdentifiedType getResult() {
         return result;
     }
 
     /**
-     * Returns a hash code value for this operation.
+     * Subclasses should override.
+     * Default implementation throws {@link UnsupportedOperationException}.
      *
      * @return {@inheritDoc}
      */
     @Override
-    public int hashCode() {
-        return super.hashCode() + parameters.hashCode() + Objects.hashCode(result);
-    }
-
-    /**
-     * Compares this operation with the given object for equality.
-     *
-     * @return {@inheritDoc}
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (super.equals(obj)) {
-            final DefaultOperation that = (DefaultOperation) obj;
-            return parameters.equals(that.parameters) &&
-                   Objects.equals(result, that.result);
-        }
-        return false;
-    }
-
-    /**
-     * Returns a string representation of this operation.
-     * The returned string is for debugging purpose and may change in any future SIS version.
-     *
-     * @return A string representation of this operation for debugging purpose.
-     */
-    @Debug
-    @Override
-    public String toString() {
-        final StringBuilder buffer = new StringBuilder(40).append("Operation").append('[');
-        final GenericName name = getName();
-        if (name != null) {
-            buffer.append('“');
-        }
-        buffer.append(name);
-        if (name != null) {
-            buffer.append('”');
-        }
-        String separator = " (";
-        for (final GeneralParameterDescriptor param : parameters.descriptors()) {
-            buffer.append(separator).append(IdentifiedObjects.toString(param.getName()));
-            separator = ", ";
-        }
-        if (separator == ", ") { // Identity comparaison is okay here.
-            buffer.append(')');
-        }
-        if (result != null) {
-            buffer.append(" : ").append(result.getName());
-        }
-        return buffer.append(']').toString();
+    public Object apply(AbstractFeature feature, ParameterValueGroup parameters) {
+        throw new UnsupportedOperationException();
     }
 }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/DenseFeature.java [UTF-8] Tue May  5 16:09:05 2015
@@ -33,7 +33,7 @@ import org.apache.sis.util.resources.Err
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Marc le Bihan
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see SparseFeature
@@ -53,7 +53,7 @@ final class DenseFeature extends Abstrac
     private final Map<String, Integer> indices;
 
     /**
-     * The properties (attributes, operations, feature associations) of this feature.
+     * The properties (attributes or feature associations) in this feature.
      *
      * Conceptually, values in this array are {@link Property} instances. However at first we will store only
      * the property <em>values</em>, and convert to an array of type {@code Property[]} only when at least one
@@ -73,10 +73,12 @@ final class DenseFeature extends Abstrac
     }
 
     /**
-     * Returns the index for the property of the given name.
+     * Returns the index for the property of the given name, or {@link DefaultFeatureType#OPERATION_INDEX}
+     * if the property is a parameterless operation.
      *
      * @param  name The property name.
-     * @return The index for the property of the given 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.
      */
     private int getIndex(final String name) throws IllegalArgumentException {
@@ -97,17 +99,22 @@ final class DenseFeature extends Abstrac
     @Override
     public Object getProperty(final String name) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
-        final int index = getIndex(name); // Invoked first because this method checks name validity.
-
-        // Are the properties currently initialized? If not, wrap the values we can find.
+        final int index = getIndex(name);
+        if (index < 0) {
+            return getOperationResult(name);
+        }
+        /*
+         * Are the Property instances currently initialized? If not, wrap the values we can find.
+         * This is a all-or-nothing converion (we do not wrap only the requested property)
+         * for avoiding the additional complexity of remembering which values were wrapped.
+         */
         if (!(properties instanceof Property[])) {
             wrapValuesInProperties();
         }
-
-        // Find the wanted property.
+        /*
+         * Find the wanted property. If the property still have a null value, we create it from its type.
+         */
         Property property = ((Property[]) properties)[index];
-
-        // If the property still have a null value, we create it, but we can only tell its type.
         if (property == null) {
             property = createProperty(name);
             properties[index] = property;
@@ -130,6 +137,10 @@ final class DenseFeature extends Abstrac
         if (!(properties instanceof Property[])) {
             wrapValuesInProperties();
         }
+        /*
+         * Following index should never be OPERATION_INDEX (a negative value) because the call
+         * to 'verifyPropertyType(name, property)' shall have rejected all Operation types.
+         */
         properties[indices.get(name)] = property;
     }
 
@@ -142,10 +153,12 @@ final class DenseFeature extends Abstrac
         if (properties != null) {
             assert c.length == properties.length;
             for (final Map.Entry<String, Integer> entry : indices.entrySet()) {
-                final int   index  = entry.getValue();
-                final Object value = properties[index];
-                if (value != null) {
-                    c[index] = createProperty(entry.getKey(), value);
+                final int index = entry.getValue();
+                if (index >= 0) {
+                    final Object value = properties[index];
+                    if (value != null) {
+                        c[index] = createProperty(entry.getKey(), value);
+                    }
                 }
             }
         }
@@ -162,8 +175,12 @@ final class DenseFeature extends Abstrac
     @Override
     public Object getPropertyValue(final String name) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
+        final int index = getIndex(name);
+        if (index < 0) {
+            return getOperationValue(name);
+        }
         if (properties != null) {
-            final Object element = properties[getIndex(name)];
+            final Object element = properties[index];
             if (element != null) {
                 if (!(properties instanceof Property[])) {
                     return element; // Most common case.
@@ -191,6 +208,10 @@ final class DenseFeature extends Abstrac
     public void setPropertyValue(final String name, Object value) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
         final int index = getIndex(name);
+        if (index < 0) {
+            setOperationValue(name, value);
+            return;
+        }
         if (properties == null) {
             final int n = indices.size();
             properties = (value != null) ? new Object[n] : new Property[n];

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureFormat.java [UTF-8] Tue May  5 16:09:05 2015
@@ -24,6 +24,7 @@ import java.text.FieldPosition;
 import java.text.ParsePosition;
 import java.text.ParseException;
 import java.util.concurrent.atomic.AtomicReference;
+import org.opengis.referencing.IdentifiedObject;
 import org.opengis.util.InternationalString;
 import org.opengis.util.GenericName;
 import org.apache.sis.io.TableAppender;
@@ -31,6 +32,7 @@ import org.apache.sis.io.TabularFormat;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.referencing.IdentifiedObjects;
 
 
 /**
@@ -132,8 +134,11 @@ public class FeatureFormat extends Tabul
     public void format(final Object object, final Appendable toAppendTo) throws IOException {
         ArgumentChecks.ensureNonNull("object",     object);
         ArgumentChecks.ensureNonNull("toAppendTo", toAppendTo);
+        /*
+         * Separate the Feature (optional) and the FeatureType (mandatory) instances.
+         */
         final DefaultFeatureType featureType;
-        final AbstractFeature     feature;
+        final AbstractFeature feature;
         if (object instanceof AbstractFeature) {
             feature     = (AbstractFeature) object;
             featureType = feature.getType();
@@ -144,11 +149,25 @@ public class FeatureFormat extends Tabul
             throw new IllegalArgumentException(Errors.getResources(displayLocale)
                     .getString(Errors.Keys.UnsupportedType_1, object.getClass()));
         }
+        /*
+         * Check if at least one attribute has at least one characteritic. In many cases there is none.
+         * In none we will ommit the "characteristics" column, which is the last column.
+         */
+        boolean hasCharacteristics = false;
+        for (final AbstractIdentifiedType propertyType : featureType.getProperties(true)) {
+            if (propertyType instanceof DefaultAttributeType<?>) {
+                if (!((DefaultAttributeType<?>) propertyType).characteristics().isEmpty()) {
+                    hasCharacteristics = true;
+                    break;
+                }
+            }
+        }
+        /*
+         * Format the column header.
+         */
         toAppendTo.append(toString(featureType.getName())).append(getLineSeparator());
-        final StringBuffer  buffer    = new StringBuffer();
-        final FieldPosition dummyFP   = new FieldPosition(-1);
-        final Vocabulary    resources = Vocabulary.getResources(displayLocale);
-        final TableAppender table     = new TableAppender(toAppendTo, columnSeparator);
+        final Vocabulary resources = Vocabulary.getResources(displayLocale);
+        final TableAppender table = new TableAppender(toAppendTo, columnSeparator);
         table.setMultiLinesCells(true);
         table.nextLine('─');
 header: for (int i=0; ; i++) {
@@ -158,6 +177,15 @@ header: for (int i=0; ; i++) {
                 case 1:  nextColumn(table); key = Vocabulary.Keys.Type; break;
                 case 2:  nextColumn(table); key = Vocabulary.Keys.Cardinality; break;
                 case 3:  nextColumn(table); key = (feature != null) ? Vocabulary.Keys.Value : Vocabulary.Keys.DefaultValue; break;
+                case 4: {
+                    if (hasCharacteristics) {
+                        nextColumn(table);
+                        key = Vocabulary.Keys.Characteristics;
+                        break;
+                    } else {
+                        break header;
+                    }
+                }
                 default: break header;
             }
             table.append(resources.getString(key));
@@ -168,13 +196,15 @@ header: for (int i=0; ; i++) {
          * Done writing the header. Now write all property rows.
          * Rows without value will be skipped only if optional.
          */
+        final StringBuffer  buffer  = new StringBuffer();
+        final FieldPosition dummyFP = new FieldPosition(-1);
         for (final AbstractIdentifiedType propertyType : featureType.getProperties(true)) {
             Object value;
             if (feature != null) {
                 value = feature.getPropertyValue(propertyType.getName().toString());
                 if (value == null) {
                     if (propertyType instanceof FieldType && ((FieldType) propertyType).getMinimumOccurs() == 0) {
-                        continue; // If no value, skip the full row.
+                        continue;   // If no value, skip the full row.
                     }
                 }
             } else if (propertyType instanceof DefaultAttributeType<?>) {
@@ -206,8 +236,8 @@ header: for (int i=0; ; i++) {
                 maximumOccurs = pt.getMaximumOccurs();
                 valueType     = toString(DefaultAssociationRole.getValueTypeName(pt));
                 valueClass    = AbstractFeature.class;
-            } else if (propertyType instanceof DefaultOperation) {
-                final AbstractIdentifiedType resultType = ((DefaultOperation) propertyType).getResult();
+            } else if (propertyType instanceof AbstractOperation) {
+                final AbstractIdentifiedType resultType = ((AbstractOperation) propertyType).getResult();
                 valueType   = toString(resultType.getName());
                 valueClass  = null;
                 minimumOccurs = -1;
@@ -240,8 +270,6 @@ header: for (int i=0; ; i++) {
                 final Format format = getFormat(valueClass);
                 if (format != null) {
                     value = format.format(value, buffer, dummyFP);
-                } else if (value instanceof InternationalString) {
-                    value = ((InternationalString) value).toString(displayLocale);
                 } else if (value instanceof AbstractFeature && propertyType instanceof DefaultAssociationRole) {
                     final String p = DefaultAssociationRole.getTitleProperty((DefaultAssociationRole) propertyType);
                     if (p != null) {
@@ -249,10 +277,33 @@ header: for (int i=0; ; i++) {
                     }
                 }
                 if (value != null) {
-                    table.append(value.toString());
+                    table.append(formatValue(value));
                 }
                 buffer.setLength(0);
             }
+            /*
+             * Column 4 - Characteristics.
+             */
+            if (hasCharacteristics) {
+                nextColumn(table);
+                if (propertyType instanceof DefaultAttributeType<?>) {
+                    String separator = "";
+                    for (final DefaultAttributeType<?> attribute : ((DefaultAttributeType<?>) propertyType).characteristics().values()) {
+                        table.append(separator).append(toString(attribute.getName()));
+                        Object c = attribute.getDefaultValue();
+                        if (feature != null) {
+                            final Object p = feature.getProperty(propertyType.getName().toString());
+                            if (p instanceof AbstractAttribute<?>) {  // Should always be true, but we are paranoiac.
+                                c = ((AbstractAttribute<?>) p).characteristics().get(attribute.getName().toString());
+                            }
+                        }
+                        if (c != null) {
+                            table.append(" = ").append(formatValue(c));
+                        }
+                        separator = ", ";
+                    }
+                }
+            }
             table.nextLine();
         }
         table.nextLine('─');
@@ -277,6 +328,22 @@ header: for (int i=0; ; i++) {
     }
 
     /**
+     * Formats the given attribute value.
+     */
+    private String formatValue(final Object value) {
+        if (value instanceof InternationalString) {
+            return ((InternationalString) value).toString(displayLocale);
+        } else if (value instanceof GenericName) {
+            return toString((GenericName) value);
+        } else if (value instanceof AbstractIdentifiedType) {
+            return toString(((AbstractIdentifiedType) value).getName());
+        } else if (value instanceof IdentifiedObject) {
+            return IdentifiedObjects.getIdentifierOrName((IdentifiedObject) value);
+        }
+        return value.toString();
+    }
+
+    /**
      * Formats the given object using a shared instance of {@code ParameterFormat}.
      * This is used for {@link DefaultParameterDescriptorGroup#toString()} implementation.
      */

Copied: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java (from r1677828, sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java?p2=sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java&p1=sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java&r1=1677828&r2=1677850&rev=1677850&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/LinkOperation.java [UTF-8] Tue May  5 16:09:05 2015
@@ -28,12 +28,6 @@ import org.apache.sis.parameter.DefaultP
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.util.ArgumentChecks;
 
-// Branch-dependent imports
-import org.opengis.feature.Feature;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.Property;
-import org.opengis.feature.PropertyType;
-
 
 /**
  * A link operation, which is like a redirection or an alias.
@@ -77,7 +71,7 @@ final class LinkOperation extends Abstra
     /**
      * The type of the result.
      */
-    private final PropertyType result;
+    private final AbstractIdentifiedType result;
 
     /**
      * The name of the referenced attribute or feature association.
@@ -90,7 +84,7 @@ final class LinkOperation extends Abstra
      * @param identification The name of the link, together with optional information.
      * @param propertyType   The referenced attribute or feature association.
      */
-    LinkOperation(final Map<String, ?> identification, final PropertyType propertyType) {
+    LinkOperation(final Map<String, ?> identification, final AbstractIdentifiedType propertyType) {
         super(identification);
         result = propertyType;
         propertyName = propertyType.getName().toString();
@@ -108,7 +102,7 @@ final class LinkOperation extends Abstra
      * Returns the expected result type.
      */
     @Override
-    public IdentifiedType getResult() {
+    public AbstractIdentifiedType getResult() {
         return result;
     }
 
@@ -128,7 +122,7 @@ final class LinkOperation extends Abstra
      * @return The property from the given feature.
      */
     @Override
-    public Property apply(final Feature feature, final ParameterValueGroup parameters) {
+    public Object apply(final AbstractFeature feature, final ParameterValueGroup parameters) {
         ArgumentChecks.ensureNonNull("feature", feature);
         return feature.getProperty(propertyName);
     }

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAssociation.java [UTF-8] Tue May  5 16:09:05 2015
@@ -124,16 +124,18 @@ final class MultiValuedAssociation exten
     /**
      * Sets the feature values. All previous values are replaced by the given collection.
      *
-     * @param values The new values.
+     * @param newValues The new values.
      */
     @Override
-    public void setValues(final Collection<? extends AbstractFeature> values) {
-        ArgumentChecks.ensureNonNull("values", values);
-        final DefaultFeatureType base = role.getValueType();
-        this.values.clear();
-        for (final AbstractFeature value : values) {
-            ensureValid(base, value.getType());
-            this.values.add(value);
+    public void setValues(final Collection<? extends AbstractFeature> newValues) {
+        if (newValues != values) {
+            ArgumentChecks.ensureNonNull("values", newValues);  // The parameter name in public API is "values".
+            final DefaultFeatureType base = role.getValueType();
+            values.clear();
+            for (final AbstractFeature value : newValues) {
+                ensureValid(base, value.getType());
+                values.add(value);
+            }
         }
     }
 

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/MultiValuedAttribute.java [UTF-8] Tue May  5 16:09:05 2015
@@ -136,13 +136,15 @@ final class MultiValuedAttribute<V> exte
     /**
      * Sets the attribute values. All previous values are replaced by the given collection.
      *
-     * @param values The new values.
+     * @param newValues The new values.
      */
     @Override
-    public void setValues(final Collection<? extends V> values) {
-        ArgumentChecks.ensureNonNull("values", values);
-        this.values.clear();
-        this.values.addAll(values);
+    public void setValues(final Collection<? extends V> newValues) {
+        if (newValues != values) {
+            ArgumentChecks.ensureNonNull("values", newValues);  // The parameter name in public API is "values".
+            values.clear();
+            values.addAll(newValues);
+        }
     }
 
     /**

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/SparseFeature.java [UTF-8] Tue May  5 16:09:05 2015
@@ -24,6 +24,7 @@ import org.opengis.metadata.quality.Data
 import org.apache.sis.internal.util.Cloner;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CorruptedObjectException;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -35,7 +36,7 @@ import org.apache.sis.util.CorruptedObje
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  *
  * @see DenseFeature
@@ -45,7 +46,7 @@ final class SparseFeature extends Abstra
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = -4486200659005766093L;
+    private static final long serialVersionUID = 2954323576287152427L;
 
     /**
      * A {@link #valuesKind} flag meaning that the {@link #properties} map contains raw values.
@@ -63,7 +64,17 @@ final class SparseFeature extends Abstra
     private static final byte CORRUPTED = 2;
 
     /**
-     * The properties (attributes, operations, feature associations) of this feature.
+     * The map of property names to keys in the {@link #properties} map. This map is a reference to the
+     * {@link DefaultFeatureType#indices} map (potentially shared by many feature instances) and shall
+     * not be modified.
+     *
+     * <p>We use those indices as {@link #properties} keys instead than using directly the property names
+     * in order to resolve aliases.</p>
+     */
+    private final Map<String, Integer> indices;
+
+    /**
+     * The properties (attributes or feature associations) in this feature.
      *
      * Conceptually, values in this map are {@link Property} instances. However at first we will store
      * only the property <em>values</em>, and build the full {@code Property} objects only if they are
@@ -72,7 +83,7 @@ final class SparseFeature extends Abstra
      *
      * @see #valuesKind
      */
-    private HashMap<String, Object> properties;
+    private HashMap<Integer, Object> properties;
 
     /**
      * {@link #PROPERTIES} if the values in the {@link #properties} map are {@link Property} instances,
@@ -91,22 +102,54 @@ final class SparseFeature extends Abstra
      */
     public SparseFeature(final DefaultFeatureType type) {
         super(type);
-        properties = new HashMap<String, Object>();
+        indices = type.indices();
+        properties = new HashMap<Integer, Object>();
+    }
+
+    /**
+     * Returns the index for the property of the given name, or {@link DefaultFeatureType#OPERATION_INDEX}
+     * if the property is a parameterless operation.
+     *
+     * @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.
+     */
+    private int getIndex(final String name) throws IllegalArgumentException {
+        final Integer index = indices.get(name);
+        if (index != null) {
+            return index;
+        }
+        throw new IllegalArgumentException(Errors.format(Errors.Keys.PropertyNotFound_2, getName(), name));
+    }
+
+    /**
+     * Returns the property name at the given index.
+     * Current implementation is inefficient, but this method should rarely be invoked.
+     */
+    private String nameOf(final Integer index) {
+        for (final Map.Entry<String, Integer> entry : indices.entrySet()) {
+            if (index.equals(entry.getValue())) {
+                return entry.getKey();
+            }
+        }
+        // Should never reach this point.
+        throw new AssertionError(index);
     }
 
     /**
      * Ensures that the {@link #properties} map contains {@link Property} instances instead than
      * property values. The conversion, if needed, will be performed at most once per feature.
      */
-    private void ensurePropertyMap() {
+    private void requireMapOfProperties() {
         if (valuesKind != PROPERTIES) {
             if (!properties.isEmpty()) { // The map is typically empty when this method is first invoked.
                 if (valuesKind != VALUES) {
                     throw new CorruptedObjectException(getName());
                 }
                 valuesKind = CORRUPTED;
-                for (final Map.Entry<String, Object> entry : properties.entrySet()) {
-                    final String key   = entry.getKey();
+                for (final Map.Entry<Integer, Object> entry : properties.entrySet()) {
+                    final String key = nameOf(entry.getKey());
                     final Object value = entry.getValue();
                     if (entry.setValue(createProperty(key, value)) != value) {
                         throw new ConcurrentModificationException(key);
@@ -127,7 +170,7 @@ final class SparseFeature extends Abstra
     @Override
     public Object getProperty(final String name) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
-        ensurePropertyMap();
+        requireMapOfProperties();
         return getPropertyInstance(name);
     }
 
@@ -137,10 +180,14 @@ final class SparseFeature extends Abstra
      */
     private Property getPropertyInstance(final String name) throws IllegalArgumentException {
         assert valuesKind == PROPERTIES : valuesKind;
-        Property property = (Property) properties.get(name);
+        final Integer index = getIndex(name);
+        if (index < 0) {
+            return (Property) getOperationResult(name);
+        }
+        Property property = (Property) properties.get(index);
         if (property == null) {
             property = createProperty(name);
-            replace(name, null, property);
+            replace(index, null, property);
         }
         return property;
     }
@@ -157,8 +204,12 @@ final class SparseFeature extends Abstra
         ArgumentChecks.ensureNonNull("property", property);
         final String name = ((Property) property).getName().toString();
         verifyPropertyType(name, (Property) property);
-        ensurePropertyMap();
-        properties.put(name, property);
+        requireMapOfProperties();
+        /*
+         * Following index should never be OPERATION_INDEX (a negative value) because the call
+         * to 'verifyPropertyType(name, property)' shall have rejected all Operation types.
+         */
+        properties.put(indices.get(name), property);
     }
 
     /**
@@ -171,7 +222,11 @@ final class SparseFeature extends Abstra
     @Override
     public Object getPropertyValue(final String name) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
-        final Object element = properties.get(name);
+        final Integer index = getIndex(name);
+        if (index < 0) {
+            return getOperationValue(name);
+        }
+        final Object element = properties.get(index);
         if (element != null) {
             if (valuesKind == VALUES) {
                 return element; // Most common case.
@@ -184,7 +239,7 @@ final class SparseFeature extends Abstra
             } else {
                 throw new CorruptedObjectException(getName());
             }
-        } else if (properties.containsKey(name)) {
+        } else if (properties.containsKey(index)) {
             return null; // Null has been explicitely set.
         } else {
             return getDefaultValue(name);
@@ -202,8 +257,13 @@ final class SparseFeature extends Abstra
     @Override
     public void setPropertyValue(final String name, final Object value) throws IllegalArgumentException {
         ArgumentChecks.ensureNonNull("name", name);
+        final Integer index = getIndex(name);
+        if (index < 0) {
+            setOperationValue(name, value);
+            return;
+        }
         if (valuesKind == VALUES) {
-            final Object previous = properties.put(name, value);
+            final Object previous = properties.put(index, value);
             /*
              * Slight optimization:  if we replaced a previous value of the same class, then we can skip the
              * checks for name and type validity since those checks have been done previously. But if we add
@@ -215,7 +275,7 @@ final class SparseFeature extends Abstra
                     toStore = verifyPropertyValue(name, value);
                 } finally {
                     if (toStore != value) {
-                        replace(name, value, toStore);
+                        replace(index, value, toStore);
                     }
                 }
             }
@@ -229,13 +289,13 @@ final class SparseFeature extends Abstra
     /**
      * Sets a value in the {@link #properties} map.
      *
-     * @param name     The name of the property to set.
+     * @param index    The key of the property to set.
      * @param oldValue The old value, used for verification purpose.
      * @param newValue The new value.
      */
-    private void replace(final String name, final Object oldValue, final Object newValue) {
-        if (properties.put(name, newValue) != oldValue) {
-            throw new ConcurrentModificationException(name);
+    private void replace(final Integer index, final Object oldValue, final Object newValue) {
+        if (properties.put(index, newValue) != oldValue) {
+            throw new ConcurrentModificationException(nameOf(index));
         }
     }
 
@@ -248,8 +308,8 @@ final class SparseFeature extends Abstra
     public DataQuality quality() {
         if (valuesKind == VALUES) {
             final Validator v = new Validator(ScopeCode.FEATURE);
-            for (final AbstractIdentifiedType pt : type.getProperties(true)) {
-                v.validateAny(pt, properties.get(pt.getName().toString()));
+            for (final Map.Entry<String, Integer> entry : indices.entrySet()) {
+                v.validateAny(type.getProperty(entry.getKey()), properties.get(entry.getValue()));
             }
             return v.quality;
         }
@@ -274,14 +334,14 @@ final class SparseFeature extends Abstra
     @SuppressWarnings("unchecked")
     public SparseFeature clone() throws CloneNotSupportedException {
         final SparseFeature clone = (SparseFeature) super.clone();
-        clone.properties = (HashMap<String,Object>) clone.properties.clone();
+        clone.properties = (HashMap<Integer,Object>) clone.properties.clone();
         switch (clone.valuesKind) {
             default:        throw new AssertionError(clone.valuesKind);
             case CORRUPTED: throw new CorruptedObjectException(clone.getName());
             case VALUES:    break; // Nothing to do.
             case PROPERTIES: {
                 final Cloner cloner = new Cloner();
-                for (final Map.Entry<String,Object> entry : clone.properties.entrySet()) {
+                for (final Map.Entry<Integer,Object> entry : clone.properties.entrySet()) {
                     final Property property = (Property) entry.getValue();
                     if (property instanceof Cloneable) {
                         entry.setValue(cloner.clone(property));

Modified: sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/main/java/org/apache/sis/feature/package-info.java [UTF-8] Tue May  5 16:09:05 2015
@@ -24,7 +24,7 @@
  *   <li><b>{@linkplain org.apache.sis.feature.DefaultFeatureType Feature types}</b><br>
  *       Define the <em>structure</em> of real-world representations. A feature type lists the
  *       {@linkplain org.apache.sis.feature.DefaultAttributeType attributes},
- *       {@linkplain org.apache.sis.feature.DefaultOperation operations} or
+ *       {@linkplain org.apache.sis.feature.AbstractOperation operations} or
  *       {@linkplain org.apache.sis.feature.DefaultAssociationRole associations to other features}
  *       (collectively called “{@linkplain org.apache.sis.feature.DefaultFeatureType#getProperties(boolean) properties}”
  *       or “characteristics”) that a feature can have.
@@ -70,7 +70,7 @@
  * {@code  └─}                                                                Property type<br>
  * {@code      ├─} {@linkplain org.apache.sis.feature.DefaultAttributeType    Attribute type}<br>
  * {@code      ├─} {@linkplain org.apache.sis.feature.DefaultAssociationRole  Feature association role}<br>
- * {@code      └─} {@linkplain org.apache.sis.feature.DefaultOperation        Operation}<br>
+ * {@code      └─} {@linkplain org.apache.sis.feature.AbstractOperation       Operation}<br>
  * </td><td class="sep" style="width: 50%; white-space: nowrap">
  *             {@linkplain org.apache.sis.feature.AbstractFeature     Feature}             (<cite>sparse</cite> or <cite>dense</cite>)<br>
  *                                                                    Property<br>

Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/DefaultFeatureTypeTest.java [UTF-8] Tue May  5 16:09:05 2015
@@ -20,7 +20,9 @@ import java.util.Map;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Collection;
+import org.opengis.util.NameFactory;
 import org.opengis.util.InternationalString;
+import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -36,14 +38,14 @@ import static org.apache.sis.test.TestUt
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.6
  * @module
  */
 @DependsOn(DefaultAttributeTypeTest.class)
 public final strictfp class DefaultFeatureTypeTest extends TestCase {
     /**
      * Creates a simple feature type without super-types.
-     * The feature contains the following attribute:
+     * The feature contains the following attributes:
      *
      * <ul>
      *   <li>{@code city}       as a  {@link String}  (mandatory)</li>
@@ -126,21 +128,25 @@ public final strictfp class DefaultFeatu
      * {@link InternationalString} and an arbitrary amount of universities.
      */
     static DefaultFeatureType worldMetropolis() {
-        return worldMetropolis(metropolis(), universityCity(), InternationalString.class);
+        return worldMetropolis(metropolis(), universityCity(), CharacteristicTypeMapTest.temperature(), InternationalString.class);
     }
 
     /**
      * Creates a sub-type of the "metropolis" type with the "region" attribute overridden to the given type.
-     * The given type should be {@link InternationalString}, but we allow other type for testing argument checks.
+     * The given type should be {@link InternationalString}, but we allow other types for testing argument checks.
      */
     private static <T> DefaultFeatureType worldMetropolis(final DefaultFeatureType metropolis,
-            final DefaultFeatureType universityCity, final Class<T> regionType)
+            final DefaultFeatureType universityCity, final DefaultAttributeType<?> temperature, final Class<T> regionType)
     {
         return new DefaultFeatureType(singletonMap(DefaultFeatureType.NAME_KEY, "World metropolis"), false,
-                new DefaultFeatureType[] {metropolis, universityCity},
-                new DefaultAttributeType<T>(singletonMap(DefaultAttributeType.NAME_KEY, "region"),
-                        regionType, 1, 1, null));
-
+                new DefaultFeatureType[] {          // Super types
+                    metropolis,
+                    universityCity
+                },
+                new DefaultAttributeType<?>[] {     // Properties
+                    new DefaultAttributeType<T>(singletonMap(DefaultAttributeType.NAME_KEY, "region"), regionType, 1, 1, null),
+                    temperature
+                });
     }
 
     /**
@@ -303,8 +309,51 @@ public final strictfp class DefaultFeatu
             fail("Duplicated attribute names shall not be allowed.");
         } catch (IllegalArgumentException e) {
             final String message = e.getMessage();
-            assertTrue(message, message.contains("name")); // Property name.
-            assertTrue(message, message.contains("City")); // Feature name.
+            assertTrue(message, message.contains("name"));      // Property name.
+            assertTrue(message, message.contains("City"));      // Feature name.
+        }
+    }
+
+    /**
+     * Same than {@link #testNameCollision()}, but resolving collisions with usage of names
+     * of the form {@code "head:tip"}.
+     *
+     * @since 0.6
+     */
+    @Test
+    @DependsOnMethod("testNameCollision")
+    public void testQualifiedNames() {
+        final NameFactory factory = DefaultFactories.forBuildin(NameFactory.class);
+        final DefaultAttributeType<String> city = new DefaultAttributeType<String>(
+                singletonMap(DefaultAttributeType.NAME_KEY, factory.createGenericName(null, "ns1", "name")),
+                String.class, 1, 1, null);
+        final DefaultAttributeType<Integer> cityId = new DefaultAttributeType<Integer>(
+                singletonMap(DefaultAttributeType.NAME_KEY, factory.createGenericName(null, "ns2", "name")),
+                Integer.class, 1, 1, null);
+        final DefaultAttributeType<Integer> population = new DefaultAttributeType<Integer>(
+                singletonMap(DefaultAttributeType.NAME_KEY, factory.createGenericName(null, "ns1", "population")),
+                Integer.class, 1, 1, null);
+        final DefaultFeatureType feature = new DefaultFeatureType(
+                singletonMap(DefaultAttributeType.NAME_KEY, "City"),
+                false, null, city, cityId, population);
+
+        final Iterator<AbstractIdentifiedType> it = feature.getProperties(false).iterator();
+        assertSame ("properties[0]", city,       it.next());
+        assertSame ("properties[1]", cityId,     it.next());
+        assertSame ("properties[2]", population, it.next());
+        assertFalse(it.hasNext());
+
+        assertSame("Shall get from fully qualified name.", city,       feature.getProperty("ns1:name"));
+        assertSame("Shall get from fully qualified name.", cityId,     feature.getProperty("ns2:name"));
+        assertSame("Shall get from fully qualified name.", population, feature.getProperty("ns1:population"));
+        assertSame("Shall get from short alias.",          population, feature.getProperty(    "population"));
+        try {
+            feature.getProperty("name");
+            fail("Expected no alias because of ambiguity.");
+        } catch (IllegalArgumentException e) {
+            final String message = e.getMessage();
+            assertTrue(message, message.contains("name"));      // Property name.
+            assertTrue(message, message.contains("City"));      // Feature name.
         }
     }
 
@@ -316,7 +365,7 @@ public final strictfp class DefaultFeatu
     @Test
     @DependsOnMethod({"testComplex", "testEquals"})
     public void testInheritance() {
-        final DefaultFeatureType city    = city(); // Tested by 'testSimple()'.
+        final DefaultFeatureType city    = city();      // Tested by 'testSimple()'.
         final DefaultFeatureType capital = capital();
         assertUnmodifiable(capital);
         assertEquals("name", "Capital", capital.getName().toString());
@@ -346,7 +395,7 @@ public final strictfp class DefaultFeatu
     @DependsOnMethod("testInheritance")
     public void testMultiInheritance() {
         final DefaultFeatureType metropolis   = metropolis();
-        final DefaultFeatureType capital      = capital(); // Tested by 'testComplex()'.
+        final DefaultFeatureType capital      = capital();      // Tested by 'testComplex()'.
         final DefaultFeatureType metroCapital = new DefaultFeatureType(
                 singletonMap(DefaultFeatureType.NAME_KEY, "Metropolis and capital"), false,
                 new DefaultFeatureType[] {metropolis, capital},
@@ -387,25 +436,26 @@ public final strictfp class DefaultFeatu
     public void testPropertyOverride() {
         final DefaultFeatureType metropolis     = metropolis();
         final DefaultFeatureType universityCity = universityCity();
+        final DefaultAttributeType<?> temperature = CharacteristicTypeMapTest.temperature();
         try {
-            worldMetropolis(metropolis, universityCity, Integer.class);
+            worldMetropolis(metropolis, universityCity, temperature, Integer.class);
             fail("Shall not be allowed to override a 'CharSequence' attribute with an 'Integer' one.");
         } catch (IllegalArgumentException e) {
             final String message = e.getMessage();
             assertTrue(message, message.contains("region"));
             assertTrue(message, message.contains("Metropolis"));
         }
-        final DefaultFeatureType worldMetropolis = worldMetropolis(metropolis, universityCity, InternationalString.class);
+        final DefaultFeatureType worldMetropolis = worldMetropolis(metropolis, universityCity, temperature, InternationalString.class);
         assertUnmodifiable(worldMetropolis);
         assertEquals     ("name", "World metropolis", worldMetropolis.getName().toString());
         assertArrayEquals("superTypes", new Object[] {metropolis, universityCity}, worldMetropolis.getSuperTypes().toArray());
         assertFalse      ("isAbstract",      worldMetropolis.isAbstract());
         assertFalse      ("isSparse",        worldMetropolis.isSparse());
         assertFalse      ("isSimple",        worldMetropolis.isSimple()); // Because of the arbitrary amount of universities.
-        assertEquals     ("instanceSize", 5, worldMetropolis.indices().size());
+        assertEquals     ("instanceSize", 6, worldMetropolis.indices().size());
 
-        assertPropertiesEquals(worldMetropolis, false, "region");
-        assertPropertiesEquals(worldMetropolis, true, "city", "population", "region", "isGlobal", "universities");
+        assertPropertiesEquals(worldMetropolis, false, "region", "temperature");
+        assertPropertiesEquals(worldMetropolis, true, "city", "population", "region", "isGlobal", "universities", "temperature");
         assertEquals("property(“region”).valueClass", InternationalString.class,
                 ((DefaultAttributeType) worldMetropolis.getProperty("region")).getValueClass());
 

Modified: sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java?rev=1677850&r1=1677849&r2=1677850&view=diff
==============================================================================
--- sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-feature/src/test/java/org/apache/sis/feature/FeatureFormatTest.java [UTF-8] Tue May  5 16:09:05 2015
@@ -34,7 +34,10 @@ import static org.apache.sis.test.Assert
  * @version 0.5
  * @module
  */
-@DependsOn(DenseFeatureTest.class)
+@DependsOn({
+    DenseFeatureTest.class,
+    CharacteristicMapTest.class
+})
 public final strictfp class FeatureFormatTest extends TestCase {
     /**
      * Tests the formatting of a {@link DefaultFeatureType}.
@@ -45,15 +48,16 @@ public final strictfp class FeatureForma
         final FeatureFormat format = new FeatureFormat(Locale.US, null);
         final String text = format.format(feature);
         assertMultilinesEquals("World metropolis\n" +
-                "┌──────────────┬─────────────────────┬─────────────┬───────────────┐\n" +
-                "│ Name         │ Type                │ Cardinality │ Default value │\n" +
-                "├──────────────┼─────────────────────┼─────────────┼───────────────┤\n" +
-                "│ city         │ String              │ [1 … 1]     │ Utopia        │\n" +
-                "│ population   │ Integer             │ [1 … 1]     │               │\n" +
-                "│ region       │ InternationalString │ [1 … 1]     │               │\n" +
-                "│ isGlobal     │ Boolean             │ [1 … 1]     │               │\n" +
-                "│ universities │ String              │ [0 … ∞]     │               │\n" +
-                "└──────────────┴─────────────────────┴─────────────┴───────────────┘\n", text);
+                "┌──────────────┬─────────────────────┬─────────────┬───────────────┬────────────────────────────┐\n" +
+                "│ Name         │ Type                │ Cardinality │ Default value │ Characteristics            │\n" +
+                "├──────────────┼─────────────────────┼─────────────┼───────────────┼────────────────────────────┤\n" +
+                "│ city         │ String              │ [1 … 1]     │ Utopia        │                            │\n" +
+                "│ population   │ Integer             │ [1 … 1]     │               │                            │\n" +
+                "│ region       │ InternationalString │ [1 … 1]     │               │                            │\n" +
+                "│ isGlobal     │ Boolean             │ [1 … 1]     │               │                            │\n" +
+                "│ universities │ String              │ [0 … ∞]     │               │                            │\n" +
+                "│ temperature  │ Float               │ [1 … 1]     │               │ accuracy = 0.1, units = °C │\n" +
+                "└──────────────┴─────────────────────┴─────────────┴───────────────┴────────────────────────────┘\n", text);
     }
 
     /**



Mime
View raw message