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
023: import java.io.File;
024: import java.net.URL;
025: import java.net.URI;
026: import java.net.URISyntaxException;
027: import java.util.Arrays;
028: import java.util.Set;
029:
030: // Units dependencies
031: import javax.units.Converter;
032: import javax.units.NonSI;
033: import javax.units.SI;
034: import javax.units.Unit;
035:
036: // OpenGIS dependencies
037: import org.opengis.parameter.InvalidParameterTypeException;
038: import org.opengis.parameter.InvalidParameterValueException;
039: import org.opengis.parameter.ParameterDescriptor;
040: import org.opengis.parameter.ParameterValue;
041: import org.opengis.util.CodeList;
042:
043: // Geotools dependencies
044: import org.geotools.resources.i18n.ErrorKeys;
045: import org.geotools.resources.i18n.Errors;
046: import org.geotools.resources.Utilities;
047: import org.geotools.measure.Units;
048:
049: /**
050: * A parameter value used by an operation method.
051: * Most CRS parameter values are numeric, but other types of parameter values are possible.
052: * The parameter type can be fetch with the
053: * <code>{@linkplain #getValue()}.{@linkplain Object#getClass() getClass()}</code> idiom.
054: * The {@link #getValue()} and {@link #setValue(Object)} methods can be invoked at any time.
055: * Others getters and setters are parameter-type dependents.
056: *
057: * @since 2.1
058: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/parameter/Parameter.java $
059: * @version $Id: Parameter.java 26799 2007-08-31 21:31:21Z desruisseaux $
060: * @author Martin Desruisseaux
061: * @author Jody Garnett (Refractions Research)
062: *
063: * @see DefaultParameterDescriptor
064: * @see ParameterGroup
065: */
066: public class Parameter extends AbstractParameter implements
067: ParameterValue {
068: /**
069: * Serial number for interoperability with different versions.
070: */
071: private static final long serialVersionUID = -5837826787089486776L;
072:
073: /**
074: * Frequently used values. <strong>Must</strong> be in increasing order.
075: *
076: * @todo To be removed when we will be allowed to compile for J2SE 1.5.
077: */
078: private static final int[] CACHED_VALUES = { -360, -180, -90, -45,
079: -30, -4, -3, -2, -1, 0, +1, +2, +3, +4, +30, +45, +90,
080: +180, +360 };
081:
082: /** Frequently used values as integers. */
083: private static final Integer[] CACHED_INTEGERS;
084: /** Frequently used values as doubles. */
085: private static final Double[] CACHED_DOUBLES;
086: static {
087: CACHED_INTEGERS = new Integer[CACHED_VALUES.length];
088: CACHED_DOUBLES = new Double[CACHED_VALUES.length];
089: for (int i = 0; i < CACHED_VALUES.length; i++) {
090: CACHED_INTEGERS[i] = new Integer(CACHED_VALUES[i]);
091: CACHED_DOUBLES[i] = new Double(CACHED_VALUES[i]);
092: }
093: }
094:
095: /**
096: * An array with a single {@link String} class.
097: * Used for {@link #parse} default implementation.
098: */
099: private static final Class[] STRING_ARGUMENT = new Class[] { String.class };
100:
101: /**
102: * The value.
103: */
104: private Object value;
105:
106: /**
107: * The unit of measure for the value, or {@code null} if it doesn't apply.
108: */
109: private Unit unit;
110:
111: /**
112: * Constructs a parameter from the specified name and value. This convenience
113: * constructor creates a {@link DefaultParameterDescriptor} object. But if such
114: * an object was available, then the preferred way to get a {@code ParameterValue}
115: * is to invokes {@link ParameterDescriptor#createValue}.
116: *
117: * @param name The parameter name.
118: * @param value The parameter value.
119: */
120: public Parameter(final String name, final int value) {
121: this (new DefaultParameterDescriptor(name, 0, Integer.MIN_VALUE,
122: Integer.MAX_VALUE));
123: this .value = wrap(value);
124: }
125:
126: /**
127: * Constructs a parameter from the specified name and value. This convenience
128: * constructor creates a {@link DefaultParameterDescriptor} object. But if such
129: * an object was available, then the preferred way to get a {@code ParameterValue} is
130: * to invokes {@link ParameterDescriptor#createValue}.
131: *
132: * @param name The parameter name.
133: * @param value The parameter value.
134: * @param unit The unit for the parameter value.
135: */
136: public Parameter(final String name, final double value,
137: final Unit unit) {
138: this (new DefaultParameterDescriptor(name, Double.NaN,
139: Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY,
140: normalize(unit)));
141: this .value = wrap(value);
142: this .unit = unit;
143: }
144:
145: /**
146: * Constructs a parameter from the specified enumeration. This convenience
147: * constructor creates a {@link DefaultParameterDescriptor} object. But if
148: * such an object was available, then the preferred way to get a {@code ParameterValue}
149: * is to invokes {@link ParameterDescriptor#createValue}.
150: *
151: * @param name The parameter name.
152: * @param value The parameter value.
153: */
154: public Parameter(final String name, final CodeList value) {
155: this (new DefaultParameterDescriptor(name, value.getClass(),
156: (CodeList) null));
157: this .value = value;
158: }
159:
160: /**
161: * Constructs a parameter value from the specified descriptor.
162: * The value will be initialized to the default value, if any.
163: *
164: * @param descriptor The abstract definition of this parameter.
165: */
166: public Parameter(final ParameterDescriptor descriptor) {
167: super (descriptor);
168: value = descriptor.getDefaultValue();
169: unit = descriptor.getUnit();
170: }
171:
172: /**
173: * Constructs a parameter value from the specified descriptor and value.
174: *
175: * @param descriptor The abstract definition of this parameter.
176: * @param value The parameter value.
177: * @throws InvalidParameterValueException if the type of {@code value} is inappropriate
178: * for this parameter, or if the value is illegal for some other reason (for example
179: * the value is numeric and out of range).
180: */
181: public Parameter(final ParameterDescriptor descriptor,
182: final Object value) throws InvalidParameterValueException {
183: super (descriptor);
184: unit = descriptor.getUnit();
185: setValue(value);
186: }
187:
188: /**
189: * Wraps the specified value in an {@link Integer} object.
190: * This method try to avoid object creation if the value
191: * is one of {@link #CACHED_VALUES frequently used values}.
192: */
193: static Integer wrap(final int value) {
194: final int i = Arrays.binarySearch(CACHED_VALUES, value);
195: return (i >= 0) ? CACHED_INTEGERS[i] : new Integer(value);
196: }
197:
198: /**
199: * Wraps the specified value in an {@link Double} object.
200: * This method try to avoid object creation if the value
201: * is one of {@link #CACHED_VALUES frequently used values}.
202: */
203: static Double wrap(final double value) {
204: final int integer = (int) value;
205: if (integer == value) {
206: final int i = Arrays.binarySearch(CACHED_VALUES, integer);
207: if (i >= 0) {
208: return CACHED_DOUBLES[i];
209: }
210: }
211: return new Double(value);
212: }
213:
214: /**
215: * Replace the specified value by the cached value, if it exists.
216: * This is used for reducing memory usage for frequently used values.
217: */
218: static Comparable replace(final Comparable value) {
219: final Comparable[] CACHED;
220: if (value instanceof Double) {
221: CACHED = CACHED_DOUBLES;
222: } else if (value instanceof Integer) {
223: CACHED = CACHED_INTEGERS;
224: } else {
225: return value;
226: }
227: final int i = Arrays.binarySearch(CACHED, value);
228: return (i >= 0) ? CACHED[i] : value;
229: }
230:
231: /**
232: * Normalize the specified unit into one of "standard" units used in projections.
233: */
234: private static Unit normalize(final Unit unit) {
235: if (unit != null) {
236: if (SI.METER.isCompatible(unit))
237: return SI.METER;
238: if (NonSI.DAY.isCompatible(unit))
239: return NonSI.DAY;
240: if (NonSI.DEGREE_ANGLE.isCompatible(unit))
241: return NonSI.DEGREE_ANGLE;
242: }
243: return unit;
244: }
245:
246: /**
247: * Ensures that the given value is valid according the specified parameter descriptor.
248: * This convenience method ensures that {@code value} is assignable to the
249: * {@linkplain ParameterDescriptor#getValueClass expected class}, is between the
250: * {@linkplain ParameterDescriptor#getMinimumValue minimum} and
251: * {@linkplain ParameterDescriptor#getMaximumValue maximum} values and is one of the
252: * {@linkplain ParameterDescriptor#getValidValues set of valid values}.
253: * If the value fails any of those tests, then an exception is thrown.
254: *
255: * @param descriptor The parameter descriptor to check against.
256: * @param value The value to check, or {@code null}.
257: * @throws InvalidParameterValueException if the parameter value is invalid.
258: */
259: public static void ensureValidValue(
260: final ParameterDescriptor descriptor, final Object value)
261: throws InvalidParameterValueException {
262: if (value == null) {
263: return;
264: }
265: final String error;
266: if (!descriptor.getValueClass().isAssignableFrom(
267: value.getClass())) {
268: error = Errors.format(
269: ErrorKeys.ILLEGAL_OPERATION_FOR_VALUE_CLASS_$1,
270: Utilities.getShortClassName(value));
271: } else {
272: final Comparable minimum = descriptor.getMinimumValue();
273: final Comparable maximum = descriptor.getMaximumValue();
274: if ((minimum != null && minimum.compareTo(value) > 0)
275: || (maximum != null && maximum.compareTo(value) < 0)) {
276: error = Errors.format(ErrorKeys.VALUE_OUT_OF_BOUNDS_$3,
277: value, minimum, maximum);
278: } else {
279: final Set validValues = descriptor.getValidValues();
280: if (validValues != null && !validValues.contains(value)) {
281: error = Errors.format(
282: ErrorKeys.ILLEGAL_ARGUMENT_$2,
283: getName(descriptor), value);
284: } else {
285: return;
286: }
287: }
288: }
289: throw new InvalidParameterValueException(error,
290: getName(descriptor), value);
291: }
292:
293: /**
294: * Format an error message for illegal method call for the current value type.
295: */
296: private String getClassTypeError() {
297: return Errors
298: .format(
299: ErrorKeys.ILLEGAL_OPERATION_FOR_VALUE_CLASS_$1,
300: Utilities
301: .getShortName(((ParameterDescriptor) descriptor)
302: .getValueClass()));
303: }
304:
305: /**
306: * Returns the unit of measure of the {@linkplain #doubleValue() parameter value}.
307: * If the parameter value has no unit (for example because it is a {@link String} type),
308: * then this method returns {@code null}. Note that "no unit" doesn't means
309: * "dimensionless".
310: *
311: * @return The unit of measure, or {@code null} if none.
312: *
313: * @see #doubleValue()
314: * @see #doubleValueList()
315: * @see #getValue
316: */
317: public Unit getUnit() {
318: return unit;
319: }
320:
321: /**
322: * Returns the unit type as one of error message code. Used for checking unit with a better
323: * error message formatting if needed.
324: * <p>
325: * Note: It is difficult to differentiate scale and angular units, since both of them are
326: * dimensionless. However, in EPSG database version 6.7, there is only 3 scale units
327: * and all of them maps to {@link Unit#ONE} or {@link Units#PPM}. Consequently, they
328: * are hard-coded and treated especially by this method.
329: *
330: * @todo Provides a better way to differentiate scale units (currently Unit.ONE)
331: * and angular units. Both are dimensionless...
332: */
333: static int getUnitMessageID(final Unit unit) {
334: // Note: ONE must be tested before RADIAN.
335: if (Unit.ONE.equals(unit) || Units.PPM.equals(unit))
336: return ErrorKeys.NON_SCALE_UNIT_$1;
337: if (SI.METER.isCompatible(unit))
338: return ErrorKeys.NON_LINEAR_UNIT_$1;
339: if (SI.SECOND.isCompatible(unit))
340: return ErrorKeys.NON_TEMPORAL_UNIT_$1;
341: if (SI.RADIAN.isCompatible(unit))
342: return ErrorKeys.NON_ANGULAR_UNIT_$1;
343: return ErrorKeys.INCOMPATIBLE_UNIT_$1;
344: }
345:
346: /**
347: * Returns the numeric value of the coordinate operation parameter in the specified unit
348: * of measure. This convenience method apply unit conversion on the fly as needed.
349: *
350: * @param unit The unit of measure for the value to be returned.
351: * @return The numeric value represented by this parameter after conversion to type
352: * {@code double} and conversion to {@code unit}.
353: * @throws InvalidParameterTypeException if the value is not a numeric type.
354: * @throws IllegalArgumentException if the specified unit is invalid for this parameter.
355: *
356: * @see #getUnit
357: * @see #setValue(double,Unit)
358: * @see #doubleValueList(Unit)
359: */
360: public double doubleValue(final Unit unit)
361: throws InvalidParameterTypeException {
362: if (this .unit == null) {
363: throw unitlessParameter(descriptor);
364: }
365: ensureNonNull("unit", unit);
366: final int expectedID = getUnitMessageID(this .unit);
367: if (getUnitMessageID(unit) != expectedID) {
368: throw new IllegalArgumentException(Errors.format(
369: expectedID, unit));
370: }
371: return this .unit.getConverterTo(unit).convert(doubleValue());
372: }
373:
374: /**
375: * Returns the numeric value of the coordinate operation parameter with its
376: * associated {@linkplain #getUnit unit of measure}.
377: *
378: * @return The numeric value represented by this parameter after conversion to type {@code double}.
379: * @throws InvalidParameterTypeException if the value is not a numeric type.
380: *
381: * @see #getUnit
382: * @see #setValue(double)
383: * @see #doubleValueList()
384: */
385: public double doubleValue() throws InvalidParameterTypeException {
386: if (value instanceof Number) {
387: return ((Number) value).doubleValue();
388: }
389: final String name = getName(descriptor);
390: if (value == null) {
391: // This is the kind of exception expected by org.geotools.referencing.wkt.Formatter.
392: throw new IllegalStateException(Errors.format(
393: ErrorKeys.MISSING_PARAMETER_$1, name));
394: }
395: // Reminder: the following is a specialization of IllegalStateException.
396: throw new InvalidParameterTypeException(getClassTypeError(),
397: name);
398: }
399:
400: /**
401: * Returns the positive integer value of an operation parameter, usually used
402: * for a count. An integer value does not have an associated unit of measure.
403: *
404: * @return The numeric value represented by this parameter after conversion to type {@code int}.
405: * @throws InvalidParameterTypeException if the value is not an integer type.
406: *
407: * @see #setValue(int)
408: * @see #intValueList
409: */
410: public int intValue() throws InvalidParameterTypeException {
411: if (value instanceof Number) {
412: return ((Number) value).intValue();
413: }
414: final String name = getName(descriptor);
415: if (value == null) {
416: throw new IllegalStateException(Errors.format(
417: ErrorKeys.MISSING_PARAMETER_$1, name));
418: }
419: throw new InvalidParameterTypeException(getClassTypeError(),
420: name);
421: }
422:
423: /**
424: * Returns the boolean value of an operation parameter.
425: * A boolean value does not have an associated unit of measure.
426: *
427: * @return The boolean value represented by this parameter.
428: * @throws InvalidParameterTypeException if the value is not a boolean type.
429: *
430: * @see #setValue(boolean)
431: */
432: public boolean booleanValue() throws InvalidParameterTypeException {
433: if (value instanceof Boolean) {
434: return ((Boolean) value).booleanValue();
435: }
436: final String name = getName(descriptor);
437: if (value == null) {
438: throw new IllegalStateException(Errors.format(
439: ErrorKeys.MISSING_PARAMETER_$1, name));
440: }
441: throw new InvalidParameterTypeException(getClassTypeError(),
442: name);
443: }
444:
445: /**
446: * Returns the string value of an operation parameter.
447: * A string value does not have an associated unit of measure.
448: *
449: * @return The string value represented by this parameter.
450: * @throws InvalidParameterTypeException if the value is not a string.
451: *
452: * @see #getValue
453: * @see #setValue(Object)
454: */
455: public String stringValue() throws InvalidParameterTypeException {
456: if (value instanceof CharSequence) {
457: return value.toString();
458: }
459: final String name = getName(descriptor);
460: if (value == null) {
461: throw new IllegalStateException(Errors.format(
462: ErrorKeys.MISSING_PARAMETER_$1, name));
463: }
464: throw new InvalidParameterTypeException(getClassTypeError(),
465: name);
466: }
467:
468: /**
469: * Returns an ordered sequence of numeric values in the specified unit of measure.
470: * This convenience method apply unit conversion on the fly as needed.
471: *
472: * @param unit The unit of measure for the value to be returned.
473: * @return The sequence of values represented by this parameter after conversion to type
474: * {@code double} and conversion to {@code unit}.
475: * @throws InvalidParameterTypeException if the value is not an array of {@code double}s.
476: * @throws IllegalArgumentException if the specified unit is invalid for this parameter.
477: *
478: * @see #getUnit
479: * @see #setValue(double[],Unit)
480: * @see #doubleValue(Unit)
481: */
482: public double[] doubleValueList(final Unit unit)
483: throws InvalidParameterTypeException {
484: if (this .unit == null) {
485: throw unitlessParameter(descriptor);
486: }
487: ensureNonNull("unit", unit);
488: final int expectedID = getUnitMessageID(this .unit);
489: if (getUnitMessageID(unit) != expectedID) {
490: throw new IllegalArgumentException(Errors.format(
491: expectedID, unit));
492: }
493: final Converter converter = this .unit.getConverterTo(unit);
494: final double[] values = (double[]) doubleValueList().clone();
495: for (int i = 0; i < values.length; i++) {
496: values[i] = converter.convert(values[i]);
497: }
498: return values;
499: }
500:
501: /**
502: * Returns an ordered sequence of two or more numeric values of an operation parameter
503: * list, where each value has the same associated {@linkplain Unit unit of measure}.
504: *
505: * @return The sequence of values represented by this parameter.
506: * @throws InvalidParameterTypeException if the value is not an array of {@code double}s.
507: *
508: * @see #getUnit
509: * @see #setValue(Object)
510: * @see #doubleValue()
511: */
512: public double[] doubleValueList()
513: throws InvalidParameterTypeException {
514: if (value instanceof double[]) {
515: return (double[]) value;
516: }
517: final String name = getName(descriptor);
518: if (value == null) {
519: throw new IllegalStateException(Errors.format(
520: ErrorKeys.MISSING_PARAMETER_$1, name));
521: }
522: throw new InvalidParameterTypeException(getClassTypeError(),
523: name);
524: }
525:
526: /**
527: * Returns an ordered sequence of two or more integer values of an operation parameter list,
528: * usually used for counts. These integer values do not have an associated unit of measure.
529: *
530: * @return The sequence of values represented by this parameter.
531: * @throws InvalidParameterTypeException if the value is not an array of {@code int}s.
532: *
533: * @see #setValue(Object)
534: * @see #intValue
535: */
536: public int[] intValueList() throws InvalidParameterTypeException {
537: if (value instanceof int[]) {
538: return (int[]) value;
539: }
540: final String name = getName(descriptor);
541: if (value == null) {
542: throw new IllegalStateException(Errors.format(
543: ErrorKeys.MISSING_PARAMETER_$1, name));
544: }
545: throw new InvalidParameterTypeException(getClassTypeError(),
546: name);
547: }
548:
549: /**
550: * Returns a reference to a file or a part of a file containing one or more parameter
551: * values. When referencing a part of a file, that file must contain multiple identified
552: * parts, such as an XML encoded document. Furthermore, the referenced file or part of a
553: * file can reference another part of the same or different files, as allowed in XML documents.
554: *
555: * @return The reference to a file containing parameter values.
556: * @throws InvalidParameterTypeException if the value is not a reference to a file or an URI.
557: *
558: * @see #getValue
559: * @see #setValue(Object)
560: */
561: public URI valueFile() throws InvalidParameterTypeException {
562: if (value instanceof URI) {
563: return (URI) value;
564: }
565: if (value instanceof File) {
566: return ((File) value).toURI();
567: }
568: Exception cause = null;
569: try {
570: if (value instanceof URL) {
571: // TODO: use the next line when we will be allowed to compile for J2SE 1.5.
572: return new URI(value.toString());
573: // return ((URL) value).toURI();
574: }
575: if (value instanceof String) {
576: return new URI((String) value);
577: }
578: } catch (URISyntaxException exception) {
579: cause = exception;
580: }
581: /*
582: * Value can't be converted.
583: */
584: final String name = getName(descriptor);
585: if (value == null) {
586: throw new IllegalStateException(Errors.format(
587: ErrorKeys.MISSING_PARAMETER_$1, name));
588: }
589: final InvalidParameterTypeException exception = new InvalidParameterTypeException(
590: getClassTypeError(), name);
591: if (cause != null) {
592: exception.initCause(cause);
593: }
594: throw exception;
595: }
596:
597: /**
598: * Returns the parameter value as an object. The object type is typically a {@link Double},
599: * {@link Integer}, {@link Boolean}, {@link String}, {@link URI}, {@code double[]} or
600: * {@code int[]}.
601: *
602: * @return The parameter value as an object.
603: *
604: * @see #setValue(Object)
605: */
606: public Object getValue() {
607: return value;
608: }
609:
610: /**
611: * Set the parameter value as a floating point and its associated unit.
612: *
613: * @param value The parameter value.
614: * @param unit The unit for the specified value.
615: * @throws InvalidParameterValueException if the floating point type is inappropriate for this
616: * parameter, or if the value is illegal for some other reason (for example a value out
617: * of range).
618: *
619: * @see #setValue(double)
620: * @see #doubleValue(Unit)
621: */
622: public void setValue(final double value, final Unit unit)
623: throws InvalidParameterValueException {
624: ensureNonNull("unit", unit);
625: final Unit targetUnit = ((ParameterDescriptor) descriptor)
626: .getUnit();
627: if (targetUnit == null) {
628: throw unitlessParameter(descriptor);
629: }
630: final int expectedID = getUnitMessageID(targetUnit);
631: if (getUnitMessageID(unit) != expectedID) {
632: throw new InvalidParameterValueException(Errors.format(
633: expectedID, unit), descriptor.getName().getCode(),
634: value);
635: }
636: final Double converted = wrap(unit.getConverterTo(targetUnit)
637: .convert(value));
638: ensureValidValue((ParameterDescriptor) descriptor, converted);
639: this .value = wrap(value);
640: this .unit = unit;
641: }
642:
643: /**
644: * Set the parameter value as a floating point.
645: * The unit, if any, stay unchanged.
646: *
647: * @param value The parameter value.
648: * @throws InvalidParameterValueException if the floating point type is inappropriate for this
649: * parameter, or if the value is illegal for some other reason (for example a value out
650: * of range).
651: *
652: * @see #setValue(double,Unit)
653: * @see #doubleValue()
654: */
655: public void setValue(final double value)
656: throws InvalidParameterValueException {
657: final Double check = wrap(value);
658: ensureValidValue((ParameterDescriptor) descriptor, check);
659: this .value = check;
660: }
661:
662: /**
663: * Set the parameter value as an integer.
664: *
665: * @param value The parameter value.
666: * @throws InvalidParameterValueException if the integer type is inappropriate for this parameter,
667: * or if the value is illegal for some other reason (for example a value out of range).
668: *
669: * @see #intValue
670: */
671: public void setValue(final int value)
672: throws InvalidParameterValueException {
673: final ParameterDescriptor descriptor = (ParameterDescriptor) this .descriptor;
674: final Class type = descriptor.getValueClass();
675: if (Double.class.equals(type) || Double.TYPE.equals(type)) {
676: setValue((double) value);
677: return;
678: }
679: final Integer check = wrap(value);
680: ensureValidValue(descriptor, check);
681: this .value = check;
682: }
683:
684: /**
685: * Set the parameter value as a boolean.
686: *
687: * @param value The parameter value.
688: * @throws InvalidParameterValueException if the boolean type is inappropriate for this parameter.
689: *
690: * @see #booleanValue
691: */
692: public void setValue(final boolean value)
693: throws InvalidParameterValueException {
694: final Boolean check = Boolean.valueOf(value);
695: ensureValidValue((ParameterDescriptor) descriptor, check);
696: this .value = check;
697: }
698:
699: /**
700: * Set the parameter value as an object. The object type is typically a {@link Double},
701: * {@link Integer}, {@link Boolean}, {@link String}, {@link URI}, {@code double[]}
702: * or {@code int[]}.
703: *
704: * @param value The parameter value.
705: * @throws InvalidParameterValueException if the type of {@code value} is inappropriate
706: * for this parameter, or if the value is illegal for some other reason (for example
707: * the value is numeric and out of range).
708: *
709: * @see #getValue
710: */
711: public void setValue(final Object value)
712: throws InvalidParameterValueException {
713: ensureValidValue((ParameterDescriptor) descriptor, value);
714: this .value = value;
715: }
716:
717: /**
718: * Set the parameter value as an array of floating point and their associated unit.
719: *
720: * @param values The parameter values.
721: * @param unit The unit for the specified value.
722: * @throws InvalidParameterValueException if the floating point type is inappropriate for this
723: * parameter, or if the value is illegal for some other reason (for example a value out
724: * of range).
725: */
726: public void setValue(double[] values, final Unit unit)
727: throws InvalidParameterValueException {
728: ensureNonNull("unit", unit);
729: final Unit targetUnit = ((ParameterDescriptor) descriptor)
730: .getUnit();
731: if (targetUnit == null) {
732: throw unitlessParameter(descriptor);
733: }
734: final int expectedID = getUnitMessageID(targetUnit);
735: if (getUnitMessageID(unit) != expectedID) {
736: throw new IllegalArgumentException(Errors.format(
737: expectedID, unit));
738: }
739: final double[] converted = (double[]) values.clone();
740: final Converter converter = unit.getConverterTo(targetUnit);
741: for (int i = 0; i < converted.length; i++) {
742: converted[i] = converter.convert(converted[i]);
743: }
744: ensureValidValue((ParameterDescriptor) descriptor, converted);
745: this .value = values;
746: this .unit = unit;
747: }
748:
749: /**
750: * Compares the specified object with this parameter for equality.
751: *
752: * @param object The object to compare to {@code this}.
753: * @return {@code true} if both objects are equal.
754: */
755: public boolean equals(final Object object) {
756: if (object == this ) {
757: // Slight optimization
758: return true;
759: }
760: if (super .equals(object)) {
761: final Parameter that = (Parameter) object;
762: return Utilities.equals(this .value, that.value)
763: && Utilities.equals(this .unit, that.unit);
764: }
765: return false;
766: }
767:
768: /**
769: * Returns a hash value for this parameter.
770: *
771: * @return The hash code value. This value doesn't need to be the same
772: * in past or future versions of this class.
773: */
774: public int hashCode() {
775: int code = super .hashCode() * 37;
776: if (value != null)
777: code += value.hashCode();
778: if (unit != null)
779: code += 37 * unit.hashCode();
780: return code ^ (int) serialVersionUID;
781: }
782: }
|