You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2014/02/08 00:28:28 UTC

svn commit: r1565847 - in /sis/branches/JDK7/core: sis-metadata/src/main/java/org/apache/sis/metadata/iso/ sis-referencing/src/main/java/org/apache/sis/parameter/ sis-referencing/src/main/java/org/apache/sis/referencing/ sis-referencing/src/main/java/o...

Author: desruisseaux
Date: Fri Feb  7 23:28:28 2014
New Revision: 1565847

URL: http://svn.apache.org/r1565847
Log:
Added tests.

Added:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java
      - copied, changed from r1565660, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorTest.java   (with props)
Modified:
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -205,7 +205,7 @@ public class ImmutableIdentifier extends
         } else {
             remarks = null;
         }
-        validate();
+        validate(null);
     }
 
     /**
@@ -252,7 +252,7 @@ public class ImmutableIdentifier extends
         this.authority = authority;
         this.version   = version;
         this.remarks   = remarks;
-        validate();
+        validate(null);
     }
 
     /**
@@ -292,6 +292,11 @@ public class ImmutableIdentifier extends
      *     <td>{@link String} or {@link InternationalString}</td>
      *     <td>{@link #getRemarks()}</td>
      *   </tr>
+     *   <tr>
+     *     <td>{@value org.apache.sis.referencing.AbstractIdentifiedObject#LOCALE_KEY}</td>
+     *     <td>{@link Locale}</td>
+     *     <td>(none)</td>
+     *   </tr>
      * </table>
      *
      * {@code "remarks"} is a localizable attributes which may have a language and country
@@ -317,7 +322,7 @@ public class ImmutableIdentifier extends
         } else if (value == null || value instanceof Citation) {
             authority = (Citation) value;
         } else {
-            throw illegalPropertyType(AUTHORITY_KEY, value);
+            throw illegalPropertyType(properties, AUTHORITY_KEY, value);
         }
         /*
          * Complete the code space if it was not explicitly set. We take a short identifier (preferred) or title
@@ -331,27 +336,30 @@ public class ImmutableIdentifier extends
         } else if (value instanceof String) {
             codeSpace = trimWhitespaces((String) value);
         } else {
-            throw illegalPropertyType(CODESPACE_KEY, value);
+            throw illegalPropertyType(properties, CODESPACE_KEY, value);
         }
-        validate();
+        validate(properties);
     }
 
     /**
      * Ensures that the properties of this {@code ImmutableIdentifier} are valid.
      */
-    private void validate() {
+    private void validate(final Map<String,?> properties) {
         if (code == null || code.isEmpty()) {
-            throw new IllegalArgumentException(Errors.format((code == null)
-                    ? Errors.Keys.MissingValueForProperty_1
-                    : Errors.Keys.EmptyProperty_1, CODE_KEY));
+            throw new IllegalArgumentException(Errors.getResources(properties)
+                    .getString((code == null) ? Errors.Keys.MissingValueForProperty_1
+                                              : Errors.Keys.EmptyProperty_1, CODE_KEY));
         }
     }
 
     /**
      * Returns the exception to be thrown when a property if of illegal type.
      */
-    private static IllegalArgumentException illegalPropertyType(final String key, final Object value) {
-        return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
+    private static IllegalArgumentException illegalPropertyType(
+            final Map<String,?> properties, final String key, final Object value)
+    {
+        return new IllegalArgumentException(Errors.getResources(properties)
+                .getString(Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -95,7 +95,8 @@ public abstract class AbstractParameterD
         super(properties);
         this.minimumOccurs = minimumOccurs;
         if (minimumOccurs < 0  || minimumOccurs > maximumOccurs) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalRange_2, minimumOccurs, maximumOccurs));
+            throw new IllegalArgumentException(Errors.getResources(properties)
+                    .getString(Errors.Keys.IllegalRange_2, minimumOccurs, maximumOccurs));
         }
     }
 

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -16,19 +16,11 @@
  */
 package org.apache.sis.parameter;
 
-import java.util.Set;
 import java.io.Serializable;
-import javax.measure.unit.Unit;
-import javax.measure.converter.UnitConverter;
-import javax.measure.converter.ConversionException;
-import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.GeneralParameterValue;
 import org.opengis.parameter.GeneralParameterDescriptor;
-import org.opengis.parameter.InvalidParameterValueException;
 import org.apache.sis.io.wkt.FormattableObject;
 import org.apache.sis.io.wkt.Formatter;
-import org.apache.sis.measure.Units;
-import org.apache.sis.util.Numbers;
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -91,124 +83,6 @@ public abstract class AbstractParameterV
     }
 
     /**
-     * Ensures that the given value is valid according the specified parameter descriptor.
-     * This convenience method ensures that {@code value} is assignable to the
-     * {@linkplain ParameterDescriptor#getValueClass() expected class}, is between the
-     * {@linkplain ParameterDescriptor#getMinimumValue() minimum} and
-     * {@linkplain ParameterDescriptor#getMaximumValue() maximum} values and is one of the
-     * {@linkplain ParameterDescriptor#getValidValues() set of valid values}.
-     * If the value fails any of those tests, then an exception is thrown.
-     *
-     * @param  <T> The type of parameter value. The given {@code value} should typically be an
-     *         instance of this class. This is not required by this method signature but is
-     *         checked by this method implementation.
-     * @param  descriptor The parameter descriptor to check against.
-     * @param  value The value to check, or {@code null}.
-     * @param  unit  The unit of the value to check, or {@code null}.
-     * @return The value casted to the descriptor parameterized type, or the
-     *         {@linkplain ParameterDescriptor#getDefaultValue() default value}
-     *         if the given value was null while the parameter is mandatory.
-     * @throws InvalidParameterValueException if the parameter value is invalid.
-     */
-    @SuppressWarnings("unchecked")
-    static <T> T ensureValidValue(final ParameterDescriptor<T> descriptor, final Object value, final Unit<?> unit)
-            throws InvalidParameterValueException
-    {
-        if (value == null) {
-            if (descriptor.getMinimumOccurs() != 0) {
-                return descriptor.getDefaultValue();
-            }
-            return null;
-        }
-        final String error;
-        final Class<T> type = descriptor.getValueClass();
-        if (!type.isInstance(value)) {
-            error = Errors.format(Errors.Keys.IllegalParameterValueClass_3, getName(descriptor), type, value.getClass());
-        } else {
-            /*
-             * Before to verify if the given value is inside the bounds, we need to convert the value
-             * to the units used by the parameter descriptor.
-             */
-            T converted = (T) value;
-            if (unit != null) {
-                final Unit<?> def = descriptor.getUnit();
-                if (def == null) {
-                    throw unitlessParameter(descriptor);
-                }
-                if (!unit.equals(def)) {
-                    final short expectedID = getUnitMessageID(def);
-                    if (getUnitMessageID(unit) != expectedID) {
-                        throw new IllegalArgumentException(Errors.format(expectedID, unit));
-                    }
-                    final UnitConverter converter;
-                    try {
-                        converter = unit.getConverterToAny(def);
-                    } catch (ConversionException e) {
-                        throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleUnits_2, unit, def), e);
-                    }
-                    if (Number.class.isAssignableFrom(type)) {
-                        Number n = (Number) value; // Given value.
-                        n = converter.convert(n.doubleValue()); // Value in units that we can compare.
-                        try {
-                            converted = (T) Numbers.cast(n, (Class<? extends Number>) type);
-                        } catch (IllegalArgumentException e) {
-                            throw new InvalidParameterValueException(e.getLocalizedMessage(), getName(descriptor), value);
-                        }
-                    }
-                }
-            }
-            final Comparable<T> minimum = descriptor.getMinimumValue();
-            final Comparable<T> maximum = descriptor.getMaximumValue();
-            if ((minimum != null && minimum.compareTo(converted) > 0) ||
-                (maximum != null && maximum.compareTo(converted) < 0))
-            {
-                error = Errors.format(Errors.Keys.ValueOutOfRange_4, getName(descriptor), minimum, maximum, converted);
-            } else {
-                final Set<T> validValues = descriptor.getValidValues();
-                if (validValues!=null && !validValues.contains(converted)) {
-                    error = Errors.format(Errors.Keys.IllegalArgumentValue_2, getName(descriptor), value);
-                } else {
-                    /*
-                     * Passed every tests - the value is valid.
-                     * Really returns the original value, not the converted one, because we store the given
-                     * unit as well. Conversions will be applied on the fly by the getter method if needed.
-                     */
-                    return (T) value;
-                }
-            }
-        }
-        throw new InvalidParameterValueException(error, getName(descriptor), value);
-    }
-
-    /**
-     * Returns an exception initialized with a "Unitless parameter" error message for the specified descriptor.
-     */
-    static IllegalStateException unitlessParameter(final GeneralParameterDescriptor descriptor) {
-        return new IllegalStateException(Errors.format(Errors.Keys.UnitlessParameter_1, getName(descriptor)));
-    }
-
-    /**
-     * Convenience method returning the name of the specified descriptor.
-     * This method is used mostly for output to be read by human, not for processing.
-     * Consequently, we may consider to returns a localized name in a future version.
-     */
-    static String getName(final GeneralParameterDescriptor descriptor) {
-        return descriptor.getName().getCode();
-    }
-
-    /**
-     * Returns the unit type as one of error message code.
-     * Used for checking unit with a better error message formatting if needed.
-     */
-    static short getUnitMessageID(final Unit<?> unit) {
-        if (Units.isLinear  (unit)) return Errors.Keys.NonLinearUnit_1;
-        if (Units.isAngular (unit)) return Errors.Keys.NonAngularUnit_1;
-        if (Units.isTemporal(unit)) return Errors.Keys.NonTemporalUnit_1;
-        if (Units.isScale   (unit)) return Errors.Keys.NonScaleUnit_1;
-        return Errors.Keys.IncompatibleUnit_1;
-    }
-
-    /**
      * Returns a hash value for this parameter.
      *
      * @return The hash code value.

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -29,6 +29,7 @@ import org.opengis.referencing.Identifie
 
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
+import org.apache.sis.util.Numbers;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.util.Numerics;
@@ -53,8 +54,8 @@ import java.util.Objects;
  *
  * @param <T> The type of elements to be returned by {@link DefaultParameterValue#getValue()}.
  *
- * @author Martin Desruisseaux (IRD, Geomatys)
- * @author Johann Sorel (Geomatys)
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @since   0.4 (derived from geotk-2.0)
  * @version 0.4
  * @module
@@ -161,15 +162,27 @@ public class DefaultParameterDescriptor<
         ensureCanCast("defaultValue", valueClass, defaultValue);
         ensureCanCast("minimum",      valueClass, minimum);
         ensureCanCast("maximum",      valueClass, maximum);
+        if (unit != null) {
+            Class<?> componentType = valueClass;
+            for (Class<?> c; (c = componentType.getComponentType()) != null;) {
+                componentType = c;
+            }
+            componentType = Numbers.primitiveToWrapper(componentType);
+            if (!Number.class.isAssignableFrom(componentType)) {
+                throw new IllegalArgumentException(Errors.getResources(properties).getString(
+                        Errors.Keys.IllegalUnitFor_2, super.getName().getCode(), unit));
+            }
+        }
         if (minimum != null && maximum != null) {
             if (minimum.compareTo(valueClass.cast(maximum)) > 0) {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalRange_2, minimum, maximum));
+                throw new IllegalArgumentException(Errors.getResources(properties)
+                        .getString(Errors.Keys.IllegalRange_2, minimum, maximum));
             }
         }
         if (validValues != null) {
             final Set<T> valids = new HashSet<>(hashMapCapacity(validValues.length));
-            for (int i=0; i<validValues.length; i++) {
-                final T value = Numerics.cached(validValues[i]);
+            for (T value : validValues) {
+                value = Numerics.cached(value);
                 ensureCanCast("validValues", valueClass, value);
                 valids.add(value);
             }
@@ -177,7 +190,10 @@ public class DefaultParameterDescriptor<
         } else {
             this.validValues = null;
         }
-        AbstractParameterValue.ensureValidValue(this, defaultValue, unit);
+        final Verifier error = Verifier.ensureValidValue(valueClass, this.validValues, minimum, maximum, defaultValue);
+        if (error != null) {
+            throw new IllegalArgumentException(error.message(properties, super.getName().getCode(), defaultValue));
+        }
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -28,6 +28,7 @@ import org.opengis.parameter.ParameterVa
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.InvalidParameterTypeException;
 import org.opengis.parameter.InvalidParameterValueException;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -35,6 +36,7 @@ import static org.apache.sis.util.Argume
 // Related to JDK7
 import java.util.Objects;
 import java.nio.file.Path;
+import org.apache.sis.util.Numbers;
 
 
 /**
@@ -321,11 +323,11 @@ public class DefaultParameterValue<T> ex
     private UnitConverter getConverterTo(final Unit<?> unit) {
         final Unit<?> source = getUnit();
         if (source == null) {
-            throw unitlessParameter(descriptor);
+            throw Verifier.unitlessParameter(descriptor);
         }
         ensureNonNull("unit", unit);
-        final short expectedID = getUnitMessageID(source);
-        if (getUnitMessageID(unit) != expectedID) {
+        final short expectedID = Verifier.getUnitMessageID(source);
+        if (Verifier.getUnitMessageID(unit) != expectedID) {
             throw new IllegalArgumentException(Errors.format(expectedID, unit));
         }
         try {
@@ -438,7 +440,7 @@ public class DefaultParameterValue<T> ex
         } catch (URISyntaxException exception) {
             cause = exception;
         }
-        final String name = getName(descriptor);
+        final String name = Verifier.getName(descriptor);
         if (value != null) {
             throw new InvalidParameterTypeException(getClassTypeError(), name);
         }
@@ -449,7 +451,7 @@ public class DefaultParameterValue<T> ex
      * Returns the exception to throw when an incompatible method is invoked for the value type.
      */
     private IllegalStateException incompatibleValue(final Object value) {
-        final String name = getName(descriptor);
+        final String name = Verifier.getName(descriptor);
         if (value != null) {
             return new InvalidParameterTypeException(getClassTypeError(), name);
         }
@@ -478,9 +480,9 @@ public class DefaultParameterValue<T> ex
      */
     @Override
     public void setValue(final Object value) throws InvalidParameterValueException {
+        // Use 'unit' instead than 'getUnit()' despite class Javadoc claims because units are not expected
+        // to be involved in this method. We just want the current unit setting to be unchanged.
         setValue(value, unit);
-        // Really 'unit', not 'getUnit()' since units are not expected to be involved in this method.
-        // We just want the current unit setting to be unchanged.
     }
 
     /**
@@ -495,13 +497,16 @@ public class DefaultParameterValue<T> ex
      */
     @Override
     public void setValue(final boolean value) throws InvalidParameterValueException {
-        setValue(value, unit); // Same comment than setValue(Object).
+        // Use 'unit' instead than 'getUnit()' despite class Javadoc claims because units are not expected
+        // to be involved in this method. We just want the current unit setting to be unchanged.
+        setValue(Boolean.valueOf(value), unit);
     }
 
     /**
      * Sets the parameter value as an integer.
      *
-     * <p>The default implementation delegates to {@link #setValue(Object, Unit)}.</p>
+     * <p>The default implementation wraps the given integer in an object of the type specified by the
+     * {@linkplain #getDescriptor() descriptor}, then delegates to {@link #setValue(Object, Unit)}.</p>
      *
      * @param  value The parameter value.
      * @throws InvalidParameterValueException if the integer type is inappropriate for this parameter,
@@ -511,13 +516,37 @@ public class DefaultParameterValue<T> ex
      */
     @Override
     public void setValue(final int value) throws InvalidParameterValueException {
-        setValue(value, unit); // Same comment than setValue(Object).
+        Number n = Integer.valueOf(value);
+        final Class<?> valueClass = ((ParameterDescriptor<?>) descriptor).getValueClass();
+        if (Number.class.isAssignableFrom(valueClass)) {
+            @SuppressWarnings("unchecked")
+            final Number c = Numbers.cast(value, (Class<? extends Number>) valueClass);
+            if (c.intValue() == value) {
+                n = c;
+            }
+        }
+        setValue(n, unit);
+        // Use 'unit' instead than 'getUnit()' despite class Javadoc claims because units are not expected
+        // to be involved in this method. We just want the current unit setting to be unchanged.
+    }
+
+    /**
+     * Wraps the given value in a type compatible with the expected value class, if possible.
+     */
+    @SuppressWarnings("unchecked")
+    private static Number wrap(final double value, final Class<?> valueClass) {
+        if (Number.class.isAssignableFrom(valueClass)) {
+            return Numbers.wrap(value, (Class<? extends Number>) valueClass);
+        } else {
+            return Numerics.valueOf(value);
+        }
     }
 
     /**
      * Sets the parameter value as a floating point. The unit, if any, stay unchanged.
      *
-     * <p>The default implementation delegates to {@link #setValue(Object, Unit)}.</p>
+     * <p>The default implementation wraps the given number in an object of the type specified by the
+     * {@linkplain #getDescriptor() descriptor}, then delegates to {@link #setValue(Object, Unit)}.</p>
      *
      * @param value The parameter value.
      * @throws InvalidParameterValueException if the floating point type is inappropriate for this
@@ -529,13 +558,16 @@ public class DefaultParameterValue<T> ex
      */
     @Override
     public void setValue(final double value) throws InvalidParameterValueException {
-        setValue(value, unit); // Same comment than setValue(Object).
+        // Use 'unit' instead than 'getUnit()' despite class Javadoc claims because units are not expected
+        // to be involved in this method. We just want the current unit setting to be unchanged.
+        setValue(wrap(value, ((ParameterDescriptor<?>) descriptor).getValueClass()), unit);
     }
 
     /**
      * Sets the parameter value as a floating point and its associated unit.
      *
-     * <p>The default implementation delegates to {@link #setValue(Object, Unit)}.</p>
+     * <p>The default implementation wraps the given number in an object of the type specified by the
+     * {@linkplain #getDescriptor() descriptor}, then delegates to {@link #setValue(Object, Unit)}.</p>
      *
      * @param  value The parameter value.
      * @param  unit The unit for the specified value.
@@ -547,7 +579,7 @@ public class DefaultParameterValue<T> ex
      */
     @Override
     public void setValue(final double value, final Unit<?> unit) throws InvalidParameterValueException {
-        setValue(value, unit);
+        setValue(wrap(value, ((ParameterDescriptor<?>) descriptor).getValueClass()), unit);
     }
 
     /**
@@ -578,7 +610,7 @@ public class DefaultParameterValue<T> ex
      */
     @SuppressWarnings("unchecked") // Safe because descriptor type is enforced by constructor signature.
     protected void setValue(final Object value, final Unit<?> unit) throws InvalidParameterValueException {
-        this.value = ensureValidValue((ParameterDescriptor<T>) descriptor, value, unit);
+        this.value = Verifier.ensureValidValue((ParameterDescriptor<T>) descriptor, value, unit);
         this.unit  = unit; // Assign only on success.
     }
 

Copied: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java (from r1565660, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java?p2=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java&r1=1565660&r2=1565847&rev=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterValue.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -16,78 +16,58 @@
  */
 package org.apache.sis.parameter;
 
+import java.util.Map;
 import java.util.Set;
-import java.io.Serializable;
 import javax.measure.unit.Unit;
 import javax.measure.converter.UnitConverter;
 import javax.measure.converter.ConversionException;
 import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.GeneralParameterValue;
 import org.opengis.parameter.GeneralParameterDescriptor;
 import org.opengis.parameter.InvalidParameterValueException;
-import org.apache.sis.io.wkt.FormattableObject;
-import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.resources.Errors;
 
-import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-
 
 /**
- * The base class of single parameter value or group of parameter values.
+ * Verifies the validity of a given value.
+ * An instance of {@code Verifier} is created only if an error is detected.
+ * In such case, the error message is given by {@link #message(String, Object)}.
  *
- * @author  Martin Desruisseaux (IRD)
+ * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4 (derived from geotk-2.0)
  * @version 0.4
  * @module
  */
-public abstract class AbstractParameterValue extends FormattableObject
-        implements GeneralParameterValue, Serializable, Cloneable
-{
+final class Verifier {
     /**
-     * Serial number for inter-operability with different versions.
+     * The {@link Errors.Keys} value that describe the invalid value.
      */
-    private static final long serialVersionUID = 8458179223988766398L;
+    private final short errorKey;
 
     /**
-     * The abstract definition of this parameter or group of parameters.
+     * {@code true} if the last element in {@link #arguments} shall be set to the erroneous value.
      */
-    final GeneralParameterDescriptor descriptor;
+    private final boolean needsValue;
 
     /**
-     * Creates a parameter value from the specified descriptor.
+     * The arguments to be used with the error message to format.
+     * The current implementation relies on the following invariants:
      *
-     * @param descriptor The abstract definition of this parameter or group of parameters.
+     * <ul>
+     *   <li>The first element in this array is always the parameter name.</li>
+     *   <li>The last element shall be set to the erroneous value if {@link #needsValue} is {@code true}.</li>
+     * </ul>
      */
-    protected AbstractParameterValue(final GeneralParameterDescriptor descriptor) {
-        ensureNonNull("descriptor", descriptor);
-        this.descriptor = descriptor;
-    }
-
-    /**
-     * Creates a new instance initialized with the values from the specified parameter object.
-     * This is a <em>shallow</em> copy constructor, since the values contained in the given
-     * object are not cloned.
-     *
-     * @param parameter The parameter to copy values from.
-     */
-    protected AbstractParameterValue(final GeneralParameterValue parameter) {
-        ensureNonNull("parameter", parameter);
-        descriptor = parameter.getDescriptor();
-        if (descriptor == null) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.MissingValueForProperty_1, "descriptor"));
-        }
-    }
+    private final Object[] arguments;
 
     /**
-     * Returns the abstract definition of this parameter or group of parameters.
-     *
-     * @return The abstract definition of this parameter or group of parameters.
+     * Stores information about an error.
      */
-    @Override
-    public GeneralParameterDescriptor getDescriptor() {
-        return descriptor;
+    private Verifier(final short errorKey, final boolean needsValue, final Object... arguments) {
+        this.errorKey   = errorKey;
+        this.needsValue = needsValue;
+        this.arguments  = arguments;
     }
 
     /**
@@ -99,12 +79,12 @@ public abstract class AbstractParameterV
      * {@linkplain ParameterDescriptor#getValidValues() set of valid values}.
      * If the value fails any of those tests, then an exception is thrown.
      *
-     * @param  <T> The type of parameter value. The given {@code value} should typically be an
-     *         instance of this class. This is not required by this method signature but is
-     *         checked by this method implementation.
+     * @param  <T> The type of parameter value. The given {@code value} should typically be an instance of this class.
+     *             This is not required by this method signature but is checked by this method implementation.
+     *
      * @param  descriptor The parameter descriptor to check against.
-     * @param  value The value to check, or {@code null}.
-     * @param  unit  The unit of the value to check, or {@code null}.
+     * @param  value      The value to check, or {@code null}.
+     * @param  unit       The unit of the value to check, or {@code null}.
      * @return The value casted to the descriptor parameterized type, or the
      *         {@linkplain ParameterDescriptor#getDefaultValue() default value}
      *         if the given value was null while the parameter is mandatory.
@@ -120,64 +100,93 @@ public abstract class AbstractParameterV
             }
             return null;
         }
-        final String error;
         final Class<T> type = descriptor.getValueClass();
-        if (!type.isInstance(value)) {
-            error = Errors.format(Errors.Keys.IllegalParameterValueClass_3, getName(descriptor), type, value.getClass());
-        } else {
-            /*
-             * Before to verify if the given value is inside the bounds, we need to convert the value
-             * to the units used by the parameter descriptor.
-             */
-            T converted = (T) value;
-            if (unit != null) {
-                final Unit<?> def = descriptor.getUnit();
-                if (def == null) {
-                    throw unitlessParameter(descriptor);
+        /*
+         * Before to verify if the given value is inside the bounds, we need to convert the value
+         * to the units used by the parameter descriptor.
+         */
+        Object convertedValue = value;
+        if (unit != null) {
+            final Unit<?> def = descriptor.getUnit();
+            if (def == null) {
+                throw unitlessParameter(descriptor);
+            }
+            if (!unit.equals(def)) {
+                final short expectedID = getUnitMessageID(def);
+                if (getUnitMessageID(unit) != expectedID) {
+                    throw new IllegalArgumentException(Errors.format(expectedID, unit));
                 }
-                if (!unit.equals(def)) {
-                    final short expectedID = getUnitMessageID(def);
-                    if (getUnitMessageID(unit) != expectedID) {
-                        throw new IllegalArgumentException(Errors.format(expectedID, unit));
-                    }
-                    final UnitConverter converter;
+                final UnitConverter converter;
+                try {
+                    converter = unit.getConverterToAny(def);
+                } catch (ConversionException e) {
+                    throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleUnits_2, unit, def), e);
+                }
+                if (Number.class.isAssignableFrom(type)) {
+                    Number n = (Number) value; // Given value.
+                    n = converter.convert(n.doubleValue()); // Value in units that we can compare.
                     try {
-                        converter = unit.getConverterToAny(def);
-                    } catch (ConversionException e) {
-                        throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleUnits_2, unit, def), e);
-                    }
-                    if (Number.class.isAssignableFrom(type)) {
-                        Number n = (Number) value; // Given value.
-                        n = converter.convert(n.doubleValue()); // Value in units that we can compare.
-                        try {
-                            converted = (T) Numbers.cast(n, (Class<? extends Number>) type);
-                        } catch (IllegalArgumentException e) {
-                            throw new InvalidParameterValueException(e.getLocalizedMessage(), getName(descriptor), value);
-                        }
+                        convertedValue = Numbers.cast(n, (Class<? extends Number>) type);
+                    } catch (IllegalArgumentException e) {
+                        throw new InvalidParameterValueException(e.getLocalizedMessage(), getName(descriptor), value);
                     }
                 }
             }
-            final Comparable<T> minimum = descriptor.getMinimumValue();
-            final Comparable<T> maximum = descriptor.getMaximumValue();
-            if ((minimum != null && minimum.compareTo(converted) > 0) ||
-                (maximum != null && maximum.compareTo(converted) < 0))
-            {
-                error = Errors.format(Errors.Keys.ValueOutOfRange_4, getName(descriptor), minimum, maximum, converted);
-            } else {
-                final Set<T> validValues = descriptor.getValidValues();
-                if (validValues!=null && !validValues.contains(converted)) {
-                    error = Errors.format(Errors.Keys.IllegalArgumentValue_2, getName(descriptor), value);
-                } else {
-                    /*
-                     * Passed every tests - the value is valid.
-                     * Really returns the original value, not the converted one, because we store the given
-                     * unit as well. Conversions will be applied on the fly by the getter method if needed.
-                     */
-                    return (T) value;
-                }
-            }
         }
-        throw new InvalidParameterValueException(error, getName(descriptor), value);
+        final Comparable<T> minimum = descriptor.getMinimumValue();
+        final Comparable<T> maximum = descriptor.getMaximumValue();
+        final Verifier error = ensureValidValue(descriptor.getValueClass(),
+                    descriptor.getValidValues(), minimum, maximum, convertedValue);
+        if (error != null) {
+            final String name = getName(descriptor);
+            throw new InvalidParameterValueException(error.message(null, name, value), name, value);
+        }
+        /*
+         * Passed every tests - the value is valid.
+         * Really returns the original value, not the converted one, because we store the given
+         * unit as well. Conversions will be applied on the fly by the getter method if needed.
+         */
+        return (T) value;
+    }
+
+    /**
+     * Compares the given value against the given descriptor properties. If the value is valid, returns {@code null}.
+     * Otherwise returns an object that can be used for formatting the error message.
+     *
+     * @param convertedValue The value <em>converted to the units specified by the descriptor</em>.
+     *        This is not necessarily the user-provided value.
+     */
+    @SuppressWarnings("unchecked")
+    static <T> Verifier ensureValidValue(final Class<T> type, final Set<T> validValues,
+            final Comparable<T> minimum, final Comparable<T> maximum, final Object convertedValue)
+    {
+        if (!type.isInstance(convertedValue)) {
+            return new Verifier(Errors.Keys.IllegalParameterValueClass_3, false, null, type, convertedValue.getClass());
+        }
+        if ((minimum != null && minimum.compareTo((T) convertedValue) > 0) ||
+            (maximum != null && maximum.compareTo((T) convertedValue) < 0))
+        {
+            return new Verifier(Errors.Keys.ValueOutOfRange_4, true, null, minimum, maximum, convertedValue);
+        }
+        if (validValues!=null && !validValues.contains(convertedValue)) {
+            return new Verifier(Errors.Keys.IllegalArgumentValue_2, true, null, convertedValue);
+        }
+        return null;
+    }
+
+    /**
+     * Returns an error message for the error detected by
+     * {@link #ensureValidValue(Class, Set, Comparable, Comparable, Object)}.
+     *
+     * @param name  The parameter name.
+     * @param value The user-supplied value (not necessarily equals to the converted value).
+     */
+    String message(final Map<?,?> properties, final String name, final Object value) {
+        arguments[0] = name;
+        if (needsValue) {
+            arguments[arguments.length - 1] = value;
+        }
+        return Errors.getResources(properties).getString(errorKey, arguments);
     }
 
     /**
@@ -207,47 +216,4 @@ public abstract class AbstractParameterV
         if (Units.isScale   (unit)) return Errors.Keys.NonScaleUnit_1;
         return Errors.Keys.IncompatibleUnit_1;
     }
-
-    /**
-     * Returns a hash value for this parameter.
-     *
-     * @return The hash code value.
-     */
-    @Override
-    public int hashCode() {
-        return descriptor.hashCode() ^ (int) serialVersionUID;
-    }
-
-    /**
-     * Compares the given object with this parameter for equality.
-     *
-     * @param  object The object to compare to {@code this}.
-     * @return {@code true} if both objects are equal.
-     */
-    @Override
-    public boolean equals(final Object object) {
-        if (object != null && object.getClass() == getClass()) {
-            return descriptor.equals(((AbstractParameterValue) object).descriptor);
-        }
-        return false;
-    }
-
-    /**
-     * Returns a copy of this parameter value or group.
-     *
-     * @return A clone of this parameter value or group.
-     */
-    @Override
-    public AbstractParameterValue clone() {
-        try {
-            return (AbstractParameterValue) super.clone();
-        } catch (CloneNotSupportedException exception) {
-            throw new AssertionError(exception); // Should not happen, since we are cloneable
-        }
-    }
-
-    @Override
-    protected String formatTo(final Formatter formatter) {
-        return null;
-    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -138,6 +138,19 @@ public class AbstractIdentifiedObject ex
     private static final long serialVersionUID = -5173281694258483264L;
 
     /**
+     * Optional key which can be given to the {@linkplain #AbstractIdentifiedObject(Map) constructor} for specifying
+     * the locale to use for producing error messages. Notes:
+     *
+     * <ul>
+     *   <li>The locale is not stored in any {@code AbstractIdentifiedObject} property;
+     *       its value is ignored if no error occurred at construction time.</li>
+     *   <li>The locale is used on a <cite>best effort</cite> basis;
+     *       not all error messages may be localized.</li>
+     * </ul>
+     */
+    public static final String LOCALE_KEY = Errors.LOCALE_KEY;
+
+    /**
      * The name for this object or code. Shall never be {@code null}.
      *
      * <p><b>Consider this field as final!</b>
@@ -245,6 +258,11 @@ public class AbstractIdentifiedObject ex
      *     <td>{@link InternationalString} or {@link String}</td>
      *     <td>{@link #getRemarks()}</td>
      *   </tr>
+     *   <tr>
+     *     <td>{@value #LOCALE_KEY}</td>
+     *     <td>{@link Locale}</td>
+     *     <td>(none)</td>
+     *   </tr>
      * </table>
      *
      * Additionally, all localizable attributes like {@code "remarks"} may have a language and country code suffix.
@@ -269,7 +287,7 @@ public class AbstractIdentifiedObject ex
         } else if (value instanceof ReferenceIdentifier) {
             name = (ReferenceIdentifier) value;
         } else {
-            throw illegalPropertyType(NAME_KEY, value);
+            throw illegalPropertyType(properties, NAME_KEY, value);
         }
 
         // -------------------------------------------------------------------
@@ -279,7 +297,7 @@ public class AbstractIdentifiedObject ex
         try {
             alias = immutableSet(true, Types.toGenericNames(value, null));
         } catch (ClassCastException e) {
-            throw (IllegalArgumentException) illegalPropertyType(ALIAS_KEY, value).initCause(e);
+            throw (IllegalArgumentException) illegalPropertyType(properties, ALIAS_KEY, value).initCause(e);
         }
 
         // -----------------------------------------------------------
@@ -293,7 +311,7 @@ public class AbstractIdentifiedObject ex
         } else if (value instanceof ReferenceIdentifier[]) {
             identifiers = immutableSet(true, (ReferenceIdentifier[]) value);
         } else {
-            throw illegalPropertyType(IDENTIFIERS_KEY, value);
+            throw illegalPropertyType(properties, IDENTIFIERS_KEY, value);
         }
 
         // ----------------------------------------
@@ -303,10 +321,13 @@ public class AbstractIdentifiedObject ex
     }
 
     /**
-     * Returns the exception to be thrown when a property if of illegal type.
+     * Returns the exception to be thrown when a property is of illegal type.
      */
-    private static IllegalArgumentException illegalPropertyType(final String key, final Object value) {
-        return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
+    private static IllegalArgumentException illegalPropertyType(
+            final Map<String,?> properties, final String key, final Object value)
+    {
+        return new IllegalArgumentException(Errors.getResources(properties)
+                .getString(Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -180,11 +180,11 @@ public class AbstractCS extends Abstract
              */
             switch (validateAxis(direction, unit)) {
                 case INVALID_DIRECTION: {
-                    throw new IllegalArgumentException(Errors.format(
+                    throw new IllegalArgumentException(Errors.getResources(properties).getString(
                             Errors.Keys.IllegalAxisDirection_2, getClass(), direction));
                 }
                 case INVALID_UNIT: {
-                    throw new IllegalArgumentException(Errors.format(
+                    throw new IllegalArgumentException(Errors.getResources(properties).getString(
                             Errors.Keys.IllegalUnitFor_2, name, unit));
                 }
             }
@@ -199,7 +199,7 @@ public class AbstractCS extends Abstract
                     final AxisDirection other = axes[j].getDirection();
                     final AxisDirection abs = AxisDirections.absolute(other);
                     if (dir.equals(abs) && !abs.equals(AxisDirection.FUTURE)) {
-                        throw new IllegalArgumentException(Errors.format(
+                        throw new IllegalArgumentException(Errors.getResources(properties).getString(
                                 Errors.Keys.ColinearAxisDirections_2, direction, other));
                     }
                 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -260,7 +260,8 @@ public class DefaultCoordinateSystemAxis
         ensureNonNull("direction",    direction);
         ensureNonNull("unit",         unit);
         if (!(minimumValue < maximumValue)) { // Use '!' for catching NaN
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalRange_2, minimumValue, maximumValue));
+            throw new IllegalArgumentException(Errors.getResources(properties).getString(
+                    Errors.Keys.IllegalRange_2, minimumValue, maximumValue));
         }
         if ((minimumValue != NEGATIVE_INFINITY) || (maximumValue != POSITIVE_INFINITY)) {
             ensureNonNull("rangeMeaning", rangeMeaning);

Added: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorTest.java?rev=1565847&view=auto
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorTest.java (added)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorTest.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -0,0 +1,193 @@
+/*
+ * 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.parameter;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Locale;
+import javax.measure.unit.Unit;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.InvalidParameterValueException;
+import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import static javax.measure.unit.SI.*;
+import static org.opengis.test.Validators.*;
+
+
+/**
+ * Tests the {@link DefaultParameterDescriptor} class.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.4 (derived from geotk-2.1)
+ * @version 0.4
+ * @module
+ */
+@DependsOn(org.apache.sis.referencing.AbstractIdentifiedObjectTest.class)
+public final strictfp class DefaultParameterDescriptorTest extends TestCase {
+    /**
+     * Strict tolerance factor for floating point comparisons. In the particular
+     * case of this test suite, we can afford to be strict since we will perform
+     * arithmetic only on integer values.
+     */
+    private static final double STRICT = 0.0;
+
+    /**
+     * Small tolerance factor for floating point comparisons resulting from some calculation.
+     */
+    private static final double EPS = 1E-10;
+
+    /**
+     * Constructs a descriptor for a mandatory parameter in a range of integer values.
+     *
+     * @param  name         The parameter name.
+     * @param  defaultValue The default value for the parameter.
+     * @param  minimum      The minimum parameter value.
+     * @param  maximum      The maximum parameter value.
+     * @return The parameter descriptor for the given range of values.
+     */
+    private static DefaultParameterDescriptor<Integer> create(final String name,
+            final int defaultValue, final int minimum, final int maximum)
+    {
+        final Map<String,Object> properties = new HashMap<>(4);
+        assertNull(properties.put(DefaultParameterDescriptor.NAME_KEY, name));
+        assertNull(properties.put(DefaultParameterDescriptor.LOCALE_KEY, Locale.US));
+        return new DefaultParameterDescriptor<>(properties,
+                 Integer.class, null, Integer.valueOf(defaultValue),
+                 Integer.valueOf(minimum), Integer.valueOf(maximum), null, true);
+    }
+
+    /**
+     * Constructs a descriptor for a mandatory parameter in a range of floating point values.
+     *
+     * @param  name         The parameter name.
+     * @param  defaultValue The default value for the parameter, or {@link Double#NaN} if none.
+     * @param  minimum      The minimum parameter value, or {@link Double#NEGATIVE_INFINITY} if none.
+     * @param  maximum      The maximum parameter value, or {@link Double#POSITIVE_INFINITY} if none.
+     * @param  unit         The unit for default, minimum and maximum values.
+     * @return The parameter descriptor for the given range of values.
+     */
+    private static DefaultParameterDescriptor<Double> create(final String name,
+            final double defaultValue, final double minimum, final double maximum, final Unit<?> unit)
+    {
+        final Map<String,Object> properties = new HashMap<>(4);
+        assertNull(properties.put(DefaultParameterDescriptor.NAME_KEY, name));
+        assertNull(properties.put(DefaultParameterDescriptor.LOCALE_KEY, Locale.US));
+        return new DefaultParameterDescriptor<>(properties, Double.class, null,
+                Double.isNaN(defaultValue)          ? null : Double.valueOf(defaultValue),
+                minimum == Double.NEGATIVE_INFINITY ? null : Double.valueOf(minimum),
+                maximum == Double.POSITIVE_INFINITY ? null : Double.valueOf(maximum), unit, true);
+    }
+
+    /**
+     * Tests {@code DefaultParameterDescriptor} constructor
+     * with valid and invalid minimum and maximum values.
+     */
+    @Test
+    public void testRangeValidation() {
+        try {
+            create("Test range", 12, 20, 4);
+            fail("minimum > maximum");
+        } catch (IllegalArgumentException exception) {
+            assertEquals("Range [20 … 4] is not valid.", exception.getMessage());
+        }
+        final ParameterDescriptor<Integer> descriptor = create("Test range", 12, 4, 20);
+        assertEquals("name", "Test range", descriptor.getName().getCode());
+        assertEquals("defaultValue",  Integer.valueOf(12), descriptor.getDefaultValue());
+        assertEquals("minimumValue",  Integer.valueOf( 4), descriptor.getMinimumValue());
+        assertEquals("maximumValue",  Integer.valueOf(20), descriptor.getMaximumValue());
+        assertEquals("minimumOccurs", 1, descriptor.getMinimumOccurs());
+        assertEquals("maximumOccurs", 1, descriptor.getMaximumOccurs());
+    }
+
+    /**
+     * Tests {@code DefaultParameterDescriptor} constructor with an invalid default value.
+     */
+    @Test
+    @DependsOnMethod("testRangeValidation")
+    public void testDefaultValueValidation() {
+        try {
+            create("Test default", 3, 4, 20);
+            fail("defaultValue < minimum");
+        } catch (IllegalArgumentException exception) {
+            assertEquals("Value ‘Test default’=3 is invalid. Expected a value in the [4 … 20] range.", exception.getMessage());
+        }
+    }
+
+    /**
+     * Tests {@code DefaultParameterDescriptor} construction for {@link Double} type.
+     * Also tests the {@link Parameter} created from the {@code createValue} method.
+     */
+    @Test
+    public void testDoubleType() {
+        final ParameterDescriptor<Double> descriptor = create("Test", 12, 4, 20, METRE);
+        assertEquals("name",         "Test",             descriptor.getName().getCode());
+        assertEquals("unit",         METRE,              descriptor.getUnit());
+        assertEquals("class",        Double.class,       descriptor.getValueClass());
+        assertEquals("defaultValue", Double.valueOf(12), descriptor.getDefaultValue());
+        assertEquals("minimum",      Double.valueOf( 4), descriptor.getMinimumValue());
+        assertEquals("maximum",      Double.valueOf(20), descriptor.getMaximumValue());
+        validate(descriptor);
+        assertEquals("DefaultParameterDescriptor[\"Test\", mandatory, class=Double, " +
+                "valid=[4.0 … 20.0], default=12.0, unit=m]", descriptor.toString());
+
+        testDoubleValue(new DefaultParameterValue<>(descriptor));
+    }
+
+    /**
+     * Helper method for {@link #testDoubleType()}.
+     * This method tests a parameter value associated to the descriptor of the above test.
+     *
+     * @return The class of the given parameter, for convenience.
+     */
+    private static void testDoubleValue(final ParameterValue<Double> parameter) {
+        assertEquals("value",    Double.valueOf(12), parameter.getValue());
+        assertEquals("intValue", 12,                 parameter.intValue());
+        assertEquals("unit",     METRE,              parameter.getUnit());
+        validate(parameter);
+
+        for (int i=4; i<=20; i++) {
+            parameter.setValue(i);
+            assertEquals("value", Double.valueOf(i), parameter.getValue());
+            assertEquals("unit",  METRE,             parameter.getUnit());
+            assertEquals("value", i,                 parameter.doubleValue(METRE), STRICT);
+            assertEquals("value", 100*i,             parameter.doubleValue(CENTIMETRE), STRICT);
+        }
+        try {
+            parameter.setValue(3.0);
+            fail("setValue(< min)");
+        } catch (InvalidParameterValueException exception) {
+            assertEquals("Test", exception.getParameterName());
+        }
+        try {
+            parameter.setValue("12");
+            fail("setValue(Sring)");
+        } catch (InvalidParameterValueException exception) {
+            assertEquals("Test", exception.getParameterName());
+        }
+        for (int i=400; i<=2000; i+=100) {
+            parameter.setValue(i, CENTIMETRE);
+            assertEquals("value", Double.valueOf(i), parameter.getValue());
+            assertEquals("unit",  CENTIMETRE,        parameter.getUnit());
+            assertEquals("value", i/100,             parameter.doubleValue(METRE), EPS);
+        }
+    }
+}

Propchange: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -95,6 +95,33 @@ public final strictfp class AbstractIden
     }
 
     /**
+     * Tests the {@link AbstractIdentifiedObject#AbstractIdentifiedObject(Map)} constructor without name.
+     * This is invalid and should thrown an exception.
+     */
+    @Test
+    public void testMissingName() {
+        final Map<String,Object> properties = new HashMap<>(4);
+        assertNull(properties.put(AbstractIdentifiedObject.REMARKS_KEY, "Not a name."));
+        try {
+            new AbstractIdentifiedObject(properties);
+            fail("Should not allow unnamed object.");
+        } catch (IllegalArgumentException e) {
+            // The message may be in any language, but shall
+            // contain at least the missing property name.
+            final String message = e.getMessage();
+            assertTrue(message, message.contains("code"));
+        }
+        // Try again, with error messages forced to English.
+        assertNull(properties.put(AbstractIdentifiedObject.LOCALE_KEY, Locale.US));
+        try {
+            new AbstractIdentifiedObject(properties);
+            fail("Should not allow unnamed object.");
+        } catch (IllegalArgumentException e) {
+            assertEquals("Missing value for “code” property.", e.getMessage());
+        }
+    }
+
+    /**
      * Tests the {@link AbstractIdentifiedObject#AbstractIdentifiedObject(Map)} constructor without identifier.
      * This method compares the property values against the expected values.
      */

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -50,6 +50,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.NamedIdentifierTest.class,
     org.apache.sis.referencing.AbstractIdentifiedObjectTest.class,
     org.apache.sis.referencing.AbstractReferenceSystemTest.class,
+    org.apache.sis.parameter.DefaultParameterDescriptorTest.class,
     org.apache.sis.referencing.datum.BursaWolfParametersTest.class,
     org.apache.sis.referencing.datum.TimeDependentBWPTest.class,
     org.apache.sis.referencing.datum.DefaultEllipsoidTest.class,

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/NonMarshalledAuthority.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -19,6 +19,7 @@ package org.apache.sis.internal.jaxb;
 import java.util.Iterator;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Locale;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.io.Serializable;
@@ -280,7 +281,7 @@ public final class NonMarshalledAuthorit
         } catch (ReflectiveOperationException e) {
             if (!warningLogged) {
                 warningLogged = true;
-                final LogRecord record = Errors.getResources(null).getLogRecord(Level.WARNING,
+                final LogRecord record = Errors.getResources((Locale) null).getLogRecord(Level.WARNING,
                         Errors.Keys.MissingRequiredModule_1, "sis-metadata");
                 /*
                  * Log directly the the logger rather than invoking the Context.warningOccured(…) method because

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -32,7 +32,6 @@ import org.apache.sis.util.CharSequences
  * @module
  */
 public final class Utilities extends Static {
-
     /**
      * Do not allow instantiation of this class.
      */

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Containers.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -246,7 +246,8 @@ public final class Containers extends St
         }
         final Object value = properties.get(key);
         if (value != null && !type.isInstance(value)) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
+            throw new IllegalArgumentException(Errors.getResources(properties)
+                    .getString(Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
         }
         return (T) value;
     }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -649,15 +649,15 @@ public final class Types extends Static 
                 try {
                     locale = Locales.parse(key, s);
                 } catch (IllformedLocaleException e) {
-                    throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalLanguageCode_1,
-                            '(' + key.substring(0, s) + ')' + key.substring(s), e));
+                    throw new IllegalArgumentException(Errors.getResources(properties).getString(
+                            Errors.Keys.IllegalLanguageCode_1, '(' + key.substring(0, s) + ')' + key.substring(s), e));
                 }
             }
             final Object value = entry.getValue();
             if (value != null) {
                 if (!(value instanceof CharSequence)) {
-                    throw new IllegalArgumentException(Errors.format(
-                            Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
+                    throw new IllegalArgumentException(Errors.getResources(properties)
+                            .getString(Errors.Keys.IllegalPropertyClass_2, key, value.getClass()));
                 }
                 if (i18n == null) {
                     i18n = (CharSequence) value;

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -17,6 +17,7 @@
 package org.apache.sis.util.resources;
 
 import java.net.URL;
+import java.util.Map;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import org.opengis.util.InternationalString;
@@ -407,17 +408,17 @@ public final class Errors extends Indexe
         public static final short MissingSchemeInURI = 62;
 
         /**
-         * Missing value for option “{0}”.
+         * Missing value for “{0}” option.
          */
         public static final short MissingValueForOption_1 = 63;
 
         /**
-         * Missing value for parameter “{0}”.
+         * Missing value for “{0}” parameter.
          */
         public static final short MissingValueForParameter_1 = 142;
 
         /**
-         * Missing value for property “{0}”.
+         * Missing value for “{0}” property.
          */
         public static final short MissingValueForProperty_1 = 64;
 
@@ -817,6 +818,21 @@ public final class Errors extends Indexe
     }
 
     /**
+     * Returns resources in the locale specified in the given property map. This convenience method looks
+     * for the {@link #LOCALE_KEY} entry. If the given map is null, or contains no entry for the locale key,
+     * or the value is not an instance of {@link Locale}, then this method fallback on the default locale.
+     *
+     * @param  properties The map of properties, or {@code null} if none.
+     * @return Resources in the given locale.
+     * @throws MissingResourceException if resources can't be found.
+     *
+     * @since 0.4
+     */
+    public static Errors getResources(final Map<?,?> properties) throws MissingResourceException {
+        return getResources(getLocale(properties));
+    }
+
+    /**
      * Gets a string for the given key from this resource bundle or one of its parents.
      *
      * @param  key The key for the desired string.
@@ -824,7 +840,7 @@ public final class Errors extends Indexe
      * @throws MissingResourceException If no object for the given key can be found.
      */
     public static String format(final short key) throws MissingResourceException {
-        return getResources(null).getString(key);
+        return getResources((Locale) null).getString(key);
     }
 
     /**
@@ -839,7 +855,7 @@ public final class Errors extends Indexe
     public static String format(final short  key,
                                 final Object arg0) throws MissingResourceException
     {
-        return getResources(null).getString(key, arg0);
+        return getResources((Locale) null).getString(key, arg0);
     }
 
     /**
@@ -856,7 +872,7 @@ public final class Errors extends Indexe
                                 final Object arg0,
                                 final Object arg1) throws MissingResourceException
     {
-        return getResources(null).getString(key, arg0, arg1);
+        return getResources((Locale) null).getString(key, arg0, arg1);
     }
 
     /**
@@ -875,7 +891,7 @@ public final class Errors extends Indexe
                                 final Object arg1,
                                 final Object arg2) throws MissingResourceException
     {
-        return getResources(null).getString(key, arg0, arg1, arg2);
+        return getResources((Locale) null).getString(key, arg0, arg1, arg2);
     }
 
     /**
@@ -896,7 +912,7 @@ public final class Errors extends Indexe
                                 final Object arg2,
                                 final Object arg3) throws MissingResourceException
     {
-        return getResources(null).getString(key, arg0, arg1, arg2, arg3);
+        return getResources((Locale) null).getString(key, arg0, arg1, arg2, arg3);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Fri Feb  7 23:28:28 2014
@@ -92,9 +92,9 @@ MismatchedMatrixSize_4            = Mism
 MissingAuthority_1                = No authority was specified for code \u201c{0}\u201d. The expected syntax is \u201cAUTHORITY:CODE\u201d.
 MissingRequiredModule_1           = This operation requires the \u201c{0}\u201d module.
 MissingSchemeInURI                = Missing scheme in URI.
-MissingValueForOption_1           = Missing value for option \u201c{0}\u201d.
-MissingValueForParameter_1        = Missing value for parameter \u201c{0}\u201d.
-MissingValueForProperty_1         = Missing value for property \u201c{0}\u201d.
+MissingValueForOption_1           = Missing value for \u201c{0}\u201d option.
+MissingValueForParameter_1        = Missing value for \u201c{0}\u201d parameter.
+MissingValueForProperty_1         = Missing value for \u201c{0}\u201d property.
 MissingValueInColumn_1            = Missing value in the \u201c{0}\u201d column.
 MutuallyExclusiveOptions_2        = Options \u201c{0}\u201d and \u201c{1}\u201d are mutually exclusive.
 NegativeArgument_2                = Argument \u2018{0}\u2019 shall not be negative. The given value was {1}.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java?rev=1565847&r1=1565846&r2=1565847&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java [UTF-8] Fri Feb  7 23:28:28 2014
@@ -21,6 +21,7 @@ import java.io.BufferedInputStream;
 import java.io.DataInputStream;
 import java.io.IOException;
 import java.text.MessageFormat;
+import java.util.Map;
 import java.util.Enumeration;
 import java.util.Locale;
 import java.util.MissingResourceException;
@@ -71,6 +72,14 @@ import org.apache.sis.util.logging.Loggi
  */
 public class IndexedResourceBundle extends ResourceBundle implements Localized {
     /**
+     * Key used in properties map for localizing some aspects of the operation being executed.
+     * The {@code getResources(Map<?,?>)} methods defined in some sub-classes will look for this property.
+     *
+     * @see org.apache.sis.referencing.AbstractIdentifiedObject#LOCALE_KEY
+     */
+    public static final String LOCALE_KEY = "locale";
+
+    /**
      * Maximum string length for text inserted into another text. This parameter is used by
      * {@link #summarize}. Resource strings are never cut to this length. However, text replacing
      * {@code "{0}"} in a string like {@code "Parameter name is {0}"} will be cut to this length.
@@ -664,6 +673,25 @@ public class IndexedResourceBundle exten
     }
 
     /**
+     * Returns the locale specified in the given map, or {@code null} if none.
+     * Value of unexpected type are ignored.
+     *
+     * @param  properties The map of properties, or {@code null} if none.
+     * @return The locale found in the given map, or {@code null} if none.
+     *
+     * @since 0.4
+     */
+    static Locale getLocale(final Map<?,?> properties) {
+        if (properties != null) {
+            final Object candidate = properties.get(LOCALE_KEY);
+            if (candidate instanceof Locale) {
+                return (Locale) candidate;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns a string representation of this object.
      * This method is for debugging purposes only.
      *