/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2001-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, Geomatys
*
* 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.geotoolkit.coverage.processing;
import java.util.Objects;
import java.io.Serializable;
import java.awt.RenderingHints;
import org.opengis.coverage.Coverage;
import org.opengis.coverage.processing.Operation;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.util.InternationalString;
import org.geotoolkit.factory.Hints;
import org.apache.sis.util.Classes;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
/**
* Provides descriptive information for a {@linkplain Coverage} processing operation.
* The descriptive information includes such information as the name of the operation,
* operation description, and number of source grid coverages required for the operation.
* <p>
* This base class implements all methods from the {@link Operation} interface. Those methods get
* the information they need from a {@link ParameterDescriptorGroup} object which must be supplied
* at construction time. Every {@linkplain ParameterDescriptor#getValueClass() value class} that
* are {@linkplain Class#isAssignableFrom(Class) assignable} to {@link Coverage} are considered as
* a <cite>source</cite> and will be included in the count returned by {@link #getNumSources()}.
* Other parameters are "ordinary" and do not get any special processing.
* <p>
* This base class declares an abstract method, {@link #doOperation doOperation}, which must be
* implemented by subclasses. This base class makes no assumption about the kind of sources and
* the kind of result that this operation works on, except that they must be at least of the
* {@link Coverage} type. Subclasses will typically restrict the kind of sources to a subclasses
* of {@code Coverage}, or restrict the number of spatio-temporal dimensions that the sources can
* have.
*
* @author Martin Desruisseaux (IRD)
* @version 3.00
*
* @since 2.2
* @module
*/
public abstract class AbstractOperation implements Operation, Serializable {
/**
* Serial number for inter-operability with different versions.
*/
private static final long serialVersionUID = -1441856042779942954L;;
/**
* The parameters descriptor.
*/
protected final ParameterDescriptorGroup descriptor;
/**
* Constructs an operation. The operation name will be the same than the
* parameter descriptor name.
*
* @param descriptor The parameters descriptor.
*/
protected AbstractOperation(final ParameterDescriptorGroup descriptor) {
ensureNonNull("descriptor", descriptor);
this.descriptor = descriptor;
}
/**
* Returns the name of the processing operation. The default implementation
* returns the {@linkplain #descriptor} code name.
*
* @todo The return type will be changed from {@link String} to {@code Identifier}.
*/
@Override
public String getName() {
return descriptor.getName().getCode();
}
/**
* Returns the description of the processing operation. If there is no description,
* returns {@code null}. The default implementation returns the {@linkplain #descriptor}
* remarks.
*
* @deprecated Return type need to be changed, maybe to {@link InternationalString}.
*/
@Override
@Deprecated
public String getDescription() {
final InternationalString remarks = descriptor.getRemarks();
return (remarks!=null) ? remarks.toString() : null;
}
/**
* Returns the URL for documentation on the processing operation. If no online documentation
* is available the string will be null. The default implementation returns {@code null}.
*
* @deprecated To be replaced by a method returning a {@code Citation}.
*/
@Override
@Deprecated
public String getDocURL() {
return null;
}
/**
* Returns the version number of the implementation.
*
* @deprecated Replacement to be determined.
*/
@Override
@Deprecated
public String getVersion() {
return descriptor.getName().getVersion();
}
/**
* Returns the vendor name of the processing operation implementation.
* The default implementation returns "Geotoolkit.org".
*
* @deprecated To be replaced by {@code getName().getAuthority()}.
*/
@Override
@Deprecated
public String getVendor() {
return "Geotoolkit.org";
}
/**
* Returns the number of source coverages required for the operation.
*/
@Override
public int getNumSources() {
return getNumSources(descriptor);
}
/**
* Returns the number of source coverages in the specified parameter group.
*/
private static int getNumSources(final ParameterDescriptorGroup descriptor) {
int count = 0;
for (final GeneralParameterDescriptor candidate : descriptor.descriptors()) {
if (candidate instanceof ParameterDescriptorGroup) {
count += getNumSources((ParameterDescriptorGroup) candidate);
continue;
}
if (candidate instanceof ParameterDescriptor<?>) {
final Class<?> type = ((ParameterDescriptor<?>) candidate).getValueClass();
if (Coverage.class.isAssignableFrom(type)) {
count++;
}
}
}
return count;
}
/**
* Returns an initially empty set of parameters.
*/
@Override
public ParameterValueGroup getParameters() {
return descriptor.createValue();
}
/**
* Applies a process operation to a coverage. This method is invoked by
* {@link DefaultCoverageProcessor}.
*
* @param parameters List of name value pairs for the parameters required for the operation.
* @param hints A set of rendering hints, or {@code null} if none. The {@code DefaultCoverageProcessor}
* may provides hints for the following keys: {@link Hints#COORDINATE_OPERATION_FACTORY}
* and {@link Hints#JAI_INSTANCE}.
* @return The result as a coverage.
*
* @throws IllegalArgumentException If a parameter has an illegal value.
* @throws CoverageProcessingException if the operation can't be applied.
*/
protected abstract Coverage doOperation(final ParameterValueGroup parameters, final Hints hints)
throws IllegalArgumentException, CoverageProcessingException;
/**
* Returns the {@code CoverageProcessor} instance used for an operation. The instance is
* fetch from the rendering hints given to the {@link #doOperation} method. If no processor
* is specified, then a default one is returned.
*
* @param hints The rendering hints, or {@code null} if none.
* @return The {@code CoverageProcessor} instance in use (never {@code null}).
*/
static AbstractCoverageProcessor getProcessor(final RenderingHints hints) {
if (hints != null) {
final Object value = hints.get(Hints.GRID_COVERAGE_PROCESSOR);
if (value instanceof AbstractCoverageProcessor) {
return (AbstractCoverageProcessor) value;
}
}
return AbstractCoverageProcessor.getInstance();
}
/**
* Returns a hash value for this operation. This value need not remain consistent between
* different implementations of the same class.
*/
@Override
public int hashCode() {
// Since we should have only one operation registered for each name,
// the descriptors hash code should be enough.
return descriptor.hashCode() ^ (int) serialVersionUID;
}
/**
* Compares the specified object with this operation for equality.
*
* @param object The object to compare with this operation.
* @return {@code true} if the given object is equals to this operation.
*/
@Override
public boolean equals(final Object object) {
if (object != null && object.getClass() == getClass()) {
final AbstractOperation that = (AbstractOperation) object;
return Objects.equals(this.descriptor, that.descriptor);
}
return false;
}
/**
* Returns a string representation of this operation. The returned string is
* implementation dependent. It is usually provided for debugging purposes only.
*/
@Override
public String toString() {
return Classes.getShortClassName(this) + '[' + getName() + ']';
}
}