DefaultParameterValueGroup changes for revisions 7705:7857

Changes in this commit:

Command line:

svn diff --extensions "--unified --ignore-space-change --ignore-all-space --ignore-eol-style" -r7705:7857 https://svn.osgeo.org/geotools/trunk/modules/library/referencing/src/main/java/org/geotools/parameter/ParameterGroup.java
Revision 7705Revision 7857
package org.geotools.parameter;

// J2SE dependencies
import java.util.Map;
import java.util.Set;
import java.util.List;
package org.geotools.parameter;

// J2SE dependencies
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.LinkedHashMap;
import java.util.Locale;

// OpenGIS dependencies
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.OperationParameterGroup;
import org.opengis.parameter.GeneralOperationParameter;
import org.opengis.parameter.ParameterNotFoundException;
import org.opengis.parameter.InvalidParameterNameException;

// Geotools dependencies
import org.geotools.referencing.IdentifiedObject;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.LinkedHashMap;

// OpenGIS dependencies
import org.opengis.parameter.InvalidParameterTypeException;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.ParameterNotFoundException;

// Geotools dependencies
import org.geotools.referencing.IdentifiedObject;
 * A group of related parameter values. The same group can be repeated more than once in an
 * {@linkplain org.geotools.referencing.operation.Operation operation} or higher level
 * <code>ParameterValueGroup</code>, if those instances contain different values of one
 * or more {@link org.geotools.parameter.ParameterValue}s which suitably distinquish among
 * those groups.
 *
 * @version $Id$
 * @author Martin Desruisseaux
 *
 * @see org.geotools.parameter.OperationParameterGroup
 * @see org.geotools.parameter.ParameterValue
 */
public class ParameterValueGroup extends org.geotools.parameter.GeneralParameterValue
                              implements org.opengis.parameter.ParameterValueGroup
{
    /**
 * A group of related parameter values. The same group can be repeated more than once in an
 * {@linkplain org.geotools.referencing.operation.Operation operation} or higher level
 * <code>ParameterValueGroup</code>, if those instances contain different values of one
 * or more {@link org.geotools.parameter.Parameter}s which suitably distinquish among
 * those groups.
 *
 * @version $Id$
 * @author Martin Desruisseaux
 *
 * @see org.geotools.parameter.ParameterGroupDescriptor
 * @see org.geotools.parameter.Parameter
 */
public class ParameterGroup extends org.geotools.parameter.AbstractParameter
                              implements org.opengis.parameter.ParameterValueGroup
{
    /**
 *
 * @param descriptor The descriptor for this group.
 */
public ParameterValueGroup(final OperationParameterGroup descriptor) {
    super(descriptor);
    final GeneralOperationParameter[] parameters = descriptor.getParameters();
    values = new GeneralParameterValue[parameters.length];
    for (int i=0; i<values.length; i++) {
        ensureNonNull("createValue", values[i] = parameters[i].createValue());
 *
 * @param descriptor The descriptor for this group.
 */
public ParameterGroup(final ParameterDescriptorGroup descriptor) {
    super(descriptor);
    final GeneralParameterDescriptor[] parameters = descriptor.getParameters();
    values = new GeneralParameterValue[parameters.length];
    for (int i=0; i<values.length; i++) {
        ensureNonNull("createValue", values[i] = parameters[i].createValue());
 * @param descriptor The descriptor for this group.
 * @param values The list of parameter values.
 */
public ParameterValueGroup(final OperationParameterGroup descriptor,
                                 GeneralParameterValue[] values)
{
    super(descriptor);
    ensureNonNull("values", values);
    this.values = values = (GeneralParameterValue[]) values.clone();
    final GeneralOperationParameter[] parameters = descriptor.getParameters();
    final Map occurences = new LinkedHashMap(Math.round(parameters.length/0.75f)+1, 0.75f);
    for (int i=0; i<parameters.length; i++) {
        ensureNonNull("parameters", parameters, i);
 * @param descriptor The descriptor for this group.
 * @param values The list of parameter values.
 */
public ParameterGroup(final ParameterDescriptorGroup descriptor,
                                 GeneralParameterValue[] values)
{
    super(descriptor);
    ensureNonNull("values", values);
    this.values = values = (GeneralParameterValue[]) values.clone();
    final GeneralParameterDescriptor[] parameters = descriptor.getParameters();
    final Map occurences = new LinkedHashMap(Math.round(parameters.length/0.75f)+1, 0.75f);
    for (int i=0; i<parameters.length; i++) {
        ensureNonNull("parameters", parameters, i);
 * Construct a parameter group from the specified list of parameters.
 *
 * @param properties The properties for the
 *        {@linkplain org.geotools.parameter.OperationParameterGroup operation parameter group}
 *        to construct from the list of parameters.
 * @param values The list of parameter values.
 */
public ParameterValueGroup(final Map properties, final GeneralParameterValue[] values) {
    super(createDescriptor(properties, values));
    this.values = (GeneralParameterValue[]) values.clone();
}
 * Construct a parameter group from the specified list of parameters.
 *
 * @param properties The properties for the
 *        {@linkplain org.geotools.parameter.ParameterGroupDescriptor operation parameter group}
 *        to construct from the list of parameters.
 * @param values The list of parameter values.
 */
public ParameterGroup(final Map properties, final GeneralParameterValue[] values) {
    super(createDescriptor(properties, values));
    this.values = (GeneralParameterValue[]) values.clone();
}
 * Work around for RFE #4093999 in Sun's bug database
 * ("Relax constraint on placement of this()/super() call in constructors").
 */
private static OperationParameterGroup createDescriptor(final Map properties,
                                                        final GeneralParameterValue[] values)
{
    ensureNonNull("values", values);
 * Work around for RFE #4093999 in Sun's bug database
 * ("Relax constraint on placement of this()/super() call in constructors").
 */
private static ParameterGroupDescriptor createDescriptor(final Map properties,
                                                        final GeneralParameterValue[] values)
{
    ensureNonNull("values", values);
    }
    ensureValidOccurs(values, occurences);
    final Set descriptors = occurences.keySet();
    return new org.geotools.parameter.OperationParameterGroup(properties,
                                      (GeneralOperationParameter[]) descriptors.toArray(
                                      new GeneralOperationParameter[descriptors.size()]));
}

/**
    }
    ensureValidOccurs(values, occurences);
    final Set descriptors = occurences.keySet();
    return new org.geotools.parameter.ParameterGroupDescriptor(properties,
                                      (GeneralParameterDescriptor[]) descriptors.toArray(
                                      new GeneralParameterDescriptor[descriptors.size()]));
}

/**
 *
 * @param values The list of parameter values.
 * @param occurences A map of the number of occurences of a value for each descriptor.
 *        The key must be {@link GeneralOperationParameter} instances and the values
 *        must be <code>int[]</code> array of length 1 initialized with the 0 value.
 */
private static void ensureValidOccurs(final GeneralParameterValue[] values,
 *
 * @param values The list of parameter values.
 * @param occurences A map of the number of occurences of a value for each descriptor.
 *        The key must be {@link GeneralParameterDescriptor} instances and the values
 *        must be <code>int[]</code> array of length 1 initialized with the 0 value.
 */
private static void ensureValidOccurs(final GeneralParameterValue[] values,
 */
for (int i=0; i<values.length; i++) {
    ensureNonNull("values", values, i);
    final GeneralOperationParameter descriptor = values[i].getDescriptor();
    final int[] count = (int[]) occurences.get(descriptor);
    if (count == null) {
        throw new IllegalArgumentException(Resources.format(
                  ResourceKeys.ERROR_ILLEGAL_DESCRIPTOR_FOR_PARAMETER_$1,
                  descriptor.getName(Locale.getDefault())));
    }
    count[0]++;
}
 */
for (int i=0; i<values.length; i++) {
    ensureNonNull("values", values, i);
    final GeneralParameterDescriptor descriptor = values[i].getDescriptor();
    final int[] count = (int[]) occurences.get(descriptor);
    if (count == null) {
        throw new IllegalArgumentException(Resources.format(
                  ResourceKeys.ERROR_ILLEGAL_DESCRIPTOR_FOR_PARAMETER_$1,
                  descriptor.getName().toString()));
    }
    count[0]++;
}
 */
for (final Iterator it=occurences.entrySet().iterator(); it.hasNext();) {
    final Map.Entry entry = (Map.Entry) it.next();
    final GeneralOperationParameter descriptor = (GeneralOperationParameter) entry.getKey();
    final int count = ((int[]) entry.getValue())[0];
    final int min   = descriptor.getMinimumOccurs();
    final int max   = descriptor.getMaximumOccurs();
 */
for (final Iterator it=occurences.entrySet().iterator(); it.hasNext();) {
    final Map.Entry entry = (Map.Entry) it.next();
    final GeneralParameterDescriptor descriptor = (GeneralParameterDescriptor) entry.getKey();
    final int count = ((int[]) entry.getValue())[0];
    final int min   = descriptor.getMinimumOccurs();
    final int max   = descriptor.getMaximumOccurs();
    if (!(count>=min && count<=max)) {
        throw new IllegalArgumentException(Resources.format(
                  ResourceKeys.ERROR_ILLEGAL_OCCURS_FOR_PARAMETER_$4,
                  descriptor.getName(Locale.getDefault()), new Integer(count),
                  new Integer(min), new Integer(max)));
    }
}
    if (!(count>=min && count<=max)) {
        throw new IllegalArgumentException(Resources.format(
                  ResourceKeys.ERROR_ILLEGAL_OCCURS_FOR_PARAMETER_$4,
                  descriptor.getName().toString(), new Integer(count),
                  new Integer(min), new Integer(max)));
    }
}
 *
 * @return The values.
 */
public GeneralParameterValue[] getValues() {
    return (GeneralParameterValue[]) values.clone();
}

/**
 * Returns the value at the specified index.
 *
 * @return The values.
 */
public List values() {
    // don't need a clone because we will copy
    // still need synchronized incase we interupt add updating the values pointer
    // (usually only a problem on 64 bit multiprocessor machines, but with a
    /// JIT all bets are off).
    GeneralParameterValue params[] = values;
    if( params == null ){
        return Collections.EMPTY_LIST;
}
    List list = new ArrayList();
    for( int i=0; i<params.length; i++){
        list.add( params[i].clone() );
    }
    return list;
}

/**
 * Returns the value at the specified index.
/**
 * Returns the first value in this group for the specified {@linkplain Identifier#getCode
 * identifier code}. If no {@linkplain org.geotools.parameter.ParameterValue parameter value}
 * is found for the given code, then this method search recursively in subgroups (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 <code>"false_easting"</code>
/**
 * Returns the first value in this group for the specified {@linkplain Identifier#getCode
 * identifier code}. If no {@linkplain org.geotools.parameter.Parameter parameter value}
 * is found for the given code, then this method search recursively in subgroups (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 <code>"false_easting"</code>
* <br><br>
* <blockquote><code>
* double value = getValue("false_easting").{@linkplain
* org.geotools.parameter.ParameterValue#doubleValue() doubleValue()};
* </code></blockquote>
*
* @param  name The case insensitive {@linkplain Identifier#getCode identifier code} of the
* <br><br>
* <blockquote><code>
* double value = getValue("false_easting").{@linkplain
* org.geotools.parameter.Parameter#doubleValue() doubleValue()};
* </code></blockquote>
*
* @param  name The case insensitive {@linkplain Identifier#getCode identifier code} of the
 * @return The parameter value for the given identifier code.
 * @throws ParameterNotFoundException if there is no parameter value for the given identifier code.
 */
public ParameterValue getValue(String name) throws ParameterNotFoundException {
    ensureNonNull("name", name);
    name = name.trim();
    List subgroups = null;
    GeneralParameterValue[] values = this.values;
    while (values != null) {
        for (int i=0; i<values.length; i++) {
            final GeneralParameterValue value = values[i];
            if (value instanceof ParameterValue) {
                if (IdentifiedObject.identifierMatches(value.getDescriptor(), name)) {
                    return (ParameterValue) value;
 * @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();
    List subgroups = null;
    GeneralParameterValue[] params = this.values;
    while (params != null) {
        for (int i=0; i<params.length; i++) {
            final GeneralParameterValue value = params[i];
            if (value instanceof ParameterValue) {
                if (IdentifiedObject.identifierMatches(value.getDescriptor(), name)) {
                    return (ParameterValue) value;
    if (subgroups==null || subgroups.isEmpty()) {
        break;
    }
    values = ((org.opengis.parameter.ParameterValueGroup) subgroups.remove(0)).getValues();
}
throw new ParameterNotFoundException(Resources.format(
          ResourceKeys.ERROR_MISSING_PARAMETER_$1, name), name);
    if (subgroups==null || subgroups.isEmpty()) {
        break;
    }
    params = Parameters.array( (org.opengis.parameter.ParameterValueGroup) subgroups.remove(0));
}
throw new ParameterNotFoundException(Resources.format(
          ResourceKeys.ERROR_MISSING_PARAMETER_$1, name), name);
 */
public boolean equals(final Object object) {
    if (super.equals(object)) {
        final ParameterValueGroup that = (ParameterValueGroup) object;
        // TODO: We should use Arrays.deepEquals instead in J2SE 1.5.
        if (this.values.length == that.values.length) {
            for (int i=0; i<values.length; i++) {
 */
public boolean equals(final Object object) {
    if (super.equals(object)) {
        final ParameterGroup that = (ParameterGroup) object;
        // TODO: We should use Arrays.deepEquals instead in J2SE 1.5.
        if (this.values.length == that.values.length) {
            for (int i=0; i<values.length; i++) {
 * @return A copy of this group of parameter values.
 */
public Object clone() {
    final ParameterValueGroup copy = (ParameterValueGroup) super.clone();
    copy.values = (GeneralParameterValue[]) copy.values.clone();
    for (int i=0; i<copy.values.length; i++) {
        copy.values[i] = (GeneralParameterValue) copy.values[i].clone();
 * @return A copy of this group of parameter values.
 */
public Object clone() {
    final ParameterGroup copy = (ParameterGroup) super.clone();
    copy.values = (GeneralParameterValue[]) copy.values.clone();
    for (int i=0; i<copy.values.length; i++) {
        copy.values[i] = (GeneralParameterValue) copy.values[i].clone();
        }
        return copy;
    }
}
        }
        return copy;
    }

    /**
     * Adds a parameter to this group.
     * <p>
     * If an existing ParameterValue is already included:
     * <ul>
     * <li>For maxOccurs == 1, the new parameter will replace the existing parameter.
     * <li>For maxOccurs > 1, the new parameter will be added
     * <li>If adding the new parameter will increase the numbe past what
     * is allowable by maxOccurs an InvalidParameterTypeException will be thrown.
     * </p>
     * <p>
     *
     * @param parameter New parameter to be added to this group
     * @throws InvalidParameterTypeException if adding this parameter
     *  would result in more parameters than allowed by maxOccurs, or if this
     *  parameter is not allowable by the groups descriptor
     */
    public void add( ParameterValue parameter ) throws InvalidParameterTypeException{
        add( (GeneralParameterValue) parameter );
}

    /**
     * Adds new parameter group to this group.
     * <p>
     * If an existing ParameterValueGroup is already included:
     * <ul>
     * <li>For maxOccurs == 1, the new group will replace the existing group.
     * <li>For maxOccurs > 1, the new group will be added
     * <li>If adding the new group will increase the number past what
     * is allowable by maxOccurs an InvalidParameterTypeException will be thrown.
     * </p>
     * <p>
     *
     * @param group New ParameterValueGroup to be added to this group
     * @throws InvalidParameterTypeException if adding this parameter
     *  would result in more parameters than allowed by maxOccurs, or if this
     *  parameter is not allowable by the groups descriptor
     */
    public void add( org.opengis.parameter.ParameterValueGroup group ) throws InvalidParameterTypeException {
        add( (GeneralParameterValue) group );
    }
    private synchronized void add( GeneralParameterValue param ){
        GeneralParameterDescriptor type = param.getDescriptor();
        if( !Parameters.allowed( (ParameterGroupDescriptor) this.getDescriptor(), type ) ){
            throw new InvalidParameterTypeException(
                "Not allowed in ParameterValueGroup:"+type.getName(),
                type.getName().toString());
        }
        final int MIN = type.getMinimumOccurs();
        final int MAX = type.getMaximumOccurs();

        if( MIN == 0 && MAX == 1 ){
            // optional parameter group - we will simply replace what is there
            int index = Parameters.indexOf( this, type );
            if(  index == -1 ){
                addImpl( param );
            }
            else {
                values[ index ] = param;
            }
        }
        else if ( Parameters.count( this, type ) < MAX ){
            addImpl( param );
        }
        else {
            throw new InvalidParameterTypeException(
                "Cannot exceed maximum allowed in ParameterValueGroup",
                type.getName().toString()
                );
        }
    }
    // Actually perform the add
    private synchronized void addImpl( GeneralParameterValue param ){
        final int LENGTH = this.values == null ? 0 : this.values.length;
        GeneralParameterValue params[] = new GeneralParameterValue[ LENGTH+1 ];
        if( LENGTH > 0 ){
            System.arraycopy( this.values, 0, params, 0, LENGTH );
        }
        params[ LENGTH ] = param ;
        this.values = params;
    }

    /**
     * Convenience method used to locate ParameterValue(s) by descriptor.
     * <p>
     * This method does not search in subgroups.
     * </p>
     * @param type ParameterDescriptor used for lookup
     * @return Array of ParameterValuelength corasponding to cardinality of the descriptor
     */
    public ParameterValue[] parameter( ParameterDescriptor parameterType ){
        List found = Parameters.list( this, parameterType );
        return (ParameterValue[]) found.toArray( new ParameterValue[ found.size()] );
    }
    /**
     * Convenience method used to locate ParameterValueGroup(s) by descriptor.
     * <p>
     * This method does not search in subgroups.
     * </p>
     * @param groupType ParameterGroupDescriptor
     * @return Array of ParameterValueGroup length corasponding to cardinality of the descriptor
     */
    public org.opengis.parameter.ParameterValueGroup[] group( ParameterGroupDescriptor groupType ){
        List found = Parameters.list( this, groupType );
        return (org.opengis.parameter.ParameterValueGroup[]) found.toArray( new org.opengis.parameter.ParameterValueGroup[ found.size()] );
    }
    /**
     * Returns Parameter Group using notation similar to list (<name> p1, p2, p3)
     */
    public String toString(){
        String name = descriptor.getName().toString( null );
        StringBuffer buf = new StringBuffer();
        buf.append( "(<" );
        buf.append( descriptor.getName().toString( null ) );
        buf.append( "> " );
        for( int i=0; i<values.length;i++){
            buf.append( values[i] );
            if( i<values.length){
                buf.append( ",");
            }
        }
        buf.append(")");
        return buf.toString();
    }
}