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());
