Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -18,30 +18,197 @@ package org.apache.sis.parameter;
 
 import java.util.Map;
 import java.util.HashMap;
+import java.util.List;
+import java.io.Serializable;
 import javax.measure.unit.Unit;
 import org.opengis.util.MemberName;
+import org.opengis.metadata.Identifier;
+import org.opengis.metadata.citation.Citation;
 import org.opengis.parameter.*; // We use almost all types from this package.
 import org.apache.sis.internal.jaxb.metadata.replace.ServiceParameter;
 import org.apache.sis.measure.Range;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.measure.MeasurementRange;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ObjectConverters;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.Static;
+
+import static 
org.apache.sis.referencing.IdentifiedObjects.isHeuristicMatchForName;
 
 
 /**
- * Static methods working on parameters and their descriptors.
+ * Convenience methods for fetching parameter values despite the variations in 
parameter names, value types and units.
+ * See {@link DefaultParameterValueGroup} javadoc for a description of the 
standard way to get and set a particular
+ * parameter in a group. The remaining of this javadoc is specific to Apache 
SIS.
+ *
+ * {@section Convenience static methods}
+ * This class provides the following convenience static methods:
+ * <ul>
+ *   <li>{@link #cast(ParameterValue, Class) cast(…, Class)} for type safety 
with parameterized types.</li>
+ *   <li>{@link #getMemberName(ParameterDescriptor)} for inter-operability 
between ISO 19111 and ISO 19115.</li>
+ *   <li>{@link #getValueDomain(ParameterDescriptor)} for information 
purpose.</li>
+ *   <li>{@link #copy(ParameterValueGroup, ParameterValueGroup)} for copying 
values into an existing instance.</li>
+ * </ul>
+ *
+ *
+ * {@section Fetching parameter values despite different names, types or units}
+ * The common way to get a parameter is to invoke the {@link 
#parameter(String)} method.
+ * This {@code Parameters} class provides an alternative way, using a {@link 
ParameterDescriptor} argument
+ * instead than a {@code String}. The methods in this class use the additional 
information provided by the
+ * descriptor for choosing a {@code String} argument that the above-cited 
{@code parameter(String)} method
+ * is more likely to know (by giving preference to a {@linkplain 
DefaultParameterDescriptor#getName() name}
+ * or {@linkplain DefaultParameterDescriptor#getAlias() alias} defined by a 
common
+ * {@linkplain org.apache.sis.metadata.iso.ImmutableIdentifier#getAuthority() 
authority}),
+ * and for applying type and unit conversions.
+ *
+ * <div class="note"><b>Example:</b>
+ * The same parameter may be known under different names. For example the
+ * {@linkplain 
org.apache.sis.referencing.datum.DefaultEllipsoid#getSemiMajorAxis()
+ * length of the semi-major axis of the ellipsoid} is commonly known as {@code 
"semi_major"}.
+ * But that parameter can also be named {@code "semi_major_axis"}, {@code 
"earth_radius"} or simply {@code "a"}
+ * in other libraries. When fetching parameter values, we do not always know 
in advance which of the above-cited
+ * names is recognized by an arbitrary {@code ParameterValueGroup} 
implementation.
+ *
+ * <p>This uncertainty is mitigated with the Apache SIS implementation since
+ * {@link DefaultParameterValueGroup#parameter(String)} compares the given 
{@code String} argument
+ * against all parameter's {@linkplain DefaultParameterDescriptor#getAlias() 
aliases} in addition
+ * to the {@linkplain DefaultParameterDescriptor#getName() name}.
+ * However we do not have the guarantee that all implementations do 
that.</p></div>
+ *
+ * The method names in this class follow the names of methods provided by the 
{@link ParameterValue} interface.
+ * Those methods are themselves inspired by JDK methods:
+ *
+ * <table class="sis">
+ *   <caption>Methods fetching parameter value</caption>
+ *   <tr><th>{@code Parameters} method</th>                     <th>{@code 
ParameterValue} method</th>                                     <th>JDK 
methods</th></tr>
+ *   <tr><td>{@link #getValue(ParameterDescriptor)}</td>        <td>{@link 
DefaultParameterValue#getValue()        getValue()}</td>        <td></td></tr>
+ *   <tr><td>{@link #booleanValue(ParameterDescriptor)}</td>    <td>{@link 
DefaultParameterValue#booleanValue()    booleanValue()}</td>    <td>{@link 
Boolean#booleanValue()}</td></tr>
+ *   <tr><td>{@link #intValue(ParameterDescriptor)}</td>        <td>{@link 
DefaultParameterValue#intValue()        intValue()}</td>        <td>{@link 
Number#intValue()}</td></tr>
+ *   <tr><td>{@link #intValueList(ParameterDescriptor)}</td>    <td>{@link 
DefaultParameterValue#intValueList()    intValueList()}</td>    <td></td></tr>
+ *   <tr><td>{@link #doubleValue(ParameterDescriptor)}</td>     <td>{@link 
DefaultParameterValue#doubleValue()     doubleValue()}</td>     <td>{@link 
Number#doubleValue()}</td></tr>
+ *   <tr><td>{@link #doubleValueList(ParameterDescriptor)}</td> <td>{@link 
DefaultParameterValue#doubleValueList() doubleValueList()}</td> <td></td></tr>
+ *   <tr><td>{@link #stringValue(ParameterDescriptor)}</td>     <td>{@link 
DefaultParameterValue#stringValue()     stringValue()}</td>     <td></td></tr>
+ * </table>
+ *
+ *
+ * {@section Note for subclass implementors}
+ * All methods in this class get their information from the {@link 
ParameterValueGroup} methods.
+ * In addition, each method in this class is isolated from all others: 
overriding one method has
+ * no impact on other methods.
+ *
+ * <div class="note"><b>Note on this class name:</b>
+ * Despite implementing the {@link ParameterValueGroup} interface, this class 
is not named
+ * {@code AbstractParameterValueGroup} because it does not implement any 
method from the interface.
+ * Extending this class or extending {@link Object} make almost no difference 
for implementors.
+ * The intend of this {@code Parameters} class is rather to extend the API 
with methods
+ * that are convenient for the way Apache SIS uses parameters.
+ * In other words, this class is intended for users rather than 
implementors.</div>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
-public final class Parameters extends Static {
+public abstract class Parameters implements ParameterValueGroup, Cloneable {
+    /**
+     * For subclass constructors only.
+     */
+    protected Parameters() {
+    }
+
+    /**
+     * Returns the given parameter value group as a {@code Parameters} 
instance.
+     * If the given parameters is already an instance of {@code Parameters}, 
then it is returned as-is.
+     * Otherwise this method returns a wrapper which delegate all method 
invocations to the given instance.
+     *
+     * <p>This method provides a way to get access to the non-static {@code 
Parameters} methods, like
+     * {@link #getValue(ParameterDescriptor)}, for an arbitrary {@code 
ParameterValueGroup} instance.</p>
+     *
+     * @param  parameters The object to cast or wrap, or {@code null}.
+     * @return The given argument as an instance of {@code Parameters} (may be 
the same reference),
+     *         or {@code null} if the given argument was null.
+     */
+    public static Parameters castOrWrap(final ParameterValueGroup parameters) {
+        if (parameters == null || parameters instanceof Parameters) {
+            return (Parameters) parameters;
+        } else {
+            return new Wrapper(parameters);
+        }
+    }
+
+    /** Wrappers used as a fallback by {@link 
Parameters#castOrWrap(ParameterValueGroup)}. */
+    private static final class Wrapper extends Parameters implements 
Serializable {
+        private static final long serialVersionUID = -5491790565456920471L;
+        private final ParameterValueGroup delegate;
+        Wrapper(final ParameterValueGroup delegate) {this.delegate = delegate;}
+
+        @Override public ParameterDescriptorGroup    getDescriptor()        
{return delegate.getDescriptor();}
+        @Override public List<GeneralParameterValue> values()               
{return delegate.values();}
+        @Override public ParameterValue<?>           parameter(String name) 
{return delegate.parameter(name);}
+        @Override public List<ParameterValueGroup>   groups   (String name) 
{return delegate.groups(name);}
+        @Override public ParameterValueGroup         addGroup (String name) 
{return delegate.addGroup(name);}
+        @Override public Parameters                  clone()                
{return new Wrapper(delegate.clone());}
+    }
+
+    /**
+     * Casts the given parameter descriptor to the given type.
+     * An exception is thrown immediately if the parameter does not have the 
expected
+     * {@linkplain DefaultParameterDescriptor#getValueClass() value class}.
+     *
+     * @param  <T>        The expected value class.
+     * @param  descriptor The descriptor to cast, or {@code null}.
+     * @param  valueClass The expected value class.
+     * @return The descriptor casted to the given value class, or {@code null} 
if the given descriptor was null.
+     * @throws ClassCastException if the given descriptor does not have the 
expected value class.
+     *
+     * @see Class#cast(Object)
+     *
+     * @category verification
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> ParameterDescriptor<T> cast(final ParameterDescriptor<?> 
descriptor, final Class<T> valueClass)
+            throws ClassCastException
+    {
+        if (descriptor != null) {
+            final Class<?> actual = descriptor.getValueClass();
+            // We require a strict equality - not 
type.isAssignableFrom(actual) - because in
+            // the later case we could have (to be strict) to return a <? 
extends T> type.
+            if (!valueClass.equals(actual)) {
+                throw new 
ClassCastException(Errors.format(Errors.Keys.IllegalParameterType_2,
+                        descriptor.getName().getCode(), actual));
+            }
+        }
+        return (ParameterDescriptor<T>) descriptor;
+    }
+
     /**
-     * Do not allow instantiation of this class.
+     * Casts the given parameter value to the given type.
+     * An exception is thrown immediately if the parameter does not have the 
expected value class.
+     *
+     * @param  <T>   The expected value class.
+     * @param  value The value to cast, or {@code null}.
+     * @param  type  The expected value class.
+     * @return The value casted to the given type, or {@code null} if the 
given value was null.
+     * @throws ClassCastException if the given value doesn't have the expected 
value class.
+     *
+     * @see Class#cast(Object)
+     *
+     * @category verification
      */
-    private Parameters() {
+    @SuppressWarnings("unchecked")
+    public static <T> ParameterValue<T> cast(final ParameterValue<?> value, 
final Class<T> type)
+            throws ClassCastException
+    {
+        if (value != null) {
+            final ParameterDescriptor<?> descriptor = value.getDescriptor();
+            final Class<?> actual = descriptor.getValueClass();
+            if (!type.equals(actual)) { // Same comment than 
cast(ParameterDescriptor)...
+                throw new 
ClassCastException(Errors.format(Errors.Keys.IllegalParameterType_2,
+                        descriptor.getName().getCode(), actual));
+            }
+        }
+        return (ParameterValue<T>) value;
     }
 
     /**
@@ -75,9 +242,15 @@ public final class Parameters extends St
 
     /**
      * Returns the domain of valid values defined by the given descriptor, or 
{@code null} if none.
-     * This method builds the range from the {@linkplain 
DefaultParameterDescriptor#getMinimumValue() minimum value},
-     * {@linkplain DefaultParameterDescriptor#getMaximumValue() maximum value} 
and, if the values are numeric, from
-     * the {@linkplain DefaultParameterDescriptor#getUnit() unit}.
+     * This method performs the following operations:
+     *
+     * <ul>
+     *   <li>If the given parameter is an instance of {@code 
DefaultParameterDescriptor},
+     *       delegate to {@link 
DefaultParameterDescriptor#getValueDomain()}.</li>
+     *   <li>Otherwise builds the range from the {@linkplain 
DefaultParameterDescriptor#getMinimumValue() minimum value},
+     *       {@linkplain DefaultParameterDescriptor#getMaximumValue() maximum 
value} and, if the values are numeric, from
+     *       the {@linkplain DefaultParameterDescriptor#getUnit() unit}.</li>
+     * </ul>
      *
      * @param  descriptor The parameter descriptor, or {@code null}.
      * @return The domain of valid values, or {@code null} if none.
@@ -114,59 +287,331 @@ public final class Parameters extends St
     }
 
     /**
-     * Casts the given parameter descriptor to the given type.
-     * An exception is thrown immediately if the parameter does not have the 
expected
-     * {@linkplain DefaultParameterDescriptor#getValueClass() value class}.
+     * Returns the name or alias of the given parameter for the authority code 
space expected by this group.
+     * If no name or alias for this group's authority can be found, then the 
primary name will be returned.
      *
-     * @param  <T>        The expected value class.
-     * @param  descriptor The descriptor to cast, or {@code null}.
-     * @param  valueClass The expected value class.
-     * @return The descriptor casted to the given value class, or {@code null} 
if the given descriptor was null.
-     * @throws ClassCastException if the given descriptor does not have the 
expected value class.
+     * @param  source The parameter for which the name is wanted.
+     * @return The name of the given parameter.
+     */
+    private String getName(final GeneralParameterDescriptor source) {
+        final ParameterDescriptorGroup descriptor = getDescriptor();
+        if (descriptor != null) {   // Paranoiac check (should never be null)
+            final Identifier group = descriptor.getName();
+            if (group != null) {    // Paranoiac check (should never be null)
+                final Citation authority = group.getAuthority();
+                if (authority != null) {
+                    final String name = IdentifiedObjects.getName(source, 
group.getAuthority());
+                    if (name != null) {
+                        return name;
+                    }
+                }
+            }
+        }
+        return IdentifiedObjects.getName(source, null);
+    }
+
+    /**
+     * Returns the parameter of the given name, or {@code null} if it does not 
exist.
+     * The default implementation iterates over the {@link #values()} and 
compares the descriptor names.
+     * The {@link DefaultParameterValueGroup} subclass will override this 
method with a more efficient
+     * implementation which avoid creating some deferred parameters.
+     */
+    ParameterValue<?> parameterIfExist(final String name) throws 
ParameterNotFoundException {
+        for (final GeneralParameterValue value : values()) {
+            if (value instanceof ParameterValue<?>) {
+                if (isHeuristicMatchForName(value.getDescriptor(), name)) {
+                    return (ParameterValue<?>) value;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the parameter value for the specified operation parameter.
+     * This method tries to do the same work than {@link #parameter(String)} 
but without
+     * instantiating optional parameters if that parameter was not already 
instantiated.
+     *
+     * @param  parameter The parameter to search.
+     * @return The requested parameter value, or {@code null} if none.
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     */
+    private ParameterValue<?> getParameter(final ParameterDescriptor<?> 
parameter) throws ParameterNotFoundException {
+        ArgumentChecks.ensureNonNull("parameter", parameter);
+        /*
+         * Search for an identifier matching this group's authority. For 
example if this ParameterValueGroup
+         * was created from an EPSG database, then we want to use the EPSG 
names instead than the OGC names.
+         */
+        final String name = getName(parameter);
+        if (parameter.getMinimumOccurs() == 0) {
+            /*
+             * The parameter is optional. We do not want to invoke 
'parameter(name)' because we do not want
+             * to create a new parameter if the user did not supplied one.  We 
search the parameter ourself
+             * (so we don't create any) and return null if we do not find any.
+             *
+             * If we find a parameter,  we can return it directly only if this 
object is an instance of a known
+             * implementation (currently DefaultParameterValueGroup only), 
otherwise we do not know if the user
+             * overrode the 'parameter' method  (we do not use 
Class.getMethod(...).getDeclaringClass() because
+             * it is presumed not worth the cost).  In case of doubt, we 
delegate to 'parameter(name)'.
+             */
+            final ParameterValue<?> value = parameterIfExist(name);
+            if (value == null || getClass() == 
DefaultParameterValueGroup.class) {
+                return value;
+            }
+        }
+        return parameter(name);
+    }
+
+    /**
+     * Returns the value of the parameter identified by the given descriptor.
+     * This method uses the following information from the given {@code 
parameter} descriptor:
      *
-     * @category verification
+     * <ul>
+     *   <li>The most appropriate {@linkplain 
DefaultParameterDescriptor#getName() name} or
+     *       {@linkplain DefaultParameterDescriptor#getAlias() alias} to use 
for searching
+     *       in this {@code ParameterValueGroup}, chosen as below:
+     *     <ul>
+     *       <li>a name or alias defined by the same
+     *           {@linkplain 
org.apache.sis.metadata.iso.ImmutableIdentifier#getAuthority() authority}, if 
any;</li>
+     *       <li>an arbitrary name or alias otherwise.</li>
+     *     </ul>
+     *   </li>
+     *   <li>The {@linkplain DefaultParameterDescriptor#getDefaultValue() 
default value}
+     *       to return if there is no value associated to the above-cited name 
or alias.</li>
+     *   <li>The {@linkplain DefaultParameterDescriptor#getUnit() unit of 
measurement}
+     *       (if any) of numerical value to return.</li>
+     *   <li>The {@linkplain DefaultParameterDescriptor#getValueClass() type} 
of value to return.</li>
+     * </ul>
+     *
+     * This method can be useful when the {@code ParameterDescriptor} are 
known in advance, for example in the
+     * implementation of some {@linkplain 
org.apache.sis.referencing.operation.DefaultOperationMethod coordinate
+     * operation method}. If the caller has no such {@code 
ParameterDescriptor} at hand, then the
+     * {@link DefaultParameterValueGroup#parameter(String) parameter(String)} 
method is probably more convenient.
+     *
+     * @param  <T> The type of the parameter value.
+     * @param  parameter The name or alias of the parameter to look for, 
together with the desired type and unit of value.
+     * @return The requested parameter value if it exists, or the {@linkplain 
DefaultParameterDescriptor#getDefaultValue()
+     *         default value} otherwise (which may be {@code null}).
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     *
+     * @see DefaultParameterValueGroup#parameter(String)
+     * @see DefaultParameterValue#getValue()
+     *
+     * @since 0.6
      */
-    @SuppressWarnings("unchecked")
-    public static <T> ParameterDescriptor<T> cast(final ParameterDescriptor<?> 
descriptor, final Class<T> valueClass)
-            throws ClassCastException
-    {
-        if (descriptor != null) {
-            final Class<?> actual = descriptor.getValueClass();
-            // We require a strict equality - not 
type.isAssignableFrom(actual) - because in
-            // the later case we could have (to be strict) to return a <? 
extends T> type.
-            if (!valueClass.equals(actual)) {
-                throw new 
ClassCastException(Errors.format(Errors.Keys.IllegalParameterType_2,
-                        descriptor.getName().getCode(), actual));
+    public <T> T getValue(final ParameterDescriptor<T> parameter) throws 
ParameterNotFoundException {
+        final ParameterValue<?> p = getParameter(parameter);
+        if (p != null) {
+            final Object value;
+            final Class<T> type = parameter.getValueClass();
+            final Unit<?>  unit = parameter.getUnit();
+            if (unit == null) {
+                value = p.getValue();
+            } else if (type.isArray()) {
+                value = p.doubleValueList(unit);
+            } else {
+                value = p.doubleValue(unit);
+            }
+            if (value != null) {
+                return ObjectConverters.convert(value, type);
             }
         }
-        return (ParameterDescriptor<T>) descriptor;
+        return parameter.getDefaultValue();     // Returning null is allowed 
here.
     }
 
     /**
-     * Casts the given parameter value to the given type.
-     * An exception is thrown immediately if the parameter does not have the 
expected value class.
+     * Returns the default value of the given descriptor, or throws an 
exception if the
+     * descriptor does not define a default value. This check should be kept 
consistent
+     * with the {@link DefaultParameterValue#incompatibleValue(Object)} check.
+     */
+    private static <T> T defaultValue(final ParameterDescriptor<T> parameter) 
throws IllegalStateException {
+        final T value = parameter.getDefaultValue();
+        if (value != null) {
+            return value;
+        } else {
+            throw new IllegalStateException(Errors.format(
+                    Errors.Keys.MissingValueForParameter_1, 
Verifier.getName(parameter)));
+        }
+    }
+
+    /**
+     * Returns the boolean value of the parameter identified by the given 
descriptor.
+     * See {@link #getValue(ParameterDescriptor)} for more information about 
how this
+     * method uses the given {@code parameter} argument.
+     *
+     * @param  parameter The name or alias of the parameter to look for.
+     * @return The requested parameter value if it exists, or the 
<strong>non-null</strong>
+     *         {@linkplain DefaultParameterDescriptor#getDefaultValue() 
default value} otherwise.
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     * @throws IllegalStateException if the value is not defined and there is 
no default value.
      *
-     * @param  <T>   The expected value class.
-     * @param  value The value to cast, or {@code null}.
-     * @param  type  The expected value class.
-     * @return The value casted to the given type, or {@code null} if the 
given value was null.
-     * @throws ClassCastException if the given value doesn't have the expected 
value class.
+     * @see DefaultParameterValue#booleanValue()
      *
-     * @category verification
+     * @since 0.6
      */
-    @SuppressWarnings("unchecked")
-    public static <T> ParameterValue<T> cast(final ParameterValue<?> value, 
final Class<T> type)
-            throws ClassCastException
-    {
+    public boolean booleanValue(final ParameterDescriptor<Boolean> parameter) 
throws ParameterNotFoundException {
+        final ParameterValue<?> value = getParameter(parameter);
+        return (value != null) ? value.booleanValue() : 
defaultValue(parameter);
+    }
+
+    /**
+     * Returns the integer value of the parameter identified by the given 
descriptor.
+     * See {@link #getValue(ParameterDescriptor)} for more information about 
how this
+     * method uses the given {@code parameter} argument.
+     *
+     * @param  parameter The name or alias of the parameter to look for.
+     * @return The requested parameter value if it exists, or the 
<strong>non-null</strong>
+     *         {@linkplain DefaultParameterDescriptor#getDefaultValue() 
default value} otherwise.
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     * @throws IllegalStateException if the value is not defined and there is 
no default value.
+     *
+     * @see DefaultParameterValue#intValue()
+     *
+     * @since 0.6
+     */
+    public int intValue(final ParameterDescriptor<? extends Number> parameter) 
throws ParameterNotFoundException {
+        final ParameterValue<?> value = getParameter(parameter);
+        return (value != null) ? value.intValue() : 
defaultValue(parameter).intValue();
+    }
+
+    /**
+     * Returns the integer values of the parameter identified by the given 
descriptor.
+     * See {@link #getValue(ParameterDescriptor)} for more information about 
how this
+     * method uses the given {@code parameter} argument.
+     *
+     * @param  parameter The name or alias of the parameter to look for.
+     * @return The requested parameter values if they exist, or the 
<strong>non-null</strong>
+     *         {@linkplain DefaultParameterDescriptor#getDefaultValue() 
default value} otherwise.
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     * @throws IllegalStateException if the value is not defined and there is 
no default value.
+     *
+     * @see DefaultParameterValue#intValueList()
+     *
+     * @since 0.6
+     */
+    public int[] intValueList(final ParameterDescriptor<int[]> parameter) 
throws ParameterNotFoundException {
+        final ParameterValue<?> value = getParameter(parameter);
+        return (value != null) ? value.intValueList() : 
defaultValue(parameter);
+    }
+
+    /**
+     * Returns the floating point value of the parameter identified by the 
given descriptor.
+     * See {@link #getValue(ParameterDescriptor)} for more information about 
how this method
+     * uses the given {@code parameter} argument.
+     *
+     * <p>If the given descriptor supplies a {@linkplain 
DefaultParameterDescriptor#getUnit()
+     * unit of measurement}, then the returned value will be converted into 
that unit.</p>
+     *
+     * @param  parameter The name or alias of the parameter to look for.
+     * @return The requested parameter value if it exists, or the 
<strong>non-null</strong>
+     *         {@linkplain DefaultParameterDescriptor#getDefaultValue() 
default value} otherwise.
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     * @throws IllegalStateException if the value is not defined and there is 
no default value.
+     *
+     * @see DefaultParameterValue#doubleValue(Unit)
+     *
+     * @since 0.6
+     */
+    public double doubleValue(final ParameterDescriptor<? extends Number> 
parameter) throws ParameterNotFoundException {
+        final ParameterValue<?> value = getParameter(parameter);
         if (value != null) {
-            final ParameterDescriptor<?> descriptor = value.getDescriptor();
-            final Class<?> actual = descriptor.getValueClass();
-            if (!type.equals(actual)) { // Same comment than 
cast(ParameterDescriptor)...
-                throw new 
ClassCastException(Errors.format(Errors.Keys.IllegalParameterType_2,
-                        descriptor.getName().getCode(), actual));
-            }
+            final Unit<?> unit = parameter.getUnit();
+            return (unit != null) ? value.doubleValue(unit) : 
value.doubleValue();
+        } else {
+            return defaultValue(parameter).doubleValue();
+        }
+    }
+
+    /**
+     * Returns the floating point values of the parameter identified by the 
given descriptor.
+     * See {@link #getValue(ParameterDescriptor)} for more information about 
how this method
+     * uses the given {@code parameter} argument.
+     *
+     * <p>If the given descriptor supplies a {@linkplain 
DefaultParameterDescriptor#getUnit()
+     * unit of measurement}, then the returned values will be converted into 
that unit.</p>
+     *
+     * @param  parameter The name or alias of the parameter to look for.
+     * @return The requested parameter values if they exists, or the 
<strong>non-null</strong>
+     *         {@linkplain DefaultParameterDescriptor#getDefaultValue() 
default value} otherwise.
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     * @throws IllegalStateException if the value is not defined and there is 
no default value.
+     *
+     * @see DefaultParameterValue#doubleValueList(Unit)
+     *
+     * @since 0.6
+     */
+    public double[] doubleValueList(final ParameterDescriptor<double[]> 
parameter) throws ParameterNotFoundException {
+        final ParameterValue<?> value = getParameter(parameter);
+        if (value != null) {
+            final Unit<?> unit = parameter.getUnit();
+            return (unit != null) ? value.doubleValueList(unit) : 
value.doubleValueList();
+        } else {
+            return defaultValue(parameter);
+        }
+    }
+
+    /**
+     * Returns the string value of the parameter identified by the given 
descriptor.
+     * See {@link #getValue(ParameterDescriptor)} for more information about 
how this
+     * method uses the given {@code parameter} argument.
+     *
+     * @param  parameter The name or alias of the parameter to look for.
+     * @return The requested parameter value if it exists, or the 
<strong>non-null</strong>
+     *         {@linkplain DefaultParameterDescriptor#getDefaultValue() 
default value} otherwise.
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     * @throws IllegalStateException if the value is not defined and there is 
no default value.
+     *
+     * @see DefaultParameterValue#stringValue()
+     *
+     * @since 0.6
+     */
+    public String stringValue(final ParameterDescriptor<? extends 
CharSequence> parameter) throws ParameterNotFoundException {
+        final ParameterValue<?> value = getParameter(parameter);
+        return (value != null) ? value.stringValue() : 
defaultValue(parameter).toString();
+    }
+
+    /**
+     * Returns the parameter identified by the given descriptor.
+     * If the identified parameter is optional and not yet created, then it 
will be created now.
+     *
+     * <p>The default implementation is equivalent to:</p>
+     *
+     * {@preformat java
+     *     return cast(parameter(name), parameter.getValueClass());
+     * }
+     *
+     * where {@code name} is a {@code parameter} {@linkplain 
DefaultParameterDescriptor#getName() name}
+     * or {@linkplain DefaultParameterDescriptor#getAlias() alias} chosen by 
the same algorithm than
+     * {@link #getValue(ParameterDescriptor)}.
+     *
+     * @param  <T> The type of the parameter value.
+     * @param  parameter The parameter to look for.
+     * @return The requested parameter instance.
+     * @throws ParameterNotFoundException if the given {@code parameter} name 
or alias is not legal for this group.
+     *
+     * @see DefaultParameterValueGroup#parameter(String)
+     *
+     * @since 0.6
+     */
+    public <T> ParameterValue<T> getOrCreate(final ParameterDescriptor<T> 
parameter) throws ParameterNotFoundException {
+        return cast(parameter(getName(parameter)), parameter.getValueClass());
+    }
+
+    /**
+     * Returns a deep copy of this group of parameter values.
+     * Included parameter values and subgroups are cloned recursively.
+     *
+     * @return A copy of this group of parameter values.
+     *
+     * @see #copy(ParameterValueGroup, ParameterValueGroup)
+     */
+    @Override
+    public Parameters clone() {
+        try {
+            return (Parameters) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);   // Should never happen since we are 
Cloneable
         }
-        return (ParameterValue<T>) value;
     }
 
     /**
@@ -184,6 +629,8 @@ public final class Parameters extends St
      * @throws InvalidParameterNameException if a {@code source} parameter 
name is unknown to the {@code destination}.
      * @throws InvalidParameterValueException if the value of a {@code source} 
parameter is invalid for the {@code destination}.
      *
+     * @see #clone()
+     *
      * @since 0.5
      */
     public static void copy(final ParameterValueGroup values, final 
ParameterValueGroup destination)

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/UninitializedParameter.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -25,7 +25,7 @@ import org.apache.sis.referencing.Identi
 /**
  * Placeholder for a mandatory parameter value which has not yet been 
initialized.
  * {@code UninitializedParameter} are immutable and contains only the 
descriptor of
- * the parameter to initialize. {@code UninitializedParameter} are replaced by 
the
+ * the parameter to initialize. {@code UninitializedParameter}s are replaced 
by the
  * actual parameter when first needed.
  *
  * @author  Martin Desruisseaux (Geomatys)

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/package-info.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/package-info.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/package-info.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/package-info.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -27,8 +27,8 @@
  *     do not contain the actual parameter value.</li>
  *   <li><b>Parameter values</b> are (<var>descriptor</var>, <var>value</var>) 
tuples, together with convenience methods
  *     for performing unit conversions and getting the values as instances of 
some commonly used types.</li>
- *   <li>Builders, formatters and static methods aim to simplify the creation 
of {@code ParameterDescriptor}s,
- *     the search for parameter values and visualizing them in a tabular 
format.</li>
+ *   <li><b>Builders</b>, <b>formatters</b> and search methods aim to simplify 
the creation of
+ *     {@code ParameterDescriptor}s, the search for parameter values and 
visualizing them in a tabular format.</li>
  * </ul>
  *
  * <p>Parameters are organized in <cite>groups</cite>.
@@ -84,8 +84,8 @@
  * if the given value is not assignable to the expected class or is not inside 
the value domain.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @since   0.5
- * @version 0.4
+ * @since   0.4
+ * @version 0.6
  * @module
  */
 package org.apache.sis.parameter;

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -37,87 +37,120 @@ import static org.apache.sis.internal.sy
 
 // Branch-dependent imports
 import java.util.Objects;
+import org.apache.sis.internal.jdk8.JDK8;
 
 
 /**
  * Base class of builders for various kind of {@link IdentifiedObject}. {@code 
Builder}s aim to make object creation
  * easier — they do not add any new functionality compared to {@link 
org.opengis.referencing.ObjectFactory}.
  * Builder methods like {@link #addName(CharSequence)} and {@link 
#addIdentifier(String)} provide convenient ways
- * to fill the {@link #properties} map, which will be given to the {@code 
ObjectFactory} methods at
- * {@code IdentifiedObject} creation time. Creations happen when any {@code 
createXXX(…)} method defined in
- * the builder subclasses is invoked.
- *
- * <p>This base class provides method for defining the following {@link 
IdentifiedObject} properties:</p>
- * <blockquote><table class="compact" summary="Builder properties.">
- * <tr><td>{@link AbstractIdentifiedObject#getName() Name}:</td>
- *     <td>Each {@code IdentifiedObject} shall have a name, which can be 
specified by a call to any of the
- *     {@code addName(…)} methods defined in this class.</td></tr>
- *
- * <tr><td>{@link AbstractIdentifiedObject#getAlias() Aliases}:</td>
- *     <td>Identified objects can optionally have an arbitrary amount of 
aliases, which are also specified
- *     by the {@code addName(…)} methods — each call after the first one adds 
an alias.</td></tr>
- *
- * <tr><td>{@link AbstractIdentifiedObject#getIdentifiers() Identifiers}:</td>
- *     <td>Identified objects can also have an arbitrary amount of 
identifiers, which are specified by the
- *     {@code addIdentifier(…)} methods. Like names, more than one identifier 
can be added by invoking
- *     the method many time.</td></tr>
- *
- * <tr><td>{@link AbstractIdentifiedObject#getRemarks() Remarks}:</td>
- *     <td>Identified objects can have at most one remark, which is specified 
by the {@code setRemarks(…)}
- *         method.</td></tr>
- * </table></blockquote>
+ * to fill the {@link #properties} map, which will be given to the {@code 
ObjectFactory} methods when any
+ * {@code createXXX(…)} method is invoked.
  *
- * {@section Builder property lifetimes}
- * The same builder can be used for creating many objects, since constructing 
a Coordinate Reference System (CRS)
- * may require constructing many components (coordinate system, datum, 
ellipsoid, prime meridian, <i>etc.</i>),
- * some of them sharing common properties. In order to simplify the most 
common usages, identification
- * properties have two different lifetimes in the {@code Builder} class:
+ * <p>This base class provides methods for defining the {@link 
IdentifiedObject} properties shown below:</p>
  *
  * <ul>
- *   <li>{@linkplain NamedIdentifier#getAuthority() Authority}, {@linkplain 
NamedIdentifier#getCodeSpace() code space}
- *       and {@linkplain NamedIdentifier#getVersion() version} information 
specified to this {@code Builder} will stay
- *       active until they are specified again, because those information are 
typically shared by all components.</li>
- *   <li>Other properties (name, aliases, identifiers and remarks) are cleared 
after each call to a {@code createXXX(…)}
- *       method, because they are usually specific to a particular {@code 
IdentifiedObject} instance.</li>
+ *   <li><p><b>{@linkplain AbstractIdentifiedObject#getName() Name}:</b>
+ *       each {@code IdentifiedObject} shall have a name, which can be 
specified by a call to any of the
+ *       {@link #addName(CharSequence) addName(…)} methods defined in this 
class.</p></li>
+ *
+ *   <li><p><b>{@linkplain AbstractIdentifiedObject#getAlias() Aliases}:</b>
+ *       identified objects can optionally have an arbitrary amount of 
aliases, which are also specified
+ *       by the {@code addName(…)} methods. Each call after the first one adds 
an alias.</p></li>
+ *
+ *   <li><p><b>{@linkplain AbstractIdentifiedObject#getIdentifiers() 
Identifiers}:</b>
+ *       identified objects can also have an arbitrary amount of identifiers, 
which are specified by any
+ *       of the {@link #addIdentifier(String) addIdentifier(…)} methods. Like 
names, more than one identifier
+ *       can be added by invoking the method many time.</p></li>
+ *
+ *   <li><p><b>{@linkplain AbstractIdentifiedObject#getRemarks() Remarks}:</b>
+ *       identified objects can have at most one remark, which is specified by 
the {@code setRemarks(…)}
+ *       method.</p></li>
  * </ul>
  *
- * {@section Usage examples}
- * The "<cite>Mercator (variant A)</cite>" projection (EPSG:9804) is also 
known as "<cite>Mercator (1SP)</cite>".
- * OGC and GeoTIFF use slightly different names, and GeoTIFF has its own code 
(7).
- * Those information can be specified as below:
+ * The names and identifiers cited in the above table can be built from {@link 
CharSequence} given to the
+ * {@code addName(…)} or {@code addIdentifier(…)} methods combined with the 
following properties:
+ *
+ * <ul>
+ *   <li><p><b>{@linkplain ImmutableIdentifier#getCodeSpace() Code space}:</b>
+ *       each {@code Identifier} name or code can be local to a code space 
defined by an authority.
+ *       Both the authority and code space can be specified by the {@link 
#setCodeSpace(Citation, String)} method,
+ *       and usually (but not necessarily) apply to all {@code Identifier} 
instances.</p></li>
+ *
+ *   <li><p><b>{@linkplain ImmutableIdentifier#getVersion() Version}:</b>
+ *       identifiers can optionally have a version specified by the {@link 
#setVersion(String)} method.
+ *       The version usually (but not necessarily) applies to all {@code 
Identifier} instances.</p></li>
+ *
+ *   <li><p><b>{@linkplain ImmutableIdentifier#getDescription() 
Description}:</b>
+ *       identifiers can optionally have a description specified by the {@link 
#setDescription(CharSequence)} method.
+ *       The description applies only to the next identifier to 
create.</p></li>
+ * </ul>
+ *
+ * {@section Namespaces and scopes}
+ * The {@code addName(…)} and {@code addIdentifier(…)} methods come in three 
flavors:
+ * <ul>
+ *   <li><p>The {@link #addIdentifier(String)} and {@link 
#addName(CharSequence)} methods combine the given argument
+ *       with the above-cited authority, code space, version and description 
information.
+ *       The result is a {@linkplain org.apache.sis.util.iso.DefaultLocalName 
local name} or identifier,
+ *       in which the code space information is stored but not shown by the 
{@code toString()} method.</p></li>
+ *
+ *   <li><p>The {@link #addIdentifier(Citation, String)} and {@link 
#addName(Citation, CharSequence)} methods use the given
+ *       {@link Citation} argument, ignoring any authority or code space 
information given to this {@code Builder}.
+ *       The result is a {@linkplain org.apache.sis.util.iso.DefaultScopedName 
scoped name} or identifier,
+ *       in which the code space information is shown by the {@code 
toString()} method.</p></li>
+ *
+ *   <li><p>The {@link #addIdentifier(Identifier)}, {@link 
#addName(Identifier)} and {@link #addName(GenericName)}
+ *       methods take the given object <cite>as-is</cite>. Any authority, code 
space, version or description
+ *       information given to the {@code Builder} are ignored.</p></li>
+ * </ul>
+ *
+ * <div class="note"><b>Example:</b>
+ * The EPSG database defines a projection named "<cite>Mercator (variant 
A)</cite>" (EPSG:9804).
+ * This projection was named "<cite>Mercator (1SP)</cite>" in older EPSG 
database versions.
+ * The same projection was also named "{@code Mercator_1SP}" by OGC some 
specifications.
+ * If we choose EPSG as our primary naming authority, then those three names 
can be declared as below:
  *
  * {@preformat java
- *   Builder builder = new Builder();
  *   builder.setCodespace (Citations.OGP, "EPSG")
- *          .addName      ("Mercator (variant A)")             // Defined in 
EPSG namespace.
- *          .addName      ("Mercator (1SP)")                   // Defined in 
EPSG namespace.
- *          .addIdentifier("9804")                             // Defined in 
EPSG namespace.
- *          .addName      (Citations.OGC,     "Mercator_1SP")
- *          .addName      (Citations.GEOTIFF, "CT_Mercator")
- *          .addIdentifier(Citations.GEOTIFF, "7")
- *          .setRemarks("The “Mercator (1SP)” method name was used prior to 
October 2010.");
- *   // At this point, the createXXX(…) method to invoke depends on the 
Builder subclass.
+ *          .addName("Mercator (variant A)")
+ *          .addName("Mercator (1SP)")
+ *          .addName(Citations.OGC, "Mercator_1SP")
  * }
  *
- * The two first names, which use the default namespace specified by the call 
to {@code setCodeSpace(…)},
- * will have the {@code "EPSG"} {@linkplain NamedIdentifier#scope() scope}. 
Since scopes are not shown
- * in {@linkplain NamedIdentifier#toString() string representation of names}, 
the string representation
- * of the two first names will omit the {@code "EPSG:"} prefix. However the 
string representation of the
- * two last names will be {@code "OGC:Mercator_1SP"} and {@code 
"GeoTIFF:CT_Mercator"} respectively.
- *
- * <p>The {@code IdentificationObject} created by this example will have the 
following properties:</p>
- * <blockquote><table class="compact" summary="IdentifiedObject properties.">
- * <tr><td>{@link AbstractIdentifiedObject#getName() Name}:</td>
- *     <td>{@code "Mercator (variant A)"} as a local name in {@code "EPSG"} 
scope.</td></tr>
- * <tr><td>{@link AbstractIdentifiedObject#getAlias() Aliases}:</td>
- *     <td>{@code "Mercator (1SP)"} as a local name in {@code "EPSG"} scope,
- *         {@code "OGC:Mercator_1SP"} and {@code "GeoTIFF:CT_Mercator"} as 
scoped names.</td></tr>
- * <tr><td>{@link AbstractIdentifiedObject#getIdentifiers() Identifiers}:</td>
- *     <td>{@code "EPSG:9804"} and {@code "GeoTIFF:7"}.</td></tr>
- * <tr><td>{@link AbstractIdentifiedObject#getRemarks() Remarks}:</td>
- *     <td>{@code "The “Mercator (1SP)” method name was used prior to October 
2010."}</td></tr>
- * </table></blockquote>
+ * The {@code toString()} representation of those three names are {@code 
"Mercator (variant A)"},
+ * {@code "Mercator (1SP)"} (note the absence of {@code "EPSG:"} prefix, which 
is stored as the
+ * name {@linkplain org.apache.sis.util.iso.DefaultLocalName#scope() scope} 
but not shown) and
+ * <code>"<b>OGC:</b>Mercator_1SP"</code> respectively.</div>
+ *
+ *
+ * {@section Builder property lifetimes}
+ * Some complex objects require the creation of many components. For example 
constructing a
+ * {@linkplain org.apache.sis.referencing.crs.AbstractCRS Coordinate Reference 
System} (CRS) may require constructing a
+ * {@linkplain org.apache.sis.referencing.cs.AbstractCS coordinate system}, a
+ * {@linkplain org.apache.sis.referencing.datum.AbstractDatum datum} and an
+ * {@linkplain org.apache.sis.referencing.datum.DefaultEllipsoid ellipsoid} 
among other components.
+ * However all those components often (but not necessarily) share the same 
authority, code space and version information.
+ * In order to simplify that common usage, two groups of properties have 
different lifetimes in the {@code Builder} class:
+ *
+ * <ul>
+ *   <li><p>
+ *       {@linkplain NamedIdentifier#getAuthority() Authority},
+ *       {@linkplain NamedIdentifier#getCodeSpace() code space} and
+ *       {@linkplain NamedIdentifier#getVersion()   version}:<br>
+ *       Kept until they are specified again, because those properties are 
typically shared by all components.
+ *   </p></li>
+ *   <li><p>
+ *       {@linkplain AbstractIdentifiedObject#getName()        Name},
+ *       {@linkplain AbstractIdentifiedObject#getAlias()       aliases},
+ *       {@linkplain AbstractIdentifiedObject#getIdentifiers() identifiers},
+ *       {@linkplain ImmutableIdentifier#getDescription()      description} and
+ *       {@linkplain AbstractIdentifiedObject#getRemarks()     remarks}:<br>
+ *       Cleared after each call to a {@code createXXX(…)} method, because 
those properties are usually specific
+ *       to a particular {@code IdentifiedObject} or {@code Identifier} 
instance.
+ *   </p></li>
+ * </ul>
  *
+ * {@section Usage examples}
  * See {@link org.apache.sis.parameter.ParameterBuilder} class javadoc for 
more examples with the
  * <cite>Mercator</cite> projection parameters.
  *
@@ -146,7 +179,7 @@ import java.util.Objects;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public abstract class Builder<B extends Builder<B>> {
@@ -250,7 +283,7 @@ public abstract class Builder<B extends
      */
     private NameSpace namespace() {
         if (namespace == null) {
-            final String codespace = (String) 
properties.get(Identifier.CODESPACE_KEY);
+            final String codespace = getCodeSpace();
             if (codespace != null) {
                 namespace = NAMES.createNameSpace(NAMES.createLocalName(null, 
codespace), null);
             }
@@ -259,8 +292,39 @@ public abstract class Builder<B extends
     }
 
     /**
-     * Sets the {@code Identifier} authority and code space. This method is 
typically invoked only once,
-     * since a compound object often uses the same code space for all 
individual components.
+     * Returns the value of the first argument given by the last call to 
{@link #setCodeSpace(Citation, String)},
+     * or {@code null} if none. The default value is {@code null}.
+     *
+     * @return The citation specified by the last call to {@code 
setCodeSpace(…)}, or {@code null} if none.
+     *
+     * @since 0.6
+     */
+    private Citation getAuthority() {
+        return (Citation) properties.get(Identifier.AUTHORITY_KEY);
+    }
+
+    /**
+     * Returns the value of the last argument given by the last call to {@link 
#setCodeSpace(Citation, String)},
+     * or {@code null} if none. The default value is {@code null}.
+     *
+     * @return The string specified by the last call to {@code 
setCodeSpace(…)}, or {@code null} if none.
+     *
+     * @since 0.6
+     */
+    private String getCodeSpace() {
+        return (String) properties.get(Identifier.CODESPACE_KEY);
+    }
+
+    /**
+     * Sets the {@code Identifier} authority and code space.
+     * The code space is often the authority's abbreviation, but not 
necessarily.
+     *
+     * <div class="note"><b>Example:</b> Coordinate Reference System (CRS) 
objects identified by codes from the
+     * EPSG database are maintained by the {@linkplain 
org.apache.sis.metadata.iso.citation.Citations#OGP OGP}
+     * authority, but the code space is {@code "EPSG"} for historical 
reasons.</div>
+     *
+     * This method is typically invoked only once, since a compound object 
often uses the same code space
+     * for all individual components.
      *
      * <p><b>Condition:</b>
      * this method can not be invoked after one or more names or identifiers 
have been added (by calls to the
@@ -275,6 +339,9 @@ public abstract class Builder<B extends
      * @return {@code this}, for method call chaining.
      * @throws IllegalStateException if {@code addName(…)} or {@code 
addIdentifier(…)} has been invoked at least
      *         once since builder construction or since the last call to a 
{@code createXXX(…)} method.
+     *
+     * @see ImmutableIdentifier#getAuthority()
+     * @see ImmutableIdentifier#getCodeSpace()
      */
     public B setCodeSpace(final Citation authority, final String codespace) {
         if (!setProperty(Identifier.CODESPACE_KEY, codespace)) {
@@ -285,6 +352,18 @@ public abstract class Builder<B extends
     }
 
     /**
+     * Returns the value given by the last call to {@link 
#setVersion(String)}, or {@code null} if none.
+     * The default value is {@code null}.
+     *
+     * @return The value specified by the last call to {@code setVersion(…)}, 
or {@code null} if none.
+     *
+     * @since 0.6
+     */
+    private String getVersion() {
+        return (String) properties.get(Identifier.VERSION_KEY);
+    }
+
+    /**
      * Sets the {@code Identifier} version of object definitions. This method 
is typically invoked only once,
      * since a compound object often uses the same version for all individual 
components.
      *
@@ -325,9 +404,8 @@ public abstract class Builder<B extends
      */
     public B addName(final CharSequence name) {
         ensureNonNull("name", name);
-        final Object old = properties.put(IdentifiedObject.NAME_KEY, 
name.toString());
-        if (old != null) {
-            properties.put(IdentifiedObject.NAME_KEY, old); // Restore 
previous value.
+        if (JDK8.putIfAbsent(properties, IdentifiedObject.NAME_KEY, 
name.toString()) != null) {
+            // A primary name is already present. Add the given name as an 
alias instead.
             aliases.add(name instanceof GenericName ? (GenericName) name : 
NAMES.createLocalName(namespace(), name));
         }
         return self();
@@ -363,15 +441,9 @@ public abstract class Builder<B extends
      */
     public B addName(final Citation authority, final CharSequence name) {
         ensureNonNull("name", name);
-        final NamedIdentifier identifier;
-        if (name instanceof InternationalString) {
-            identifier = new NamedIdentifier(authority, (InternationalString) 
name);
-        } else {
-            identifier = new NamedIdentifier(authority, name.toString());
-        }
-        final Object old = properties.put(IdentifiedObject.NAME_KEY, 
identifier);
-        if (old != null) {
-            properties.put(IdentifiedObject.NAME_KEY, old); // Restore 
previous value.
+        final NamedIdentifier identifier = new NamedIdentifier(authority, 
name);
+        if (JDK8.putIfAbsent(properties, IdentifiedObject.NAME_KEY, 
identifier) != null) {
+            // A primary name is already present. Add the given name as an 
alias instead.
             aliases.add(identifier);
         }
         return self();
@@ -396,9 +468,8 @@ public abstract class Builder<B extends
      */
     public B addName(final Identifier name) {
         ensureNonNull("name", name);
-        final Object old = properties.put(IdentifiedObject.NAME_KEY, name);
-        if (old != null) {
-            properties.put(IdentifiedObject.NAME_KEY, old); // Restore 
previous value.
+        if (JDK8.putIfAbsent(properties, IdentifiedObject.NAME_KEY, name) != 
null) {
+            // A primary name is already present. Add the given name as an 
alias instead.
             aliases.add(name instanceof GenericName ? (GenericName) name : new 
NamedIdentifier(name));
         }
         return self();
@@ -424,7 +495,7 @@ public abstract class Builder<B extends
     public B addName(final GenericName name) {
         ensureNonNull("name", name);
         if (properties.get(IdentifiedObject.NAME_KEY) == null) {
-            properties.put(IdentifiedObject.NAME_KEY, new 
NamedIdentifier(name));
+            properties.put(IdentifiedObject.NAME_KEY, (name instanceof 
Identifier) ? name : new NamedIdentifier(name));
         } else {
             aliases.add(name);
         }
@@ -432,6 +503,32 @@ public abstract class Builder<B extends
     }
 
     /**
+     * Adds a deprecated name given by a {@code CharSequence}. Some objects 
have deprecated names for historical reasons.
+     * The deprecated name typically has a replacement, which can be given by 
the {@code supersededBy} argument.
+     * The later, if non-null, shall be a name specified by a previous call to 
an {@code addName(…)} method.
+     *
+     * <p>The given string will be combined with the authority, {@link 
#setCodeSpace(Citation, String) code space} and
+     * {@link #setVersion(String) version} information for creating the 
deprecated {@link NamedIdentifier} object.</p>
+     *
+     * <p><b>Lifetime:</b>
+     * all identifiers are cleared after a {@code createXXX(…)} method has 
been invoked.</p>
+     *
+     * @param  name The {@code IdentifiedObject} deprecated name.
+     * @param  supersededBy The name to use instead of this one, or {@code 
null} if none.
+     * @return {@code this}, for method call chaining.
+     *
+     * @since 0.6
+     */
+    public B addDeprecatedName(final CharSequence name, final CharSequence 
supersededBy) {
+        ensureNonNull("name", name);
+        final DeprecatedName dn = new DeprecatedName(getAuthority(), 
getCodeSpace(), name, getVersion(), supersededBy);
+        if (JDK8.putIfAbsent(properties, IdentifiedObject.NAME_KEY, dn) != 
null) {
+            aliases.add(dn);
+        }
+        return self();
+    }
+
+    /**
      * Adds an {@code IdentifiedObject} identifier given by a {@code String}.
      * The given string will be combined with the authority, {@link 
#setCodeSpace(Citation, String) code space}
      * and {@link #setVersion(String) version} information for creating the 
{@link Identifier} object.
@@ -444,8 +541,7 @@ public abstract class Builder<B extends
      */
     public B addIdentifier(final String identifier) {
         ensureNonNull("identifier", identifier);
-        identifiers.add(new ImmutableIdentifier((Citation) 
properties.get(Identifier.AUTHORITY_KEY),
-                (String) properties.get(Identifier.CODESPACE_KEY), 
identifier));
+        identifiers.add(new ImmutableIdentifier(getAuthority(), 
getCodeSpace(), identifier, getVersion(), null));
         return self();
     }
 
@@ -464,6 +560,7 @@ public abstract class Builder<B extends
      */
     public B addIdentifier(final Citation authority, final String identifier) {
         ensureNonNull("identifier", identifier);
+        // Do not use the version information since it applies to the default 
authority rather than the given one.
         identifiers.add(new ImmutableIdentifier(authority, 
Citations.getUnicodeIdentifier(authority), identifier));
         return self();
     }
@@ -487,6 +584,30 @@ public abstract class Builder<B extends
     }
 
     /**
+     * Adds a deprecated identifier given by a {@code String}. Some objects 
have deprecated identifiers for
+     * historical reasons. The deprecated identifier typically has a 
replacement, which can be given by the
+     * {@code supersededBy} argument. The later, if non-null, shall be an 
identifier specified by a previous
+     * call to an {@code addIdentifier(…)} method.
+     *
+     * <p>The given string will be combined with the authority, {@link 
#setCodeSpace(Citation, String) code space}
+     * and {@link #setVersion(String) version} information for creating the 
deprecated {@link Identifier} object.</p>
+     *
+     * <p><b>Lifetime:</b>
+     * all identifiers are cleared after a {@code createXXX(…)} method has 
been invoked.</p>
+     *
+     * @param  identifier   The {@code IdentifiedObject} deprecated identifier.
+     * @param  supersededBy The identifier to use instead of this one, or 
{@code null} if none.
+     * @return {@code this}, for method call chaining.
+     *
+     * @since 0.6
+     */
+    public B addDeprecatedIdentifier(final String identifier, final String 
supersededBy) {
+        ensureNonNull("identifier", identifier);
+        identifiers.add(new DeprecatedCode(getAuthority(), getCodeSpace(), 
identifier, getVersion(), supersededBy));
+        return self();
+    }
+
+    /**
      * Sets the parameter description as a {@code String} or {@code 
InternationalString} instance.
      * Calls to this method overwrite any previous value.
      *
@@ -545,13 +666,20 @@ public abstract class Builder<B extends
      * @see #properties
      */
     protected void onCreate(final boolean cleanup) {
-        properties.put(IdentifiedObject.ALIAS_KEY,       cleanup ? null : 
aliases    .toArray(new GenericName[aliases    .size()]));
-        properties.put(IdentifiedObject.IDENTIFIERS_KEY, cleanup ? null : 
identifiers.toArray(new Identifier [identifiers.size()]));
+        final GenericName[] valueAlias;
+        final Identifier[]  valueIds;
         if (cleanup) {
             properties .put(IdentifiedObject.NAME_KEY, null);
             properties .remove(IdentifiedObject.REMARKS_KEY);
             aliases    .clear();
             identifiers.clear();
+            valueAlias = null;
+            valueIds   = null;
+        } else {
+            valueAlias = aliases    .toArray(new GenericName[aliases    
.size()]);
+            valueIds   = identifiers.toArray(new Identifier 
[identifiers.size()]);
         }
+        properties.put(IdentifiedObject.ALIAS_KEY,       valueAlias);
+        properties.put(IdentifiedObject.IDENTIFIERS_KEY, valueIds);
     }
 }

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -36,6 +36,7 @@ import org.apache.sis.internal.system.De
 import org.apache.sis.metadata.iso.citation.Citations;  // For javadoc
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.util.collection.WeakValueHashMap;
+import org.apache.sis.util.ArgumentChecks;
 
 import static org.apache.sis.internal.util.Citations.getUnicodeIdentifier;
 
@@ -89,7 +90,7 @@ import java.util.Objects;
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 public class NamedIdentifier extends ImmutableIdentifier implements 
GenericName {
@@ -160,37 +161,36 @@ public class NamedIdentifier extends Imm
     }
 
     /**
-     * Constructs an identifier from an authority and localizable code.
-     * This is a convenience constructor for commonly-used parameters.
-     *
-     * @param authority The authority (e.g. {@link Citations#OGC} or {@link 
Citations#EPSG}),
-     *                  or {@code null} if not available.
-     * @param code      The code. The {@code code.toString(Locale.ROOT)} 
return value will be used for the
-     *                  {@link #getCode() code} property, and the complete 
international string will be used
-     *                  for the {@link #getName() name} property.
-     */
-    public NamedIdentifier(final Citation authority, final InternationalString 
code) {
-        this(authority, code.toString(Locale.ROOT));
-        name = createName(authority, code);
-        isNameSupplied = true; // Because 'code' is an international string.
-    }
-
-    /**
      * Constructs an identifier from an authority and code.
      * This is a convenience constructor for commonly-used parameters.
      *
-     * @param authority The authority (e.g. {@link Citations#OGC} or {@link 
Citations#EPSG}),
-     *                  or {@code null} if not available.
-     * @param code      The code. This parameter is mandatory.
+     * <p>If the given code is an {@link InternationalString}, then the {@code 
code.toString(Locale.ROOT)}
+     * return value will be used for the {@link #getCode() code} property, and 
the complete international
+     * string will be used for the {@link #getName() name} property.</p>
+     *
+     * @param authority
+     *          Organization or party responsible for definition and 
maintenance of the code
+     *          space or code, or {@code null} if not available.
+     * @param code
+     *          Identifier code or name, optionally from a controlled list or 
pattern defined by
+     *          the authority. The code can not be null.
      */
-    public NamedIdentifier(final Citation authority, final String code) {
-        super(authority, getUnicodeIdentifier(authority), code);
+    public NamedIdentifier(final Citation authority, final CharSequence code) {
+        super(authority, getUnicodeIdentifier(authority), toString(code));
+        if (code instanceof InternationalString) {
+            name = createName(authority, code);
+            isNameSupplied = true; // Because 'code' is an international 
string.
+        }
     }
 
     /**
-     * Creates an identifier from the specified code and authority,
+     * Constructs an identifier from an authority and localizable code,
      * with an optional version number and remarks.
      *
+     * <p>If the given code is an {@link InternationalString}, then the {@code 
code.toString(Locale.ROOT)}
+     * return value will be used for the {@link #getCode() code} property, and 
the complete international
+     * string will be used for the {@link #getName() name} property.</p>
+     *
      * @param authority
      *          Organization or party responsible for definition and 
maintenance of the code
      *          space or code, or {@code null} if not available.
@@ -206,10 +206,26 @@ public class NamedIdentifier extends Imm
      * @param remarks
      *          Comments on or information about this identifier, or {@code 
null} if none.
      */
-    public NamedIdentifier(final Citation authority, final String codeSpace,
-            final String code, final String version, final InternationalString 
remarks)
+    public NamedIdentifier(final Citation authority, final String codeSpace, 
final CharSequence code,
+            final String version, final InternationalString remarks)
     {
-        super(authority, codeSpace, code, version, remarks);
+        super(authority, codeSpace, toString(code), version, remarks);
+        if (code instanceof InternationalString) {
+            name = createName(authority, code);
+            isNameSupplied = true; // Because 'code' is an international 
string.
+        }
+    }
+
+    /**
+     * Returns the unlocalized string representation of the given code.
+     */
+    private static String toString(final CharSequence code) {
+        ArgumentChecks.ensureNonNull("code", code);
+        if (code instanceof InternationalString) {
+            return ((InternationalString) code).toString(Locale.ROOT);
+        } else {
+            return code.toString();
+        }
     }
 
     /**

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -43,7 +43,7 @@ import java.util.Objects;
 
 
 /**
- * Specifies the relationship of a coordinate system to the earth.
+ * Specifies the relationship of a {@linkplain 
org.apache.sis.referencing.cs.AbstractCS Coordinate System} to the earth.
  * A datum can be defined as a set of real points on the earth that have 
coordinates.
  * Each datum subtype can be associated with only specific types of
  * {@linkplain org.apache.sis.referencing.cs.AbstractCS coordinate systems}, 
thus creating specific types of

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -28,6 +28,7 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.apache.sis.util.Utilities;
+import org.apache.sis.util.Workaround;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
@@ -243,6 +244,7 @@ public class DefaultOperationMethod exte
      * Work around for RFE #4093999 in Sun's bug database
      * ("Relax constraint on placement of this()/super() call in 
constructors").
      */
+    @Workaround(library="JDK", version="1.7")
     private static Map<String,?> getProperties(final MathTransform transform) {
         ensureNonNull("transform", transform);
         if (transform instanceof Parameterized) {

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/builder/package-info.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -16,7 +16,8 @@
  */
 
 /**
- * Helper classes for creating {@code MathTransform}s from a set of points.
+ * Helper classes for creating {@linkplain 
org.apache.sis.referencing.operation.transform.AbstractMathTransform
+ * Math Transforms} from a set of points.
  * The builder classes require a matched set of known positions, one from a 
"source" data set and another
  * from a "target" data set. The builder will then provide a transformation 
positions from the "source" CRS
  * to the "target" CRS.

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -32,6 +32,7 @@ import javax.measure.converter.Conversio
 import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.cs.CoordinateSystem;
@@ -508,6 +509,8 @@ public class DefaultMathTransformFactory
      * @throws NoSuchIdentifierException if there is no transform registered 
for the coordinate operation method.
      * @throws FactoryException if the object creation failed. This exception 
is thrown
      *         if some required parameter has not been supplied, or has 
illegal value.
+     *
+     * @see 
org.apache.sis.parameter.ParameterBuilder#createGroupForMapProjection(ParameterDescriptor...)
      */
     @Override
     public MathTransform createBaseToDerived(final CoordinateReferenceSystem 
baseCRS,

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterDescriptorGroupTest.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -47,6 +47,11 @@ import static org.opengis.referencing.Id
 @DependsOn(DefaultParameterDescriptorTest.class)
 public final strictfp class DefaultParameterDescriptorGroupTest extends 
TestCase {
     /**
+     * The default value used by the parameters in the {@link #M1_M1_O1_O2} 
descriptor.
+     */
+    static final Integer DEFAULT_VALUE = 10;
+
+    /**
      * A group of 4 parameters of type {@link Integer} with default value 10.
      * The two first parameters are mandatory, while the two last parameters 
are optional.
      * The very last parameter has a maximum number of occurrence of 2, which 
is illegal
@@ -54,7 +59,6 @@ public final strictfp class DefaultParam
      */
     static final DefaultParameterDescriptorGroup M1_M1_O1_O2;
     static {
-        final Integer DEFAULT_VALUE = 10;
         final Class<Integer> type = Integer.class;
         final Map<String,Object> properties = new HashMap<>(4);
         M1_M1_O1_O2 = new 
DefaultParameterDescriptorGroup(singletonMap(NAME_KEY, "Test group"), 0, 1,

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/DefaultParameterValueGroupTest.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -18,6 +18,7 @@ package org.apache.sis.parameter;
 
 import java.util.List;
 import java.util.Arrays;
+import java.util.ArrayList;
 import org.opengis.parameter.GeneralParameterDescriptor;
 import org.opengis.parameter.GeneralParameterValue;
 import org.opengis.parameter.ParameterDescriptor;
@@ -42,7 +43,7 @@ import static org.opengis.referencing.Id
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 @DependsOn({
@@ -143,8 +144,8 @@ public final strictfp class DefaultParam
         assertEquals("parameter(“Mandatory 2”)", 20, 
group.parameter("Mandatory 2").intValue());
         values.clear();
         assertEquals("size", 2, values.size());
-        assertEquals("parameter(“Mandatory 2”)", 10, 
group.parameter("Mandatory 2").intValue());
-        // The above 10 is the default value specified by the descriptor.
+        assertEquals("parameter(“Mandatory 2”)", 
DefaultParameterDescriptorGroupTest.DEFAULT_VALUE,
+                group.parameter("Mandatory 2").getValue());
     }
 
     /**
@@ -164,9 +165,8 @@ public final strictfp class DefaultParam
         } catch (IndexOutOfBoundsException e) {
             assertNotNull(e.getMessage());
         }
-        assertEquals(10, ((ParameterValue<?>) values.get(0)).intValue());
-        assertEquals(10, ((ParameterValue<?>) values.get(1)).intValue());
-        // 10 is the default value specified by the descriptor.
+        assertEquals(DefaultParameterDescriptorGroupTest.DEFAULT_VALUE, 
((ParameterValue<?>) values.get(0)).getValue());
+        assertEquals(DefaultParameterDescriptorGroupTest.DEFAULT_VALUE, 
((ParameterValue<?>) values.get(1)).getValue());
     }
 
     /**
@@ -229,6 +229,63 @@ public final strictfp class DefaultParam
     }
 
     /**
+     * Tests {@code DefaultParameterValueGroup.values().addAll(…)} with 
subgroups.
+     *
+     * @since 0.6
+     */
+    @Test
+    @DependsOnMethod({"testValuesAddAll", "testAddGroup", 
"testEqualsAndHashCode"})
+    public void testValuesAddAllWithSubgroups() {
+        final DefaultParameterDescriptorGroup group, subGroup;
+        final List<GeneralParameterDescriptor> descriptors = new 
ArrayList<>(descriptor.descriptors());
+        subGroup = new DefaultParameterDescriptorGroup(singletonMap(NAME_KEY, 
"theSubGroup"),
+                2, 4, descriptors.toArray(new 
GeneralParameterDescriptor[descriptors.size()]));
+        descriptors.add(subGroup);
+        group = new DefaultParameterDescriptorGroup(singletonMap(NAME_KEY, 
"theGroup"),
+                descriptors.toArray(new 
GeneralParameterDescriptor[descriptors.size()]));
+        /*
+         * Prepare the GeneralParameterValue instances that we are going to 
add in the above group.
+         * We assign arbitrary integer values to each instance if order to be 
able to differentiate
+         * them, but the purpose of this test is not to verify those integer 
values.
+         *
+         * We intentionally:
+         *   - Omit the creation of a mandatory parameter value
+         *   - Create more sub-groups than the minimum required.
+         */
+        final ParameterValue<?>   v2 = (ParameterValue<?>) 
descriptor.descriptor("Mandatory 2").createValue();
+        final ParameterValue<?>   v3 = (ParameterValue<?>) 
descriptor.descriptor( "Optional 3").createValue();
+        final ParameterValueGroup g1 = subGroup.createValue();
+        final ParameterValueGroup g2 = subGroup.createValue();
+        final ParameterValueGroup g3 = subGroup.createValue();
+        v2.setValue(4);
+        v3.setValue(8);
+        g1.parameter("Mandatory 1").setValue(3);
+        g2.parameter( "Optional 4").setValue(7);
+        g3.parameter("Mandatory 2").setValue(5);
+        final List<GeneralParameterValue> expected = new ArrayList<>(6);
+        assertTrue(expected.add(v2));
+        assertTrue(expected.add(v3));
+        assertTrue(expected.add(g1));
+        assertTrue(expected.add(g2));
+        assertTrue(expected.add(g3));
+        /*
+         * A newly created group should be initialized with 4 
GeneralParameterValue instances because of
+         * the mandatory ones. After we added our own instances created above, 
the group should contains
+         * 6 instances (one more than what we added) because of the "Mandatory 
1" parameter that we did
+         * not provided. Note that the element order in the 'values' 
collection does not need to be the
+         * order in which we provided our GeneralParameterValue instances.
+         */
+        final List<GeneralParameterValue> values = 
group.createValue().values();
+        assertEquals("Initial size", 4,         values.size());
+        assertTrue  ("List shall be modified",  values.addAll(expected));
+        assertEquals("Size after addAll(…)", 6, values.size());
+        final ParameterValue<?> v1 = (ParameterValue<?>) values.get(0);
+        assertEquals("Default value", 
DefaultParameterDescriptorGroupTest.DEFAULT_VALUE, v1.getValue());
+        assertTrue(expected.add(v1));
+        assertSetEquals(expected, values);
+    }
+
+    /**
      * Tests that attempts to add an invalid parameter cause an {@link 
InvalidParameterNameException} to be thrown.
      */
     @Test

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParameterBuilderTest.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -22,6 +22,7 @@ import javax.measure.unit.NonSI;
 import org.opengis.util.GenericName;
 import org.opengis.parameter.ParameterDescriptor;
 import org.apache.sis.metadata.iso.citation.HardCodedCitations;
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -34,7 +35,7 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.6
  * @module
  */
 @DependsOn({
@@ -44,9 +45,38 @@ import static org.junit.Assert.*;
 })
 public final strictfp class ParameterBuilderTest extends TestCase {
     /**
+     * Tests various {@code create(…)} methods.
+     */
+    @Test
+    public void testCreate() {
+        final ParameterBuilder builder = new ParameterBuilder();
+        ParameterDescriptor<Double> p = builder.addName("Test 1").create(0, 
SI.METRE);
+        assertEquals("name", "Test 1",    p.getName().getCode());
+        assertEquals("defaultValue", 0.0, p.getDefaultValue(), 0);
+        assertNull  ("minimumValue",      p.getMinimumValue());
+        assertNull  ("maximumValue",      p.getMaximumValue());
+        assertEquals("unit", SI.METRE,    p.getUnit());
+
+        p = builder.addName("Test 2").create(Double.NaN, SI.METRE);
+        assertEquals("name", "Test 2",    p.getName().getCode());
+        assertNull  ("defaultValue",      p.getDefaultValue());
+        assertNull  ("minimumValue",      p.getMinimumValue());
+        assertNull  ("maximumValue",      p.getMaximumValue());
+        assertEquals("unit", SI.METRE,    p.getUnit());
+
+        p = builder.addName("Test 3").createBounded(1, 4, 3, SI.METRE);
+        assertEquals("name", "Test 3",    p.getName().getCode());
+        assertEquals("defaultValue", 3.0, p.getDefaultValue(), 0);
+        assertEquals("minimumValue", 1.0, p.getMinimumValue());
+        assertEquals("maximumValue", 4.0, p.getMaximumValue());
+        assertEquals("unit", SI.METRE,    p.getUnit());
+    }
+
+    /**
      * Tests the "<cite>Mercator (variant A)</cite>" example given in Javadoc.
      */
     @Test
+    @DependsOnMethod("testCreate")
     public void testMercatorProjection() {
         final ParameterBuilder builder = new ParameterBuilder();
         builder.setCodeSpace(HardCodedCitations.OGP, "EPSG").setRequired(true);

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -16,8 +16,9 @@
  */
 package org.apache.sis.parameter;
 
-import java.util.Collection;
 import java.util.Set;
+import java.util.Collection;
+import java.util.Collections;
 import javax.measure.unit.SI;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDirection;
@@ -42,12 +43,14 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.5
+ * @version 0.6
  * @module
  */
 @DependsOn({
     DefaultParameterDescriptorTest.class,
-    DefaultParameterValueTest.class
+    DefaultParameterDescriptorGroupTest.class,
+    DefaultParameterValueTest.class,
+    DefaultParameterValueGroupTest.class
 })
 public final strictfp class ParametersTest extends TestCase {
     /**
@@ -155,4 +158,38 @@ public final strictfp class ParametersTe
         assertEquals("Optional 4 (second occurrence)", 50,
                 ((ParameterValue<?>) destination.values().get(4)).intValue());
     }
+
+    /**
+     * Tests {@link Parameters#getValue(ParameterDescriptor)} and {@link 
Parameters#intValue(ParameterDescriptor)}.
+     *
+     * @since 0.6
+     */
+    @Test
+    public void testGetIntValue() {
+        final ParameterDescriptor<Integer> descriptor = 
DefaultParameterDescriptorTest.create("My param", 5, 15, 10);
+        final ParameterDescriptor<Integer> incomplete = 
DefaultParameterDescriptorTest.createSimpleOptional("My param", Integer.class);
+        final Parameters group = Parameters.castOrWrap(new 
DefaultParameterDescriptorGroup(Collections.singletonMap(
+                DefaultParameterDescriptorGroup.NAME_KEY, "My group"), 1, 1, 
incomplete).createValue());
+        /*
+         * Test when the ParameterValueGroup is empty. We test both with the 
"incomplete" descriptor,
+         * which contain no default value, and with the complete one, which 
provide a default value.
+         */
+        assertNull("No value and no default value.", 
group.getValue(incomplete));
+        assertEquals("No value, should fallback on default.", 
Integer.valueOf(10), group.getValue(descriptor));
+        try {
+            group.intValue(incomplete);
+            fail("Can not return when there is no value.");
+        } catch (IllegalStateException e) {
+            final String message = e.getMessage();
+            assertTrue(message, message.contains("My param"));
+        }
+        /*
+         * Define a value and test again.
+         */
+        group.parameter("My param").setValue(12);
+        assertEquals(Integer.valueOf(12), group.getValue(incomplete));
+        assertEquals(Integer.valueOf(12), group.getValue(descriptor));
+        assertEquals(12, group.intValue(incomplete));
+        assertEquals(12, group.intValue(descriptor));
+    }
 }

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/parameter/TensorParametersTest.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -161,7 +161,7 @@ public strictfp class TensorParametersTe
     {
         assertEquals("name", names[row][column], actual.getName().getCode());
         assertAliasTipEquals((aliases != null) ? aliases[row][column] : null, 
actual);
-        assertIdentifierEqualsEPSG((identifiers != null) ? 
identifiers[row][column] : 0, actual);
+        assertEpsgIdentifierEquals((identifiers != null) ? 
identifiers[row][column] : 0, actual.getIdentifiers());
         assertEquals("defaultValue", defaultValue, actual.getDefaultValue());
     }
 

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultOperationMethodTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultOperationMethodTest.java?rev=1667396&r1=1667395&r2=1667396&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultOperationMethodTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/DefaultOperationMethodTest.java
 [UTF-8] Tue Mar 17 20:37:55 2015
@@ -32,8 +32,7 @@ import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.apache.sis.test.MetadataAssert.*;
-import static org.apache.sis.test.TestUtilities.getSingleton;
+import static org.apache.sis.test.ReferencingAssert.*;
 
 
 /**
@@ -87,7 +86,7 @@ public final strictfp class DefaultOpera
     public void testConstruction() {
         final OperationMethod method = create("Mercator (variant A)", "9804", 
"EPSG guidance note #7-2", 2);
         assertEpsgIdentifierEquals("Mercator (variant A)", method.getName());
-        assertEpsgIdentifierEquals("9804", 
getSingleton(method.getIdentifiers()));
+        assertEpsgIdentifierEquals(9804, method.getIdentifiers());
         assertEquals("formula", "EPSG guidance note #7-2", 
method.getFormula().getCitation().getTitle().toString());
         assertEquals("sourceDimensions", Integer.valueOf(2), 
method.getSourceDimensions());
         assertEquals("targetDimensions", Integer.valueOf(2), 
method.getTargetDimensions());


Reply via email to