/* * Geotools 2 - OpenSource mapping toolkit * (C) 2004, Geotools Project Managment Committee (PMC) * (C) 2004, Institut de Recherche pour le Développement * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * This package contains documentation from OpenGIS specifications. * OpenGIS consortium's work is fully acknowledged here. */ package org.geotools.parameter; // J2SE dependencies import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; // OpenGIS dependencies import org.opengis.metadata.Identifier; import org.opengis.parameter.GeneralParameterDescriptor; import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.InvalidParameterCardinalityException; import org.opengis.parameter.InvalidParameterTypeException; import org.opengis.parameter.ParameterDescriptor; import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.parameter.ParameterNotFoundException; import org.opengis.parameter.ParameterValue; import org.opengis.parameter.ParameterValueGroup; // Geotools dependencies import org.geotools.referencing.AbstractIdentifiedObject; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Errors; import org.geotools.resources.Utilities; /** * A group of related parameter values. The same group can be repeated more than once in an * {@linkplain org.opengis.referencing.operation.Operation operation} or higher level * {@link ParameterValueGroup}, if those instances contain different * values of one or more {@link ParameterValue}s which suitably distinquish among * those groups. * * @since 2.1 * @version $Id$ * @author Martin Desruisseaux * @author Jody Garnett (Refractions Research) * * @see DefaultParameterDescriptorGroup * @see Parameter */ public class ParameterGroup extends AbstractParameter implements ParameterValueGroup { /** * Serial number for interoperability with different versions. */ private static final long serialVersionUID = -1985309386356545126L; /** * An empty parameter value group. This group contains no parameter value. */ public static ParameterValueGroup EMPTY = new ParameterGroup( Collections.singletonMap(ParameterDescriptorGroup.NAME_KEY, "Void"), new ParameterValue[0]); /** * The {@linkplain #values() parameter values} for this group. * Note: consider as final. This field is not final only in order * to allows {@link #clone} to work. */ private ArrayList/**/ values; /** * A view of {@link #values} as an immutable list. Will be constructed only when first * needed. Note that while this list may be immutable, elements in this * list stay modifiable. The goal is to allows the following idiom: * *
     * values().get(i).setValue(myValue);
     * 
*/ private transient List asList; /** * Constructs a parameter group from the specified descriptor. * All {@linkplain #values parameter values} will be initialized * to their default value. * * @param descriptor The descriptor for this group. */ public ParameterGroup(final ParameterDescriptorGroup descriptor) { super(descriptor); final List/**/ parameters = descriptor.descriptors(); values = new ArrayList/**/(parameters.size()); for (final Iterator it=parameters.iterator(); it.hasNext();) { final GeneralParameterDescriptor element = (GeneralParameterDescriptor) it.next(); for (int count=element.getMinimumOccurs(); --count>=0;) { final GeneralParameterValue value = element.createValue(); ensureNonNull("createValue", value); values.add(value); } } } /** * Constructs a parameter group from the specified descriptor and list of parameters. * * @param descriptor The descriptor for this group. * @param values The list of parameter values. * * @throws IllegalStateException if the number of {@linkplain ParameterValue parameter} * occurences doesn't matches the number declared in the * {@linkplain ParameterDescriptorGroup descriptor}. */ public ParameterGroup(final ParameterDescriptorGroup descriptor, final GeneralParameterValue[] values) { super(descriptor); ensureNonNull("values", values); this.values = new ArrayList(values.length); for (int i=0; i*/ parameters = descriptor.descriptors(); final Map occurences = new LinkedHashMap(Math.round(parameters.size()/0.75f)+1, 0.75f); for (final Iterator it=parameters.iterator(); it.hasNext();) { final GeneralParameterDescriptor param = (GeneralParameterDescriptor) it.next(); ensureNonNull("parameters", param); occurences.put(param, new int[1]); // The value 'int[1]' will be used by 'ensureValidOccurs' } ensureValidOccurs(values, occurences); } /** * Constructs a parameter group from the specified list of parameters. * * @param properties The properties for the * {@linkplain DefaultParameterDescriptorGroup operation parameter group} * to construct from the list of parameters. * @param values The list of parameter values. * * @throws IllegalStateException if the number of {@linkplain ParameterValue parameter} * occurences doesn't matches the number declared in the * {@linkplain ParameterDescriptorGroup descriptor}. */ public ParameterGroup(final Map properties, final GeneralParameterValue[] values) { super(createDescriptor(properties, values)); this.values = new ArrayList(values.length); for (int i=0; i=min && count<=max)) { final String name = getName(descriptor); throw new InvalidParameterCardinalityException(Errors.format( ErrorKeys.ILLEGAL_OCCURS_FOR_PARAMETER_$4, name, new Integer(count), new Integer(min), new Integer(max)), name); } } } /** * Returns the values in this group. Changes in this list are reflected on this * {@code ParameterValueGroup}. The returned list supports the * {@link List#add(Object) add} operation. */ public List values() { if (asList == null) { asList = new ParameterValueList((ParameterDescriptorGroup) descriptor, values); } return asList; } /** * Returns the parameter value at the specified index. * * @param index The zero-based index. * @return The parameter value at the specified index. * @throws IndexOutOfBoundsException if the specified index is out of bounds. */ final GeneralParameterValue parameter(final int index) throws IndexOutOfBoundsException { return (GeneralParameterValue) values.get(index); // Remove cast with J2SE 1.5. } /** * Returns the value in this group for the specified * {@linkplain Identifier#getCode identifier code}. * If no {@linkplain ParameterValue parameter value} is found but * a {@linkplain ParameterDescriptor parameter descriptor} is found * (which may occurs if the parameter is optional, i.e. * {@linkplain ParameterDescriptor#getMinimumOccurs minimumOccurs} == 0), * then a {@linkplain ParameterValue parameter value} is * automatically created and initialized to its * {@linkplain ParameterDescriptor#getDefaultValue default value} (if any). * *

This convenience method provides a way to get and set parameter values by name. For * example the following idiom fetches a floating point value for the * "false_easting" parameter:

* *
* double value = * parameter("false_easting").{@linkplain ParameterValue#doubleValue() doubleValue()}; *
* *

This method do not search recursively in subgroups. This is because more than one * subgroup may exist for the same {@linkplain ParameterDescriptorGroup descriptor}. The * user must {@linkplain #groups query all subgroups} and select explicitly * the appropriate one to use.

* * @param name The case insensitive {@linkplain Identifier#getCode identifier code} of the * parameter to search for. * @return The parameter value for the given identifier code. * @throws ParameterNotFoundException if there is no parameter value for the given identifier * code. */ public ParameterValue parameter(String name) throws ParameterNotFoundException { ensureNonNull("name", name); name = name.trim(); for (final Iterator it=values.iterator(); it.hasNext();) { final GeneralParameterValue value = (GeneralParameterValue) it.next(); if (value instanceof ParameterValue) { if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), name)) { return (ParameterValue) value; } } } /* * No existing parameter found. Check if an optional parameter exists. * If such a descriptor is found, create it, add it to the list of values * and returns it. */ // TODO: The following lines should be considerably shorter with J2SE 1.5: // for (GeneralParameterDescriptor descriptor : getDescriptor().descriptors()) { for (final Iterator it=((ParameterDescriptorGroup) getDescriptor()).descriptors().iterator(); it.hasNext();) { final GeneralParameterDescriptor descriptor = (GeneralParameterDescriptor) it.next(); if (descriptor instanceof ParameterDescriptor) { if (AbstractIdentifiedObject.nameMatches(descriptor, name)) { // TODO: remove the first cast with J2SE 1.5. final ParameterValue value = (ParameterValue) ((ParameterDescriptor) descriptor).createValue(); values.add(value); return value; } } } throw new ParameterNotFoundException(Errors.format( ErrorKeys.MISSING_PARAMETER_$1, name), name); } /** * Returns all subgroups with the specified name. This method do not create new groups. * If the requested group is optional (i.e. * {@linkplain ParameterDescriptor#getMinimumOccurs minimumOccurs} == 0) * and no value were set, then this method returns an empty set. * * @param name The case insensitive {@linkplain Identifier#getCode identifier code} * of the parameter group to search for. * @return The set of all parameter group for the given identifier code. * @throws ParameterNotFoundException if no {@linkplain ParameterDescriptorGroup descriptor} * was found for the given name. */ public List/**/ groups(String name) throws ParameterNotFoundException { ensureNonNull("name", name); name = name.trim(); final List groups = new ArrayList(Math.min(values.size(), 10)); for (final Iterator it=values.iterator(); it.hasNext();) { final GeneralParameterValue value = (GeneralParameterValue) it.next(); if (value instanceof ParameterValueGroup) { if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), name)) { groups.add(value); } } } /* * No groups were found. Check if the group actually exists (i.e. is declared in the * descriptor). If it doesn't exists, then an exception is thrown. If it exists (i.e. * it is simply an optional group not yet defined), then returns an empty list. */ if (groups.isEmpty()) { final GeneralParameterDescriptor check = ((ParameterDescriptorGroup) descriptor).descriptor(name); if (!(check instanceof ParameterDescriptorGroup)) { throw new ParameterNotFoundException(Errors.format( ErrorKeys.MISSING_PARAMETER_$1, name), name); } } return groups; } /** * Creates a new group of the specified name. The specified name must be the * {@linkplain Identifier#getCode identifier code} of a {@linkplain ParameterDescriptorGroup * descriptor group}. * * @param name The case insensitive {@linkplain Identifier#getCode identifier code} of the * parameter group to create. * @return A newly created parameter group for the given identifier code. * @throws ParameterNotFoundException if no {@linkplain ParameterDescriptorGroup descriptor} * was found for the given name. * @throws InvalidParameterCardinalityException if this parameter group already contains the * {@linkplain ParameterDescriptorGroup#getMaximumOccurs maximum number of occurences} * of subgroups of the given name. */ public ParameterValueGroup addGroup(String name) throws ParameterNotFoundException, InvalidParameterCardinalityException { final GeneralParameterDescriptor check = ((ParameterDescriptorGroup) descriptor).descriptor(name); if (!(check instanceof ParameterDescriptorGroup)) { throw new ParameterNotFoundException(Errors.format( ErrorKeys.MISSING_PARAMETER_$1, name), name); } int count = 0; for (final Iterator it=values.iterator(); it.hasNext();) { final GeneralParameterValue value = (GeneralParameterValue) it.next(); if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), name)) { count++; } } if (count >= check.getMaximumOccurs()) { throw new InvalidParameterCardinalityException(Errors.format( ErrorKeys.TOO_MANY_OCCURENCES_$2, name, new Integer(count)), name); } final ParameterValueGroup value = (ParameterValueGroup) // Remove this cast for J2SE 1.5 ((ParameterDescriptorGroup) check).createValue(); values.add(value); return value; } /** * Compares the specified object with this parameter for equality. * * @param object The object to compare to {@code this}. * @return {@code true} if both objects are equal. */ public boolean equals(final Object object) { if (object == this) { return true; } if (super.equals(object)) { final ParameterGroup that = (ParameterGroup) object; return Utilities.equals(this.values, that.values); } return false; } /** * Returns a hash value for this parameter. * * @return The hash code value. This value doesn't need to be the same * in past or future versions of this class. */ public int hashCode() { return super.hashCode() ^ values.hashCode(); } /** * Returns a deep copy of this group of parameter values. * Included parameter values and subgroups are cloned recursively. * * @return A copy of this group of parameter values. */ public Object clone() { final ParameterGroup copy = (ParameterGroup) super.clone(); copy.values = (ArrayList/**/) copy.values.clone(); for (int i=copy.values.size(); --i>=0;) { // TODO: remove cast with J2SE 1.5 copy.values.set(i, ((GeneralParameterValue) copy.values.get(i)).clone()); } copy.asList = null; return copy; } }