You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2014/03/12 23:44:22 UTC
svn commit: r1576972 [3/5] - in /sis/branches/JDK6: ./
core/sis-feature/src/main/java/org/apache/sis/feature/
core/sis-metadata/src/main/java/org/apache/sis/io/wkt/
core/sis-metadata/src/main/java/org/apache/sis/metadata/
core/sis-metadata/src/main/jav...
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java?rev=1576972&r1=1576971&r2=1576972&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -19,35 +19,33 @@ package org.apache.sis.parameter;
import java.util.Arrays;
import java.util.Set;
import java.util.Map;
-import java.util.Collection;
-import java.util.LinkedHashSet;
import javax.measure.unit.Unit;
-
import org.opengis.util.CodeList;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterDescriptor;
-
-import org.apache.sis.util.Debug;
import org.apache.sis.util.Classes;
import org.apache.sis.util.Numbers;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.collection.Containers;
+import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.io.wkt.ElementKind;
+import org.apache.sis.measure.Range;
+import org.apache.sis.measure.MeasurementRange;
import org.apache.sis.internal.util.Numerics;
+import org.apache.sis.internal.util.CollectionsExt;
+import org.apache.sis.internal.referencing.WKTUtilities;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.referencing.AbstractIdentifiedObject;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
import static org.apache.sis.util.ArgumentChecks.ensureCanCast;
-import static org.apache.sis.util.collection.Containers.hashMapCapacity;
-import static org.apache.sis.internal.util.CollectionsExt.unmodifiableOrCopy;
// Related to JDK7
import org.apache.sis.internal.jdk7.Objects;
/**
- * The definition of a parameter used by an operation method.
+ * The definition of a single parameter used by an operation method.
* For {@linkplain org.apache.sis.referencing.crs.AbstractCRS Coordinate Reference Systems}
* most parameter values are numeric, but other types of parameter values are possible.
*
@@ -59,9 +57,10 @@ import org.apache.sis.internal.jdk7.Obje
* but other types are allowed as well.</li>
* <li>Whether this parameter is optional or mandatory. This is specified by the {@linkplain #getMinimumOccurs()
* minimum occurences} number, which can be 0 or 1 respectively.</li>
- * <li>The {@linkplain #getDefaultValue() default value} and its {@linkplain #getUnit() unit of measurement}.</li>
* <li>The domain of values, as a {@linkplain #getMinimumValue() minimum value}, {@linkplain #getMaximumValue()
* maximum value} or an enumeration of {@linkplain #getValidValues() valid values}.</li>
+ * <li>The {@linkplain #getDefaultValue() default value}.</li>
+ * <li>The {@linkplain #getUnit() unit of measurement}.</li>
* </ul>
*
* @param <T> The type of elements to be returned by {@link DefaultParameterValue#getValue()}.
@@ -79,66 +78,56 @@ public class DefaultParameterDescriptor<
/**
* Serial number for inter-operability with different versions.
*/
- private static final long serialVersionUID = -295668622297737705L;
-
- /**
- * Key for the <code>{@value}</code> property to be given to the constructor.
- * This is used for setting the value to be returned by {@link #getMinimumValue()}.
- */
- public static final String MINIMUM_VALUE_KEY = "minimumValue";
-
- /**
- * Key for the <code>{@value}</code> property to be given to the constructor.
- * This is used for setting the value to be returned by {@link #getMaximumValue()}.
- */
- public static final String MAXIMUM_VALUE_KEY = "maximumValue";
-
- /**
- * Key for the <code>{@value}</code> property to be given to the constructor.
- * This is used for setting the value to be returned by {@link #getValidValues()}.
- */
- public static final String VALID_VALUES_KEY = "validValues";
+ private static final long serialVersionUID = 7433401733923393656L;
/**
* {@code true} if this parameter is mandatory, or {@code false} if it is optional.
+ *
+ * @see #getMinimumOccurs()
*/
private final boolean required;
/**
* The class that describe the type of parameter values.
+ *
+ * @see #getValueClass()
*/
private final Class<T> valueClass;
/**
* A set of valid values (usually from a {@linkplain CodeList code list})
* or {@code null} if it doesn't apply. This set is immutable.
+ *
+ * @see #getValidValues()
*/
private final Set<T> validValues;
/**
- * The default value for the parameter, or {@code null}.
- */
- private final T defaultValue;
-
- /**
- * The minimum parameter value, or {@code null}.
- */
- private final Comparable<T> minimumValue;
-
- /**
- * The maximum parameter value, or {@code null}.
+ * The minimum and maximum parameter value with their unit of measurement, or {@code null} if none.
+ * If this field is non-null, then <code>valueDomain.{@linkplain Range#getElementType() getElementType()}</code>
+ * shall be one of the following:
+ *
+ * <ul>
+ * <li>If {@link #valueClass} is not an array, then the range element type shall be the same class.</li>
+ * <li>If {@code valueClass} is an array, then the range element type shall be the wrapper of
+ * <code>valueClass.{@linkplain Class#getComponentType() getComponentType()}</code>.</li>
+ * </ul>
+ *
+ * @see #getValueDomain()
*/
- private final Comparable<T> maximumValue;
+ private final Range<?> valueDomain;
/**
- * The unit for default, minimum and maximum values, or {@code null}.
+ * The default value for the parameter, or {@code null}.
+ *
+ * @see #getDefaultValue()
*/
- private final Unit<?> unit;
+ private final T defaultValue;
/**
- * Constructs a descriptor from a set of properties. The properties given in argument follow the same rules
- * than for the {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}.
- * Additionally, the following properties are understood by this constructor:
+ * Constructs a descriptor from the given properties. The properties map is given unchanged to the
+ * {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}.
+ * The following table is a reminder of main (not all) properties:
*
* <table class="sis">
* <tr>
@@ -147,24 +136,6 @@ public class DefaultParameterDescriptor<
* <th>Returned by</th>
* </tr>
* <tr>
- * <td>{@value #MINIMUM_VALUE_KEY}</td>
- * <td>{@code Comparable<T>}</td>
- * <td>{@link #getMinimumValue()}</td>
- * </tr>
- * <tr>
- * <td>{@value #MAXIMUM_VALUE_KEY}</td>
- * <td>{@code Comparable<T>}</td>
- * <td>{@link #getMaximumValue()}</td>
- * </tr>
- * <tr>
- * <td>{@value #VALID_VALUES_KEY}</td>
- * <td>{@code Collection<T>} or {@code T[]}</td>
- * <td>{@link #getValidValues()}</td>
- * </tr>
- * <tr>
- * <th colspan="3" class="hsep">Defined in parent class (reminder)</th>
- * </tr>
- * <tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
* <td>{@link org.opengis.referencing.ReferenceIdentifier} or {@link String}</td>
* <td>{@link #getName()}</td>
@@ -186,96 +157,95 @@ public class DefaultParameterDescriptor<
* </tr>
* </table>
*
- * Generally speaking, information provided in the {@code properties} map are considered ignorable metadata
- * (except the parameter name) while information provided as explicit arguments may have an impact on coordinate
- * transformation results. See {@link #equals(Object, ComparisonMode)} for more information.
+ * The {@code valueDomain} argument combines the {@linkplain #getMinimumValue() minimum value},
+ * {@linkplain #getMaximumValue() maximum value}, {@linkplain #getUnit() unit of measurement}
+ * (if any) and information about whether the bounds are inclusive or exclusive.
+ * If this argument is non-null, then it shall comply to the following conditions:
+ *
+ * <ul>
+ * <li>The range shall be non-{@linkplain Range#isEmpty() empty}.</li>
+ * <li><code>valueDomain.{@linkplain Range#getElementType() getElementType()}</code> shall be equals
+ * to one of the following:
+ * <ul>
+ * <li>to {@code valueClass} if the later is not an array,</li>
+ * <li>or to <code>{@linkplain Numbers#primitiveToWrapper(Class)
+ * primitiveToWrapper}(valueClass.{@linkplain Class#getComponentType() getComponentType()})</code>
+ * if {@code valueClass} is an array.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * If both {@code valueDomain} and {@code validValues} are non-null, then all valid values shall be contained
+ * in the value domain.
*
* @param properties The properties to be given to the identified object.
* @param valueClass The class that describes the type of the parameter value.
+ * @param valueDomain The minimum value, maximum value and unit of measurement, or {@code null} if none.
+ * @param validValues The list of valid values, or {@code null} if there is no restriction.
+ * This property is mostly for restricting values to a {@linkplain CodeList code list}
+ * or enumeration subset. It is not necessary to provide this property when all values
+ * from the code list or enumeration are valid.
* @param defaultValue The default value for the parameter, or {@code null} if none.
- * @param unit The unit of measurement for the default, minimum and maximum values, or {@code null} if none.
* @param required {@code true} if this parameter is mandatory, or {@code false} if it is optional.
*/
@SuppressWarnings("unchecked")
public DefaultParameterDescriptor(final Map<String,?> properties,
final Class<T> valueClass,
+ final Range<?> valueDomain,
+ final T[] validValues,
final T defaultValue,
- final Unit<?> unit,
final boolean required)
{
super(properties);
- final Comparable<T> minimumValue = Containers.property(properties, MINIMUM_VALUE_KEY, Comparable.class);
- final Comparable<T> maximumValue = Containers.property(properties, MAXIMUM_VALUE_KEY, Comparable.class);
- ensureNonNull("valueClass", valueClass);
- ensureCanCast("defaultValue", valueClass, defaultValue);
- ensureCanCast(MINIMUM_VALUE_KEY, valueClass, minimumValue);
- ensureCanCast(MAXIMUM_VALUE_KEY, valueClass, maximumValue);
- this.required = required;
- this.valueClass = valueClass;
- this.defaultValue = Numerics.cached(defaultValue);
- this.minimumValue = Numerics.cached(minimumValue);
- this.maximumValue = Numerics.cached(maximumValue);
- this.unit = unit;
- /*
- * If the caller specified a unit of measurement, then
- * verify that the values are of some numerical type.
- */
- if (unit != null) {
- Class<?> componentType = valueClass;
- for (Class<?> c; (c = componentType.getComponentType()) != null;) {
- componentType = c;
+ ensureNonNull("valueClass", valueClass);
+ ensureCanCast("defaultValue", valueClass, defaultValue);
+ if (valueDomain != null) {
+ Class<?> componentType = valueClass.getComponentType();
+ if (componentType != null) {
+ componentType = Numbers.primitiveToWrapper(componentType);
+ } else {
+ componentType = valueClass;
}
- componentType = Numbers.primitiveToWrapper(componentType);
- if (!Number.class.isAssignableFrom(componentType)) {
+ final Class<?> elementType = valueDomain.getElementType();
+ if (elementType != componentType) {
throw new IllegalArgumentException(Errors.getResources(properties).getString(
- Errors.Keys.IllegalUnitFor_2, super.getName().getCode(), unit));
+ Errors.Keys.IllegalArgumentClass_2, "valueDomain",
+ "Range<" + Classes.getShortName(elementType) + '>'));
}
- }
- /*
- * If the caller specified minimum and maximum values, then
- * verify that the minimum is not greater than the maximum.
- */
- if (minimumValue != null && maximumValue != null) {
- if (minimumValue.compareTo(valueClass.cast(maximumValue)) > 0) {
+ if (valueDomain.isEmpty()) {
throw new IllegalArgumentException(Errors.getResources(properties)
- .getString(Errors.Keys.IllegalRange_2, minimumValue, maximumValue));
+ .getString(Errors.Keys.IllegalRange_2, valueDomain.getMinValue(), valueDomain.getMaxValue()));
}
}
+ this.required = required;
+ this.valueClass = valueClass;
+ this.valueDomain = valueDomain;
+ this.defaultValue = Numerics.cached(defaultValue);
/*
* If the caller specified a set of valid values, then copy the values in
* a new set and verify their type and inclusion in the [min … max] range.
*/
- final Object values = properties.get(VALID_VALUES_KEY);
- if (values != null) {
- final Object[] array;
- if (values instanceof Object[]) {
- array = (Object[]) values;
- } else if (values instanceof Collection<?>) {
- array = ((Collection<?>) values).toArray();
- } else {
- throw new IllegalArgumentException(Errors.getResources(properties)
- .getString(Errors.Keys.IllegalPropertyClass_2, VALID_VALUES_KEY, values.getClass()));
- }
- final Set<T> valids = new LinkedHashSet<T>(hashMapCapacity(array.length));
- for (Object value : array) {
+ if (validValues != null) {
+ final Set<T> valids = CollectionsExt.createSetForType(valueClass, validValues.length);
+ for (T value : validValues) {
if (value != null) {
value = Numerics.cached(value);
- final Verifier error = Verifier.ensureValidValue(valueClass, null, minimumValue, maximumValue, value);
+ final Verifier error = Verifier.ensureValidValue(valueClass, null, valueDomain, value);
if (error != null) {
throw new IllegalArgumentException(error.message(properties, super.getName().getCode(), value));
}
+ valids.add(value);
}
- valids.add((T) value);
}
- validValues = unmodifiableOrCopy(valids);
+ this.validValues = CollectionsExt.unmodifiableOrCopy(valids);
} else {
- validValues = null;
+ this.validValues = null;
}
/*
* Finally, verify the default value if any.
*/
if (defaultValue != null) {
- final Verifier error = Verifier.ensureValidValue(valueClass, validValues, minimumValue, maximumValue, defaultValue);
+ final Verifier error = Verifier.ensureValidValue(valueClass, this.validValues, valueDomain, defaultValue);
if (error != null) {
throw new IllegalArgumentException(error.message(properties, super.getName().getCode(), defaultValue));
}
@@ -290,16 +260,33 @@ public class DefaultParameterDescriptor<
* <p>This constructor performs a shallow copy, i.e. the properties are not cloned.</p>
*
* @param descriptor The descriptor to shallow copy.
+ *
+ * @see #castOrCopy(ParameterDescriptor)
*/
- public DefaultParameterDescriptor(final ParameterDescriptor<T> descriptor) {
+ @SuppressWarnings("unchecked")
+ protected DefaultParameterDescriptor(final ParameterDescriptor<T> descriptor) {
super(descriptor);
required = descriptor.getMinimumOccurs() != 0;
valueClass = descriptor.getValueClass();
validValues = descriptor.getValidValues();
defaultValue = descriptor.getDefaultValue();
- minimumValue = descriptor.getMinimumValue();
- maximumValue = descriptor.getMaximumValue();
- unit = descriptor.getUnit();
+ valueDomain = Parameters.getValueDomain(descriptor);
+ }
+
+ /**
+ * Returns a SIS parameter implementation with the same values than the given arbitrary implementation.
+ * If the given object is {@code null}, then this method returns {@code null}.
+ * Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged.
+ * Otherwise a new SIS implementation is created and initialized to the values of the given object.
+ *
+ * @param <T> The type of values.
+ * @param object The object to get as a SIS implementation, or {@code null} if none.
+ * @return A SIS implementation containing the values of the given object (may be the
+ * given object itself), or {@code null} if the argument was null.
+ */
+ public static <T> DefaultParameterDescriptor<T> castOrCopy(final ParameterDescriptor<T> object) {
+ return (object == null) || (object instanceof DefaultParameterDescriptor<?>)
+ ? (DefaultParameterDescriptor<T>) object : new DefaultParameterDescriptor<T>(object);
}
/**
@@ -320,7 +307,7 @@ public class DefaultParameterDescriptor<
}
/**
- * The minimum number of times that values for this parameter group or parameter are required.
+ * The minimum number of times that values for this parameter are required.
* A value of 0 means an optional parameter and a value of 1 means a mandatory parameter.
*
* @see #getMaximumOccurs()
@@ -331,7 +318,7 @@ public class DefaultParameterDescriptor<
}
/**
- * The maximum number of times that values for this parameter group or parameter can be included.
+ * The maximum number of times that values for this parameter can be included.
* For a {@code ParameterDescriptor}, the value is always 1.
*
* @return The maximum occurrence.
@@ -361,17 +348,17 @@ public class DefaultParameterDescriptor<
* @return The parameter value class.
*/
@Override
- public Class<T> getValueClass() {
+ public final Class<T> getValueClass() {
return valueClass;
}
/**
* If this parameter allows only a finite set of values, returns that set.
- * The set of valid values is usually a {@linkplain CodeList code list} or enumerations.
+ * The set of valid values is usually a {@linkplain CodeList code list} or enumeration.
* This method returns {@code null} if this parameter does not limit values to a finite set.
*
* @return A finite set of valid values (usually from a {@linkplain CodeList code list}),
- * or {@code null} if it does not apply.
+ * or {@code null} if it does not apply or if there is no restriction.
*/
@Override
public Set<T> getValidValues() {
@@ -379,15 +366,27 @@ public class DefaultParameterDescriptor<
}
/**
- * Returns the default value for the parameter. The return type can be any type
- * including a {@link Number} or a {@link String}. If there is no default value,
- * then this method returns {@code null}.
- *
- * @return The default value, or {@code null} in none.
+ * Returns the domain of values with their unit of measurement (if any), or {@code null} if none.
+ * The {@code Range} object combines the {@linkplain #getValueClass() value class},
+ * {@linkplain #getMinimumValue() minimum value}, {@linkplain #getMaximumValue() maximum value}
+ * and whether these values are inclusive or inclusive. If the range is an instance of
+ * {@link MeasurementRange}, then it contains also the {@linkplain #getUnit() unit of measurement}.
+ *
+ * <div class="note"><b>API note:</b> If this method returns a non-null value, then its type is either exactly
+ * {@code Range<T>}, or {@code Range<E>} where {@code <E>} is the {@linkplain Class#getComponentType() component
+ * type} of {@code <T>} (using wrapper classes for primitive types).</div>
+ *
+ * @return The domain of values, or {@code null}.
+ *
+ * @see Parameters#getValueDomain(ParameterDescriptor)
+ */
+ /* Implementation note: this method is final because the constructor performs various checks on range validity,
+ * and we can not express those rules in the method signature. The 'Verifier.ensureValidValue(…)' method needs
+ * some guarantees about range validity, so we can not let users override this method with a range that may
+ * break them.
*/
- @Override
- public T getDefaultValue() {
- return defaultValue;
+ public final Range<?> getValueDomain() {
+ return valueDomain;
}
/**
@@ -395,11 +394,17 @@ public class DefaultParameterDescriptor<
* value is inappropriate for the {@linkplain #getValueClass() value class}, then
* this method returns {@code null}.
*
- * @return The minimum parameter value (often an instance of {@link Double}), or {@code null}.
+ * <p>This is a convenience method for
+ * <code>{@linkplain #getValueDomain()}.{@linkplain Range#getMinValue() getMinValue()}</code>.
+ * Note that this method said nothing about whether the value is {@linkplain Range#isMinIncluded() inclusive}.</p>
+ *
+ * @return The minimum parameter value (often an instance of {@link Double}), or {@code null} if unbounded.
*/
@Override
+ @SuppressWarnings("unchecked")
public Comparable<T> getMinimumValue() {
- return minimumValue;
+ return (valueDomain != null && valueDomain.getElementType() == valueClass)
+ ? (Comparable<T>) valueDomain.getMinValue() : null;
}
/**
@@ -407,25 +412,46 @@ public class DefaultParameterDescriptor<
* value is inappropriate for the {@linkplain #getValueClass() value type}, then
* this method returns {@code null}.
*
- * @return The minimum parameter value (often an instance of {@link Double}), or {@code null}.
+ * <p>This is a convenience method for
+ * <code>{@linkplain #getValueDomain()}.{@linkplain Range#getMaxValue() getMaxValue()}</code>.
+ * Note that this method said nothing about whether the value is {@linkplain Range#isMaxIncluded() inclusive}.</p>
+ *
+ * @return The minimum parameter value (often an instance of {@link Double}), or {@code null} if unbounded.
*/
@Override
+ @SuppressWarnings("unchecked")
public Comparable<T> getMaximumValue() {
- return maximumValue;
+ return (valueDomain != null && valueDomain.getElementType() == valueClass)
+ ? (Comparable<T>) valueDomain.getMaxValue() : null;
+ }
+
+ /**
+ * Returns the default value for the parameter. The return type can be any type
+ * including a {@link Number} or a {@link String}. If there is no default value,
+ * then this method returns {@code null}.
+ *
+ * @return The default value, or {@code null} in none.
+ */
+ @Override
+ public T getDefaultValue() {
+ return defaultValue;
}
/**
* Returns the unit of measurement for the
- * {@linkplain #getDefaultValue() default},
- * {@linkplain #getMinimumValue() minimum} and
- * {@linkplain #getMaximumValue() maximum} values.
+ * {@linkplain #getMinimumValue() minimum},
+ * {@linkplain #getMaximumValue() maximum} and
+ * {@linkplain #getDefaultValue() default} values.
* This attribute apply only if the values is of numeric type (usually an instance of {@link Double}).
*
+ * <p>This is a convenience method for
+ * <code>{@linkplain #getValueDomain()}.{@linkplain MeasurementRange#unit() unit()}</code>.</p>
+ *
* @return The unit for numeric value, or {@code null} if it doesn't apply to the value type.
*/
@Override
public Unit<?> getUnit() {
- return unit;
+ return (valueDomain instanceof MeasurementRange<?>) ? ((MeasurementRange<?>) valueDomain).unit() : null;
}
/**
@@ -473,20 +499,18 @@ public class DefaultParameterDescriptor<
getMaximumOccurs() == that.getMaximumOccurs() &&
getValueClass() == that.getValueClass() &&
Objects. equals(getValidValues(), that.getValidValues()) &&
- Objects.deepEquals(getDefaultValue(), that.getDefaultValue()) &&
Objects. equals(getMinimumValue(), that.getMinimumValue()) &&
Objects. equals(getMaximumValue(), that.getMaximumValue()) &&
+ Objects.deepEquals(getDefaultValue(), that.getDefaultValue()) &&
Objects. equals(getUnit(), that.getUnit());
}
case STRICT: {
final DefaultParameterDescriptor<?> that = (DefaultParameterDescriptor<?>) object;
- return this.required == that.required &&
- this.valueClass == that.valueClass &&
- Objects. equals(this.validValues, that.validValues) &&
- Objects.deepEquals(this.defaultValue, that.defaultValue) &&
- Objects. equals(this.minimumValue, that.minimumValue) &&
- Objects. equals(this.maximumValue, that.maximumValue) &&
- Objects. equals(this.unit, that.unit);
+ return this.required == that.required &&
+ this.valueClass == that.valueClass &&
+ Objects. equals(this.validValues, that.validValues) &&
+ Objects. equals(this.valueDomain, that.valueDomain) &&
+ Objects.deepEquals(this.defaultValue, that.defaultValue);
}
}
}
@@ -494,39 +518,37 @@ public class DefaultParameterDescriptor<
}
/**
- * {@inheritDoc}
+ * Invoked by {@link #hashCode()} for computing the hash code when first needed.
*
* @return {@inheritDoc}
*/
@Override
protected long computeHashCode() {
- return Arrays.deepHashCode(new Object[] {required, valueClass, defaultValue, minimumValue, maximumValue, unit})
+ return Arrays.deepHashCode(new Object[] {required, valueClass, valueDomain, defaultValue})
+ super.computeHashCode();
}
/**
- * Returns a string representation of this descriptor. The string returned by this
- * method is for information purpose only and may change in future SIS version.
+ * Formats this parameter as a pseudo-<cite>Well Known Text</cite> element. The WKT specification
+ * does not define any representation of parameter descriptors. Apache SIS fallback on the
+ * {@linkplain DefaultParameterValue#formatTo(Formatter) same representation than parameter value},
+ * with the descriptor {@linkplain #getDefaultValue() default value} in place of the parameter value.
+ * The text formatted by this method is {@linkplain Formatter#setInvalidWKT flagged as invalid WKT}.
+ *
+ * @param formatter The formatter where to format the inner content of this WKT element.
+ * @return {@code "Parameter"}.
*/
- @Debug
@Override
- public String toString() {
- final StringBuilder buffer = new StringBuilder(Classes.getShortClassName(this))
- .append("[\"").append(getName().getCode()).append("\", ")
- .append(getMinimumOccurs() == 0 ? "optional" : "mandatory");
- buffer.append(", class=").append(Classes.getShortName(valueClass));
- if (minimumValue != null || maximumValue != null) {
- buffer.append(", valid=[").append(minimumValue != null ? minimumValue : "-∞")
- .append(" … ") .append(maximumValue != null ? maximumValue : "∞").append(']');
- } else if (validValues != null) {
- buffer.append(", valid=").append(validValues);
- }
- if (defaultValue != null) {
- buffer.append(", default=").append(defaultValue);
- }
+ protected String formatTo(final Formatter formatter) {
+ WKTUtilities.appendName(this, formatter, ElementKind.PARAMETER);
+ formatter.setInvalidWKT(this, null);
+ formatter.appendAny(defaultValue);
+ final Unit<?> unit = getUnit();
if (unit != null) {
- buffer.append(", unit=").append(unit);
+ if (!formatter.getConvention().isSimplified() || !unit.equals(formatter.toContextualUnit(unit))) {
+ formatter.append(unit);
+ }
}
- return buffer.append(']').toString();
+ return "Parameter";
}
}
Copied: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java (from r1576954, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java?p2=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java&r1=1576954&r2=1576972&rev=1576972&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -240,7 +240,7 @@ public class DefaultParameterDescriptorG
@Override public boolean contains(final Object object) {
Set<GeneralParameterDescriptor> s = asSet;
if (s == null) {
- asSet = s = new HashSet<>(this); // No synchronization: not a big problem if created twice.
+ asSet = s = new HashSet<GeneralParameterDescriptor>(this); // No synchronization: not a big problem if created twice.
}
return s.contains(object);
}
@@ -432,13 +432,14 @@ public class DefaultParameterDescriptorG
* @return {@code "ParameterGroup"}.
*/
@Override
+ @SuppressWarnings({"unchecked","rawtypes"})
protected String formatTo(final Formatter formatter) {
WKTUtilities.appendName(this, formatter, null);
formatter.setInvalidWKT(this, null);
for (GeneralParameterDescriptor parameter : descriptors) {
if (!(parameter instanceof FormattableObject)) {
if (parameter instanceof ParameterDescriptor<?>) {
- parameter = new DefaultParameterDescriptor<>((ParameterDescriptor<?>) parameter);
+ parameter = new DefaultParameterDescriptor((ParameterDescriptor<?>) parameter);
} else if (parameter instanceof ParameterDescriptorGroup) {
parameter = new DefaultParameterDescriptorGroup((ParameterDescriptorGroup) parameter);
} else {
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java?rev=1576972&r1=1576971&r2=1576972&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -45,37 +45,43 @@ import org.apache.sis.internal.jdk7.Obje
/**
- * A parameter value used by an operation method. Most CRS parameter values are numeric and can
- * be obtained by the {@link #intValue()} or {@link #doubleValue()} methods. But other types of
- * parameter values are possible and can be handled by the more generic {@link #getValue()} and
- * {@link #setValue(Object)} methods. The type and constraints on parameter values are given by
- * the {@linkplain #getDescriptor() descriptor}.
+ * A single parameter value used by an operation method. Most CRS parameter values are numeric and can be obtained
+ * by the {@link #intValue()} or {@link #doubleValue()} methods. But other types of parameter values are possible
+ * and can be handled by the more generic {@link #getValue()} and {@link #setValue(Object)} methods.
*
- * <p>The following table summarizes the ISO 19111 attributes with the corresponding getter and
- * setter methods:</p>
+ * <p>All {@code xxxValue()} methods in this class are convenience methods converting the value from {@code Object}
+ * to some commonly used types. Those types are specified in ISO 19111 as an union of attributes, listed below with
+ * the corresponding getter and setter methods:</p>
*
* <table class="sis">
- * <tr><th>ISO attribute</th> <th>Java type</th> <th>Getter method</th> <th>Setter method</th></tr>
- * <tr><td></td> <td>{@link Object}</td> <td>{@link #getValue()}</td> <td>{@link #setValue(Object)}</td></tr>
- * <tr><td>{@code stringValue}</td> <td>{@link String}</td> <td>{@link #stringValue()}</td> <td>{@code setValue(Object)}</td></tr>
- * <tr><td>{@code value}</td> <td>{@code double}</td> <td>{@link #doubleValue()}</td> <td>{@link #setValue(double)}</td></tr>
- * <tr><td></td> <td>{@code double}</td> <td>{@link #doubleValue(Unit)}</td> <td>{@link #setValue(double, Unit)}</td></tr>
- * <tr><td>{@code valueList}</td> <td>{@code double[]}</td> <td>{@link #doubleValueList()}</td> <td>{@code setValue(Object)}</td></tr>
- * <tr><td></td> <td>{@code double[]}</td> <td>{@link #doubleValueList(Unit)}</td> <td>{@link #setValue(double[], Unit)}</td></tr>
- * <tr><td>{@code integerValue}</td> <td>{@code int}</td> <td>{@link #intValue()}</td> <td>{@link #setValue(int)}</td></tr>
- * <tr><td>{@code integerValueList}</td> <td>{@code int[]}</td> <td>{@link #intValueList()}</td> <td>{@code setValue(Object)}</td></tr>
- * <tr><td>{@code booleanValue}</td> <td>{@code boolean}</td> <td>{@link #booleanValue()}</td> <td>{@link #setValue(boolean)}</td></tr>
- * <tr><td>{@code valueFile}</td> <td>{@link URI}</td> <td>{@link #valueFile()}</td> <td>{@code setValue(Object)}</td></tr>
- * <tr><td>{@code valueFileCitation}</td> <td>{@link Citation}</td> <td>{@code getValue()}</td> <td>{@code setValue(Object)}</td></tr>
+ * <tr><th>ISO attribute</th> <th>Java type</th> <th>Getter method</th> <th>Setter method</th></tr>
+ * <tr><td></td> <td>{@link Object}</td> <td>{@link #getValue()}</td> <td>{@link #setValue(Object)}</td></tr>
+ * <tr><td>stringValue</td> <td>{@link String}</td> <td>{@link #stringValue()}</td> <td>{@link #setValue(Object)}</td></tr>
+ * <tr><td>value</td> <td>{@code double}</td> <td>{@link #doubleValue()}</td> <td>{@link #setValue(double)}</td></tr>
+ * <tr><td></td> <td>{@code double}</td> <td>{@link #doubleValue(Unit)}</td> <td>{@link #setValue(double, Unit)}</td></tr>
+ * <tr><td>valueList</td> <td>{@code double[]}</td> <td>{@link #doubleValueList()}</td> <td>{@link #setValue(Object)}</td></tr>
+ * <tr><td></td> <td>{@code double[]}</td> <td>{@link #doubleValueList(Unit)}</td> <td>{@link #setValue(double[], Unit)}</td></tr>
+ * <tr><td>integerValue</td> <td>{@code int}</td> <td>{@link #intValue()}</td> <td>{@link #setValue(int)}</td></tr>
+ * <tr><td>integerValueList</td> <td>{@code int[]}</td> <td>{@link #intValueList()}</td> <td>{@link #setValue(Object)}</td></tr>
+ * <tr><td>booleanValue</td> <td>{@code boolean}</td> <td>{@link #booleanValue()}</td> <td>{@link #setValue(boolean)}</td></tr>
+ * <tr><td>valueFile</td> <td>{@link URI}</td> <td>{@link #valueFile()}</td> <td>{@link #setValue(Object)}</td></tr>
+ * <tr><td>valueFileCitation</td> <td>{@link Citation}</td> <td>{@link #getValue()}</td> <td>{@link #setValue(Object)}</td></tr>
* </table>
*
- * Instances of {@code ParameterValue} are created by the {@link ParameterDescriptor#createValue()} method.
- * The parameter type can be fetch with the following idiom:
+ * The type and constraints on parameter values are given by the {@linkplain #getDescriptor() descriptor},
+ * which is specified at construction time. The parameter type can be fetch with the following idiom:
*
* {@preformat java
* Class<T> valueClass = parameter.getDescriptor().getValueClass();
* }
*
+ * {@section Instantiation}
+ * A {@linkplain DefaultParameterDescriptor parameter descriptor} must be defined before parameter value can be created.
+ * Descriptors are usually pre-defined by map projection or process providers. Given a descriptor, a parameter value can
+ * be created by a call to the {@link #DefaultParameterValue(ParameterDescriptor)} constructor or by a call to the
+ * {@link ParameterDescriptor#createValue()} method. The later is recommended since it allows descriptors to return
+ * specialized implementations.
+ *
* {@section Implementation note for subclasses}
* All read and write operations (except constructors, {@link #equals(Object)} and {@link #hashCode()})
* ultimately delegates to the following methods:
@@ -97,7 +103,7 @@ import org.apache.sis.internal.jdk7.Obje
* @module
*
* @see DefaultParameterDescriptor
- * @see DefaultParameterGroup
+ * @see DefaultParameterValueGroup
*/
public class DefaultParameterValue<T> extends FormattableObject implements ParameterValue<T>, Serializable, Cloneable {
/**
@@ -609,7 +615,7 @@ public class DefaultParameterValue<T> ex
*/
@Override
public void setValue(final double[] values, final Unit<?> unit) throws InvalidParameterValueException {
- setValue(value, unit);
+ setValue((Object) values, unit);
}
/**
@@ -630,9 +636,38 @@ public class DefaultParameterValue<T> ex
* @throws InvalidParameterValueException if the type of {@code value} is inappropriate for this parameter,
* or if the value is illegal for some other reason (for example the value is numeric and out of range).
*/
+ @SuppressWarnings("unchecked")
protected void setValue(final Object value, final Unit<?> unit) throws InvalidParameterValueException {
- this.value = Verifier.ensureValidValue(descriptor, value, unit);
- this.unit = unit; // Assign only on success.
+ final T convertedValue = Verifier.ensureValidValue(descriptor, value, unit);
+ if (value != null) {
+ validate(convertedValue);
+ this.value = (T) value; // Type has been verified by Verifier.ensureValidValue(…).
+ } else {
+ this.value = descriptor.getDefaultValue();
+ }
+ this.unit = unit; // Assign only on success.
+ }
+
+ /**
+ * Invoked by {@link #setValue(Object, Unit)} after the basic verifications have been done and before
+ * the value is stored. Subclasses can override this method for performing additional verifications.
+ *
+ * {@section Unit of measurement}
+ * If the user specified a unit of measurement, then the value given to this method has been converted
+ * to the unit specified by the {@linkplain #getDescriptor() descriptor}, for easier comparisons against
+ * standardized values. This converted value may be different than the value to be stored in this
+ * {@code ParameterValue}, since the later value will be stored in the unit specified by the user.
+ *
+ * {@section Standard validations}
+ * The checks for {@linkplain DefaultParameterDescriptor#getValueClass() value class},
+ * for {@linkplain DefaultParameterDescriptor#getValueDomain() value domain} and for
+ * {@linkplain DefaultParameterDescriptor#getValidValues() valid values} are performed
+ * before this method is invoked. The default implementation of this method does nothing.
+ *
+ * @param value The value converted to the unit of measurement specified by the descriptor.
+ * @throws InvalidParameterValueException If the given value is invalid for implementation-specific reasons.
+ */
+ protected void validate(final T value) throws InvalidParameterValueException {
}
/**
Copied: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java (from r1576954, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java?p2=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java&r1=1576954&r2=1576972&rev=1576972&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -34,7 +34,7 @@ import org.apache.sis.util.Debug;
import static org.apache.sis.referencing.IdentifiedObjects.isHeuristicMatchForName;
// Related to JDK7
-import java.util.Objects;
+import org.apache.sis.internal.jdk7.Objects;
/**
@@ -249,7 +249,7 @@ public class DefaultParameterValueGroup
public List<ParameterValueGroup> groups(final String name) throws ParameterNotFoundException {
ArgumentChecks.ensureNonNull("name", name);
final ParameterValueList values = this.values; // Protect against accidental changes.
- final List<ParameterValueGroup> groups = new ArrayList<>(4);
+ final List<ParameterValueGroup> groups = new ArrayList<ParameterValueGroup>(4);
final int size = values.size();
for (int i=0; i<size; i++) {
final GeneralParameterDescriptor descriptor = values.descriptor(i);
Copied: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java (from r1576954, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java?p2=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java&r1=1576954&r2=1576972&rev=1576972&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -226,7 +226,7 @@ public class ParameterBuilder extends Bu
} else if (Number.class.isAssignableFrom(valueClass)) {
valueDomain = new NumberRange((Class) valueClass, (Number) minimumValue, true, (Number) maximumValue, true);
} else {
- valueDomain = new Range<>(valueClass, minimumValue, true, maximumValue, true);
+ valueDomain = new Range<T>(valueClass, minimumValue, true, maximumValue, true);
}
return create(valueClass, valueDomain, null, defaultValue);
}
@@ -277,7 +277,7 @@ public class ParameterBuilder extends Bu
final ParameterDescriptor<T> descriptor;
onCreate(false);
try {
- descriptor = new DefaultParameterDescriptor<>(properties,
+ descriptor = new DefaultParameterDescriptor<T>(properties,
valueClass, valueDomain, validValues, defaultValue, required);
} finally {
onCreate(true);
Copied: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java (from r1576954, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java?p2=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java&r1=1576954&r2=1576972&rev=1576972&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -113,7 +113,7 @@ public class ParameterFormat extends Tab
/**
* An instance created when first needed and potentially shared.
*/
- private static final AtomicReference<ParameterFormat> INSTANCE = new AtomicReference<>();
+ private static final AtomicReference<ParameterFormat> INSTANCE = new AtomicReference<ParameterFormat>();
/**
* The default column separator. User can change the separator
@@ -257,8 +257,8 @@ public class ParameterFormat extends Tab
* Creates a new formatter for the default locale and timezone.
*/
public ParameterFormat() {
- super(Locale.getDefault(Locale.Category.FORMAT), TimeZone.getDefault());
- displayLocale = Locale.getDefault(Locale.Category.DISPLAY);
+ super(Locale.getDefault(), TimeZone.getDefault());
+ displayLocale = super.getLocale(); // Implemented as Locale.getDefault(Locale.Category.DISPLAY) on the JDK7 branch.
columnSeparator = SEPARATOR;
}
@@ -286,22 +286,6 @@ public class ParameterFormat extends Tab
}
/**
- * Returns the locale for the given category.
- *
- * <ul>
- * <li>{@link java.util.Locale.Category#FORMAT} specifies the locale to use for values.</li>
- * <li>{@link java.util.Locale.Category#DISPLAY} specifies the locale to use for labels.</li>
- * </ul>
- *
- * @param category The category for which a locale is desired.
- * @return The locale for the given category (never {@code null}).
- */
- @Override
- public Locale getLocale(final Locale.Category category) {
- return (category == Locale.Category.DISPLAY) ? displayLocale : super.getLocale(category);
- }
-
- /**
* Returns the amount of information to put in the table.
* The default value is {@link ContentLevel#BRIEF}.
*
@@ -451,7 +435,7 @@ public class ParameterFormat extends Tab
int codespaceWidth = 0;
final Collection<?> elements = (values != null) ? values.values() : group.descriptors();
final Map<GeneralParameterDescriptor, ParameterTableRow> descriptorValues =
- new LinkedHashMap<>(hashMapCapacity(elements.size()));
+ new LinkedHashMap<GeneralParameterDescriptor, ParameterTableRow>(hashMapCapacity(elements.size()));
List<Object> deferredGroups = null; // To be created only if needed (it is usually not).
for (final Object element : elements) {
final GeneralParameterValue parameter;
@@ -465,7 +449,7 @@ public class ParameterFormat extends Tab
}
if (descriptor instanceof ParameterDescriptorGroup) {
if (deferredGroups == null) {
- deferredGroups = new ArrayList<>(4);
+ deferredGroups = new ArrayList<Object>(4);
}
deferredGroups.add(element);
continue;
@@ -700,8 +684,8 @@ public class ParameterFormat extends Tab
* the scope of some alias to be processed below.
*/
boolean hasIdentifiers = false;
- final List<String[]> rows = new ArrayList<>();
- final Map<String,Integer> columnIndices = new LinkedHashMap<>();
+ final List<String[]> rows = new ArrayList<String[]>();
+ final Map<String,Integer> columnIndices = new LinkedHashMap<String,Integer>();
columnIndices.put(null, 0); // See above comment for the meaning of "null" here.
if (preferredCodespaces != null) {
for (final String codespace : preferredCodespaces) {
Copied: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java (from r1576954, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java?p2=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java&r1=1576954&r2=1576972&rev=1576972&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -117,9 +117,9 @@ final class ParameterTableRow {
ParameterTableRow(final IdentifiedObject object, final Locale locale,
final Set<String> preferredCodespaces, final boolean isBrief)
{
- values = new ArrayList<>(2); // In the vast majority of cases, we will have only one value.
- units = new ArrayList<>(2);
- identifiers = new LinkedHashMap<>();
+ values = new ArrayList<Object>(2); // In the vast majority of cases, we will have only one value.
+ units = new ArrayList<Object>(2);
+ identifiers = new LinkedHashMap<String,Set<Object>>();
ReferenceIdentifier name = object.getName();
if (name != null) { // Paranoiac check.
final String codespace = name.getCodeSpace();
@@ -191,7 +191,7 @@ final class ParameterTableRow {
}
Set<Object> ids = identifiers.get(codespace);
if (ids == null) {
- ids = new LinkedHashSet<>(8);
+ ids = new LinkedHashSet<Object>(8);
identifiers.put(codespace, ids);
}
ids.add(identifier);
Copied: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java (from r1576954, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java?p2=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java&r1=1576954&r2=1576972&rev=1576972&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -35,6 +35,9 @@ import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.resources.Errors;
+// Related to JDK7
+import org.apache.sis.internal.jdk7.JDK7;
+
/**
* The list to be returned by {@link DefaultParameterValueGroup#values()}.
@@ -314,7 +317,7 @@ final class ParameterValueList extends A
if (size == 0) {
return "[]";
}
- final String lineSeparator = System.lineSeparator();
+ final String lineSeparator = JDK7.lineSeparator();
final StringBuilder buffer = new StringBuilder();
for (int i=0; i<size; i++) {
buffer.append(values[i]).append(lineSeparator);
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java?rev=1576972&r1=1576971&r2=1576972&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -16,14 +16,18 @@
*/
package org.apache.sis.parameter;
+import javax.measure.unit.Unit;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterValue;
+import org.apache.sis.measure.Range;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.measure.MeasurementRange;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.Static;
/**
- * Static methods working on parameters.
+ * Static methods working on parameters and their descriptors.
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.4 (derived from geotk-2.1)
@@ -91,4 +95,44 @@ public final class Parameters extends St
}
return (ParameterValue<T>) value;
}
+
+ /**
+ * 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}.
+ *
+ * @param descriptor The parameter descriptor, or {@code null}.
+ * @return The domain of valid values, or {@code null} if none.
+ *
+ * @see DefaultParameterDescriptor#getValueDomain()
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public static Range<?> getValueDomain(final ParameterDescriptor<?> descriptor) {
+ if (descriptor != null) {
+ if (descriptor instanceof DefaultParameterDescriptor<?>) {
+ return ((DefaultParameterDescriptor<?>) descriptor).getValueDomain();
+ }
+ final Class<?> valueClass = descriptor.getValueClass();
+ final Comparable<?> minimumValue = descriptor.getMinimumValue();
+ final Comparable<?> maximumValue = descriptor.getMaximumValue();
+ if ((minimumValue == null || valueClass.isInstance(minimumValue)) &&
+ (maximumValue == null || valueClass.isInstance(maximumValue)))
+ {
+ if (Number.class.isAssignableFrom(valueClass)) {
+ final Unit<?> unit = descriptor.getUnit();
+ if (unit != null) {
+ return new MeasurementRange((Class) valueClass,
+ (Number) minimumValue, true, (Number) maximumValue, true, unit);
+ } else if (minimumValue != null || maximumValue != null) {
+ return new NumberRange((Class) valueClass,
+ (Number) minimumValue, true, (Number) maximumValue, true);
+ }
+ } else if (minimumValue != null || maximumValue != null) {
+ return new Range(valueClass, minimumValue, true, maximumValue, true);
+ }
+ }
+ }
+ return null;
+ }
}
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java?rev=1576972&r1=1576971&r2=1576972&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/parameter/Verifier.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -18,12 +18,14 @@ package org.apache.sis.parameter;
import java.util.Map;
import java.util.Set;
+import java.lang.reflect.Array;
import javax.measure.unit.Unit;
import javax.measure.converter.UnitConverter;
import javax.measure.converter.ConversionException;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.InvalidParameterValueException;
+import org.apache.sis.measure.Range;
import org.apache.sis.measure.Units;
import org.apache.sis.util.Numbers;
import org.apache.sis.util.resources.Errors;
@@ -32,7 +34,7 @@ import org.apache.sis.util.resources.Err
/**
* Verifies the validity of a given value.
* An instance of {@code Verifier} is created only if an error is detected.
- * In such case, the error message is given by {@link #message(String, Object)}.
+ * In such case, the error message is given by {@link #message(Map, String, Object)}.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @since 0.4 (derived from geotk-2.0)
@@ -55,7 +57,8 @@ final class Verifier {
* The current implementation relies on the following invariants:
*
* <ul>
- * <li>The first element in this array is always the parameter name.</li>
+ * <li>The first element in this array will be the parameter name. Before the name is known,
+ * this element is either {@code null} or the index to append to the name.</li>
* <li>The last element shall be set to the erroneous value if {@link #needsValue} is {@code true}.</li>
* </ul>
*/
@@ -72,7 +75,7 @@ final class Verifier {
/**
* Ensures that the given value is valid according the specified parameter descriptor.
- * This convenience method ensures that {@code value} is assignable to the
+ * This method ensures that {@code value} is assignable to the
* {@linkplain ParameterDescriptor#getValueClass() expected class}, is between the
* {@linkplain ParameterDescriptor#getMinimumValue() minimum} and
* {@linkplain ParameterDescriptor#getMaximumValue() maximum} values and is one of the
@@ -85,20 +88,21 @@ final class Verifier {
* @param descriptor The parameter descriptor to check against.
* @param value The value to check, or {@code null}.
* @param unit The unit of the value to check, or {@code null}.
- * @return The value casted to the descriptor parameterized type, or the
- * {@linkplain ParameterDescriptor#getDefaultValue() default value}
- * if the given value was null.
+ * @return The given value converted to the descriptor unit if any,
+ * then casted to the descriptor parameterized type.
* @throws InvalidParameterValueException if the parameter value is invalid.
*/
@SuppressWarnings("unchecked")
static <T> T ensureValidValue(final ParameterDescriptor<T> descriptor, final Object value, final Unit<?> unit)
throws InvalidParameterValueException
{
- final Class<T> type = descriptor.getValueClass();
+ final Class<T> valueClass = descriptor.getValueClass();
/*
* Before to verify if the given value is inside the bounds, we need to convert the value
- * to the units used by the parameter descriptor.
+ * to the units used by the parameter descriptor. The first part of this block verifies
+ * the validity of the unit argument, so we execute it even if 'value' is null.
*/
+ UnitConverter converter = null;
Object convertedValue = value;
if (unit != null) {
final Unit<?> def = descriptor.getUnit();
@@ -111,39 +115,85 @@ final class Verifier {
if (getUnitMessageID(unit) != expectedID) {
throw new IllegalArgumentException(Errors.format(expectedID, unit));
}
- if (value != null && Number.class.isAssignableFrom(type)) {
- final UnitConverter converter;
+ /*
+ * Verify the type of the user's value before to perform the unit conversion,
+ * because the conversion will create a new object not necessarily of the same type.
+ */
+ if (value != null) {
+ if (!valueClass.isInstance(value)) {
+ final String name = getName(descriptor);
+ throw new InvalidParameterValueException(
+ Errors.format(Errors.Keys.IllegalParameterValueClass_3,
+ name, valueClass, value.getClass()), name, value);
+ }
+ /*
+ * From this point we will perform the actual unit conversion. The value may be either
+ * a Number instance, or an array of numbers (typically an array of type double[]). In
+ * the array case, we will store the converted values in a new array of the same type.
+ */
try {
converter = unit.getConverterToAny(def);
} catch (ConversionException e) {
throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleUnits_2, unit, def), e);
}
- Number n = (Number) value; // Given value.
- n = converter.convert(n.doubleValue()); // Value in units that we can compare.
- try {
- convertedValue = Numbers.cast(n, (Class<? extends Number>) type);
- } catch (IllegalArgumentException e) {
- throw new InvalidParameterValueException(e.getLocalizedMessage(), getName(descriptor), value);
+ Class<?> componentType = valueClass.getComponentType();
+ if (componentType == null) {
+ /*
+ * Usual case where the value is not an array. Convert the value directly.
+ * Note that the value can only be a number because the unit is associated
+ * to MeasurementRange, which accepts only numbers.
+ */
+ Number n = converter.convert(((Number) value).doubleValue());
+ try {
+ convertedValue = Numbers.cast(n, (Class<? extends Number>) valueClass);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidParameterValueException(e.getLocalizedMessage(), getName(descriptor), value);
+ }
+ } else {
+ /*
+ * The value is an array. Creates a new array and store the converted values
+ * using Array reflection.
+ */
+ final int length = Array.getLength(value);
+ convertedValue = Array.newInstance(componentType, length);
+ componentType = Numbers.primitiveToWrapper(componentType);
+ for (int i=0; i<length; i++) {
+ Number n = (Number) Array.get(value, i);
+ n = converter.convert(n.doubleValue()); // Value in units that we can compare.
+ try {
+ n = Numbers.cast(n, (Class<? extends Number>) componentType);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidParameterValueException(e.getLocalizedMessage(),
+ getName(descriptor) + '[' + i + ']', value);
+ }
+ Array.set(convertedValue, i, n);
+ }
}
}
}
}
- if (convertedValue == null) {
- return descriptor.getDefaultValue();
- }
- final Comparable<T> minimum = descriptor.getMinimumValue();
- final Comparable<T> maximum = descriptor.getMaximumValue();
- final Verifier error = ensureValidValue(type, descriptor.getValidValues(), minimum, maximum, convertedValue);
- if (error != null) {
- final String name = getName(descriptor);
- throw new InvalidParameterValueException(error.message(null, name, value), name, value);
- }
/*
- * Passed every tests - the value is valid.
- * Really returns the original value, not the converted one, because we store the given
- * unit as well. Conversions will be applied on the fly by the getter method if needed.
+ * At this point the user's value has been fully converted to the unit of measurement specified
+ * by the ParameterDescriptor. Now compares the converted value to the restricting given by the
+ * descriptor (set of valid values and range of value domain).
*/
- return (T) value;
+ if (convertedValue != null) {
+ final Verifier error;
+ final Set<T> validValues = descriptor.getValidValues();
+ if (descriptor instanceof DefaultParameterDescriptor<?>) {
+ error = ensureValidValue(valueClass, validValues,
+ ((DefaultParameterDescriptor<?>) descriptor).getValueDomain(), convertedValue);
+ } else {
+ error = ensureValidValue(valueClass, validValues,
+ descriptor.getMinimumValue(), descriptor.getMaximumValue(), convertedValue);
+ }
+ if (error != null) {
+ error.convertRange(converter);
+ final String name = getName(descriptor);
+ throw new InvalidParameterValueException(error.message(null, name, value), name, value);
+ }
+ }
+ return (T) convertedValue;
}
/**
@@ -154,31 +204,102 @@ final class Verifier {
* This is not necessarily the user-provided value.
*/
@SuppressWarnings("unchecked")
- static <T> Verifier ensureValidValue(final Class<T> type, final Set<T> validValues,
+ static <T> Verifier ensureValidValue(final Class<T> valueClass, final Set<T> validValues,
+ final Range<?> valueDomain, final Object convertedValue)
+ {
+ final Verifier verifier = ensureValidValue(valueClass, validValues, null, null, convertedValue);
+ if (verifier == null && valueDomain != null) {
+ if (!valueClass.isArray()) {
+ /*
+ * Following assertion should never fail with DefaultParameterDescriptor instances.
+ * It could fail if the user overrides DefaultParameterDescriptor.getValueDomain()
+ * in a way that break the method contract.
+ */
+ assert valueDomain.getElementType() == valueClass : valueDomain;
+ if (!((Range) valueDomain).contains((Comparable<?>) convertedValue)) {
+ return new Verifier(Errors.Keys.ValueOutOfRange_4, true, null,
+ valueDomain.getMinValue(), valueDomain.getMaxValue(), convertedValue);
+ }
+ } else {
+ /*
+ * Following assertion should never fail under the same condition than above.
+ */
+ assert valueDomain.getElementType() == Numbers.primitiveToWrapper(valueClass.getComponentType()) : valueDomain;
+ final int length = Array.getLength(convertedValue);
+ for (int i=0; i<length; i++) {
+ final Object e = Array.get(convertedValue, i);
+ if (!((Range) valueDomain).contains((Comparable<?>) e)) {
+ return new Verifier(Errors.Keys.ValueOutOfRange_4, true, i,
+ valueDomain.getMinValue(), valueDomain.getMaxValue(), e);
+ }
+ }
+ }
+ }
+ return verifier;
+ }
+
+ /**
+ * Same as {@link #ensureValidValue(Class, Set, Range, Object)}, used as a fallback when
+ * the descriptor is not an instance of {@link DefaultParameterDescriptor}.
+ *
+ * <div class="note"><b>Implementation note:</b>
+ * At the difference of {@code ensureValidValue(…, Range, …)}, this method does not need to verify array elements
+ * because the type returned by {@link ParameterDescriptor#getMinimumValue()} and {@code getMaximumValue()}
+ * methods (namely {@code Comparable<T>}) does not allow usage with arrays.</div>
+ *
+ * @param convertedValue The value <em>converted to the units specified by the descriptor</em>.
+ * This is not necessarily the user-provided value.
+ */
+ @SuppressWarnings("unchecked")
+ private static <T> Verifier ensureValidValue(final Class<T> valueClass, final Set<T> validValues,
final Comparable<T> minimum, final Comparable<T> maximum, final Object convertedValue)
{
- if (!type.isInstance(convertedValue)) {
- return new Verifier(Errors.Keys.IllegalParameterValueClass_3, false, null, type, convertedValue.getClass());
+ if (!valueClass.isInstance(convertedValue)) {
+ return new Verifier(Errors.Keys.IllegalParameterValueClass_3, false, null, valueClass, convertedValue.getClass());
+ }
+ if (validValues != null && !validValues.contains(convertedValue)) {
+ return new Verifier(Errors.Keys.IllegalParameterValue_2, true, null, convertedValue);
}
if ((minimum != null && minimum.compareTo((T) convertedValue) > 0) ||
(maximum != null && maximum.compareTo((T) convertedValue) < 0))
{
return new Verifier(Errors.Keys.ValueOutOfRange_4, true, null, minimum, maximum, convertedValue);
}
- if (validValues != null && !validValues.contains(convertedValue)) {
- return new Verifier(Errors.Keys.IllegalParameterValue_2, true, null, convertedValue);
- }
return null;
}
/**
+ * Converts the information about an "value out of range" error. The range in the error message will be formatted
+ * in the unit given by the user, which is not necessarily the same than the unit of the parameter descriptor.
+ *
+ * @param converter The conversion from user unit to descriptor unit, or {@code null} if none. This method
+ * uses the inverse of that conversion for converting the given minimum and maximum values.
+ */
+ private void convertRange(UnitConverter converter) {
+ if (converter != null && errorKey == Errors.Keys.ValueOutOfRange_4) {
+ converter = converter.inverse();
+ Object minimumValue = arguments[1];
+ Object maximumValue = arguments[2];
+ minimumValue = (minimumValue != null) ? converter.convert(((Number) minimumValue).doubleValue()) : "-∞";
+ maximumValue = (maximumValue != null) ? converter.convert(((Number) maximumValue).doubleValue()) : "∞";
+ arguments[1] = minimumValue;
+ arguments[2] = maximumValue;
+ }
+ }
+
+ /**
* Returns an error message for the error detected by
- * {@link #ensureValidValue(Class, Set, Comparable, Comparable, Object)}.
+ * {@link #ensureValidValue(Class, Set, Range, Object)}.
*
* @param name The parameter name.
* @param value The user-supplied value (not necessarily equals to the converted value).
*/
- String message(final Map<?,?> properties, final String name, final Object value) {
+ String message(final Map<?,?> properties, String name, Object value) {
+ final Object index = arguments[0];
+ if (index != null) {
+ name = name + '[' + index + ']';
+ value = Array.get(value, (Integer) index);
+ }
arguments[0] = name;
if (needsValue) {
arguments[arguments.length - 1] = value;
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1576972&r1=1576971&r2=1576972&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -296,6 +296,10 @@ public class AbstractIdentifiedObject ex
// -------------------------------------
Object value = properties.get(NAME_KEY);
if (value == null || value instanceof String) {
+ if (value == null && properties.get(ReferenceIdentifier.CODE_KEY) == null) {
+ throw new IllegalArgumentException(Errors.getResources(properties)
+ .getString(Errors.Keys.MissingValueForProperty_1, NAME_KEY));
+ }
name = new NamedIdentifier(PropertiesConverter.convert(properties));
} else if (value instanceof ReferenceIdentifier) {
name = (ReferenceIdentifier) value;
@@ -362,7 +366,7 @@ public class AbstractIdentifiedObject ex
/**
* Returns a SIS identified object implementation with the values of the given arbitrary implementation.
- * This method performs the first applicable actions in the following choices:
+ * This method performs the first applicable action in the following choices:
*
* <ul>
* <li>If the given object is {@code null}, then this method returns {@code null}.</li>
@@ -371,8 +375,10 @@ public class AbstractIdentifiedObject ex
* {@link org.opengis.referencing.cs.CoordinateSystem},
* {@link org.opengis.referencing.cs.CoordinateSystemAxis},
* {@link org.opengis.referencing.datum.Datum},
- * {@link org.opengis.referencing.datum.Ellipsoid} or
+ * {@link org.opengis.referencing.datum.Ellipsoid},
* {@link org.opengis.referencing.datum.PrimeMeridian},
+ * {@link org.opengis.parameter.ParameterDescriptor} or
+ * {@link org.opengis.parameter.ParameterDescriptorGroup},
* then this method delegates to the {@code castOrCopy(…)} method of the corresponding SIS subclass.
* Note that if the given object implements more than one of the above-cited interfaces,
* then the {@code castOrCopy(…)} method to be used is unspecified.</li>
Copied: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java (from r1576954, sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java?p2=sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java&p1=sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java&r1=1576954&r2=1576972&rev=1576972&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -36,7 +36,7 @@ import static org.apache.sis.util.Argume
import static org.apache.sis.internal.system.DefaultFactories.NAMES;
// Related to JDK7
-import java.util.Objects;
+import org.apache.sis.internal.jdk7.Objects;
/**
@@ -189,9 +189,9 @@ public abstract class Builder<B extends
*/
protected Builder() {
assert verifyParameterizedType(getClass());
- properties = new HashMap<>(8);
- aliases = new ArrayList<>(4);
- identifiers = new ArrayList<>(4);
+ properties = new HashMap<String,Object>(8);
+ aliases = new ArrayList<GenericName>(4);
+ identifiers = new ArrayList<ReferenceIdentifier>(4);
}
/**
Modified: sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java?rev=1576972&r1=1576971&r2=1576972&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] (original)
+++ sis/branches/JDK6/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] Wed Mar 12 22:44:18 2014
@@ -32,6 +32,7 @@ import org.opengis.metadata.citation.Cit
import org.opengis.metadata.Identifier;
import org.opengis.referencing.ReferenceIdentifier;
import org.opengis.parameter.InvalidParameterValueException;
+import org.apache.sis.internal.referencing.NameToIdentifier;
import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.metadata.iso.ImmutableIdentifier;
@@ -58,13 +59,23 @@ import org.apache.sis.internal.jdk7.Obje
* {@linkplain AbstractIdentifiedObject#getAlias() aliases} and have those names used in contexts
* where {@code ReferenceIdentifier} instances are required, like GML marshalling time.
*
- * {@section Name inference}
- * The generic name will be inferred from {@code ReferenceIdentifier} attributes.
- * More specifically, a {@link ScopedName} will be created using the shortest authority's
- * {@linkplain Citation#getAlternateTitles() alternate titles} (or the {@linkplain Citation#getTitle() main title}
- * if there is no alternate titles) as the {@linkplain ScopedName#scope() scope}, and the {@linkplain #getCode() code}
- * as the name {@linkplain ScopedName#tip() tip}. Note that according ISO 19115, citation alternate titles often
- * contains abbreviation (for example "DCW" as an alternative title for "<cite>Digital Chart of the World</cite>").
+ * {@section Name ↔ Identifier mapping}
+ * The {@code GenericName} attributes will be inferred from {@code ReferenceIdentifier} attributes as below:
+ *
+ * <ul>
+ * <li><b>{@linkplain #tip() Tip}:</b> derived from the identifier {@linkplain #getCode() code}.</li>
+ * <li><b>{@linkplain #head() Head}:</b> derived from the identifier {@linkplain #getCodeSpace() code space}.</li>
+ * <li><b>{@linkplain #scope() Scope}:</b> derived from the shortest {@linkplain #getAuthority() authority}'s
+ * {@linkplain Citation#getAlternateTitles() alternate titles}, or the {@linkplain Citation#getTitle() main title}
+ * if there is no alternate titles. This policy exploits the ISO 19115 comment saying that citation alternate titles
+ * often contain abbreviation (for example "DCW" as an alternative title for "<cite>Digital Chart of the World</cite>").</li>
+ * </ul>
+ *
+ * <div class="note"><b>Example:</b>
+ * If the identifier attributes are {@code authority} = {@link Citations#OGP}, {@code codeSpace} = {@code "EPSG"}
+ * and {@code code} = {@code "4326"}, then the name attributes will be {@code scope} = {@code "OGP"},
+ * {@code head} = {@code "EPSG"}, {@code tip} = {@code "4326"} and {@link #toString()} = {@code "EPSG:4326"}.
+ * Note that the scope does not appear in the string representation of names.</div>
*
*
* {@section Immutability and thread safety}
@@ -84,7 +95,7 @@ public class NamedIdentifier extends Imm
/**
* Serial number for inter-operability with different versions.
*/
- private static final long serialVersionUID = 8474731565582874497L;
+ private static final long serialVersionUID = -3982456534858346939L;
/**
* A pool of {@link NameSpace} values for given {@link InternationalString}.
@@ -93,8 +104,8 @@ public class NamedIdentifier extends Imm
new WeakValueHashMap<CharSequence,NameSpace>(CharSequence.class);
/**
- * The name of this identifier as a generic name. If {@code null}, will be constructed
- * only when first needed.
+ * The name of this identifier as a generic name.
+ * If {@code null}, will be constructed only when first needed.
*/
private transient GenericName name;
@@ -102,7 +113,7 @@ public class NamedIdentifier extends Imm
* {@code true} if {@link #name} has been given explicitly by the user.
* Consider this field as final - it is not only for constructors convenience.
*/
- private boolean isNameSupplied;
+ private transient boolean isNameSupplied;
/**
* Creates a new identifier from the specified one. This is a copy constructor
@@ -110,7 +121,7 @@ public class NamedIdentifier extends Imm
* available) from the given identifier.
*
* <p>If the given identifier implements the {@link GenericName} interface, then calls to
- * {@link #tip()}, {@link #head()}, {@link #scope()} and similar methods will delegates
+ * {@link #tip()}, {@link #head()}, {@link #scope()} and similar methods will delegate
* to that name.</p>
*
* @param identifier The identifier to copy.
@@ -124,6 +135,19 @@ public class NamedIdentifier extends Imm
}
/**
+ * Creates a new identifier from the specified name. This constructor infers the identifier attributes
+ * (code, codespace and authority) from the given name. Calls to name-related methods like {@link #tip()},
+ * {@link #head()} and {@link #scope()} will delegate to the given name.
+ *
+ * @param name The name to wrap.
+ */
+ public NamedIdentifier(final GenericName name) {
+ super(name instanceof ReferenceIdentifier ? (ReferenceIdentifier) name : new NameToIdentifier(name));
+ this.name = name;
+ isNameSupplied = true;
+ }
+
+ /**
* Constructs an identifier from the given properties. The content of the properties map is used as
* described in the {@linkplain ImmutableIdentifier#ImmutableIdentifier(Map) super-class constructor}.
*
@@ -216,25 +240,23 @@ public class NamedIdentifier extends Imm
*/
private GenericName createName(final Citation authority, final CharSequence code) {
final NameFactory factory = DefaultFactories.NAMES;
- if (authority == null) {
- return factory.createLocalName(null, code);
+ final String title = Citations.getIdentifier(authority); // Whitespaces trimed by Citations.
+ NameSpace scope = null;
+ if (title != null) {
+ synchronized (SCOPES) {
+ scope = SCOPES.get(title);
+ if (scope == null) {
+ scope = factory.createNameSpace(factory.createLocalName(null, title), null);
+ SCOPES.put(title, scope);
+ }
+ }
}
- final String title;
final String codeSpace = super.getCodeSpace();
if (codeSpace != null) {
- title = codeSpace; // Whitespaces trimed by constructor.
+ return factory.createGenericName(scope, codeSpace, code);
} else {
- title = Citations.getIdentifier(authority); // Whitespaces trimed by Citations.
- }
- NameSpace scope;
- synchronized (SCOPES) {
- scope = SCOPES.get(title);
- if (scope == null) {
- scope = factory.createNameSpace(factory.createLocalName(null, title), null);
- SCOPES.put(title, scope);
- }
+ return factory.createLocalName(scope, code);
}
- return factory.createLocalName(scope, code).toFullyQualifiedName();
}
/**
@@ -266,10 +288,10 @@ public class NamedIdentifier extends Imm
/**
* Returns the scope (name space) in which this name is local.
- * By default, this is the same value than {@link #getCodeSpace()} provided as a name space.
+ * By default, this is the same value than the {@link #getAuthority() authority} provided as a name space.
*
* @see #head()
- * @see #getCodeSpace()
+ * @see #getAuthority()
*
* @return The scope of this name.
*/
@@ -340,7 +362,7 @@ public class NamedIdentifier extends Imm
/**
* Returns a string representation of this generic name. This string representation
* is local-independent. It contains all elements listed by {@link #getParsedNames()}
- * separated by an arbitrary character (usually {@code :} or {@code /}).
+ * separated by a namespace-dependent character (usually {@code :} or {@code /}).
*
* @return A local-independent string representation of this generic name.
*
@@ -403,9 +425,7 @@ public class NamedIdentifier extends Imm
*/
private void writeObject(final ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
- if (isNameSupplied) {
- out.writeObject(name);
- }
+ out.writeObject(isNameSupplied ? name : null);
}
/**
@@ -414,8 +434,7 @@ public class NamedIdentifier extends Imm
*/
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
- if (isNameSupplied) {
- name = (GenericName) in.readObject();
- }
+ name = (GenericName) in.readObject();
+ isNameSupplied = (name != null);
}
}