sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1739766 - in /sis/branches/JDK8/core: sis-feature/src/main/java/org/apache/sis/feature/ sis-feature/src/main/java/org/apache/sis/internal/feature/ sis-feature/src/test/java/org/apache/sis/feature/ sis-feature/src/test/java/org/apache/sis/i...
Date Mon, 18 Apr 2016 14:43:16 GMT
Author: desruisseaux
Date: Mon Apr 18 14:43:16 2016
New Revision: 1739766

URL: http://svn.apache.org/viewvc?rev=1739766&view=rev
Log:
Rename BoundsOperation as EnvelopeOperation and refactor in a way which try to find the
CoordinateOperation at construction time instead than searching them for every feature instance.

Added:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java
      - copied, changed from r1739765, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/BoundsOperation.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java   (with props)
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java
      - copied, changed from r1739765, sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/BoundsOperationTest.java
Removed:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/BoundsOperation.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/BoundsOperationTest.java
Modified:
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java
    sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/NameConvention.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeTypeBuilderTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/NameConventionTest.java
    sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java

Copied: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java (from r1739765, sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/BoundsOperation.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java?p2=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java&p1=sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/BoundsOperation.java&r1=1739765&r2=1739766&rev=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/BoundsOperation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/EnvelopeOperation.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -16,77 +16,196 @@
  */
 package org.apache.sis.feature;
 
-import java.util.Collections;
+import java.util.Arrays;
+import java.util.Set;
 import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import com.esri.core.geometry.Geometry;
+import java.util.LinkedHashMap;
+import org.opengis.util.GenericName;
+import org.opengis.util.FactoryException;
 import org.opengis.geometry.Envelope;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.TransformException;
 import org.apache.sis.internal.feature.NameConvention;
+import org.apache.sis.internal.feature.Geometries;
+import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.geometry.Envelopes;
 import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.util.resources.Errors;
 
 // Branch-dependent imports
+import java.util.Objects;
+import org.opengis.feature.Attribute;
 import org.opengis.feature.AttributeType;
 import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureType;
 import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.MultiValuedPropertyException;
+import org.opengis.feature.Operation;
 import org.opengis.feature.Property;
 import org.opengis.feature.PropertyType;
 
 
 /**
- * Calculate feature bounds operation.
- * <br>
- * This operation loops on all first level geometry properties and compute the
- * resulting envelope.
- * <br>
- * Geometries can be in different coordinate reference systems, they will be
- * transformed to the operation crs.
- * <br>
- * If the operation CRS has not been defined then the first none-empty geometry
- * crs will be used.
- * <br>
- * This operation can only be read, not setted.
+ * An operation computing the envelope that encompass all geometries found in a list of attributes.
+ * Geometries can be in different coordinate reference systems; they will be transformed to the first
+ * non-null CRS in the following choices:
+ *
+ * <ol>
+ *   <li>the CRS specified at construction time,</li>
+ *   <li>the CRS of the default geometry, or</li>
+ *   <li>the CRS of the first non-empty geometry.</li>
+ * </ol>
+ *
+ * <div class="section">Limitations</div>
+ * If a geometry contains other geometries, this operation queries only the envelope of the root geometry.
+ * It is the root geometry responsibility to take in account the envelope of all its children.
+ *
+ * <p>This operation is read-only. Calls to {@code Attribute.setValue(Envelope)} will result in an
+ * {@link IllegalStateException} to be thrown.</p>
  *
  * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @since   0.7
  * @version 0.7
  * @module
  */
-final class BoundsOperation extends AbstractOperation {
+final class EnvelopeOperation extends AbstractOperation {
     /**
      * For cross-version compatibility.
      */
     private static final long serialVersionUID = 6250548001562807671L;
 
-    private static final AttributeType<Envelope> TYPE = new DefaultAttributeType<>(
-            Collections.singletonMap(NAME_KEY, "Envelope"),Envelope.class,1,1,null);
+    /**
+     * The parameter descriptor for the "Envelope" operation, which does not take any parameter.
+     */
+    private static final ParameterDescriptorGroup EMPTY_PARAMS = LinkOperation.parameters("Envelope", 1);
+
+    /**
+     * The names of all properties containing a geometry object.
+     */
+    private final String[] attributeNames;
+
+    /**
+     * The coordinate reference system of the envelope to compute, or {@code null}
+     * for using the CRS of the default geometry or the first non-empty geometry.
+     */
+    final CoordinateReferenceSystem crs;
+
+    /**
+     * The coordinate conversions or transformations from the CRS used by the geometries to the CRS requested
+     * by the user, or {@code null} if there is no operation to apply.  If non-null, the length of this array
+     * shall be equal to the length of the {@link #attributeNames} array and element at index <var>i</var> is
+     * the operation from the {@code attributeNames[i]} geometry CRS to the {@link #crs}.
+     *
+     * <p>This array contains null element when the {@code MathTransform} associated to the coordinate operation
+     * is the identity transform.</p>
+     */
+    private final CoordinateOperation[] attributeToCRS;
 
     /**
-     * The parameter descriptor for the "Bounds" operation, which does not take any parameter.
+     * The property names as an unmodifiable set, created when first needed.
      */
-    private static final ParameterDescriptorGroup EMPTY_PARAMS = LinkOperation.parameters("Bounds", 1);
+    private transient Set<String> dependencies;
 
-    private final CoordinateReferenceSystem crs;
+    /**
+     * The type of the result returned by the envelope operation.
+     */
+    private final AttributeType<Envelope> resultType;
 
     /**
+     * Creates a new operation computing the envelope of features of the given type.
      *
-     * @param identification The name and other information to be given to this operation.
-     * @param crs result envelope CRS, can be {@code null}
+     * @param identification     the name and other information to be given to this operation.
+     * @param crs                the coordinate reference system of envelopes to computes, or {@code null}.
+     * @param geometryAttributes the operation or attribute type from which to get geometry values.
      */
-    BoundsOperation(Map<String,?> identification, CoordinateReferenceSystem crs) {
+    EnvelopeOperation(final Map<String,?> identification, CoordinateReferenceSystem crs,
+            final PropertyType[] geometryAttributes) throws FactoryException
+    {
         super(identification);
+        String defaultGeometry = null;
+        final String characteristicName = NameConvention.CRS_CHARACTERISTIC.toString();
+        /*
+         * Get all property names without duplicated values. If a property is a link to an attribute,
+         * then the key will be the name of the referenced attribute instead than the operation name.
+         * The intend is to avoid querying the same geometry twice if the attribute is also specified
+         * explicitely in the array of properties.
+         *
+         * The map values will be the default Coordinate Reference System, or null if none.
+         */
+        boolean characterizedByCRS = false;
+        final Map<String,CoordinateReferenceSystem> names = new LinkedHashMap<>(4);
+        for (IdentifiedType property : geometryAttributes) {
+            if (NameConvention.isGeometryAttribute(property)) {
+                final GenericName name = property.getName();
+                final String attributeName = (property instanceof LinkOperation)
+                                             ? ((LinkOperation) property).referentName : name.toString();
+                final boolean isDefault = NameConvention.DEFAULT_GEOMETRY_PROPERTY.equals(name.tip());
+                if (isDefault) {
+                    defaultGeometry = attributeName;
+                }
+                CoordinateReferenceSystem attributeCRS = null;
+                while (property instanceof Operation) {
+                    property = ((Operation) property).getResult();
+                }
+                /*
+                 * At this point 'property' is an attribute, otherwise isGeometryAttribute(property) would have
+                 * returned false. Set 'characterizedByCRS' to true if we find at least one attribute which may
+                 * have the "CRS" characteristic. Note that we can not rely on 'attributeCRS' being non-null
+                 * because an attribute may be characterized by a CRS without providing default CRS.
+                 */
+                final AttributeType<?> at = ((AttributeType<?>) property).characteristics().get(characteristicName);
+                if (at != null && CoordinateReferenceSystem.class.isAssignableFrom(at.getValueClass())) {
+                    attributeCRS = (CoordinateReferenceSystem) at.getDefaultValue();              // May still null.
+                    if (crs == null && isDefault) {
+                        crs = attributeCRS;
+                    }
+                    characterizedByCRS = true;
+                }
+                names.putIfAbsent(attributeName, attributeCRS);
+            }
+        }
+        /*
+         * Copy the names in an array with the default geometry first. If possible, find the coordinate operations
+         * now in order to avoid the potentially costly call to CRS.findOperation(…) for each feature on which this
+         * EnvelopeOperation will be applied.
+         */
+        names.remove(null);                                                                     // Paranoiac safety.
+        attributeNames = new String[names.size()];
+        attributeToCRS = characterizedByCRS ? new CoordinateOperation[attributeNames.length] : null;
+        int n = (defaultGeometry == null) ? 0 : 1;
+        for (final Map.Entry<String,CoordinateReferenceSystem> entry : names.entrySet()) {
+            final int i;
+            final String name = entry.getKey();
+            if (name.equals(defaultGeometry)) {
+                defaultGeometry = null;
+                i = 0;
+            } else {
+                i = n++;
+            }
+            attributeNames[i] = name;
+            if (characterizedByCRS) {
+                final CoordinateReferenceSystem value = entry.getValue();
+                if (value != null) {
+                    if (crs == null) {
+                        crs = value;                                    // Fallback if default geometry has no CRS.
+                    }
+                    final CoordinateOperation op = CRS.findOperation(value, crs, null);
+                    if (!op.getMathTransform().isIdentity()) {
+                        attributeToCRS[i] = op;
+                    }
+                }
+            }
+        }
+        resultType = FeatureOperations.POOL.unique(new DefaultAttributeType<>(
+                resultIdentification(identification), Envelope.class, 1, 1, null));
         this.crs = crs;
     }
 
     /**
-     * Bounds operation do not require any parameter.
+     * Returns an empty group of parameters since this operation does not require any parameter.
      *
      * @return empty parameter group.
      */
@@ -96,108 +215,165 @@ final class BoundsOperation extends Abst
     }
 
     /**
-     * Bounds operation generates a Envelope result, or {@code null}.
+     * Returns the type of results computed by this operation, which is {@code AttributeType<Envelope>}.
+     * The attribute type name depends on the value of {@code "result.*"} properties (if any)
+     * given at construction time.
      *
-     * @return bounds envelope type
+     * @return an {@code AttributeType<Envelope>}.
      */
     @Override
     public IdentifiedType getResult() {
-        return TYPE;
+        return resultType;
+    }
+
+    /**
+     * Returns the names of feature properties that this operation needs for performing its task.
+     */
+    @Override
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
+    public synchronized Set<String> getDependencies() {
+        if (dependencies == null) {
+            dependencies = CollectionsExt.immutableSet(true, attributeNames);
+        }
+        return dependencies;
     }
 
     /**
-     * {@inheritDoc }
+     * Returns an attribute whose value is the union of the envelopes of all geometries in the given feature
+     * found in properties specified at construction time.
      *
-     * @param  feature    The feature on which to execute the operation.
-     *                    Can not be {@code null}.
-     * @param  parameters The parameters to use for executing the operation.
-     *                    Can be {@code null}.
-     * @return The operation result, never null.
+     * @param  feature     the feature on which to execute the operation.
+     * @param  parameters  ignored (can be {@code null}).
+     * @return the envelope of geometries in feature property values.
      */
     @Override
     public Property apply(Feature feature, ParameterValueGroup parameters) {
-        return new BoundsAttribute(feature);
+        return new Result(feature);
     }
 
+
+
+
     /**
-     * Operation attribute.
+     * The attributes that contains the result of union of all envelope extracted from other attributes.
      * Value is calculated each time it is accessed.
      */
-    private final class BoundsAttribute extends AbstractAttribute<Envelope> {
-
+    private final class Result extends AbstractAttribute<Envelope> {
+        /**
+         * For cross-version compatibility.
+         */
+        private static final long serialVersionUID = 926172863066901618L;
+
+        /**
+         * The feature specified to the {@link StringJoinOperation#apply(Feature, ParameterValueGroup)} method.
+         */
         private final Feature feature;
 
-        public BoundsAttribute(final Feature feature) {
-            super(TYPE);
+        /**
+         * Creates a new attribute for the given feature.
+         */
+        Result(final Feature feature) {
+            super(resultType);
             this.feature = feature;
         }
 
+        /**
+         * Computes an envelope which is the union of envelope of geometry values of all properties
+         * specified to the {@link EnvelopeOperation} constructor.
+         *
+         * @return the union of envelopes of all geometries in the attribute specified to the constructor,
+         *         or {@code null} if none.
+         */
         @Override
-        public Envelope getValue() throws MultiValuedPropertyException {
-            try {
-                return calculate(feature, crs);
-            } catch (TransformException ex) {
-                Logger.getLogger("org.apache.sis.feature").log(Level.WARNING, ex.getLocalizedMessage(), ex);
+        public Envelope getValue() throws IllegalStateException {
+            final String[] attributeNames = EnvelopeOperation.this.attributeNames;
+            GeneralEnvelope envelope = null;                                        // Union of all envelopes.
+            for (int i=0; i<attributeNames.length; i++) {
+                Envelope genv;                                                      // Envelope of a single geometry.
+                final String name = attributeNames[i];
+                if (attributeToCRS == null) {
+                    /*
+                     * If there is no CRS characteristic on any of the properties to query, then invoke the
+                     * Feature.getPropertyValue(String) method instead than Feature.getProperty(String) in
+                     * order to avoid forcing DenseFeature and SparseFeature implementations to wrap the
+                     * property values into real property instances. This is an optimization for reducing
+                     * the amount of objects to create.
+                     */
+                    genv = Geometries.getEnvelope(feature.getPropertyValue(name));
+                    if (genv == null) continue;
+                } else {
+                    /*
+                     * If there is at least one CRS characteristic to query, then we need the full Property instance.
+                     * We do not distinguish which particular property may have a CRS characteristic because SIS 0.7
+                     * implementations of DenseFeature and SparseFeature have a "all of nothing" behavior anyway.
+                     */
+                    final Property property = feature.getProperty(name);
+                    genv = Geometries.getEnvelope(property.getValue());
+                    if (genv == null) continue;
+                    /*
+                     * Get the CRS characteristic if present. Most of the time, 'at' will be null and we will
+                     * fallback on the 'attributeToCRS' operations computed at construction time. In the rare
+                     * cases where a CRS characteristic is associated to a particular feature, we will let
+                     * Envelopes.transform(…) searches a coordinate operation.
+                     */
+                    final Attribute<?> at = ((Attribute<?>) property).characteristics()
+                                    .get(NameConvention.CRS_CHARACTERISTIC.toString());
+                    try {
+                        if (at == null) {
+                            final CoordinateOperation op = attributeToCRS[i];
+                            if (op != null) {                           // Null operation means identity transform.
+                                genv = Envelopes.transform(op, genv);
+                            }
+                        } else {                                                        // Should be a rare case.
+                            final Object geomCRS = at.getValue();
+                            if (!(geomCRS instanceof CoordinateReferenceSystem)) {
+                                throw new IllegalStateException(Errors.format(Errors.Keys.UnspecifiedCRS));
+                            }
+                            ((GeneralEnvelope) genv).setCoordinateReferenceSystem((CoordinateReferenceSystem) geomCRS);
+                            genv = Envelopes.transform(genv, crs);
+                        }
+                    } catch (TransformException e) {
+                        throw new IllegalStateException(Errors.format(Errors.Keys.CanNotTransformEnvelope), e);
+                    }
+                }
+                if (envelope == null) {
+                    envelope = GeneralEnvelope.castOrCopy(genv);        // Should always be a cast without copy.
+                } else {
+                    envelope.add(genv);
+                }
             }
-            return null;
+            return envelope;
         }
 
+        /**
+         * Unconditionally throws an {@link UnsupportedOperationException}.
+         */
         @Override
         public void setValue(Envelope value) {
-            throw new UnsupportedOperationException("Bounds operation attribute can not be set.");
+            throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, Attribute.class));
         }
-
     }
 
-    GeneralEnvelope calculate(Feature feature, CoordinateReferenceSystem crs) throws TransformException {
-
-        GeneralEnvelope bounds = null;
-
-        final FeatureType type = feature.getType();
-        for(PropertyType pt : type.getProperties(true)){
-            if(!pt.getName().equals(NameConvention.DEFAULT_GEOMETRY_PROPERTY)){
-                if(!NameConvention.isGeometryAttribute(pt)) continue;
-            }
-
-            final Object val = feature.getPropertyValue(pt.getName().toString());
-
-            if(val instanceof Geometry){
-                final Geometry geom = (Geometry)val;
+    /**
+     * Computes a hash-code value for this operation.
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + Arrays.hashCode(attributeNames) + Arrays.hashCode(attributeToCRS);
+    }
 
-                final com.esri.core.geometry.Envelope env = new com.esri.core.geometry.Envelope();
-                geom.queryEnvelope(env);
-                if(env.isEmpty()) continue;
-
-                //extract geometry enveloppe
-                final CoordinateReferenceSystem geomCrs = NameConvention.getCoordinateReferenceSystem(pt);
-                Envelope genv;
-                if(geomCrs!=null){
-                    genv = new GeneralEnvelope(geomCrs);
-                }else{
-                    genv = new GeneralEnvelope(2);
-                }
-                ((GeneralEnvelope)genv).setRange(0, env.getXMin(), env.getXMax());
-                ((GeneralEnvelope)genv).setRange(1, env.getYMin(), env.getYMax());
-
-                //ensure it is in the wanted crs
-                if(crs!=null){
-                    genv = Envelopes.transform(genv, crs);
-                }
-
-                if(bounds==null){
-                    if(crs==null){
-                        bounds = (GeneralEnvelope)genv;
-                    }else{
-                        bounds = new GeneralEnvelope(crs);
-                        bounds.setEnvelope(genv);
-                    }
-                }else{
-                    bounds.add(genv);
-                }
-            }
+    /**
+     * Compares this operation with the given object for equality.
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (super.equals(obj)) {
+            // 'this.result' is compared (indirectly) by the super class.
+            final EnvelopeOperation that = (EnvelopeOperation) obj;
+            return Arrays.equals(attributeNames, that.attributeNames) &&
+                   Arrays.equals(attributeToCRS, that.attributeToCRS) &&
+                   Objects.equals(crs, that.crs);
         }
-
-        return bounds;
+        return false;
     }
-
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/FeatureOperations.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -18,6 +18,7 @@ package org.apache.sis.feature;
 
 import java.util.Map;
 import org.opengis.util.GenericName;
+import org.opengis.util.FactoryException;
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.util.ArgumentChecks;
@@ -80,17 +81,17 @@ import org.opengis.feature.PropertyType;
  *   <tr>
  *     <td>"result.definition"</td>
  *     <td>{@link InternationalString} or {@link String}</td>
- *     <td>{@link AbstractAttribute#getDefinition() Attribute.getDefinition()} on the {@linkplain AbstractOperation#getResult() result}</td>
+ *     <td>{@link DefaultAttributeType#getDefinition() Attribute.getDefinition()} on the {@linkplain AbstractOperation#getResult() result}</td>
  *   </tr>
  *   <tr>
  *     <td>"result.designation"</td>
  *     <td>{@link InternationalString} or {@link String}</td>
- *     <td>{@link AbstractAttribute#getDesignation() Attribute.getDesignation()} on the {@linkplain AbstractOperation#getResult() result}</td>
+ *     <td>{@link DefaultAttributeType#getDesignation() Attribute.getDesignation()} on the {@linkplain AbstractOperation#getResult() result}</td>
  *   </tr>
  *   <tr>
  *     <td>"result.description"</td>
  *     <td>{@link InternationalString} or {@link String}</td>
- *     <td>{@link AbstractAttribute#getDescription() Attribute.getDescription()} on the {@linkplain AbstractOperation#getResult() result}</td>
+ *     <td>{@link DefaultAttributeType#getDescription() Attribute.getDescription()} on the {@linkplain AbstractOperation#getResult() result}</td>
  *   </tr>
  *   <tr>
  *     <td>{@value org.apache.sis.referencing.AbstractIdentifiedObject#LOCALE_KEY}</td>
@@ -225,13 +226,41 @@ public final class FeatureOperations ext
     }
 
     /**
-     * Creates a calculate bounds operation type.
+     * Creates an operation computing the envelope that encompass all geometries found in the given attributes.
+     * Geometries can be in different coordinate reference systems; they will be transformed to the first non-null
+     * CRS in the following choices:
+     *
+     * <ol>
+     *   <li>the CRS specified to this method,</li>
+     *   <li>the CRS of the default geometry, or</li>
+     *   <li>the CRS of the first non-empty geometry.</li>
+     * </ol>
+     *
+     * The {@linkplain AbstractOperation#getResult() result} of this operation is an {@code Attribute}
+     * with values of type {@link org.opengis.geometry.Envelope}. If the {@code crs} argument given to
+     * this method is non-null, then the
+     * {@linkplain org.apache.sis.geometry.GeneralEnvelope#getCoordinateReferenceSystem() envelope CRS}
+     * will be that CRS.
+     *
+     * <div class="section">Limitations</div>
+     * If a geometry contains other geometries, this operation queries only the envelope of the root geometry.
+     * It is the root geometry responsibility to take in account the envelope of all its children.
      *
-     * @param  identification  the name and other information to be given to the operation.
-     * @param  baseCRS         created envelope CRS.
-     * @return Operation
+     * <div class="section">Read/write behavior</div>
+     * This operation is read-only. Calls to {@code Attribute.setValue(Envelope)} will result in an
+     * {@link IllegalStateException} to be thrown.
+     *
+     * @param  identification     the name and other information to be given to the operation.
+     * @param  crs                the Coordinate Reference System in which to express the envelope, or {@code null}.
+     * @param  geometryAttributes the operation or attribute type from which to get geometry values.
+     *                            Any element which is {@code null} or has a non-geometric value class will be ignored.
+     * @return an operation which will compute the envelope encompassing all geometries in the given attributes.
+     * @throws FactoryException if a coordinate operation to the target CRS can not be created.
      */
-    public static Operation bounds(final Map<String,?> identification, CoordinateReferenceSystem baseCRS) {
-        return new BoundsOperation(identification, baseCRS);
+    public static Operation envelope(final Map<String,?> identification, final CoordinateReferenceSystem crs,
+            final PropertyType... geometryAttributes) throws FactoryException
+    {
+        ArgumentChecks.ensureNonNull("geometryAttributes", geometryAttributes);
+        return POOL.unique(new EnvelopeOperation(identification, crs, geometryAttributes));
     }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/feature/StringJoinOperation.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -168,7 +168,7 @@ final class StringJoinOperation extends
     }
 
     /**
-     * Concatenate operation do not require any parameter.
+     * Returns an empty group of parameters since this operation does not require any parameter.
      *
      * @return empty parameter group.
      */
@@ -178,9 +178,11 @@ final class StringJoinOperation extends
     }
 
     /**
-     * Concatenate operation generates a {@link String} result.
+     * Returns the type of results computed by this operation, which is {@code AttributeType<String>}.
+     * The attribute type name depends on the value of {@code "result.*"} properties (if any)
+     * given at construction time.
      *
-     * @return concatenated string type.
+     * @return an {@code AttributeType<String>}.
      */
     @Override
     public IdentifiedType getResult() {

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FeatureTypeBuilder.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -690,13 +690,14 @@ public class FeatureTypeBuilder {
                 throw new IllegalArgumentException("Property "+defGeomAttribute+" used in default geometry does not exist");
             }
             final PropertyType geomAtt = properties.get(defGeomAttribute);
-            final CoordinateReferenceSystem crs = NameConvention.getCoordinateReferenceSystem(geomAtt);
+            final CoordinateReferenceSystem crs = null; // TODO NameConvention.getCoordinateReferenceSystem(geomAtt);
             final Operation att = FeatureOperations.link(
                     Collections.singletonMap(AbstractOperation.NAME_KEY, DEFAULT_GEOMETRY_PROPERTY), geomAtt);
             properties.put(DEFAULT_GEOMETRY_PROPERTY, att);
 
-            final Operation boundAtt = FeatureOperations.bounds(Collections.singletonMap(AbstractOperation.NAME_KEY, ENVELOPE_PROPERTY), crs);
-            properties.put(ENVELOPE_PROPERTY, boundAtt);
+            // TODO
+//            final Operation boundAtt = FeatureOperations.bounds(Collections.singletonMap(AbstractOperation.NAME_KEY, ENVELOPE_PROPERTY), null, crs);
+//            properties.put(ENVELOPE_PROPERTY, boundAtt);
 
         }
 

Added: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java?rev=1739766&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java (added)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.feature;
+
+import com.esri.core.geometry.Geometry;
+import com.esri.core.geometry.Envelope2D;
+import org.apache.sis.geometry.GeneralEnvelope;
+import org.apache.sis.util.Static;
+
+
+/**
+ * Utility methods on geometric objects defined in libraries outside Apache SIS.
+ * We use this class for isolating dependencies from the {@code org.apache.feature} package
+ * to ESRI's API or to Java Topology Suite (JTS) API.
+ * This gives us a single place to review if we want to support different geometry libraries,
+ * or if Apache SIS come with its own implementation.
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+public final class Geometries extends Static {
+    /**
+     * Do not allow instantiation of this class.
+     */
+    private Geometries() {
+    }
+
+    /**
+     * Returns {@code true} if the given type is one of the type known to Apache SIS.
+     *
+     * @param  type  the type to verify.
+     * @return {@code true} if the given type is one of the geometry type known to SIS.
+     */
+    public static boolean isKnownType(final Class<?> type) {
+        return Geometry.class.isAssignableFrom(type);
+    }
+
+    /**
+     * If the given object is one of the recognized type and its envelope is non-empty,
+     * returns that envelope as an Apache SIS implementation. Otherwise returns {@code null}.
+     *
+     * @param  geometry  the geometry from which to get the envelope, or {@code null}.
+     * @return the envelope of the given object, or {@code null} if the object is not
+     *         a recognized geometry or its envelope is empty.
+     */
+    public static GeneralEnvelope getEnvelope(final Object geometry) {
+        if (geometry instanceof Geometry) {
+            final Envelope2D bounds = new Envelope2D();
+            ((Geometry) geometry).queryEnvelope2D(bounds);
+            if (!bounds.isEmpty()) {                                    // Test if there is NaN values.
+                final GeneralEnvelope env = new GeneralEnvelope(2);
+                env.setRange(0, bounds.xmin, bounds.xmax);
+                env.setRange(1, bounds.ymin, bounds.ymax);
+                return env;
+            }
+        }
+        return null;
+    }
+}

Propchange: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Geometries.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Modified: sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/NameConvention.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/NameConvention.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/NameConvention.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/main/java/org/apache/sis/internal/feature/NameConvention.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.internal.feature;
 
-import com.esri.core.geometry.Geometry;
 import org.opengis.util.LocalName;
 import org.opengis.util.ScopedName;
 import org.opengis.util.GenericName;
@@ -28,10 +27,11 @@ 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.PropertyType;
+import org.opengis.feature.Property;
 
 
 /**
@@ -100,12 +100,12 @@ public final class NameConvention extend
      * <p>Properties of this name are usually {@linkplain org.apache.sis.feature.FeatureOperations#link
      * operations acting as a redirection to another attribute}.</p>
      *
-     * <p>The {@linkplain org.apache.sis.feature.DefaultAttributeType#getValueClass() value class} can be the
-     * {@link Geometry} class from ESRI's API, or the {@code Geometry} class from <cite>Java Topology Suite</cite>
-     * (JTS) library, or any other class defined in future SIS versions. See {@link #isGeometryAttribute(PropertyType)}
-     * for testing whether the value is a supported type.</p>
+     * <p>The {@linkplain org.apache.sis.feature.DefaultAttributeType#getValueClass() value class} can be
+     * the {@link com.esri.core.geometry.Geometry} class from ESRI's API, or the {@code Geometry} class from
+     * <cite>Java Topology Suite</cite> (JTS) library, or any other class defined in future SIS versions.
+     * See {@link #isGeometryAttribute(IdentifiedType)} for testing whether the value is a supported type.</p>
      *
-     * @see #isGeometryAttribute(PropertyType)
+     * @see #isGeometryAttribute(IdentifiedType)
      */
     public static final LocalName DEFAULT_GEOMETRY_PROPERTY;
 
@@ -165,7 +165,7 @@ public final class NameConvention extend
         NAMESPACE                     = factory.createGenericName(null, "Apache", Constants.SIS);
         NameSpace ns                  = factory.createNameSpace(NAMESPACE, null);
         ID_PROPERTY                   = factory.createLocalName(ns, "@identifier");
-        DEFAULT_GEOMETRY_PROPERTY     = factory.createLocalName(ns, "@defaultGeometry");
+        DEFAULT_GEOMETRY_PROPERTY     = factory.createLocalName(ns, "@geometry");
         ENVELOPE_PROPERTY             = factory.createLocalName(ns, "@envelope");
         CRS_CHARACTERISTIC            = factory.createLocalName(ns, "@crs");
         MAXIMAL_LENGTH_CHARACTERISTIC = factory.createLocalName(ns, "@maximalLength");
@@ -225,49 +225,102 @@ public final class NameConvention extend
         while (type instanceof Operation) {
             type = ((Operation) type).getResult();
         }
-        if (type instanceof AttributeType<?>) {
-            final Class<?> valueClass = ((AttributeType<?>) type).getValueClass();
-            return Geometry.class.isAssignableFrom(valueClass);
-        }
-        return false;
+        return (type instanceof AttributeType<?>) && Geometries.isKnownType(((AttributeType<?>) type).getValueClass());
     }
 
     /**
-     * Returns the coordinate reference systems associated to the given operation or attribute type,
-     * or {@code null} if none. This method searches for a characteristic named {@link #CRS_CHARACTERISTIC}.
+     * Returns whether the given operation or attribute type is characterized by a coordinate reference system.
+     * This method verifies whether a characteristic named {@link #CRS_CHARACTERISTIC} with values assignable to
+     * {@link CoordinateReferenceSystem} exists (directly or indirectly) for the given type.
      *
      * @param  type  the operation or attribute type for which to get the CRS, or {@code null}.
-     * @return The Coordinate Reference System for the given type, or {@code null} if none.
+     * @return {@code true} if a characteristic for Coordinate Reference System has been found.
+     */
+    public static boolean characterizedByCRS(final IdentifiedType type) {
+        return hasCharacteristic(type, CRS_CHARACTERISTIC.toString(), CoordinateReferenceSystem.class);
+    }
+
+    /**
+     * Returns the Coordinate Reference Systems characteristic for the given attribute, or {@code null} if none.
+     * This method gets the value or default value from the characteristic named {@link #CRS_CHARACTERISTIC}.
+     *
+     * @param  attribute  the attribute for which to get the CRS, or {@code null}.
+     * @return The Coordinate Reference System characteristic of the given attribute, or {@code null} if none.
      * @throws ClassCastException if {@link #CRS_CHARACTERISTIC} has been found but is associated
      *         to an object which is not a {@link CoordinateReferenceSystem} instance.
      */
-    public static CoordinateReferenceSystem getCoordinateReferenceSystem(IdentifiedType type) {
+    public static CoordinateReferenceSystem getCrsCharacteristic(final Property attribute) {
+        return (CoordinateReferenceSystem) getCharacteristic(attribute, CRS_CHARACTERISTIC.toString());
+    }
+
+    /**
+     * Returns whether the given operation or attribute type is characterized by a maximal length.
+     * This method verifies whether a characteristic named {@link #MAXIMAL_LENGTH_CHARACTERISTIC}
+     * with values of class {@link Integer} exists (directly or indirectly) for the given type.
+     *
+     * @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) {
+        return hasCharacteristic(type, MAXIMAL_LENGTH_CHARACTERISTIC.toString(), Integer.class);
+    }
+
+    /**
+     * Returns the maximal length characteristic for the given attribute, or {@code null} if none.
+     * This method gets the value or default value from the characteristic named {@link #MAXIMAL_LENGTH_CHARACTERISTIC}.
+     *
+     * @param  attribute  the attribute for which to get the CRS, or {@code null}.
+     * @return The Coordinate Reference System characteristic of the given attribute, or {@code null} if none.
+     * @throws ClassCastException if {@link #MAXIMAL_LENGTH_CHARACTERISTIC} has been found but is associated
+     *         to an object which is not an {@link Integer} instance.
+     */
+    public static Integer getMaximalLengthCharacteristic(final Property attribute) {
+        return (Integer) getCharacteristic(attribute, MAXIMAL_LENGTH_CHARACTERISTIC.toString());
+    }
+
+    /**
+     * Returns {@code true} if the given operation or attribute type has a characteristic of the given name,
+     * and the values of that characteristic are assignable to the given {@code valueClass}.
+     *
+     * @param  type        the operation or attribute type for which to test the existence of a characteristic.
+     * @param  name        the name of the characteristic to test.
+     * @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();
         }
         if (type instanceof AttributeType<?>) {
-            final AttributeType<?> at = ((AttributeType<?>) type).characteristics().get(CRS_CHARACTERISTIC.toString());
+            final AttributeType<?> at = ((AttributeType<?>) type).characteristics().get(name);
             if (at != null) {
-                return (CoordinateReferenceSystem) at.getDefaultValue();
+                return valueClass.isAssignableFrom(at.getValueClass());
             }
         }
-        return null;
+        return false;
     }
 
     /**
-     * Returns the maximal string length associated to the given attribute type, or {@code null} if none.
-     * This method searches for a characteristic named {@link #MAXIMAL_LENGTH_CHARACTERISTIC}.
-     *
-     * @param  type  the attribute type for which to get the maximal string length, or {@code null}.
-     * @return The maximal string length for the given type, or {@code null} if none.
-     * @throws ClassCastException if {@link #MAXIMAL_LENGTH_CHARACTERISTIC} has been found
-     *         but is associated to an object which is not an {@link Integer} instance.
-     */
-    public static Integer getMaximalLength(final AttributeType<?> type){
-        if (type != null) {
-            final AttributeType<?> at = type.characteristics().get(MAXIMAL_LENGTH_CHARACTERISTIC.toString());
+     * Fetches from the given property the value or default value of the named characteristic.
+     * If the given property is null, or is not an attribute, or does not have characteristics
+     * of the given name, then this method returns {@code null}.
+     *
+     * @param  attribute  the attribute from which to get the characteristic value or default value, or {@code null}.
+     * @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);
             if (at != null) {
-                return (Integer) at.getDefaultValue();
+                final Object value = at.getValue();
+                if (value != null) {
+                    return value;
+                }
+            }
+            final AttributeType<?> type = ((Attribute<?>) attribute).getType().characteristics().get(name);
+            if (type != null) {
+                return type.getDefaultValue();
             }
         }
         return null;

Copied: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java (from r1739765, sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/BoundsOperationTest.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java?p2=sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java&p1=sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/BoundsOperationTest.java&r1=1739765&r2=1739766&rev=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/BoundsOperationTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/EnvelopeOperationTest.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -16,116 +16,159 @@
  */
 package org.apache.sis.feature;
 
+import java.util.Arrays;
+import java.util.Map;
 import java.util.Collections;
 import com.esri.core.geometry.Point;
 import com.esri.core.geometry.Polygon;
+import org.opengis.geometry.Envelope;
+import org.opengis.util.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.internal.feature.NameConvention;
+import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.geometry.GeneralEnvelope;
-import org.apache.sis.referencing.CommonCRS;
+
+// Test dependencies
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
-import org.apache.sis.util.iso.Names;
-import org.apache.sis.internal.feature.FeatureTypeBuilder;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.apache.sis.test.ReferencingAssert.*;
+
+// Branch-dependent imports
+import org.opengis.feature.PropertyType;
 
 
 /**
- * Tests {@link BoundsOperation}.
+ * Tests {@link EnvelopeOperation}.
  *
  * @author  Johann Sorel (Geomatys)
  * @since   0.7
  * @version 0.7
  * @module
  */
-@DependsOn({
-    AbstractOperationTest.class,
-    DenseFeatureTest.class
-})
-public final strictfp class BoundsOperationTest extends TestCase {
+@DependsOn(LinkOperationTest.class)
+public final strictfp class EnvelopeOperationTest extends TestCase {
     /**
      * Creates a feature type with a bounds operation.
      * The feature contains the following properties:
      *
      * <ul>
-     *   <li>{@code name} as a  {@link String}</li>
+     *   <li>{@code name} as a {@link String}</li>
      *   <li>{@code classes} as a {@link Polygon}</li>
      *   <li>{@code climbing wall} as a {@link Point}</li>
      *   <li>{@code gymnasium} as a {@link Polygon}</li>
+     *   <li>{@code @geometry} as a link to the default geometry</li>
      *   <li>{@code bounds} as the feature envelope attribute.</li>
      * </ul>
      *
-     * @return The feature for a city.
+     * @param  defaultGeometry 1 for using "classes" as the default geometry, or 3 for "gymnasium".
+     * @return the feature for a school.
+     */
+    private static DefaultFeatureType school(final int defaultGeometry) throws FactoryException {
+        final DefaultAttributeType<?> standardCRS = new DefaultAttributeType<>(
+                name(NameConvention.CRS_CHARACTERISTIC), CoordinateReferenceSystem.class, 1, 1, HardCodedCRS.WGS84_φλ);
+
+        final DefaultAttributeType<?> normalizedCRS = new DefaultAttributeType<>(
+                name(NameConvention.CRS_CHARACTERISTIC), CoordinateReferenceSystem.class, 1, 1, HardCodedCRS.WGS84);
+
+        final PropertyType[] attributes = {
+            new DefaultAttributeType<>(name("name"),          String.class,  1, 1, null),
+            new DefaultAttributeType<>(name("classes"),       Polygon.class, 1, 1, null, standardCRS),
+            new DefaultAttributeType<>(name("climbing wall"), Point.class,   1, 1, null, standardCRS),
+            new DefaultAttributeType<>(name("gymnasium"),     Polygon.class, 1, 1, null, normalizedCRS),
+            null,
+            null
+        };
+        attributes[4] = FeatureOperations.link(name(NameConvention.DEFAULT_GEOMETRY_PROPERTY), attributes[defaultGeometry]);
+        attributes[5] = FeatureOperations.envelope(name("bounds"), null, attributes);
+        return new DefaultFeatureType(name("school"), false, null, attributes);
+    }
+
+    /**
+     * Creates a map of identification properties containing only an entry for the given name.
      */
-    private static DefaultFeatureType school() {
-        //Create type with an aggregation
-        final FeatureTypeBuilder ftb = new FeatureTypeBuilder();
-        ftb.setName("school");
-        ftb.addProperty("name", String.class);
-        ftb.addProperty("classes", Polygon.class, CommonCRS.WGS84.geographic());
-        ftb.addProperty("climbing wall", Point.class, CommonCRS.WGS84.geographic());
-        ftb.addProperty("gymnasium", Polygon.class, CommonCRS.WGS84.normalizedGeographic());
-        ftb.addProperty(FeatureOperations.bounds(
-                Collections.singletonMap(AbstractOperation.NAME_KEY, Names.parseGenericName(null, ":", "bounds")),
-                CommonCRS.WGS84.geographic()));
-        return ftb.build();
+    private static Map<String,?> name(final Object name) {
+        return Collections.singletonMap(DefaultAttributeType.NAME_KEY, name);
+    }
+
+    /**
+     * Tests the constructor. The set of attributes on which the operation depends shall include
+     * "classes", "climbing wall" and "gymnasium" but not "name" since the later does not contain
+     * a geometry. Furthermore the default CRS shall be {@code HardCodedCRS.WGS84}, not
+     * {@code HardCodedCRS.WGS84_φλ}, because this test uses "gymnasium" as the default geometry.
+     *
+     * @throws FactoryException if an error occurred while searching for the coordinate operations.
+     */
+    @Test
+    public void testConstruction() throws FactoryException {
+        final PropertyType property = school(3).getProperty("bounds");
+        assertInstanceOf("bounds", EnvelopeOperation.class, property);
+        final EnvelopeOperation op = (EnvelopeOperation) property;
+        assertSame("crs", HardCodedCRS.WGS84, op.crs);
+        assertSetEquals(Arrays.asList("classes", "climbing wall", "gymnasium"), op.getDependencies());
     }
 
     /**
      * Implementation of the test methods.
      */
     private static void run(final AbstractFeature feature) {
-        GeneralEnvelope bounds;
+        assertNull("Before a geometry is set", feature.getPropertyValue("bounds"));
+        GeneralEnvelope expected;
 
-        //no geometry set
-        assertNull(feature.getPropertyValue("bounds"));
-
-        //set one geometry
+        // Set one geometry
         Polygon classes = new Polygon();
         classes.startPath(10, 20);
         classes.lineTo(10, 30);
         classes.lineTo(15, 30);
         classes.lineTo(15, 20);
         feature.setPropertyValue("classes", classes);
-        bounds = new GeneralEnvelope(CommonCRS.WGS84.geographic());
-        bounds.setRange(0, 10, 15);
-        bounds.setRange(1, 20, 30);
-        assertEquals(bounds,feature.getPropertyValue("bounds"));
+        expected = new GeneralEnvelope(HardCodedCRS.WGS84_φλ);
+        expected.setRange(0, 10, 15);
+        expected.setRange(1, 20, 30);
+        assertEnvelopeEquals(expected, (Envelope) feature.getPropertyValue("bounds"));
 
-        //set second geometry
+        // Set second geometry
         Point wall = new Point(18, 40);
         feature.setPropertyValue("climbing wall", wall);
-        bounds = new GeneralEnvelope(CommonCRS.WGS84.geographic());
-        bounds.setRange(0, 10, 18);
-        bounds.setRange(1, 20, 40);
-        assertEquals(bounds,feature.getPropertyValue("bounds"));
+        expected = new GeneralEnvelope(HardCodedCRS.WGS84_φλ);
+        expected.setRange(0, 10, 18);
+        expected.setRange(1, 20, 40);
+        assertEnvelopeEquals(expected, (Envelope) feature.getPropertyValue("bounds"));
 
-        //set third geometry, this geometry has crs axis reversed
+        // Set third geometry. This geometry has CRS axis order reversed.
         Polygon gymnasium = new Polygon();
         gymnasium.startPath(-5, -30);
         gymnasium.lineTo(-6, -30);
         gymnasium.lineTo(-6, -31);
         gymnasium.lineTo(-5, -31);
         feature.setPropertyValue("gymnasium", gymnasium);
-        bounds = new GeneralEnvelope(CommonCRS.WGS84.geographic());
-        bounds.setRange(0, -31, 18);
-        bounds.setRange(1, -6, 40);
-        assertEquals(bounds,feature.getPropertyValue("bounds"));
+        expected = new GeneralEnvelope(HardCodedCRS.WGS84_φλ);
+        expected.setRange(0, -31, 18);
+        expected.setRange(1,  -6, 40);
+        assertEnvelopeEquals(expected, (Envelope) feature.getPropertyValue("bounds"));
     }
 
     /**
      * Tests a dense type with operations.
+     *
+     * @throws FactoryException if an error occurred while searching for the coordinate operations.
      */
     @Test
-    public void testDenseFeature() {
-        run(new DenseFeature(school()));
+    @DependsOnMethod("testConstruction")
+    public void testDenseFeature() throws FactoryException {
+        run(new DenseFeature(school(1)));
     }
 
     /**
      * Tests a sparse feature type with operations.
+     *
+     * @throws FactoryException if an error occurred while searching for the coordinate operations.
      */
     @Test
-    public void testSparseFeature() {
-        run(new SparseFeature(school()));
+    @DependsOnMethod("testConstruction")
+    public void testSparseFeature() throws FactoryException {
+        run(new SparseFeature(school(2)));
     }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/feature/StringJoinOperationTest.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -39,10 +39,7 @@ import org.opengis.feature.InvalidProper
  * @version 0.7
  * @module
  */
-@DependsOn({
-    AbstractOperationTest.class,
-    DenseFeatureTest.class
-})
+@DependsOn(LinkOperationTest.class)
 public final strictfp class StringJoinOperationTest extends TestCase {
     /**
      * Creates a feature type with an string join operation.

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeTypeBuilderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeTypeBuilderTest.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeTypeBuilderTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/AttributeTypeBuilderTest.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -21,6 +21,7 @@ import org.junit.Test;
 import org.opengis.feature.AttributeType;
 import static org.junit.Assert.*;
 
+
 /**
  * Tests {@link AttributeTypeBuilder}.
  *
@@ -48,7 +49,7 @@ public class AttributeTypeBuilderTest ex
         }
 
         atb.setName("myScope","myName");
-        final AttributeType att = atb.build();
+        final AttributeType<?> att = atb.build();
 
         assertEquals("myScope:myName", att.getName().toString());
         assertEquals(Object.class, att.getValueClass());
@@ -58,7 +59,7 @@ public class AttributeTypeBuilderTest ex
         assertEquals(null, att.getDesignation());
         assertEquals(1, att.getMinimumOccurs());
         assertEquals(1, att.getMaximumOccurs());
-        
+
     }
 
     /**
@@ -77,7 +78,7 @@ public class AttributeTypeBuilderTest ex
         atb.setMinimumOccurs(10);
         atb.setMaximumOccurs(60);
         atb.setLengthCharacteristic(80);
-        final AttributeType att = atb.build();
+        final AttributeType<?> att = atb.build();
 
         assertEquals("myScope:myName", att.getName().toString());
         assertEquals("test definition", att.getDefinition().toString());
@@ -87,7 +88,7 @@ public class AttributeTypeBuilderTest ex
         assertEquals("test text with words and letters.", att.getDefaultValue());
         assertEquals(10, att.getMinimumOccurs());
         assertEquals(60, att.getMaximumOccurs());
-        assertEquals(80, (int)NameConvention.getMaximalLength(att));
+//      assertEquals(Integer.valueOf(80), NameConvention.getMaximalLengthCharacteristic(att));
     }
 
     /**
@@ -106,7 +107,7 @@ public class AttributeTypeBuilderTest ex
         atb.setMinimumOccurs(10);
         atb.setMaximumOccurs(60);
         atb.setLengthCharacteristic(80);
-        AttributeType att = atb.build();
+        AttributeType<?> att = atb.build();
 
         //copy the attribute
         atb = new AttributeTypeBuilder();
@@ -121,7 +122,7 @@ public class AttributeTypeBuilderTest ex
         assertEquals("test text with words and letters.", att.getDefaultValue());
         assertEquals(10, att.getMinimumOccurs());
         assertEquals(60, att.getMaximumOccurs());
-        assertEquals(80, (int)NameConvention.getMaximalLength(att));
+//      assertEquals(Integer.valueOf(80), NameConvention.getMaximalLengthCharacteristic(att));
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/NameConventionTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/NameConventionTest.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/NameConventionTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/internal/feature/NameConventionTest.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -29,7 +29,7 @@ import org.junit.Test;
 import static org.junit.Assert.*;
 
 // Branch-dependent imports
-import org.opengis.feature.AttributeType;
+import org.opengis.feature.Property;
 import org.opengis.feature.IdentifiedType;
 
 
@@ -37,6 +37,7 @@ import org.opengis.feature.IdentifiedTyp
  * Tests {@link NameConvention}.
  *
  * @author  Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
  * @since   0.7
  * @version 0.7
  * @module
@@ -67,13 +68,15 @@ public final strictfp class NameConventi
     }
 
     /**
-     * Tests {@link NameConvention#getCoordinateReferenceSystem(IdentifiedType)} method.
+     * Tests {@link NameConvention#characterizedByCRS(IdentifiedType)} and
+     * {@link NameConvention#getCrsCharacteristic(Property)} methods.
      */
     @Test
-    public void testGetCoordinateReferenceSystem() {
+    public void testGetCrsCharacteristic() {
         final Map<String,?> properties = Collections.singletonMap(DefaultAttributeType.NAME_KEY, "geometry");
         DefaultAttributeType<Point> type = new DefaultAttributeType<>(properties, Point.class, 1, 1, null);
-        assertNull("Without characteristic", NameConvention.getCoordinateReferenceSystem(type));
+        assertFalse("characterizedByCRS",  NameConvention.characterizedByCRS(type));
+        assertNull("getCrsCharacteristic", NameConvention.getCrsCharacteristic(type.newInstance()));
         /*
          * Creates an attribute associated to an attribute (i.e. a "characteristic") for storing
          * the Coordinate Reference System of the "geometry" attribute. Then test again.
@@ -83,17 +86,20 @@ public final strictfp class NameConventi
                 CoordinateReferenceSystem.class, 1, 1, HardCodedCRS.WGS84);
 
         type = new DefaultAttributeType<>(properties, Point.class, 1, 1, null, characteristic);
-        assertEquals(HardCodedCRS.WGS84, NameConvention.getCoordinateReferenceSystem(type));
+        assertTrue(NameConvention.characterizedByCRS(type));
+        assertEquals(HardCodedCRS.WGS84, NameConvention.getCrsCharacteristic(type.newInstance()));
     }
 
     /**
-     * Tests {@link NameConvention#getMaximalLength(AttributeType)} method.
+     * Tests {@link NameConvention#characterizedByMaximalLength(IdentifiedType)} and
+     * {@link NameConvention#getMaximalLengthCharacteristic(Property)} methods.
      */
     @Test
-    public void testGetMaximalLength() {
+    public void testGetMaximalLengthCharacteristic() {
         final Map<String,?> properties = Collections.singletonMap(DefaultAttributeType.NAME_KEY, "name");
         DefaultAttributeType<String> type = new DefaultAttributeType<>(properties, String.class, 1, 1, null);
-        assertNull("Without characteristic", NameConvention.getMaximalLength(type));
+        assertFalse("characterizedByMaximalLength",  NameConvention.characterizedByMaximalLength(type));
+        assertNull("getMaximalLengthCharacteristic", NameConvention.getMaximalLengthCharacteristic(type.newInstance()));
         /*
          * Creates an attribute associated to an attribute (i.e. a "characteristic") for storing
          * the maximal length of the "name" attribute. Then test again.
@@ -103,6 +109,7 @@ public final strictfp class NameConventi
                 Integer.class, 1, 1, 120);
 
         type = new DefaultAttributeType<>(properties, String.class, 1, 1, null, characteristic);
-        assertEquals(Integer.valueOf(120), NameConvention.getMaximalLength(type));
+        assertTrue("characterizedByMaximalLength", NameConvention.characterizedByMaximalLength(type));
+        assertEquals(Integer.valueOf(120), NameConvention.getMaximalLengthCharacteristic(type.newInstance()));
     }
 }

Modified: sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -45,7 +45,7 @@ import org.junit.BeforeClass;
     org.apache.sis.feature.AbstractOperationTest.class,
     org.apache.sis.feature.LinkOperationTest.class,
     org.apache.sis.feature.StringJoinOperationTest.class,
-    org.apache.sis.feature.BoundsOperationTest.class,
+    org.apache.sis.feature.EnvelopeOperationTest.class,
     org.apache.sis.feature.FeatureFormatTest.class,
     org.apache.sis.feature.FeaturesTest.class,
     org.apache.sis.filter.DefaultLiteralTest.class,

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java?rev=1739766&r1=1739765&r2=1739766&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java [UTF-8] Mon Apr 18 14:43:16 2016
@@ -35,6 +35,7 @@ import org.opengis.referencing.cs.Coordi
 import org.opengis.referencing.cs.RangeMeaning;
 import org.opengis.util.GenericName;
 import org.apache.sis.geometry.AbstractEnvelope;
+import org.apache.sis.geometry.Envelopes;
 import org.apache.sis.geometry.GeneralDirectPosition;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.referencing.IdentifiedObjects;
@@ -51,7 +52,7 @@ import static java.lang.StrictMath.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.6
+ * @version 0.7
  * @module
  */
 public strictfp class ReferencingAssert extends MetadataAssert {
@@ -66,8 +67,8 @@ public strictfp class ReferencingAssert
      * The authority is expected to be {@link Citations#OGC}. We expect the exact same authority
      * instance because identifiers in OGC namespace are often hard-coded in SIS.
      *
-     * @param expected The expected identifier code.
-     * @param actual   The identifier to verify.
+     * @param expected  the expected identifier code.
+     * @param actual    the identifier to verify.
      *
      * @since 0.6
      */
@@ -84,8 +85,8 @@ public strictfp class ReferencingAssert
      * Asserts that the given identifier has the expected code and the {@code "EPSG"} code space.
      * The authority is expected to have the {@code "EPSG"} title, alternate title or identifier.
      *
-     * @param expected The expected identifier code.
-     * @param actual   The identifier to verify.
+     * @param expected  the expected identifier code.
+     * @param actual    the identifier to verify.
      *
      * @since 0.5
      */
@@ -103,9 +104,9 @@ public strictfp class ReferencingAssert
      * No other identifier than the given one is expected. The authority is expected to have the {@code "EPSG"} title,
      * alternate title or identifier.
      *
-     * @param name       The expected EPSG name.
-     * @param identifier The expected EPSG identifier.
-     * @param object     The object to verify.
+     * @param name        the expected EPSG name.
+     * @param identifier  the expected EPSG identifier.
+     * @param object      the object to verify.
      *
      * @since 0.6
      */
@@ -119,8 +120,8 @@ public strictfp class ReferencingAssert
      * Asserts that the tip of the unique alias of the given object is equals to the expected value.
      * As a special case if the expected value is null, then this method verifies that the given object has no alias.
      *
-     * @param expected The expected alias, or {@code null} if we expect no alias.
-     * @param object   The object for which to test the alias.
+     * @param expected  the expected alias, or {@code null} if we expect no alias.
+     * @param object    the object for which to test the alias.
      */
     public static void assertAliasTipEquals(final String expected, final IdentifiedObject object) {
         final Collection<GenericName> aliases = object.getAlias();
@@ -134,14 +135,14 @@ public strictfp class ReferencingAssert
     /**
      * Compares the given coordinate system axis against the expected values.
      *
-     * @param name          The expected axis name code.
-     * @param abbreviation  The expected axis abbreviation.
-     * @param direction     The expected axis direction.
-     * @param minimumValue  The expected axis minimal value.
-     * @param maximumValue  The expected axis maximal value.
-     * @param unit          The expected axis unit of measurement.
-     * @param rangeMeaning  The expected axis range meaning.
-     * @param axis          The axis to verify.
+     * @param name           the expected axis name code.
+     * @param abbreviation   the expected axis abbreviation.
+     * @param direction      the expected axis direction.
+     * @param minimumValue   the expected axis minimal value.
+     * @param maximumValue   the expected axis maximal value.
+     * @param unit           the expected axis unit of measurement.
+     * @param rangeMeaning   the expected axis range meaning.
+     * @param axis           the axis to verify.
      */
     public static void assertAxisEquals(final String name, final String abbreviation, final AxisDirection direction,
             final double minimumValue, final double maximumValue, final Unit<?> unit, final RangeMeaning rangeMeaning,
@@ -161,9 +162,9 @@ public strictfp class ReferencingAssert
      * a positive delta. Only the elements in the given descriptor are compared, and
      * the comparisons are done in the units declared in the descriptor.
      *
-     * @param expected  The expected parameter values.
-     * @param actual    The actual parameter values.
-     * @param tolerance The tolerance threshold for comparison of numerical values.
+     * @param expected   the expected parameter values.
+     * @param actual     the actual parameter values.
+     * @param tolerance  the tolerance threshold for comparison of numerical values.
      */
     public static void assertParameterEquals(final ParameterValueGroup expected,
             final ParameterValueGroup actual, final double tolerance)
@@ -196,13 +197,13 @@ public strictfp class ReferencingAssert
      * to the given values. The matrix doesn't need to be square. The last row is handled especially
      * if the {@code affine} argument is {@code true}.
      *
-     * @param expected  The values which are expected on the diagonal. If the length of this array
-     *                  is less than the matrix size, then the last element in the array is repeated
-     *                  for all remaining diagonal elements.
-     * @param affine    If {@code true}, then the last row is expected to contains the value 1
-     *                  in the last column, and all other columns set to 0.
-     * @param matrix    The matrix to test.
-     * @param tolerance The tolerance threshold while comparing floating point values.
+     * @param expected   the values which are expected on the diagonal. If the length of this array
+     *                   is less than the matrix size, then the last element in the array is repeated
+     *                   for all remaining diagonal elements.
+     * @param affine     if {@code true}, then the last row is expected to contains the value 1
+     *                   in the last column, and all other columns set to 0.
+     * @param matrix     the matrix to test.
+     * @param tolerance  the tolerance threshold while comparing floating point values.
      */
     public static void assertDiagonalEquals(final double[] expected, final boolean affine,
             final Matrix matrix, final double tolerance)
@@ -231,9 +232,9 @@ public strictfp class ReferencingAssert
     /**
      * Compares two affine transforms for equality.
      *
-     * @param expected  The expected affine transform.
-     * @param actual    The actual affine transform.
-     * @param tolerance The tolerance threshold.
+     * @param expected   the expected affine transform.
+     * @param actual     the actual affine transform.
+     * @param tolerance  the tolerance threshold.
      */
     public static void assertTransformEquals(final AffineTransform expected, final AffineTransform actual, final double tolerance) {
         assertEquals("scaleX",     expected.getScaleX(),     actual.getScaleX(),     tolerance);
@@ -247,10 +248,10 @@ public strictfp class ReferencingAssert
     /**
      * Asserts that two rectangles have the same location and the same size.
      *
-     * @param expected The expected rectangle.
-     * @param actual   The rectangle to compare with the expected one.
-     * @param tolx     The tolerance threshold on location along the <var>x</var> axis.
-     * @param toly     The tolerance threshold on location along the <var>y</var> axis.
+     * @param expected  the expected rectangle.
+     * @param actual    the rectangle to compare with the expected one.
+     * @param tolx      the tolerance threshold on location along the <var>x</var> axis.
+     * @param toly      the tolerance threshold on location along the <var>y</var> axis.
      */
     public static void assertRectangleEquals(final RectangularShape expected,
             final RectangularShape actual, final double tolx, final double toly)
@@ -266,6 +267,36 @@ public strictfp class ReferencingAssert
     }
 
     /**
+     * Asserts that two envelopes have the same minimum and maximum ordinates.
+     * This method ignores the envelope type (i.e. the implementation class) and the CRS.
+     *
+     * @param expected    the expected envelope.
+     * @param actual      the envelope to compare with the expected one.
+     * @param tolerances  the tolerance threshold on location along each axis. If this array length is shorter
+     *                    than the number of dimensions, then the last tolerance is reused for all remaining axes.
+     *                    If this array is empty, then the tolerance threshold is zero.
+     *
+     * @since 0.7
+     */
+    public static void assertEnvelopeEquals(final Envelope expected, final Envelope actual, final double... tolerances) {
+        final int dimension = expected.getDimension();
+        assertEquals("dimension", dimension, actual.getDimension());
+        double tolerance = 0;
+        for (int i=0; i<dimension; i++) {
+            if (i < tolerances.length) {
+                tolerance = tolerances[i];
+            }
+            if (abs(expected.getMinimum(i) - actual.getMinimum(i)) > tolerance ||
+                abs(expected.getMaximum(i) - actual.getMaximum(i)) > tolerance)
+            {
+                fail("Envelopes are not equal:\n"
+                        + "expected " + Envelopes.toString(expected) + "\n"
+                        + " but got " + Envelopes.toString(actual));
+            }
+        }
+    }
+
+    /**
      * Tests if the given {@code outer} shape contains the given {@code inner} rectangle.
      * This method will also verify class consistency by invoking the {@code intersects}
      * method, and by interchanging the arguments.
@@ -273,8 +304,8 @@ public strictfp class ReferencingAssert
      * <p>This method can be used for testing the {@code outer} implementation -
      * it should not be needed for standard JDK implementations.</p>
      *
-     * @param outer The shape which is expected to contains the given rectangle.
-     * @param inner The rectangle which should be contained by the shape.
+     * @param outer  the shape which is expected to contains the given rectangle.
+     * @param inner  the rectangle which should be contained by the shape.
      */
     public static void assertContains(final RectangularShape outer, final Rectangle2D inner) {
         assertTrue("outer.contains(inner)",   outer.contains  (inner));
@@ -292,8 +323,8 @@ public strictfp class ReferencingAssert
      * This method will also verify class consistency by invoking the {@code intersects}
      * method, and by interchanging the arguments.
      *
-     * @param outer The envelope which is expected to contains the given inner envelope.
-     * @param inner The envelope which should be contained by the outer envelope.
+     * @param outer  the envelope which is expected to contains the given inner envelope.
+     * @param inner  the envelope which should be contained by the outer envelope.
      */
     public static void assertContains(final AbstractEnvelope outer, final Envelope inner) {
         assertTrue("outer.contains(inner)",   outer.contains  (inner, true));
@@ -322,8 +353,8 @@ public strictfp class ReferencingAssert
      * <p>This method can be used for testing the {@code r1} implementation - it should not
      * be needed for standard implementations.</p>
      *
-     * @param r1 The first shape to test.
-     * @param r2 The second rectangle to test.
+     * @param r1  the first shape to test.
+     * @param r2  the second rectangle to test.
      */
     public static void assertDisjoint(final RectangularShape r1, final Rectangle2D r2) {
         assertFalse("r1.intersects(r2)", r1.intersects(r2));
@@ -355,8 +386,8 @@ public strictfp class ReferencingAssert
      * This method will also verify class consistency by invoking the {@code contains} method,
      * and by interchanging the arguments.
      *
-     * @param e1 The first envelope to test.
-     * @param e2 The second envelope to test.
+     * @param e1  the first envelope to test.
+     * @param e2  the second envelope to test.
      */
     public static void assertDisjoint(final AbstractEnvelope e1, final Envelope e2) {
         assertFalse("e1.intersects(e2)", e1.intersects(e2, false));
@@ -395,7 +426,7 @@ public strictfp class ReferencingAssert
      * Tests if the given transform is the identity transform.
      * If the current transform is linear, then this method will also verifies {@link Matrix#isIdentity()}.
      *
-     * @param transform The transform to test.
+     * @param transform  the transform to test.
      *
      * @since 0.6
      */
@@ -410,7 +441,7 @@ public strictfp class ReferencingAssert
      * Tests if the given transform is <strong>not</strong> the identity transform.
      * If the current transform is linear, then this method will also verifies {@link Matrix#isIdentity()}.
      *
-     * @param transform The transform to test.
+     * @param transform  the transform to test.
      *
      * @since 0.6
      */



Mime
View raw message