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: package org.geotools.parameter;
018:
019: // J2SE dependencies
020: import java.io.Serializable;
021: import java.util.AbstractList;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.RandomAccess;
025:
026: // OpenGIS dependencies
027: import org.opengis.parameter.GeneralParameterDescriptor;
028: import org.opengis.parameter.GeneralParameterValue;
029: import org.opengis.parameter.InvalidParameterCardinalityException;
030: import org.opengis.parameter.InvalidParameterNameException;
031: import org.opengis.parameter.ParameterDescriptor;
032: import org.opengis.parameter.ParameterDescriptorGroup;
033: import org.opengis.parameter.ParameterValue;
034:
035: // Geotools dependencies
036: import org.geotools.referencing.AbstractIdentifiedObject;
037: import org.geotools.resources.i18n.ErrorKeys;
038: import org.geotools.resources.i18n.Errors;
039:
040: /**
041: * The list to be returned by {@link Parameter#values}.
042: * This class performs check on the parameter value to be added or removed.
043: * This implementation supports {@link #add} and {@link #remove} operations.
044: *
045: * @since 2.1
046: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/parameter/ParameterValueList.java $
047: * @version $Id: ParameterValueList.java 20874 2006-08-07 10:00:01Z jgarnett $
048: * @author Martin Desruisseaux
049: */
050: final class ParameterValueList extends AbstractList implements
051: RandomAccess, Serializable {
052: /**
053: * Serial number for interoperability with different versions.
054: */
055: private static final long serialVersionUID = -7446077551686135264L;
056:
057: /**
058: * The descriptor.
059: */
060: private final ParameterDescriptorGroup descriptor;
061:
062: /**
063: * The parameter values for this list.
064: */
065: private final List/*<GeneralParameterValue>*/values;
066:
067: /**
068: * Constructs a parameter list.
069: *
070: * @param descriptor The descriptor for this list.
071: * @param values The parameter values for this list.
072: */
073: public ParameterValueList(
074: final ParameterDescriptorGroup descriptor, final List values) {
075: this .descriptor = descriptor;
076: this .values = values;
077: }
078:
079: /*
080: * CAUTION: Some methods are NOT forwarded to 'values', and this is on purpose!
081: * This include all modification methods (add, set, remove, etc.).
082: * We must rely on the default AbstractList implementation for them.
083: */
084: public boolean isEmpty() {
085: return values.isEmpty();
086: }
087:
088: public int size() {
089: return values.size();
090: }
091:
092: public Object get(int i) {
093: return values.get(i);
094: }
095:
096: public int indexOf(Object o) {
097: return values.indexOf(o);
098: }
099:
100: public int lastIndexOf(Object o) {
101: return values.lastIndexOf(o);
102: }
103:
104: public boolean equals(Object o) {
105: return values.equals(o);
106: }
107:
108: public int hashCode() {
109: return values.hashCode();
110: }
111:
112: public String toString() {
113: return values.toString();
114: }
115:
116: /**
117: * Adds a value to this list. This method is automatically invoked by the default
118: * implementation of some collection methods like {@link #addAll}.
119: *
120: * Method to be removed with J2SE 1.5.
121: */
122: public boolean add(final Object object) {
123: return add((GeneralParameterValue) object);
124: }
125:
126: /**
127: * Adds a {@linkplain ParameterValue parameter value} or an other
128: * {@linkplain ParameterGroup parameter group} to this group. If an existing parameter
129: * is already included for the same {@linkplain ParameterDescriptor#getName identifier},
130: * then there is a choice:
131: * <UL>
132: * <LI>For <code>{@linkplain GeneralParameterDescriptor#getMaximumOccurs maximumOccurs}
133: * == 1</code>, the new parameter will replace the existing parameter.</LI>
134: * <LI>For <code>{@linkplain GeneralParameterDescriptor#getMaximumOccurs maximumOccurs}
135: * > 1</code>, the new parameter will be added. If adding the new parameter will
136: * increase the number past what is allowable by {@code maximumOccurs}, then
137: * an {@link IllegalStateException} will be thrown.</LI>
138: * </UL>
139: *
140: * @param parameter New parameter to be added to this group.
141: * @return {@code true} if this object changed as a result of this call.
142: * @throws IllegalArgumentException if the specified parameter is not allowable by the
143: * groups descriptor.
144: * @throws InvalidParameterCardinalityException if adding this parameter would result in
145: * more parameters than allowed by {@code maximumOccurs}.
146: */
147: public boolean add(final GeneralParameterValue parameter) {
148: modCount++;
149: final GeneralParameterDescriptor type = parameter
150: .getDescriptor();
151: final List descriptors = ((ParameterDescriptorGroup) descriptor)
152: .descriptors();
153: final String name = type.getName().getCode();
154: if (!descriptors.contains(type)) {
155: /*
156: * For a more accurate error message, check if the operation failed because
157: * the parameter name was not found, or the parameter descriptor doesn't matches.
158: */
159: for (final Iterator it = descriptors.iterator(); it
160: .hasNext();) {
161: if (AbstractIdentifiedObject.nameMatches(
162: (GeneralParameterDescriptor) it.next(), name)) {
163: /*
164: * Found a matching name. Consequently, the operation failed because
165: * the descriptor was illegal.
166: */
167: throw new IllegalArgumentException(
168: Errors
169: .format(
170: ErrorKeys.ILLEGAL_DESCRIPTOR_FOR_PARAMETER_$1,
171: name));
172: }
173: }
174: /*
175: * Found no matching name. Consequently, the operation failed because the name
176: * was invalid.
177: */
178: final Object value;
179: if (parameter instanceof ParameterValue) {
180: value = ((ParameterValue) parameter).getValue();
181: } else {
182: value = "(group)";
183: }
184: throw new InvalidParameterNameException(Errors.format(
185: ErrorKeys.ILLEGAL_ARGUMENT_$2, name, value), name);
186: }
187: final int max = type.getMaximumOccurs();
188: if (max == 1) {
189: /*
190: * Optional or mandatory parameter - we will simply replace what is there.
191: */
192: for (int i = values.size(); --i >= 0;) {
193: final GeneralParameterValue oldValue = (GeneralParameterValue) values
194: .get(i);
195: final GeneralParameterDescriptor oldDescriptor = oldValue
196: .getDescriptor();
197: if (type.equals(oldDescriptor)) {
198: assert AbstractIdentifiedObject.nameMatches(
199: oldDescriptor, name) : parameter;
200: final boolean same = parameter.equals(oldValue);
201: values.set(i, parameter);
202: return !same;
203: }
204: }
205: // Value will be added at the end of this method.
206: } else {
207: /*
208: * Parameter added (usually a group). Check the cardinality.
209: */
210: int count = 0;
211: for (final Iterator it = values.iterator(); it.hasNext();) {
212: final GeneralParameterValue value = (GeneralParameterValue) it
213: .next();
214: if (AbstractIdentifiedObject.nameMatches(value
215: .getDescriptor(), name)) {
216: count++;
217: }
218: }
219: if (count >= max) {
220: throw new InvalidParameterCardinalityException(Errors
221: .format(ErrorKeys.TOO_MANY_OCCURENCES_$2, name,
222: new Integer(count)), name);
223: }
224: }
225: values.add(parameter);
226: return true;
227: }
228:
229: /**
230: * Remove the value at the specified index.
231: *
232: * @param index The index of the value to remove.
233: */
234: public Object remove(final int index) {
235: // Remove cast with J2SE 1.5.
236: return remove(((GeneralParameterValue) values.get(index))
237: .getDescriptor(), index);
238: }
239:
240: /**
241: * Remove the value at the specified index.
242: *
243: * @param type The descriptor of the value to remove.
244: * @param index The index of the value to remove.
245: */
246: private GeneralParameterValue remove(
247: final GeneralParameterDescriptor type, final int index) {
248: modCount++;
249: int count = 0;
250: final String name = type.getName().getCode();
251: for (final Iterator it = values.iterator(); it.hasNext();) {
252: final GeneralParameterValue value = (GeneralParameterValue) it
253: .next();
254: if (AbstractIdentifiedObject.nameMatches(value
255: .getDescriptor(), name)) {
256: count++;
257: }
258: }
259: final int min = type.getMinimumOccurs();
260: if (count <= min) {
261: final int max = type.getMaximumOccurs();
262: throw new InvalidParameterCardinalityException(Errors
263: .format(ErrorKeys.ILLEGAL_OCCURS_FOR_PARAMETER_$4,
264: name, new Integer(count - 1), new Integer(
265: min), new Integer(max)), name);
266: }
267: // Note: remove cast with J2SE 1.5.
268: final GeneralParameterValue value = (GeneralParameterValue) values
269: .remove(index);
270: assert value != null && type.equals(value.getDescriptor()) : value;
271: return value;
272: }
273: }
|