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.util.Arrays;
024: import java.util.Collections;
025: import java.util.HashSet;
026: import java.util.Iterator;
027: import java.util.LinkedList;
028: import java.util.List;
029: import java.util.Map;
030: import java.util.Set;
031:
032: // OpenGIS dependencies
033: import org.opengis.metadata.Identifier; // For javadoc
034: import org.opengis.metadata.citation.Citation;
035: import org.opengis.parameter.GeneralParameterDescriptor;
036: import org.opengis.parameter.GeneralParameterValue;
037: import org.opengis.parameter.InvalidParameterNameException;
038: import org.opengis.parameter.ParameterDescriptor;
039: import org.opengis.parameter.ParameterDescriptorGroup;
040: import org.opengis.parameter.ParameterNotFoundException;
041: import org.opengis.parameter.ParameterValueGroup;
042:
043: // Geotools dependencies
044: import org.geotools.referencing.AbstractIdentifiedObject;
045: import org.geotools.referencing.NamedIdentifier;
046: import org.geotools.resources.UnmodifiableArrayList;
047: import org.geotools.resources.i18n.ErrorKeys;
048: import org.geotools.resources.i18n.Errors;
049:
050: /**
051: * The definition of a group of related parameters used by an operation method.
052: *
053: * @since 2.1
054: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/parameter/DefaultParameterDescriptorGroup.java $
055: * @version $Id: DefaultParameterDescriptorGroup.java 25262 2007-04-23 21:11:16Z desruisseaux $
056: * @author Martin Desruisseaux
057: *
058: * @see ParameterGroup
059: * @see DefaultParameterDescriptor
060: */
061: public class DefaultParameterDescriptorGroup extends
062: AbstractParameterDescriptor implements ParameterDescriptorGroup {
063: /**
064: * Serial number for interoperability with different versions.
065: */
066: private static final long serialVersionUID = -4613190550542423839L;
067:
068: /**
069: * The maximum number of times that values for this parameter group or
070: * parameter are required.
071: */
072: private final int maximumOccurs;
073:
074: /**
075: * The {@linkplain #descriptors() parameter descriptors} for this group.
076: */
077: private final GeneralParameterDescriptor[] parameters;
078:
079: /**
080: * A view of {@link #parameters} as an immutable list. Will be constructed
081: * only when first needed.
082: */
083: private transient List asList;
084:
085: /**
086: * Constructs a group with the same values than the specified one. This copy constructor
087: * may be used in order to wraps an arbitrary implementation into a Geotools one.
088: *
089: * @since 2.2
090: */
091: public DefaultParameterDescriptorGroup(
092: final ParameterDescriptorGroup group) {
093: super (group);
094: maximumOccurs = group.getMaximumOccurs();
095: final List/*<GeneralParameterDescriptor>*/c = group
096: .descriptors();
097: parameters = (GeneralParameterDescriptor[]) c
098: .toArray(new GeneralParameterDescriptor[c.size()]);
099: }
100:
101: /**
102: * Constructs a parameter group from a name.
103: * This parameter group will be required exactly once.
104: *
105: * @param name The parameter group name.
106: * @param parameters The {@linkplain #descriptors() parameter descriptors} for this group.
107: */
108: public DefaultParameterDescriptorGroup(final String name,
109: final GeneralParameterDescriptor[] parameters) {
110: this (Collections.singletonMap(NAME_KEY, name), parameters);
111: }
112:
113: /**
114: * Constructs a parameter group from a name and an authority.
115: * This parameter group will be required exactly once.
116: *
117: * @param authority The authority (e.g.
118: * {@link org.geotools.metadata.iso.citation.Citations#OGC OGC}).
119: * @param name The parameter group name.
120: * @param parameters The {@linkplain #descriptors() parameter descriptors} for this group.
121: *
122: * @since 2.2
123: */
124: public DefaultParameterDescriptorGroup(final Citation authority,
125: final String name,
126: final GeneralParameterDescriptor[] parameters) {
127: this (Collections.singletonMap(NAME_KEY, new NamedIdentifier(
128: authority, name)), parameters);
129: }
130:
131: /**
132: * Constructs a parameter group from a set of properties.
133: * This parameter group will be required exactly once. The properties map is given unchanged to
134: * the {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}.
135: *
136: * @param properties Set of properties. Should contains at least {@code "name"}.
137: * @param parameters The {@linkplain #descriptors() parameter descriptors} for this group.
138: */
139: public DefaultParameterDescriptorGroup(final Map properties,
140: final GeneralParameterDescriptor[] parameters) {
141: this (properties, 1, 1, parameters);
142: }
143:
144: /**
145: * Constructs a parameter group from a set of properties. The properties map is given
146: * unchanged to the {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map)
147: * super-class constructor}.
148: *
149: * @param properties Set of properties. Should contains at least {@code "name"}.
150: * @param minimumOccurs The {@linkplain #getMinimumOccurs minimum number of times}
151: * that values for this parameter group are required.
152: * @param maximumOccurs The {@linkplain #getMaximumOccurs maximum number of times}
153: * that values for this parameter group are required.
154: * @param parameters The {@linkplain #descriptors() parameter descriptors} for this group.
155: */
156: public DefaultParameterDescriptorGroup(final Map properties,
157: final int minimumOccurs, final int maximumOccurs,
158: GeneralParameterDescriptor[] parameters) {
159: super (properties, minimumOccurs, maximumOccurs);
160: this .maximumOccurs = maximumOccurs;
161: ensureNonNull("parameters", parameters);
162: this .parameters = new GeneralParameterDescriptor[parameters.length];
163: for (int i = 0; i < parameters.length; i++) {
164: this .parameters[i] = parameters[i];
165: ensureNonNull("parameters", parameters, i);
166: }
167: /*
168: * Ensure there is no conflict in parameter names.
169: */
170: parameters = this .parameters;
171: for (int i = 0; i < parameters.length; i++) {
172: final String name = parameters[i].getName().getCode();
173: for (int j = 0; j < parameters.length; j++) {
174: if (i != j) {
175: if (nameMatches(parameters[j], name)) {
176: throw new InvalidParameterNameException(
177: Errors
178: .format(
179: ErrorKeys.PARAMETER_NAME_CLASH_$4,
180: parameters[j].getName()
181: .getCode(),
182: new Integer(j), name,
183: new Integer(i)), name);
184: }
185: }
186: }
187: }
188: }
189:
190: /**
191: * The maximum number of times that values for this parameter group are required.
192: *
193: * @see #getMinimumOccurs
194: */
195: public int getMaximumOccurs() {
196: return maximumOccurs;
197: }
198:
199: /**
200: * Creates a new instance of {@linkplain ParameterGroup parameter value group}
201: * initialized with the {@linkplain ParameterDescriptor#getDefaultValue default values}.
202: * The {@linkplain ParameterValueGroup#getDescriptor parameter value descriptor}
203: * for the created group will be {@code this} object.
204: */
205: public GeneralParameterValue createValue() {
206: return new ParameterGroup(this );
207: }
208:
209: /**
210: * A view of {@link #parameters} as an unmodifiable list. This class overides
211: * {@link #contains} with a faster implementation based on {@link HashSet}.
212: * It can help for map projection implementations (among other), which test
213: * often for a parameter validity.
214: */
215: private static final class AsList extends UnmodifiableArrayList {
216: /** For compatibility with different versions. */
217: private static final long serialVersionUID = -2116304004367396735L;
218:
219: /** The element as a set. Will be constructed only when first needed. */
220: private transient Set asSet;
221:
222: /** Constructs a list for the specified array. */
223: public AsList(final GeneralParameterDescriptor[] array) {
224: super (array);
225: }
226:
227: /** Test for the inclusion of the specified descriptor. */
228: public boolean contains(final Object object) {
229: if (asSet == null) {
230: asSet = new HashSet(this );
231: }
232: return asSet.contains(object);
233: }
234: }
235:
236: /**
237: * Returns the parameters in this group.
238: */
239: public List descriptors() {
240: if (asList == null) {
241: if (parameters == null) {
242: asList = Collections.EMPTY_LIST;
243: } else
244: switch (parameters.length) {
245: case 0:
246: asList = Collections.EMPTY_LIST;
247: break;
248: case 1:
249: asList = Collections.singletonList(parameters[0]);
250: break;
251: case 2: // fall through
252: case 3:
253: asList = new UnmodifiableArrayList(parameters);
254: break;
255: default:
256: asList = new AsList(parameters);
257: break;
258: }
259: }
260: return asList;
261: }
262:
263: /**
264: * Returns the first parameter in this group for the specified {@linkplain Identifier#getCode
265: * identifier code}.
266: *
267: * @param name The case insensitive {@linkplain Identifier#getCode identifier code} of the
268: * parameter to search for.
269: * @return The parameter for the given identifier code.
270: * @throws ParameterNotFoundException if there is no parameter for the given identifier code.
271: */
272: public GeneralParameterDescriptor descriptor(String name)
273: throws ParameterNotFoundException {
274: ensureNonNull("name", name);
275: name = name.trim();
276: List subgroups = null;
277: List/*<GeneralParameterDescriptor>*/parameters = descriptors();
278: while (parameters != null) {
279: for (final Iterator it = parameters.iterator(); it
280: .hasNext();) {
281: final GeneralParameterDescriptor param = (GeneralParameterDescriptor) it
282: .next();
283: if (param instanceof ParameterDescriptor) {
284: if (nameMatches(param, name)) {
285: return (ParameterDescriptor) param;
286: }
287: } else if (param instanceof DefaultParameterDescriptorGroup) {
288: if (subgroups == null) {
289: subgroups = new LinkedList();
290: }
291: assert !subgroups.contains(param) : param;
292: subgroups.add(param);
293: }
294: }
295: /*
296: * Looks in subgroups only after all parameters in the current group have been verified.
297: * Search in a "first in, first out" basis.
298: */
299: if (subgroups == null || subgroups.isEmpty()) {
300: break;
301: }
302: parameters = ((DefaultParameterDescriptorGroup) subgroups
303: .remove(0)).descriptors();
304: }
305: throw new ParameterNotFoundException(Errors.format(
306: ErrorKeys.MISSING_PARAMETER_$1, name), name);
307: }
308:
309: /**
310: * Compares the specified object with this parameter group for equality.
311: *
312: * @param object The object to compare to {@code this}.
313: * @param compareMetadata {@code true} for performing a strict comparaison, or
314: * {@code false} for comparing only properties relevant to transformations.
315: * @return {@code true} if both objects are equal.
316: */
317: public boolean equals(final AbstractIdentifiedObject object,
318: final boolean compareMetadata) {
319: if (object == this ) {
320: // Slight optimization
321: return true;
322: }
323: if (super .equals(object, compareMetadata)) {
324: final DefaultParameterDescriptorGroup that = (DefaultParameterDescriptorGroup) object;
325: return Arrays.equals(this .parameters, that.parameters);
326: }
327: return false;
328: }
329:
330: /**
331: * Returns a hash value for this parameter.
332: *
333: * @return The hash code value. This value doesn't need to be the same
334: * in past or future versions of this class.
335: */
336: public int hashCode() {
337: int code = super .hashCode();
338: // TODO: We should use Arrays.deepHashCode instead in J2SE 1.5.
339: for (int i = 0; i < parameters.length; i++) {
340: code = code * 37 + parameters[i].hashCode();
341: }
342: return code;
343: }
344: }
|