Search in sources :

Example 6 with DefaultParameterDescriptorGroup

use of org.apache.sis.parameter.DefaultParameterDescriptorGroup in project sis by apache.

the class CC_OperationParameterGroup method merge.

/**
 * Invoked by {@link DefaultParameterDescriptorGroup#setDescriptors(GeneralParameterDescriptor[])}
 * for merging into a single set the descriptors which are repeated twice in a GML document.
 *
 * <p>The {@code descriptors} argument gives the descriptors listed explicitely inside a
 * {@code <gml:OperationParameterGroup>} or {@code <gml:OperationMethod>} element. Those
 * descriptors are said "incomplete" (from SIS point of view) because they are missing the
 * {@link ParameterDescriptor#getValueClass()} property, which does not exist in GML but
 * is mandatory for us. However an exception to this "incompleteness" happen when SIS has
 * been able to match the {@code <gml:OperationMethod>} parent to one of the pre-defined
 * operations in the {@link org.apache.sis.internal.referencing.provider} package.</p>
 *
 * <p>The {@code fromValues} argument gives the descriptors declared in each {@code <gml:ParameterValue>}
 * instances of a {@code <gml:ParameterValueGroup>} or {@code <gml:AbstractSingleOperation>} element.
 * Contrarily to the {@code descriptors} argument, the {@code fromValues} instances should have non-null
 * {@link ParameterDescriptor#getValueClass()} property inferred by SIS from the parameter value.</p>
 *
 * <p>So the preferred descriptors from more complete to less complete are:</p>
 * <ol>
 *   <li>{@code descriptors} if and only if they contain pre-defined parameters inferred by SIS from the {@code <gml:OperationMethod>} name.</li>
 *   <li>{@code fromValues}, which contain the descriptors declared in the {@code <gml:ParameterValue>} instances.</li>
 *   <li>{@code descriptors}, which contain the descriptor listed in {@code <gml:OperationParameterGroup>} or {@code <gml:OperationMethod>}.</li>
 * </ol>
 *
 * <div class="note"><b>Note:</b>
 * this code is defined in this {@code CC_OperationParameterGroup} class instead than in the
 * {@link DefaultParameterDescriptorGroup} class in the hope to reduce the amount of code
 * processed by the JVM in the common case where JAXB (un)marshalling is not needed.</div>
 *
 * @param  descriptors   the descriptors declared in the {@code ParameterDescriptorGroup}.
 * @param  fromValues    the descriptors declared in the {@code ParameterValue} instances.
 *                       They are said "valid" because they contain the mandatory {@code valueClass} property.
 * @param  replacements  an {@code IdentityHashMap} where to store the replacements that the caller needs to
 *                       apply in the {@code GeneralParameterValue} instances.
 * @return a sequence containing the merged set of parameter descriptors.
 *
 * @see <a href="http://issues.apache.org/jira/browse/SIS-290">SIS-290</a>
 */
public static GeneralParameterDescriptor[] merge(final List<GeneralParameterDescriptor> descriptors, final GeneralParameterDescriptor[] fromValues, final Map<GeneralParameterDescriptor, GeneralParameterDescriptor> replacements) {
    if (descriptors.isEmpty()) {
        return fromValues;
    }
    final Map<String, GeneralParameterDescriptor> union = new LinkedHashMap<>(Containers.hashMapCapacity(descriptors.size()));
    /*
         * Collect the descriptors declared explicitely in the ParameterDescriptorGroup. We should never have
         * two descriptors of the same name since the DefaultParameterDescriptorGroup constructor checked for
         * name ambiguity. If a name collision is nevertheless detected, this would mean that a descriptor's
         * name mutated.
         */
    for (final GeneralParameterDescriptor p : descriptors) {
        final String name = p.getName().getCode();
        if (union.put(name, p) != null) {
            throw new CorruptedObjectException(name);
        }
    }
    /*
         * Verify if any descriptors found in the ParameterValue instances could replace the descriptors in the group.
         * We give precedence to the descriptors having a non-null 'valueClass' property, which normally appear in the
         * 'fromValues' array.
         */
    for (final GeneralParameterDescriptor valueDescriptor : fromValues) {
        final String name = valueDescriptor.getName().getCode();
        GeneralParameterDescriptor complete = valueDescriptor;
        GeneralParameterDescriptor previous = union.put(name, complete);
        if (previous != null) {
            if (previous instanceof ParameterDescriptor<?>) {
                verifyEquivalence(name, complete instanceof ParameterDescriptor<?>);
                final Class<?> valueClass = ((ParameterDescriptor<?>) previous).getValueClass();
                if (valueClass != null) {
                    /*
                         * This may happen if the 'descriptors' argument contain the parameters of a pre-defined
                         * method from the 'org.apache.sis.internal.referencing.provider' package instead than a
                         * descriptor from the GML file.  In such case, presume that 'previous' is actually more
                         * complete than 'complete'.
                         *
                         * Note that 'r' should never be null unless JAXB unmarshalled the elements in reverse
                         * order (e.g. <gml:ParameterValue> before <gml:OperationMethod>). Since this behavior
                         * may depend on JAXB implementation, we are better to check for such case.
                         */
                    final Class<?> r = ((ParameterDescriptor<?>) complete).getValueClass();
                    if (r != null) {
                        verifyEquivalence(name, valueClass == r);
                    }
                    // Restore the previous value in the map and swap 'previous' with 'replacement'.
                    previous = union.put(name, complete = previous);
                }
            } else if (previous instanceof ParameterDescriptorGroup) {
                verifyEquivalence(name, complete instanceof ParameterDescriptorGroup);
            }
            /*
                 * Verify that the replacement contains at least all the information provided by the previous
                 * descriptor. The replacement is allowed to contain more information however.
                 */
            final GeneralParameterDescriptor replacement = CC_GeneralOperationParameter.merge(previous, complete);
            if (replacement != valueDescriptor) {
                union.put(name, replacement);
                if (replacements.put(valueDescriptor, replacement) != null) {
                    // Should never happen, unless the parameter name changed during execution of this loop.
                    throw new CorruptedObjectException(name);
                }
            }
        }
    }
    return union.values().toArray(new GeneralParameterDescriptor[union.size()]);
}
Also used : GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) ParameterDescriptor(org.opengis.parameter.ParameterDescriptor) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) CorruptedObjectException(org.apache.sis.util.CorruptedObjectException) LinkedHashMap(java.util.LinkedHashMap)

Example 7 with DefaultParameterDescriptorGroup

use of org.apache.sis.parameter.DefaultParameterDescriptorGroup in project sis by apache.

the class OperationMethodSetTest method createMethod.

/**
 * Creates a new two-dimensional operation method for an operation of the given name.
 *
 * @param  type    the value to be returned by {@link DefaultOperationMethod#getOperationType()}.
 * @param  method  the operation name (example: "Mercator (variant A)").
 * @return the operation method.
 */
@SuppressWarnings("serial")
private static DefaultOperationMethod createMethod(final Class<? extends Projection> type, final String method) {
    Map<String, ?> properties = Collections.singletonMap(DefaultOperationMethod.NAME_KEY, method);
    final ParameterDescriptorGroup parameters = new DefaultParameterDescriptorGroup(properties, 1, 1);
    /*
         * Recycle the ParameterDescriptorGroup name for DefaultOperationMethod.
         * This save us one object creation, and is often the same name anyway.
         */
    properties = Collections.singletonMap(DefaultOperationMethod.NAME_KEY, parameters.getName());
    return new DefaultOperationMethod(properties, 2, 2, parameters) {

        @Override
        public Class<? extends Projection> getOperationType() {
            return type;
        }
    };
}
Also used : DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) DefaultOperationMethod(org.apache.sis.referencing.operation.DefaultOperationMethod)

Example 8 with DefaultParameterDescriptorGroup

use of org.apache.sis.parameter.DefaultParameterDescriptorGroup in project sis by apache.

the class CC_GeneralOperationParameter method merge.

/**
 * Returns a descriptor with the given properties, completed with information not found in GML.
 * Those extra information are given by the {@code complete} descriptor.
 *
 * @param  caller         the public source class to report if a log message need to be emitted.
 * @param  properties     properties as declared in the GML document, to be used if {@code complete} is incompatible.
 * @param  merged         more complete properties, to be used if {@code complete} is compatible.
 * @param  minimumOccurs  value to assign to {@link DefaultParameterDescriptorGroup#getMinimumOccurs()}.
 * @param  maximumOccurs  value to assign to {@link DefaultParameterDescriptorGroup#getMaximumOccurs()}.
 * @param  provided       parameter descriptors declared in the GML document. This array will be overwritten.
 * @param  complete       more complete parameter descriptors.
 * @param  canSubstitute  {@code true} if this method is allowed to return {@code complete}.
 * @return the parameter descriptor group to use (may be the {@code complete} instance).
 *
 * @see <a href="http://issues.apache.org/jira/browse/SIS-290">SIS-290</a>
 */
static ParameterDescriptorGroup merge(final Class<?> caller, final Map<String, ?> properties, final Map<String, ?> merged, final int minimumOccurs, final int maximumOccurs, final GeneralParameterDescriptor[] provided, final ParameterDescriptorGroup complete, boolean canSubstitute) {
    boolean isCompatible = true;
    final Set<GeneralParameterDescriptor> included = new HashSet<>(Containers.hashMapCapacity(provided.length));
    for (int i = 0; i < provided.length; i++) {
        final GeneralParameterDescriptor p = provided[i];
        try {
            /*
                 * Replace the descriptors provided in the GML document by descriptors from the 'complete' instance,
                 * if possible. Keep trace of the complete descriptors that we found in this process.
                 */
            GeneralParameterDescriptor predefined = complete.descriptor(p.getName().getCode());
            if (predefined != null) {
                // Safety in case 'complete' is a user's implementation.
                canSubstitute &= (provided[i] = merge(p, predefined)) == predefined;
                if (!included.add(predefined)) {
                    // Broken hashCode/equals, or object mutated.
                    throw new CorruptedObjectException(predefined);
                }
                continue;
            }
        } catch (ParameterNotFoundException e) {
            /*
                 * Log at Level.WARNING for the first parameter (canSubstitute == true) and at Level.FINE
                 * for all other (canSubstitute == false).  We do not use CC_GeneralOperationParameter as
                 * the source class because this is an internal class. We rather use the first public class
                 * in the caller hierarchy, which is either DefaultParameterValueGroup or DefaultOperationMethod.
                 */
            Context.warningOccured(Context.current(), caller, (caller == DefaultParameterValueGroup.class) ? "setValues" : "setDescriptors", e, canSubstitute);
        }
        /*
             * If a parameter was not found in the 'complete' descriptor, we will not be able to use that descriptor.
             * But we may still be able to use its properties (name, alias, identifier) provided that the parameter
             * not found was optional.
             */
        isCompatible &= p.getMinimumOccurs() == 0;
        canSubstitute = false;
    }
    if (isCompatible) {
        /*
             * At this point, we determined that all mandatory parameters in the GML document exist in the 'complete'
             * descriptor. However the converse is not necessarily true. Verify that all parameters missing in the GML
             * document were optional.
             */
        for (final GeneralParameterDescriptor descriptor : complete.descriptors()) {
            if (!included.contains(descriptor) && descriptor.getMinimumOccurs() != 0 && !CC_OperationMethod.isImplicitParameter(descriptor)) {
                canSubstitute = false;
                isCompatible = false;
                break;
            }
        }
    }
    if (canSubstitute) {
        return complete;
    } else {
        return new DefaultParameterDescriptorGroup(isCompatible ? merged : properties, minimumOccurs, maximumOccurs, provided);
    }
}
Also used : DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) GeneralParameterDescriptor(org.opengis.parameter.GeneralParameterDescriptor) CorruptedObjectException(org.apache.sis.util.CorruptedObjectException) ParameterNotFoundException(org.opengis.parameter.ParameterNotFoundException) HashSet(java.util.HashSet)

Example 9 with DefaultParameterDescriptorGroup

use of org.apache.sis.parameter.DefaultParameterDescriptorGroup in project sis by apache.

the class EPSGDataAccess method createOperationMethod.

/**
 * Creates description of the algorithm and parameters used to perform a coordinate operation.
 * An {@code OperationMethod} is a kind of metadata: it does not perform any coordinate operation
 * (e.g. map projection) by itself, but tells us what is needed in order to perform such operation.
 *
 * <div class="note"><b>Example:</b>
 * some EPSG codes for operation methods are:
 *
 * <table class="sis" summary="EPSG codes examples">
 *   <tr><th>Code</th> <th>Description</th></tr>
 *   <tr><td>9804</td> <td>Mercator (variant A)</td></tr>
 *   <tr><td>9802</td> <td>Lambert Conic Conformal (2SP)</td></tr>
 *   <tr><td>9810</td> <td>Polar Stereographic (variant A)</td></tr>
 *   <tr><td>9624</td> <td>Affine parametric transformation</td></tr>
 * </table></div>
 *
 * @param  code  value allocated by EPSG.
 * @return the operation method for the given code.
 * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
 * @throws FactoryException if the object creation failed for some other reason.
 */
@Override
public synchronized OperationMethod createOperationMethod(final String code) throws NoSuchAuthorityCodeException, FactoryException {
    ArgumentChecks.ensureNonNull("code", code);
    OperationMethod returnValue = null;
    try (ResultSet result = executeQuery("Coordinate_Operation Method", "COORD_OP_METHOD_CODE", "COORD_OP_METHOD_NAME", "SELECT COORD_OP_METHOD_CODE," + " COORD_OP_METHOD_NAME," + " REMARKS," + " DEPRECATED" + " FROM [Coordinate_Operation Method]" + " WHERE COORD_OP_METHOD_CODE = ?", code)) {
        while (result.next()) {
            final Integer epsg = getInteger(code, result, 1);
            final String name = getString(code, result, 2);
            final String remarks = getOptionalString(result, 3);
            final boolean deprecated = getOptionalBoolean(result, 4);
            final Integer[] dim = getDimensionsForMethod(epsg);
            final ParameterDescriptor<?>[] descriptors = createParameterDescriptors(epsg);
            Map<String, Object> properties = createProperties("Coordinate_Operation Method", name, epsg, remarks, deprecated);
            // We do not store the formula at this time, because the text is very verbose and rarely used.
            final OperationMethod method = new DefaultOperationMethod(properties, dim[0], dim[1], new DefaultParameterDescriptorGroup(properties, 1, 1, descriptors));
            returnValue = ensureSingleton(method, returnValue, code);
        }
    } catch (SQLException exception) {
        throw databaseFailure(OperationMethod.class, code, exception);
    }
    if (returnValue == null) {
        throw noSuchAuthorityCode(OperationMethod.class, code);
    }
    return returnValue;
}
Also used : SQLException(java.sql.SQLException) ParameterDescriptor(org.opengis.parameter.ParameterDescriptor) DefaultParameterDescriptor(org.apache.sis.parameter.DefaultParameterDescriptor) InternationalString(org.opengis.util.InternationalString) SimpleInternationalString(org.apache.sis.util.iso.SimpleInternationalString) DefaultOperationMethod(org.apache.sis.referencing.operation.DefaultOperationMethod) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) ResultSet(java.sql.ResultSet) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject) IdentifiedObject(org.opengis.referencing.IdentifiedObject) DefaultOperationMethod(org.apache.sis.referencing.operation.DefaultOperationMethod)

Example 10 with DefaultParameterDescriptorGroup

use of org.apache.sis.parameter.DefaultParameterDescriptorGroup in project sis by apache.

the class DefaultOperationMethod method updateDescriptors.

/**
 * Invoked by {@link AbstractSingleOperation} for completing the parameter descriptor.
 */
final void updateDescriptors(final GeneralParameterDescriptor[] descriptors) {
    final ParameterDescriptorGroup previous = parameters;
    parameters = new DefaultParameterDescriptorGroup(IdentifiedObjects.getProperties(previous), previous.getMinimumOccurs(), previous.getMaximumOccurs(), descriptors);
}
Also used : DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup) ParameterDescriptorGroup(org.opengis.parameter.ParameterDescriptorGroup) DefaultParameterDescriptorGroup(org.apache.sis.parameter.DefaultParameterDescriptorGroup)

Aggregations

DefaultParameterDescriptorGroup (org.apache.sis.parameter.DefaultParameterDescriptorGroup)11 ParameterDescriptorGroup (org.opengis.parameter.ParameterDescriptorGroup)9 HashMap (java.util.HashMap)5 GeneralParameterDescriptor (org.opengis.parameter.GeneralParameterDescriptor)5 DependsOnMethod (org.apache.sis.test.DependsOnMethod)4 Test (org.junit.Test)4 DefaultOperationMethod (org.apache.sis.referencing.operation.DefaultOperationMethod)3 CorruptedObjectException (org.apache.sis.util.CorruptedObjectException)2 ParameterDescriptor (org.opengis.parameter.ParameterDescriptor)2 ResultSet (java.sql.ResultSet)1 SQLException (java.sql.SQLException)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 ImmutableIdentifier (org.apache.sis.metadata.iso.ImmutableIdentifier)1 DefaultCitation (org.apache.sis.metadata.iso.citation.DefaultCitation)1 DefaultParameterDescriptor (org.apache.sis.parameter.DefaultParameterDescriptor)1 AbstractIdentifiedObject (org.apache.sis.referencing.AbstractIdentifiedObject)1 SimpleInternationalString (org.apache.sis.util.iso.SimpleInternationalString)1 ParameterNotFoundException (org.opengis.parameter.ParameterNotFoundException)1 IdentifiedObject (org.opengis.referencing.IdentifiedObject)1