001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2004, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * This package contains documentation from OpenGIS specifications.
018: * OpenGIS consortium's work is fully acknowledged here.
019: */
020: package org.geotools.parameter;
021:
022: // J2SE dependencies and extensions
023: import java.util.Collections;
024: import java.util.HashMap;
025: import java.util.HashSet;
026: import java.util.Map;
027: import java.util.Set;
028: import javax.units.Unit;
029:
030: // OpenGIS dependencies
031: import org.opengis.util.CodeList;
032: import org.opengis.util.InternationalString;
033: import org.opengis.metadata.citation.Citation;
034: import org.opengis.parameter.ParameterDescriptor;
035: import org.opengis.parameter.GeneralParameterValue;
036:
037: // Geotools dependencies
038: import org.geotools.referencing.AbstractIdentifiedObject;
039: import org.geotools.referencing.NamedIdentifier;
040: import org.geotools.resources.ClassChanger;
041: import org.geotools.resources.Utilities;
042: import org.geotools.resources.i18n.Errors;
043: import org.geotools.resources.i18n.ErrorKeys;
044:
045: /**
046: * The definition of a parameter used by an operation method.
047: * For {@linkplain org.opengis.referencing.crs.CoordinateReferenceSystem Coordinate
048: * Reference Systems} most parameter values are numeric, but other types
049: * of parameter values are possible.
050: * <P>
051: * For numeric values, the {@linkplain #getValueClass value class} is usually
052: * <code>{@linkplain Double}.class</code>, <code>{@linkplain Integer}.class</code> or
053: * some other Java wrapper class.
054: * <P>
055: * This class contains numerous convenience constructors. But all of them ultimately invoke
056: * {@linkplain #DefaultParameterDescriptor(Map,Class,Object[],Object,Comparable,Comparable,Unit,boolean)
057: * a single, full-featured constructor}. All other constructors are just shortcuts.
058: *
059: * @since 2.1
060: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/parameter/DefaultParameterDescriptor.java $
061: * @version $Id: DefaultParameterDescriptor.java 24973 2007-03-30 21:57:48Z chorner $
062: * @author Martin Desruisseaux
063: *
064: * @see Parameter
065: * @see DefaultParameterDescriptorGroup
066: */
067: public class DefaultParameterDescriptor extends
068: AbstractParameterDescriptor implements ParameterDescriptor {
069: /**
070: * Serial number for interoperability with different versions.
071: */
072: private static final long serialVersionUID = -295668622297737705L;
073:
074: /**
075: * The class that describe the type of the parameter.
076: * This class can never be a primitive.
077: */
078: private final Class valueClass;
079:
080: /**
081: * The class that describe the type of the parameter, maybe as a primitive. This is the
082: * value class that the user specified at construction time. This is usually identical
083: * to {@code valueClass}. However, some optimization may be done for some primitive
084: * types, for example a special implementation of {@link Parameter} for the
085: * {@code double} type.
086: */
087: private final Class primitiveClass;
088:
089: /**
090: * A immutable, finite set of valid values (usually from a {linkplain org.opengis.util.CodeList
091: * code list}) or {@code null} if it doesn't apply. This set is immutable.
092: */
093: private final Set validValues;
094:
095: /**
096: * The default value for the parameter, or {@code null}.
097: */
098: private final Object defaultValue;
099:
100: /**
101: * The minimum parameter value, or {@code null}.
102: */
103: private final Comparable minimum;
104:
105: /**
106: * The maximum parameter value, or {@code null}.
107: */
108: private final Comparable maximum;
109:
110: /**
111: * The unit for default, minimum and maximum values, or {@code null}.
112: */
113: private final Unit unit;
114:
115: /**
116: * Constructs a descriptor with the same values than the specified one. This copy constructor
117: * may be used in order to wraps an arbitrary implementation into a Geotools one.
118: *
119: * @since 2.2
120: */
121: public DefaultParameterDescriptor(
122: final ParameterDescriptor descriptor) {
123: super (descriptor);
124: valueClass = descriptor.getValueClass();
125: validValues = descriptor.getValidValues();
126: defaultValue = descriptor.getDefaultValue();
127: minimum = descriptor.getMinimumValue();
128: maximum = descriptor.getMaximumValue();
129: unit = descriptor.getUnit();
130: primitiveClass = (descriptor instanceof DefaultParameterDescriptor) ? ((DefaultParameterDescriptor) descriptor).primitiveClass
131: : valueClass;
132: }
133:
134: /**
135: * Constructs a mandatory parameter for a range of integer values.
136: *
137: * @param name The parameter name.
138: * @param defaultValue The default value for the parameter.
139: * @param minimum The minimum parameter value, or {@link Integer#MIN_VALUE} if none.
140: * @param maximum The maximum parameter value, or {@link Integer#MAX_VALUE} if none.
141: */
142: public DefaultParameterDescriptor(final String name,
143: final int defaultValue, final int minimum, final int maximum) {
144: this (Collections.singletonMap(NAME_KEY, name), defaultValue,
145: minimum, maximum, true);
146: }
147:
148: /**
149: * Constructs a parameter for a range of integer values.
150: *
151: * @param properties The parameter properties (name, identifiers, alias...).
152: * @param defaultValue The default value for the parameter.
153: * @param minimum The minimum parameter value, or {@link Integer#MIN_VALUE} if none.
154: * @param maximum The maximum parameter value, or {@link Integer#MAX_VALUE} if none.
155: * @param required {@code true} if this parameter is required, {@code false} otherwise.
156: */
157: public DefaultParameterDescriptor(final Map properties,
158: final int defaultValue, final int minimum,
159: final int maximum, final boolean required) {
160: this (properties, required, Integer.class, null, Parameter
161: .wrap(defaultValue),
162: minimum == Integer.MIN_VALUE ? null : Parameter
163: .wrap(minimum),
164: maximum == Integer.MAX_VALUE ? null : Parameter
165: .wrap(maximum), null);
166: }
167:
168: /**
169: * Constructs a mandatory parameter for a range of floating point values.
170: *
171: * @param name The parameter name.
172: * @param defaultValue The default value for the parameter, or {@link Double#NaN} if none.
173: * @param minimum The minimum parameter value, or {@link Double#NEGATIVE_INFINITY} if none.
174: * @param maximum The maximum parameter value, or {@link Double#POSITIVE_INFINITY} if none.
175: * @param unit The unit for default, minimum and maximum values.
176: */
177: public DefaultParameterDescriptor(final String name,
178: final double defaultValue, final double minimum,
179: final double maximum, final Unit unit) {
180: this (Collections.singletonMap(NAME_KEY, name), defaultValue,
181: minimum, maximum, unit, true);
182: }
183:
184: /**
185: * Constructs a parameter for a range of floating point values.
186: *
187: * @param properties The parameter properties (name, identifiers, alias...).
188: * @param defaultValue The default value for the parameter, or {@link Double#NaN} if none.
189: * @param minimum The minimum parameter value, or {@link Double#NEGATIVE_INFINITY} if none.
190: * @param maximum The maximum parameter value, or {@link Double#POSITIVE_INFINITY} if none.
191: * @param unit The unit for default, minimum and maximum values.
192: * @param required {@code true} if this parameter is required, {@code false} otherwise.
193: */
194: public DefaultParameterDescriptor(final Map properties,
195: final double defaultValue, final double minimum,
196: final double maximum, final Unit unit,
197: final boolean required) {
198: this (properties, required, Double.class, null, Double
199: .isNaN(defaultValue) ? null : Parameter
200: .wrap(defaultValue),
201: minimum == Double.NEGATIVE_INFINITY ? null : Parameter
202: .wrap(minimum),
203: maximum == Double.POSITIVE_INFINITY ? null : Parameter
204: .wrap(maximum), unit);
205: }
206:
207: /**
208: * Constructs a parameter for a name and a default value. The parameter type will
209: * be assumed the same than the default value class.
210: *
211: * @param name The parameter name.
212: * @param remarks An optional description as a {@link String} or an
213: * {@link InternationalString}, or {@code null} if none.
214: * @param defaultValue The default value.
215: * @param required {@code true} if this parameter is required, {@code false} otherwise.
216: */
217: public DefaultParameterDescriptor(final String name,
218: final CharSequence remarks, final Object defaultValue,
219: final boolean required) {
220: this (
221: toMap(name, remarks),
222: defaultValue.getClass(),
223: (defaultValue instanceof CodeList) ? getCodeLists(defaultValue
224: .getClass())
225: : null, defaultValue, null, null, null,
226: required);
227: }
228:
229: /**
230: * Work around for RFE #4093999 in Sun's bug database
231: * ("Relax constraint on placement of this()/super() call in constructors").
232: */
233: private static final Map toMap(final String name,
234: final CharSequence remarks) {
235: if (remarks == null) {
236: return Collections.singletonMap(NAME_KEY, name);
237: }
238: final Map properties = new HashMap(4);
239: properties.put(NAME_KEY, name);
240: properties.put(REMARKS_KEY, remarks);
241: return properties;
242: }
243:
244: /**
245: * Constructs a parameter for a {@linkplain CodeList code list} (or enumeration).
246: *
247: * @param name The parameter name.
248: * @param defaultValue The default value.
249: */
250: public DefaultParameterDescriptor(final String name,
251: final CodeList defaultValue) {
252: this (name, defaultValue.getClass(), defaultValue);
253: }
254:
255: /**
256: * Constructs a parameter for a {@linkplain CodeList code list} (or enumeration). This
257: * constructor is used by the {@link #DefaultParameterDescriptor(String,CodeList)} constructor.
258: *
259: * @param name The parameter name.
260: * @param valueClass The class that describe the type of the parameter.
261: * Must be a subclass of {@link CodeList}.
262: * @param defaultValue The default value, or {@code null}.
263: */
264: DefaultParameterDescriptor(final String name,
265: final Class valueClass, final CodeList defaultValue) {
266: this (name, valueClass, getCodeLists(valueClass), defaultValue);
267: }
268:
269: /**
270: * Returns the enumeration found in the specified {@code CodeList} class.
271: * Returns {@code null} if no values were found.
272: */
273: private static CodeList[] getCodeLists(final Class type) {
274: try {
275: return (CodeList[]) type
276: .getMethod("values", (Class[]) null).invoke(null,
277: (Object[]) null);
278: } catch (Exception exception) {
279: // No code list defined. Not a problem; we will just
280: // not provide any set of code to check against.
281: return null;
282: }
283: }
284:
285: /**
286: * Constructs a mandatory parameter for a set of predefined values.
287: *
288: * @param name The parameter name.
289: * @param valueClass The class that describe the type of the parameter.
290: * @param validValues A finite set of valid values (usually from a
291: * {linkplain org.opengis.util.CodeList code list}) or {@code null}
292: * if it doesn't apply.
293: * @param defaultValue The default value for the parameter, or {@code null}.
294: */
295: public DefaultParameterDescriptor(final String name,
296: final Class valueClass, final Object[] validValues,
297: final Object defaultValue) {
298: this (Collections.singletonMap(NAME_KEY, name), valueClass,
299: validValues, defaultValue, null, null, null, true);
300: }
301:
302: /**
303: * Constructs a parameter from an authority and a name.
304: *
305: * @param authority The authority (e.g.
306: * {@link org.geotools.metadata.iso.citation.Citations#OGC OGC}).
307: * @param name The parameter name.
308: * @param valueClass The class that describe the type of the parameter.
309: * @param validValues A finite set of valid values (usually from a
310: * {linkplain org.opengis.util.CodeList code list}) or {@code null}
311: * if it doesn't apply.
312: * @param defaultValue The default value for the parameter, or {@code null}.
313: * @param minimum The minimum parameter value, or {@code null}.
314: * @param maximum The maximum parameter value, or {@code null}.
315: * @param unit The unit for default, minimum and maximum values.
316: * @param required {@code true} if this parameter is required,
317: * or {@code false} if it is optional.
318: *
319: * @since 2.2
320: */
321: public DefaultParameterDescriptor(final Citation authority,
322: final String name, final Class valueClass,
323: final Object[] validValues, final Object defaultValue,
324: final Comparable minimum, final Comparable maximum,
325: final Unit unit, final boolean required) {
326: this (Collections.singletonMap(NAME_KEY, new NamedIdentifier(
327: authority, name)), valueClass, validValues,
328: defaultValue, minimum, maximum, unit, required);
329: }
330:
331: /**
332: * Constructs a parameter from a set of properties. The properties map is
333: * given unchanged to the {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map)
334: * super-class constructor}.
335: *
336: * @param properties Set of properties. Should contains at least <code>"name"</code>.
337: * @param valueClass The class that describe the type of the parameter.
338: * @param validValues A finite set of valid values (usually from a
339: * {linkplain org.opengis.util.CodeList code list}) or {@code null}
340: * if it doesn't apply.
341: * @param defaultValue The default value for the parameter, or {@code null}.
342: * @param minimum The minimum parameter value, or {@code null}.
343: * @param maximum The maximum parameter value, or {@code null}.
344: * @param unit The unit for default, minimum and maximum values.
345: * @param required {@code true} if this parameter is required,
346: * or {@code false} if it is optional.
347: */
348: public DefaultParameterDescriptor(final Map properties,
349: final Class valueClass, final Object[] validValues,
350: final Object defaultValue, final Comparable minimum,
351: final Comparable maximum, final Unit unit,
352: final boolean required) {
353: this (properties, required, valueClass, validValues,
354: defaultValue, Parameter.replace(minimum), Parameter
355: .replace(maximum), unit);
356: }
357:
358: /**
359: * Constructs a parameter from a set of properties. The properties map is given unchanged to the
360: * {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}.
361: * <p>
362: * This constructor assumes that minimum, maximum and default values are
363: * already replaced by their cached values, if available.
364: *
365: * @param properties Set of properties. Should contains at least <code>"name"</code>.
366: * @param required {@code true} if this parameter is required, or {@code false}
367: * if it is optional.
368: * @param valueClass The class that describe the type of the parameter.
369: * @param validValues A finite set of valid values (usually from a
370: * {linkplain org.opengis.util.CodeList code list}) or {@code null}
371: * if it doesn't apply.
372: * @param defaultValue The default value for the parameter, or {@code null}.
373: * @param minimum The minimum parameter value, or {@code null}.
374: * @param maximum The maximum parameter value, or {@code null}.
375: * @param unit The unit for default, minimum and maximum values.
376: */
377: private DefaultParameterDescriptor(final Map properties,
378: final boolean required, Class valueClass,
379: final Object[] validValues, final Object defaultValue,
380: final Comparable minimum, final Comparable maximum,
381: final Unit unit) {
382: super (properties, required ? 1 : 0, 1);
383: this .primitiveClass = valueClass;
384: this .defaultValue = defaultValue;
385: this .minimum = minimum;
386: this .maximum = maximum;
387: this .unit = unit;
388: ensureNonNull("valueClass", valueClass);
389: if (valueClass.isPrimitive()) {
390: valueClass = ClassChanger.toWrapper(valueClass);
391: }
392: this .valueClass = valueClass;
393: AbstractParameter.ensureValidClass(valueClass, defaultValue);
394: AbstractParameter.ensureValidClass(valueClass, minimum);
395: AbstractParameter.ensureValidClass(valueClass, maximum);
396: if (minimum != null && maximum != null) {
397: if (minimum.compareTo(maximum) > 0) {
398: throw new IllegalArgumentException(Errors.format(
399: ErrorKeys.BAD_RANGE_$2, minimum, maximum));
400: }
401: }
402: if (validValues != null) {
403: final Set valids = new HashSet(Math.max(
404: validValues.length * 4 / 3 + 1, 8), 0.75f);
405: for (int i = 0; i < validValues.length; i++) {
406: final Object value = validValues[i];
407: AbstractParameter.ensureValidClass(valueClass, value);
408: valids.add(value);
409: }
410: this .validValues = Collections.unmodifiableSet(valids);
411: } else {
412: this .validValues = null;
413: }
414: if (defaultValue != null) {
415: Parameter.ensureValidValue(this , defaultValue);
416: }
417: }
418:
419: /**
420: * The maximum number of times that values for this parameter group or
421: * parameter can be included. For a {@linkplain DefaultParameterDescriptor
422: * single parameter}, the value is always 1.
423: *
424: * @see #getMinimumOccurs
425: */
426: public int getMaximumOccurs() {
427: return 1;
428: }
429:
430: /**
431: * Creates a new instance of {@linkplain org.geotools.parameter.Parameter parameter value}
432: * initialized with the {@linkplain #getDefaultValue default value}.
433: * The {@linkplain org.geotools.parameter.Parameter#getDescriptor parameter value
434: * descriptor} for the created parameter value will be {@code this} object.
435: * <P>
436: * If the {@linkplain #getValueClass value class} specified at construction time was
437: * a primitive type (e.g. <code>Double.{@linkplain Double#TYPE TYPE}</code> instead
438: * of <code>{@linkplain Double}.class</code>), then this method may returns a specialized
439: * parameter value implementation for this primitive type. Specialized implementations may
440: * use less storage space and be more flexible during conversions (for example from
441: * {@code float} to {@link String}), but this flexibility is not always wanted.
442: */
443: public GeneralParameterValue createValue() {
444: if (Double.TYPE.equals(primitiveClass)) {
445: return new FloatParameter(this );
446: }
447: return new Parameter(this );
448: }
449:
450: /**
451: * Returns the class that describe the type of the parameter. If the value class specified
452: * at construction time was a primitive type (e.g. {@code double}), it is converted to
453: * the corresponding wrapper class (e.g. {@link Double}).
454: *
455: * @return The parameter value class (never a primitive type).
456: */
457: public Class getValueClass() {
458: return valueClass;
459: }
460:
461: /**
462: * If this parameter allows only a finite set of values, returns this set.
463: * This set is usually a {linkplain org.opengis.util.CodeList code list} or
464: * enumerations. This method returns {@code null} if this parameter
465: * doesn't limits values to a finite set.
466: *
467: * @return A finite set of valid values (usually from a
468: * {linkplain org.opengis.util.CodeList code list}),
469: * or {@code null} if it doesn't apply.
470: */
471: public Set getValidValues() {
472: return validValues;
473: }
474:
475: /**
476: * Returns the default value for the parameter. The return type can be any type
477: * including a {@link Number} or a {@link String}. If there is no default value,
478: * then this method returns {@code null}.
479: *
480: * @return The default value, or {@code null} in none.
481: */
482: public Object getDefaultValue() {
483: return defaultValue;
484: }
485:
486: /**
487: * Returns the minimum parameter value. If there is no minimum value, or if minimum
488: * value is inappropriate for the {@linkplain #getValueClass parameter type}, then
489: * this method returns {@code null}.
490: *
491: * @return The minimum parameter value (often an instance of {@link Double}), or {@code null}.
492: */
493: public Comparable getMinimumValue() {
494: return minimum;
495: }
496:
497: /**
498: * Returns the maximum parameter value. If there is no maximum value, or if maximum
499: * value is inappropriate for the {@linkplain #getValueClass parameter type}, then
500: * this method returns {@code null}.
501: *
502: * @return The minimum parameter value (often an instance of {@link Double}), or {@code null}.
503: */
504: public Comparable getMaximumValue() {
505: return maximum;
506: }
507:
508: /**
509: * Returns the unit for
510: * {@linkplain #getDefaultValue default},
511: * {@linkplain #getMinimumValue minimum} and
512: * {@linkplain #getMaximumValue maximum} values.
513: * This attribute apply only if the values is of numeric type (usually an instance
514: * of {@link Double}).
515: *
516: * @return The unit for numeric value, or {@code null} if it
517: * doesn't apply to the value type.
518: */
519: public Unit getUnit() {
520: return unit;
521: }
522:
523: /**
524: * Compares the specified object with this parameter for equality.
525: *
526: * @param object The object to compare to {@code this}.
527: * @param compareMetadata {@code true} for performing a strict comparaison, or
528: * {@code false} for comparing only properties relevant to transformations.
529: * @return {@code true} if both objects are equal.
530: */
531: public boolean equals(final AbstractIdentifiedObject object,
532: final boolean compareMetadata) {
533: if (object == this ) {
534: return true;
535: }
536: if (super .equals(object, compareMetadata)) {
537: if (!compareMetadata) {
538: /*
539: * Tests for name, since parameters with different name have
540: * completly different meaning. For example there is no difference
541: * between "semi_major" and "semi_minor" parameters except the name.
542: * We don't perform this comparaison if the user asked for metadata
543: * comparaison, because in such case the names have already been
544: * compared by the subclass.
545: */
546: if (!nameMatches(object.getName().getCode())
547: && !nameMatches(object, getName().getCode())) {
548: return false;
549: }
550: }
551: final DefaultParameterDescriptor that = (DefaultParameterDescriptor) object;
552: return Utilities.equals(this .primitiveClass,
553: that.primitiveClass)
554: && Utilities.equals(this .validValues,
555: that.validValues)
556: && Utilities.equals(this .defaultValue,
557: that.defaultValue)
558: && Utilities.equals(this .minimum, that.minimum)
559: && Utilities.equals(this .maximum, that.maximum)
560: && Utilities.equals(this .unit, that.unit);
561: }
562: return false;
563: }
564:
565: /**
566: * Returns a hash value for this parameter.
567: *
568: * @return The hash code value. This value doesn't need to be the same
569: * in past or future versions of this class.
570: */
571: public int hashCode() {
572: int code = super .hashCode() * 37 + valueClass.hashCode();
573: if (defaultValue != null)
574: code += (37) * defaultValue.hashCode();
575: if (minimum != null)
576: code += (37 * 37) * minimum.hashCode();
577: if (maximum != null)
578: code += (37 * 37 * 37) * maximum.hashCode();
579: if (unit != null)
580: code += unit.hashCode();
581: return code;
582: }
583: }
|