Package org.geotools.parameter

Source Code of org.geotools.parameter.ParameterGroup

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*
*    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;
*    version 2.1 of the License.
*
*    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.
*
*    This package contains documentation from OpenGIS specifications.
*    OpenGIS consortium's work is fully acknowledged here.
*/
package org.geotools.parameter;

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;

import org.opengis.metadata.Identifier; // For javadoc
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;

import org.geotools.referencing.AbstractIdentifiedObject;
import org.geotools.resources.i18n.ErrorKeys;
import org.geotools.resources.i18n.Errors;
import org.geotools.util.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
*
*
* @source $URL$
* @version $Id$
* @author Martin Desruisseaux (IRD)
* @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<GeneralParameterValue> 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, <strong>elements</strong> in this
     * list stay modifiable. The goal is to allows the following idiom:
     *
     * <blockquote><pre>
     * values().get(i).setValue(myValue);
     * </pre></blockquote>
     */
    private transient List<GeneralParameterValue> 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<GeneralParameterDescriptor> parameters = descriptor.descriptors();
        values = new ArrayList<GeneralParameterValue>(parameters.size());
        for (final GeneralParameterDescriptor element : parameters) {
            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<GeneralParameterValue>(values.length);
        for (int i=0; i<values.length; i++) {
            this.values.add(values[i]);
        }
        final List<GeneralParameterDescriptor> parameters = descriptor.descriptors();
        final Map<GeneralParameterDescriptor,int[]> occurences =
                new LinkedHashMap<GeneralParameterDescriptor,int[]>(Math.round(parameters.size()/0.75f)+1, 0.75f);
        for (final GeneralParameterDescriptor param : parameters) {
            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<String,?> properties, final GeneralParameterValue[] values) {
        super(createDescriptor(properties, values));
        this.values = new ArrayList<GeneralParameterValue>(values.length);
        for (int i=0; i<values.length; i++) {
            this.values.add(values[i]);
        }
    }

    /**
     * Work around for RFE #4093999 in Sun's bug database
     * ("Relax constraint on placement of this()/super() call in constructors").
     *
     * @throws IllegalStateException if the number of {@linkplain ParameterValue parameter}
     *         occurences doesn't matches the number declared in the
     *         {@linkplain ParameterDescriptorGroup descriptor}.
     */
    private static ParameterDescriptorGroup createDescriptor(final Map<String,?> properties,
                                                             final GeneralParameterValue[] values)
    {
        ensureNonNull("values", values);
        final Map<GeneralParameterDescriptor,int[]> occurences =
                new LinkedHashMap<GeneralParameterDescriptor,int[]>(Math.round(values.length/0.75f)+1, 0.75f);
        for (int i=0; i<values.length; i++) {
            ensureNonNull("values", values, i);
            occurences.put(values[i].getDescriptor(), new int[1]);
            // The value 'int[1]' will be used by 'ensureValidOccurs'
        }
        ensureValidOccurs(values, occurences);
        final Set<GeneralParameterDescriptor> descriptors = occurences.keySet();
        return new DefaultParameterDescriptorGroup(properties,
                   descriptors.toArray(new GeneralParameterDescriptor[descriptors.size()]));
    }

    /**
     * Make sure that the number of occurences of each values is inside the expected range.
     *
     * @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[]} array of length 1 initialized with the 0 value.
     *
     * @throws IllegalStateException if the number of {@linkplain ParameterValue parameter}
     *         occurences doesn't matches the number declared in the
     *         {@linkplain ParameterDescriptorGroup descriptor}.
     */
    private static void ensureValidOccurs(final GeneralParameterValue[] values,
                                          final Map<GeneralParameterDescriptor,int[]> occurences)
    {
        /*
         * Count the parameters occurences.
         */
        for (int i=0; i<values.length; i++) {
            ensureNonNull("values", values, i);
            final GeneralParameterDescriptor descriptor = values[i].getDescriptor();
            final int[] count = occurences.get(descriptor);
            if (count == null) {
                final String name = getName(descriptor);
                throw new InvalidParameterTypeException(Errors.format(
                          ErrorKeys.ILLEGAL_DESCRIPTOR_FOR_PARAMETER_$1, name), name);
            }
            count[0]++;
        }
        /*
         * Now check if the occurences are in the expected ranges.
         */
        for (final Map.Entry<GeneralParameterDescriptor,int[]> entry : occurences.entrySet()) {
            final GeneralParameterDescriptor descriptor = entry.getKey();
            final int count = entry.getValue()[0];
            final int min   = descriptor.getMinimumOccurs();
            final int max   = descriptor.getMaximumOccurs();
            if (!(count>=min && count<=max)) {
                final String name = getName(descriptor);
                throw new InvalidParameterCardinalityException(Errors.format(
                          ErrorKeys.ILLEGAL_OCCURS_FOR_PARAMETER_$4, name, count, min, max), name);
            }
        }
    }

    /**
     * Returns the abstract definition of this group of parameters.
     */
    @Override
    public ParameterDescriptorGroup getDescriptor() {
        return (ParameterDescriptorGroup) super.getDescriptor();
    }

    /**
     * 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<GeneralParameterValue> 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 values.get(index);
    }

    /**
     * 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.
     * <code>{@linkplain ParameterDescriptor#getMinimumOccurs minimumOccurs} == 0</code>),
     * then a {@linkplain ParameterValue parameter value} is
     * automatically created and initialized to its
     * {@linkplain ParameterDescriptor#getDefaultValue default value} (if any).
     *
     * <P>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> parameter:</P>
     *
     * <blockquote><code>
     * double value =
     * parameter("false_easting").{@linkplain ParameterValue#doubleValue() doubleValue()};
     * </code></blockquote>
     *
     * <P>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.</P>
     *
     * @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 GeneralParameterValue value : values) {
            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.
         */
        for (final GeneralParameterDescriptor descriptor : getDescriptor().descriptors()) {
            if (descriptor instanceof ParameterDescriptor) {
                if (AbstractIdentifiedObject.nameMatches(descriptor, name)) {
                    final ParameterValue value = ((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.
     * <code>{@linkplain ParameterDescriptor#getMinimumOccurs minimumOccurs} == 0</code>)
     * 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<ParameterValueGroup> groups(String name) throws ParameterNotFoundException {
        ensureNonNull("name", name);
        name = name.trim();
        final List<ParameterValueGroup> groups =
                new ArrayList<ParameterValueGroup>(Math.min(values.size(), 10));
        for (final GeneralParameterValue value : values) {
            if (value instanceof ParameterValueGroup) {
                if (AbstractIdentifiedObject.nameMatches(value.getDescriptor(), name)) {
                    groups.add((ParameterValueGroup) 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, count), name);
        }
        final ParameterValueGroup value = ((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.
     */
    @Override
    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.
     */
    @Override
    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.
     */
    @Override
    public ParameterGroup clone() {
        final ParameterGroup copy = (ParameterGroup) super.clone();
        copy.values = (ArrayList<GeneralParameterValue>) copy.values.clone();
        for (int i=copy.values.size(); --i>=0;) {
            // TODO: remove cast with J2SE 1.5
            copy.values.set(i, copy.values.get(i).clone());
        }
        copy.asList = null;
        return copy;
    }
}
TOP

Related Classes of org.geotools.parameter.ParameterGroup

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.