001/* 002 * GeoAPI - Java interfaces for OGC/ISO standards 003 * Copyright © 2003-2024 Open Geospatial Consortium, Inc. 004 * http://www.geoapi.org 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.opengis.parameter; 019 020import java.net.URI; 021import javax.measure.Unit; 022import javax.measure.UnitConverter; 023import javax.measure.IncommensurableException; 024import org.opengis.annotation.UML; 025import org.opengis.annotation.Classifier; 026import org.opengis.annotation.Stereotype; 027import org.opengis.metadata.citation.Citation; 028import org.opengis.metadata.Identifier; 029import org.opengis.geometry.Geometry; 030 031import static org.opengis.annotation.Obligation.*; 032import static org.opengis.annotation.Specification.*; 033 034 035/** 036 * A single parameter value used by an operation method. Most CRS parameter values are numeric and can be obtained 037 * by the {@link #intValue()} or {@link #doubleValue()} methods. But other types of parameter values are possible 038 * and can be handled by the more generic {@link #getValue()} and {@link #setValue(Object)} methods. 039 * 040 * <p>All {@code xxxValue()} methods in this interface are convenience methods converting the value from {@code Object} 041 * to some commonly used types. Those types are specified in ISO 19111 as a union of attributes, listed below with the 042 * corresponding getter and setter methods:</p> 043 * 044 * <table class="ogc"> 045 * <caption>Common value types</caption> 046 * <tr><th>ISO attribute</th> <th>Java type</th> <th>Getter method</th> <th>Setter method</th></tr> 047 * <tr><td></td> <td>{@link Object}</td> <td>{@link #getValue()}</td> <td>{@link #setValue(Object)}</td></tr> 048 * <tr><td>stringValue</td> <td>{@link String}</td> <td>{@link #stringValue()}</td> <td>{@link #setValue(Object)}</td></tr> 049 * <tr><td>value</td> <td>{@code double}</td> <td>{@link #doubleValue()}</td> <td>{@link #setValue(double)}</td></tr> 050 * <tr><td></td> <td>{@code double}</td> <td>{@link #doubleValue(Unit)}</td> <td>{@link #setValue(double, Unit)}</td></tr> 051 * <tr><td>valueList</td> <td>{@code double[]}</td> <td>{@link #doubleValueList()}</td> <td>{@link #setValue(Object)}</td></tr> 052 * <tr><td></td> <td>{@code double[]}</td> <td>{@link #doubleValueList(Unit)}</td> <td>{@link #setValue(double[], Unit)}</td></tr> 053 * <tr><td>integerValue</td> <td>{@code int}</td> <td>{@link #intValue()}</td> <td>{@link #setValue(int)}</td></tr> 054 * <tr><td>integerValueList</td> <td>{@code int[]}</td> <td>{@link #intValueList()}</td> <td>{@link #setValue(Object)}</td></tr> 055 * <tr><td>booleanValue</td> <td>{@code boolean}</td> <td>{@link #booleanValue()}</td> <td>{@link #setValue(boolean)}</td></tr> 056 * <tr><td>valueFile</td> <td>{@link URI}</td> <td>{@link #valueFile()}</td> <td>{@link #setValue(Object)}</td></tr> 057 * <tr><td>valueFileCitation</td> <td>{@link Citation}</td> <td>{@link #getValue()}</td> <td>{@link #setValue(Object)}</td></tr> 058 * <tr><td>geographicObject</td> <td>{@link Geometry}</td> <td>{@link #getValue()}</td> <td>{@link #setValue(Object)}</td></tr> 059 * </table> 060 * 061 * The type and constraints on parameter values are given by the {@linkplain #getDescriptor() descriptor}, 062 * Instances of {@code ParameterValue} are created by the {@link ParameterDescriptor#createValue()} method. 063 * 064 * @departure integration 065 * This interface merges the {@code OperationParameterValue} interface and {@code ParameterValue} union. 066 * The {@code valueFileCitation} and {@code geographicObject} properties were omitted because those more 067 * complex objects can be specified by setting the {@code <T>} parameterized type to 068 * {@link Citation} and {@link Geometry} respectively. 069 * 070 * @param <T> the type of parameter values. 071 * 072 * @author OGC Topic 2 (for abstract model and documentation) 073 * @author Martin Desruisseaux (IRD, Geomatys) 074 * @author Jody Garnett (Refractions Research) 075 * @version 3.1 076 * @since 1.0 077 * 078 * @see ParameterDescriptor 079 * @see ParameterValueGroup 080 */ 081@Classifier(Stereotype.UNION) 082@UML(identifier="OperationParameterValue", specification=ISO_19111) 083public interface ParameterValue<T> extends GeneralParameterValue { 084 /** 085 * Returns the abstract definition of this parameter value. 086 * 087 * @return the abstract definition of this parameter value. 088 */ 089 @Override 090 @UML(identifier="parameter", obligation=MANDATORY, specification=ISO_19111) 091 ParameterDescriptor<T> getDescriptor(); 092 093 /** 094 * Returns the name of this parameter, for error messages only. 095 * All parameter shall have a name since it is a mandatory property, 096 * but if this parameter is nevertheless unnamed, an arbitrary value is returned. 097 * 098 * @return name of this parameter for error message. 099 */ 100 private String getName() { 101 ParameterDescriptor<?> descriptor = getDescriptor(); 102 if (descriptor != null) { 103 Identifier name = descriptor.getName(); 104 if (name != null) { 105 String code = name.getCode(); 106 if (code != null) { 107 return code; 108 } 109 } 110 } 111 return "unnamed"; 112 } 113 114 /** 115 * Returns a message saying that the value of this parameter cannot be converted to the specified unit. 116 * 117 * @param unit the illegal unit of measurement. 118 * @return a message saying that this parameter value cannot be converted. 119 */ 120 private String cannotConvert(final Unit<?> unit) { 121 return "The “" + getName() + "” parameter value cannot be converted to “" + unit + "” units."; 122 } 123 124 /** 125 * Returns the unit of measure of the parameter value. 126 * If the parameter value has no unit (for example because it is a {@link String} type), 127 * then this method returns {@code null}. Note that "no unit" doesn't means 128 * "dimensionless". 129 * 130 * @return the unit of measure of the parameter value. 131 * 132 * @see #doubleValue() 133 * @see #doubleValueList() 134 * @see #getValue() 135 */ 136 Unit<?> getUnit(); 137 138 /** 139 * Returns the numeric value of this parameter in the specified unit of measure. 140 * This convenience method applies unit conversion on the fly as needed. 141 * The default implementation invokes {@link #getValue()} and {@link #getUnit()}, 142 * then tries to cast and convert the value. 143 * 144 * @param unit the unit of measure for the value to be returned. 145 * @return the numeric value represented by this parameter after conversion to type 146 * {@code double} and conversion to {@code unit}. 147 * @throws IllegalArgumentException if the specified unit is invalid for this parameter. 148 * @throws InvalidParameterTypeException if the value is not a numeric type. 149 * @throws IllegalStateException if the value cannot be returned for another reason. 150 * 151 * @see #getUnit() 152 * @see #setValue(double,Unit) 153 * @see #doubleValueList(Unit) 154 */ 155 default double doubleValue(final Unit<?> unit) throws IllegalArgumentException, IllegalStateException { 156 final T value = getValue(); 157 final Number number; 158 try { 159 number = (Number) value; 160 } catch (ClassCastException cause) { 161 throw new InvalidParameterTypeException(cause, getName()); 162 } 163 final Unit<?> source = getUnit(); 164 try { 165 return source.getConverterToAny(unit).convert(number).doubleValue(); 166 } catch (IncommensurableException cause) { 167 throw new IllegalArgumentException(cannotConvert(unit), cause); 168 } 169 } 170 171 /** 172 * Returns the numeric value of this operation parameter. 173 * The unit of measurement is specified by {@link #getUnit()}. 174 * The default implementation invokes {@link #getValue()}, then tries to cast the value. 175 * 176 * @return the numeric value represented by this parameter after conversion to type {@code double}. 177 * @throws InvalidParameterTypeException if the value is not a numeric type. 178 * @throws IllegalStateException if the value cannot be returned for another reason. 179 * @unitof Measure 180 * 181 * @departure rename 182 * Renamed the method from "{@code value}" to "{@code doubleValue}" for consistency 183 * with {@code Number.doubleValue()} and the other "{@code *Value}" methods defined 184 * in this interface. 185 * 186 * @see #getUnit() 187 * @see #setValue(double) 188 * @see #doubleValueList() 189 */ 190 @UML(identifier="ParameterValue.value", obligation=CONDITIONAL, specification=ISO_19111) 191 default double doubleValue() throws IllegalStateException { 192 final T value = getValue(); 193 try { 194 return ((Number) value).doubleValue(); 195 } catch (NullPointerException | ClassCastException cause) { 196 throw new InvalidParameterTypeException(cause, getName()); 197 } 198 } 199 200 /** 201 * Returns the integer value of this parameter, usually used for a count. 202 * An integer value does not have an associated unit of measure. 203 * The default implementation invokes {@link #getValue()}, then tries to cast the value. 204 * 205 * @return the numeric value represented by this parameter after conversion to type {@code int}. 206 * @throws InvalidParameterTypeException if the value is not an integer type. 207 * @throws IllegalStateException if the value cannot be returned for another reason. 208 * 209 * @departure rename 210 * Renamed the method from "{@code integerValue}" to "{@code intValue}" for 211 * consistency with {@code Number.intValue()} and the {@code int} Java primitive type. 212 * 213 * @see #setValue(int) 214 * @see #intValueList() 215 */ 216 @UML(identifier="ParameterValue.integerValue", obligation=CONDITIONAL, specification=ISO_19111) 217 default int intValue() throws IllegalStateException { 218 final T value = getValue(); 219 try { 220 return Math.toIntExact(((Number) value).longValue()); 221 } catch (NullPointerException | ClassCastException | ArithmeticException cause) { 222 throw new InvalidParameterTypeException(cause, getName()); 223 } 224 } 225 226 /** 227 * Returns the Boolean value of this parameter. 228 * A Boolean value does not have an associated unit of measure. 229 * The default implementation invokes {@link #getValue()}, then tries to cast the value. 230 * 231 * @return the Boolean value represented by this parameter. 232 * @throws InvalidParameterTypeException if the value is not a Boolean type. 233 * @throws IllegalStateException if the value cannot be returned for another reason. 234 * 235 * @see #setValue(boolean) 236 */ 237 @UML(identifier="ParameterValue.booleanValue", obligation=CONDITIONAL, specification=ISO_19111) 238 default boolean booleanValue() throws IllegalStateException { 239 final T value = getValue(); 240 try { 241 return (Boolean) value; 242 } catch (NullPointerException | ClassCastException cause) { 243 throw new InvalidParameterTypeException(cause, getName()); 244 } 245 } 246 247 /** 248 * Returns the string value of this parameter. 249 * A string value does not have an associated unit of measure. 250 * The default implementation invokes {@link #getValue()}, then tries to cast the value. 251 * 252 * @return the string value represented by this parameter. 253 * @throws InvalidParameterTypeException if the value is not a string. 254 * @throws IllegalStateException if the value cannot be returned for another reason. 255 * 256 * @see #getValue() 257 * @see #setValue(Object) 258 */ 259 @UML(identifier="ParameterValue.stringValue", obligation=CONDITIONAL, specification=ISO_19111) 260 default String stringValue() throws IllegalStateException { 261 final T value = getValue(); 262 try { 263 return (String) value; 264 } catch (ClassCastException cause) { 265 throw new InvalidParameterTypeException(cause, getName()); 266 } 267 } 268 269 /** 270 * Returns an ordered sequence of numeric values in the specified unit of measure. 271 * This convenience method applies unit conversions on the fly as needed. 272 * The default implementation invokes {@link #doubleValueList()}, then tries to convert the values. 273 * 274 * @param unit the unit of measure for the value to be returned. 275 * @return the sequence of values represented by this parameter after conversion to type 276 * {@code double} and conversion to {@code unit}. 277 * @throws IllegalArgumentException if the specified unit is invalid for this parameter. 278 * @throws InvalidParameterTypeException if the value is not an array of {@code double}s. 279 * @throws IllegalStateException if the value cannot be returned for another reason. 280 * 281 * @see #getUnit() 282 * @see #setValue(double[],Unit) 283 * @see #doubleValue(Unit) 284 */ 285 default double[] doubleValueList(Unit<?> unit) throws IllegalArgumentException, IllegalStateException { 286 double[] values = doubleValueList(); 287 final Unit<?> source = getUnit(); 288 try { 289 final UnitConverter c = source.getConverterToAny(unit); 290 if (!c.isIdentity()) { 291 values = values.clone(); 292 for (int i=0; i < values.length; i++) { 293 values[i] = c.convert(values[i]); 294 } 295 } 296 } catch (IncommensurableException cause) { 297 throw new InvalidParameterTypeException(cause, getName()); 298 } 299 return values; 300 } 301 302 /** 303 * Returns an ordered sequence of two or more numeric values of this parameter, 304 * where each value has the same associated unit of measure. 305 * The default implementation invokes {@link #getValue()}, then tries to cast the value. 306 * 307 * @return the sequence of values represented by this parameter. 308 * @throws InvalidParameterTypeException if the value is not an array of {@code double}s. 309 * @throws IllegalStateException if the value cannot be returned for another reason. 310 * @unitof Measure 311 * 312 * @departure rename 313 * Renamed the method from "{@code valueList}" to "{@code doubleValueList}" both for 314 * consistency with {@code doubleValue()} and also because, like {@code doubleValue()}, 315 * this method returns an array of {@code double} values rather than a {@code Measure} 316 * object. 317 * 318 * @see #getUnit() 319 * @see #setValue(Object) 320 * @see #doubleValue() 321 */ 322 @UML(identifier="ParameterValue.valueList", obligation=CONDITIONAL, specification=ISO_19111) 323 default double[] doubleValueList() throws IllegalStateException { 324 final T value = getValue(); 325 try { 326 return (double[]) value; 327 } catch (ClassCastException cause) { 328 throw new InvalidParameterTypeException(cause, getName()); 329 } 330 } 331 332 /** 333 * Returns an ordered sequence of two or more integer values of this parameter, usually used for counts. 334 * These integer values do not have an associated unit of measure. 335 * The default implementation invokes {@link #getValue()}, then tries to cast the value. 336 * 337 * @return the sequence of values represented by this parameter. 338 * @throws InvalidParameterTypeException if the value is not an array of {@code int}s. 339 * @throws IllegalStateException if the value cannot be returned for another reason. 340 * 341 * @departure rename 342 * Renamed the attribute from "{@code integerValueList}" to "{@code intValueList}" 343 * for consistency with {@code intValue()}. 344 * 345 * @see #setValue(Object) 346 * @see #intValue() 347 */ 348 @UML(identifier="ParameterValue.integerValueList", obligation=CONDITIONAL, specification=ISO_19111) 349 default int[] intValueList() throws IllegalStateException { 350 final T value = getValue(); 351 try { 352 return (int[]) value; 353 } catch (ClassCastException cause) { 354 throw new InvalidParameterTypeException(cause, getName()); 355 } 356 } 357 358 /** 359 * Returns a reference to a file or a part of a file containing one or more parameter values. 360 * When referencing a part of a file, that file must contain multiple identified parts, such 361 * as an XML encoded document. Furthermore, the referenced file or part of a file can reference 362 * another part of the same or different files, as allowed in XML documents. 363 * 364 * <p>The default implementation invokes {@link #getValue()}, then tries to cast the value.</p> 365 * 366 * @return the reference to a file containing parameter values. 367 * @throws InvalidParameterTypeException if the value is not a reference to a file or a URI. 368 * @throws IllegalStateException if the value cannot be returned for another reason. 369 * 370 * @see #getValue() 371 * @see #setValue(Object) 372 */ 373 @UML(identifier="ParameterValue.valueFile", obligation=CONDITIONAL, specification=ISO_19111) 374 default URI valueFile() throws IllegalStateException { 375 final T value = getValue(); 376 try { 377 return (URI) value; 378 } catch (ClassCastException cause) { 379 throw new InvalidParameterTypeException(cause, getName()); 380 } 381 } 382 383 /** 384 * Returns the parameter value as an object. The object type is typically (but not restricted to) 385 * {@link Double}, {@link Integer}, {@link Boolean}, {@link String}, {@link URI}, {@code double[]} or {@code int[]}. 386 * If no value has been set, then this method returns the 387 * {@linkplain ParameterDescriptor#getDefaultValue() default value} (which may be null). 388 * 389 * @return the parameter value as an object, or {@code null} if no value has been set and 390 * there is no default value. 391 * 392 * @see #setValue(Object) 393 */ 394 T getValue(); 395 396 /** 397 * Sets the parameter value as an array of floating point and their associated unit. 398 * 399 * @param values the parameter values. 400 * @param unit the unit for the specified value. 401 * @throws InvalidParameterValueException if the floating point type is inappropriate for this 402 * parameter, or if the value is illegal for some other reason (for example a value out 403 * of range). 404 */ 405 void setValue(double[] values, Unit<?> unit) throws InvalidParameterValueException; 406 407 /** 408 * Sets the parameter value as a floating point and its associated unit. 409 * 410 * @param value the parameter value. 411 * @param unit the unit for the specified values. 412 * @throws InvalidParameterValueException if the floating point type is inappropriate for this 413 * parameter, or if the value is illegal for some other reason (for example a value out 414 * of range). 415 * 416 * @see #setValue(double) 417 * @see #doubleValue(Unit) 418 */ 419 void setValue(double value, Unit<?> unit) throws InvalidParameterValueException; 420 421 /** 422 * Sets the parameter value as a floating point. 423 * The default implementation delegates to {@link #setValue(Object)}. 424 * 425 * @param value the parameter value. 426 * @throws InvalidParameterValueException if the floating point type is inappropriate for this 427 * parameter, or if the value is illegal for some other reason (for example a value out 428 * of range). 429 * 430 * @see #setValue(double,Unit) 431 * @see #doubleValue() 432 */ 433 default void setValue(double value) throws InvalidParameterValueException { 434 setValue((Object) value); 435 } 436 437 /** 438 * Sets the parameter value as an integer. 439 * The default implementation delegates to {@link #setValue(Object)}. 440 * 441 * @param value the parameter value. 442 * @throws InvalidParameterValueException if the integer type is inappropriate for this parameter, 443 * or if the value is illegal for some other reason (for example a value out of range). 444 * 445 * @see #intValue() 446 */ 447 default void setValue(int value) throws InvalidParameterValueException { 448 setValue((Object) value); 449 } 450 451 /** 452 * Sets the parameter value as a Boolean. 453 * The default implementation delegates to {@link #setValue(Object)}. 454 * 455 * @param value the parameter value. 456 * @throws InvalidParameterValueException if the Boolean type is inappropriate for this parameter. 457 * 458 * @see #booleanValue() 459 */ 460 default void setValue(boolean value) throws InvalidParameterValueException { 461 setValue((Object) value); 462 } 463 464 /** 465 * Sets the parameter value as an object. The object type is typically (but not restricted to) 466 * {@link Double}, {@link Integer}, {@link Boolean}, {@link String}, {@link URI}, {@code double[]} or {@code int[]}. 467 * 468 * <p>The argument is not restricted to the parameterized type {@code T} because the type 469 * is typically unknown (as in <code>group.{@linkplain ParameterValueGroup#parameter(String) 470 * parameter}("<var>name</var>").setValue(<var>value</var>)</code>) and 471 * because some implementations may choose to convert a wider range of types.</p> 472 * 473 * @param value the parameter value. 474 * @throws InvalidParameterValueException if the type of {@code value} is inappropriate 475 * for this parameter, or if the value is illegal for some other reason (for example 476 * the value is numeric and out of range). 477 * 478 * @see #getValue() 479 */ 480 void setValue(Object value) throws InvalidParameterValueException; 481 482 /** 483 * Returns a copy of this parameter value. 484 * 485 * @return a copy of this parameter value. 486 */ 487 @Override 488 ParameterValue<T> clone(); 489}