All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotoolkit.parameter.DefaultParameterDescriptor Maven / Gradle / Ivy

/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2004-2012, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2009-2012, Geomatys
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    This package contains documentation from OpenGIS specifications.
 *    OpenGIS consortium's work is fully acknowledged here.
 */
package org.geotoolkit.parameter;

import java.util.Set;
import java.util.Map;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Collections;
import javax.measure.unit.Unit;
import net.jcip.annotations.Immutable;

import org.opengis.util.CodeList;
import org.opengis.util.InternationalString;
import org.opengis.metadata.citation.Citation;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.referencing.IdentifiedObject;

import org.geotoolkit.util.Utilities;
import org.geotoolkit.util.ComparisonMode;
import org.geotoolkit.util.converter.Classes;
import org.geotoolkit.util.collection.XCollections;
import org.geotoolkit.resources.Errors;
import org.geotoolkit.referencing.NamedIdentifier;
import org.geotoolkit.referencing.IdentifiedObjects;
import org.geotoolkit.referencing.AbstractIdentifiedObject;
import org.geotoolkit.metadata.iso.citation.Citations;

import static org.geotoolkit.util.Utilities.*;
import static org.geotoolkit.util.ArgumentChecks.ensureNonNull;
import static org.geotoolkit.util.ArgumentChecks.ensureCanCast;


/**
 * The definition of a parameter used by an operation method. For
 * {@linkplain org.geotoolkit.referencing.crs.AbstractCRS Coordinate Reference Systems}
 * most parameter values are numeric, but other types of parameter values are possible.
 * 

* For numeric values, the {@linkplain #getValueClass value class} is usually * {@link Double}, {@link Integer} or some other Java wrapper class. *

* This class contains numerous convenience constructors. But all of them ultimately invoke * {@linkplain #DefaultParameterDescriptor(Map,Class,Object[],Object,Comparable,Comparable,Unit,boolean) * a single, full-featured constructor}. All other constructors are just shortcuts. * * @param The type of elements to be returned by {@link ParameterValue#getValue}. * * @author Martin Desruisseaux (IRD, Geomatys) * @author Johann Sorel (Geomatys) * @version 3.18 * * @see Parameter * @see DefaultParameterDescriptorGroup * * @since 2.0 * @module */ @Immutable public class DefaultParameterDescriptor extends AbstractParameterDescriptor implements ParameterDescriptor { /** * Serial number for inter-operability with different versions. */ private static final long serialVersionUID = -295668622297737705L; /** * Some frequently used {@link Double} values. As of Java 6, those values don't * seem to be cached by {@link Double#valueOf} like JDK does for integers. */ private static final Map CACHE = new HashMap(13); static { cache( 0.0); cache( 1.0); cache( -90.0); cache( +90.0); cache(-180.0); cache(+180.0); cache(-180.0*60*60); cache(+180.0*60*60); cache(Double.NEGATIVE_INFINITY); cache(Double.POSITIVE_INFINITY); } /** * Helper method for the construction of the {@link #CACHE} map. */ private static void cache(final Double value) { if (CACHE.put(value,value) != null) { throw new AssertionError(value); } } /** * If the given value is presents in the cache, returns the cached value. */ private static T cached(final T value) { @SuppressWarnings("unchecked") final T candidate = (T) (Object) CACHE.get(value); return (candidate != null) ? candidate : value; } /** * The class that describe the type of the parameter. * This is the value class that the user specified at construction time. */ private final Class valueClass; /** * A immutable, finite set of valid values (usually from a {@linkplain CodeList code list}) * or {@code null} if it doesn't apply. This set is immutable. */ private final Set validValues; /** * The default value for the parameter, or {@code null}. */ private final T defaultValue; /** * The minimum parameter value, or {@code null}. */ private final Comparable minimum; /** * The maximum parameter value, or {@code null}. */ private final Comparable maximum; /** * The unit for default, minimum and maximum values, or {@code null}. */ private final Unit unit; /** * Constructs a descriptor with the same values than the specified one. This copy constructor * can be used in order to wrap an arbitrary implementation into a Geotk one. * * @param descriptor The descriptor to copy. * * @since 2.2 */ public DefaultParameterDescriptor(final ParameterDescriptor descriptor) { super(descriptor); valueClass = descriptor.getValueClass(); validValues = descriptor.getValidValues(); defaultValue = descriptor.getDefaultValue(); minimum = descriptor.getMinimumValue(); maximum = descriptor.getMaximumValue(); unit = descriptor.getUnit(); } /** * Constructs a descriptor for a mandatory parameter having a set of valid values. * The descriptor has no minimal or maximal value and no unit. * * @param name The parameter name. * @param valueClass The class that describe the type of the parameter. * @param validValues A finite set of valid values (usually from a {@linkplain CodeList * code list}) or {@code null} if it doesn't apply. * @param defaultValue The default value for the parameter, or {@code null} if none. */ public DefaultParameterDescriptor(final String name, final Class valueClass, final T[] validValues, final T defaultValue) { this(Collections.singletonMap(NAME_KEY, name), valueClass, validValues, defaultValue, null, null, null, true); } /** * Constructs a descriptor from an authority and a name. * * @param authority The authority (example: {@link Citations#OGC OGC}). * @param name The parameter name. * @param valueClass The class that describes the type of the parameter value. * @param validValues A finite set of valid values (usually from a {@linkplain CodeList * code list}) or {@code null} if it doesn't apply. * @param defaultValue The default value for the parameter, or {@code null} if none. * @param minimum The minimum parameter value (inclusive), or {@code null} if none. * @param maximum The maximum parameter value (inclusive), 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 required, or {@code false} if it is optional. * * @since 2.2 */ public DefaultParameterDescriptor(final Citation authority, final String name, final Class valueClass, final T[] validValues, final T defaultValue, final Comparable minimum, final Comparable maximum, final Unit unit, final boolean required) { this(Collections.singletonMap(NAME_KEY, new NamedIdentifier(authority, name)), valueClass, validValues, defaultValue, minimum, maximum, unit, required); } /** * Constructs a descriptor from a name and a default value. * * @param name The parameter name. * @param remarks An optional description as a {@link String} or an {@link InternationalString}. * @param valueClass The class that describe the type of the parameter. * @param defaultValue The default value. * @param required {@code true} if this parameter is required, {@code false} otherwise. * * @since 2.5 */ public DefaultParameterDescriptor(final String name, final CharSequence remarks, final Class valueClass, final T defaultValue, final boolean required) { this(properties(name, remarks), valueClass, codeList(valueClass), defaultValue, null, null, null, required); } /** * Constructs a descriptor from a set of properties. The properties map is given unchanged to the * {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}. * * @param properties Set of properties. Should contains at least {@code "name"}. * @param valueClass The class that describes the type of the parameter value. * @param validValues A finite set of valid values (usually from a {@linkplain CodeList * code list}) or {@code null} if it doesn't apply. * @param defaultValue The default value for the parameter, or {@code null} if none. * @param minimum The minimum parameter value (inclusive), or {@code null} if none. * @param maximum The maximum parameter value (inclusive), 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 required, or {@code false} if it is optional. */ public DefaultParameterDescriptor(final Map properties, final Class valueClass, final T[] validValues, final T defaultValue, final Comparable minimum, final Comparable maximum, final Unit unit, final boolean required) { super(properties, required ? 1 : 0, 1); this.valueClass = valueClass; this.defaultValue = cached(defaultValue); this.minimum = cached(minimum); this.maximum = cached(maximum); this.unit = unit; ensureNonNull("valueClass", valueClass); ensureCanCast("defaultValue", valueClass, defaultValue); ensureCanCast("minimum", valueClass, minimum); ensureCanCast("maximum", valueClass, maximum); if (minimum!=null && maximum!=null) { if (minimum.compareTo(valueClass.cast(maximum)) > 0) { throw new IllegalArgumentException(Errors.format( Errors.Keys.ILLEGAL_RANGE_$2, minimum, maximum)); } } if (validValues != null) { final Set valids = new HashSet(Math.max(XCollections.hashMapCapacity(validValues.length), 8)); for (int i=0; i create(final String name, final int defaultValue, final int minimum, final int maximum) { return create(Collections.singletonMap(NAME_KEY, name), defaultValue, minimum, maximum, true); } /** * Constructs a descriptor for a parameter in a range of integer values. * * @param properties The parameter properties (name, identifiers, alias...). * @param defaultValue The default value for the parameter. * @param minimum The minimum parameter value, or {@link Integer#MIN_VALUE} if none. * @param maximum The maximum parameter value, or {@link Integer#MAX_VALUE} if none. * @param required {@code true} if this parameter is required, {@code false} otherwise. * @return The parameter descriptor for the given range of values. * * @since 2.5 */ public static DefaultParameterDescriptor create(final Map properties, final int defaultValue, final int minimum, final int maximum, final boolean required) { return new DefaultParameterDescriptor(properties, Integer.class, null, Integer.valueOf(defaultValue), (minimum == Integer.MIN_VALUE) ? null : Integer.valueOf(minimum), (maximum == Integer.MAX_VALUE) ? null : Integer.valueOf(maximum), null, required); } /** * Constructs a descriptor for a mandatory parameter in a range of floating point values. * * @param name The parameter name. * @param defaultValue The default value for the parameter, or {@link Double#NaN} if none. * @param minimum The minimum parameter value, or {@link Double#NEGATIVE_INFINITY} if none. * @param maximum The maximum parameter value, or {@link Double#POSITIVE_INFINITY} if none. * @param unit The unit for default, minimum and maximum values. * @return The parameter descriptor for the given range of values. * * @since 2.5 */ public static DefaultParameterDescriptor create(final String name, final double defaultValue, final double minimum, final double maximum, final Unit unit) { return create(Collections.singletonMap(NAME_KEY, name), defaultValue, minimum, maximum, unit, true); } /** * Constructs a descriptor for a parameter in a range of floating point values. * * @param properties The parameter properties (name, identifiers, alias...). * @param defaultValue The default value for the parameter, or {@link Double#NaN} if none. * @param minimum The minimum parameter value, or {@link Double#NEGATIVE_INFINITY} if none. * @param maximum The maximum parameter value, or {@link Double#POSITIVE_INFINITY} if none. * @param unit The unit of measurement for default, minimum and maximum values. * @param required {@code true} if this parameter is required, {@code false} otherwise. * @return The parameter descriptor for the given range of values. * * @since 2.5 */ public static DefaultParameterDescriptor create(final Map properties, final double defaultValue, final double minimum, final double maximum, final Unit unit, final boolean required) { return new DefaultParameterDescriptor(properties, Double.class, null, Double.isNaN(defaultValue) ? null : Double.valueOf(defaultValue), minimum == Double.NEGATIVE_INFINITY ? null : Double.valueOf(minimum), maximum == Double.POSITIVE_INFINITY ? null : Double.valueOf(maximum), unit, required); } /** * Work around for RFE #4093999 in Sun's bug database * ("Relax constraint on placement of this()/super() call in constructors"). */ private static T[] codeList(final Class valueClass) { T[] codeList = null; if (CodeList.class.isAssignableFrom(valueClass)) { try { @SuppressWarnings("unchecked") // Type checked with reflection. final T[] tmp = (T[]) valueClass.getMethod("values", (Class[]) null).invoke(null, (Object[]) null); codeList = tmp; } catch (Exception exception) { // No code list defined. Not a problem; we will just // not provide any set of code to check against. } } return codeList; } /** * Work around for RFE #4093999 in Sun's bug database * ("Relax constraint on placement of this()/super() call in constructors"). */ private static Map properties(final String name, final CharSequence remarks) { final Map properties; if (remarks == null ){ properties = Collections.singletonMap(NAME_KEY, (CharSequence) name); } else { properties = new HashMap(4); properties.put(NAME_KEY, name); properties.put(REMARKS_KEY, remarks); } return properties; } /** * The maximum number of times that values for this parameter group or parameter can be * included. For a {@linkplain DefaultParameterDescriptor single parameter}, the value * is always 1. * * @return The maximum occurrence. * * @see #getMinimumOccurs */ @Override public int getMaximumOccurs() { return 1; } /** * Creates a new instance of {@code ParameterValue} initialized with the * {@linkplain #getDefaultValue default value}. The {@linkplain DefaultParameterDescriptor * parameter descriptor} for the created parameter value will be {@code this} object. * * @return A parameter initialized to the default value. */ @Override @SuppressWarnings("unchecked") public ParameterValue createValue() { if (valueClass == Double.class) { return (ParameterValue) new FloatParameter((ParameterDescriptor) this); } return new Parameter(this); } /** * Returns the class that describe the type of the parameter. * * @return The parameter value class. */ @Override public Class getValueClass() { return valueClass; } /** * If this parameter allows only a finite set of values, returns this set. This set is * usually a {@linkplain CodeList code list} or enumerations. This method returns * {@code null} if this parameter doesn't limits values to a finite set. * * @return A finite set of valid values (usually from a {@linkplain CodeList code list}), * or {@code null} if it doesn't apply. */ @Override public Set getValidValues() { return validValues; } /** * 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 minimum parameter value. If there is no minimum value, or if minimum * value is inappropriate for the {@linkplain #getValueClass parameter type}, then * this method returns {@code null}. * * @return The minimum parameter value (often an instance of {@link Double}), or {@code null}. */ @Override public Comparable getMinimumValue() { return minimum; } /** * Returns the maximum parameter value. If there is no maximum value, or if maximum * value is inappropriate for the {@linkplain #getValueClass parameter type}, then * this method returns {@code null}. * * @return The minimum parameter value (often an instance of {@link Double}), or {@code null}. */ @Override public Comparable getMaximumValue() { return maximum; } /** * Returns the unit for {@linkplain #getDefaultValue default}, * {@linkplain #getMinimumValue minimum} and * {@linkplain #getMaximumValue maximum} values. * This attribute apply only if the values is of numeric type * (usually an instance of {@link Double}). * * @return The unit for numeric value, or {@code null} if it doesn't apply to the value type. */ @Override public Unit getUnit() { return unit; } /** * Compares the specified object with this parameter for equality. * * @param object The object to compare to {@code this}. * @param mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or * {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only properties * relevant to transformations. * @return {@code true} if both objects are equal. */ @Override @SuppressWarnings("fallthrough") public boolean equals(final Object object, final ComparisonMode mode) { if (object == this) { return true; } if (super.equals(object, mode)) { switch (mode) { default: { /* * Tests for name, since parameters with different name have * completely different meaning. For example there is no difference * between "semi_major" and "semi_minor" parameters except the name. * We don't perform this comparison if the user asked for metadata * comparison, because in such case the names have already been * compared by the subclass. */ final IdentifiedObject that = (IdentifiedObject) object; if (!nameMatches(that. getName().getCode()) && !IdentifiedObjects.nameMatches(that, getName().getCode())) { return false; } // Fall through } case BY_CONTRACT: { final ParameterDescriptor that = (ParameterDescriptor) object; return Utilities. equals(getValidValues(), that.getValidValues()) && Utilities.deepEquals(getDefaultValue(), that.getDefaultValue()) && Utilities. equals(getMinimumValue(), that.getMinimumValue()) && Utilities. equals(getMaximumValue(), that.getMaximumValue()) && Utilities. equals(getUnit(), that.getUnit()); } case STRICT: { final DefaultParameterDescriptor that = (DefaultParameterDescriptor) object; return Utilities. equals(this.validValues, that.validValues) && Utilities.deepEquals(this.defaultValue, that.defaultValue) && Utilities. equals(this.minimum, that.minimum) && Utilities. equals(this.maximum, that.maximum) && Utilities. equals(this.unit, that.unit); } } } return false; } /** * {@inheritDoc} */ @Override protected int computeHashCode() { return hash(valueClass, hash(deepHashCode(defaultValue), hash(minimum, hash(maximum, hash(unit, 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 version. * * @since 3.17 */ @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 (minimum != null || maximum != null) { buffer.append(", valid=[").append(minimum != null ? minimum : "-\u221E") .append(" \u2026 ") .append(maximum != null ? maximum : "\u221E").append(']'); } else if (validValues != null) { buffer.append(", valid=").append(validValues); } if (defaultValue != null) { buffer.append(", default=").append(defaultValue); } if (unit != null) { buffer.append(", unit=").append(unit); } return buffer.append(']').toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy