/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-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. */ package org.geotools.coverage.processing; import java.util.List; import java.util.Locale; import java.util.Iterator; import java.util.ArrayList; import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.LogRecord; import java.awt.RenderingHints; import java.io.IOException; import java.io.Writer; import org.opengis.coverage.Coverage; import org.opengis.coverage.processing.Operation; import org.opengis.coverage.processing.OperationNotFoundException; import org.opengis.parameter.ParameterNotFoundException; import org.opengis.parameter.ParameterValueGroup; import org.opengis.util.InternationalString; import org.geotools.coverage.AbstractCoverage; import org.geotools.coverage.grid.Interpolator2D; import org.geotools.resources.image.ImageUtilities; import org.geotools.resources.Arguments; import org.geotools.resources.i18n.Errors; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Loggings; import org.geotools.resources.i18n.LoggingKeys; import org.geotools.resources.i18n.Vocabulary; import org.geotools.resources.i18n.VocabularyKeys; import org.geotools.util.logging.Logging; /** * Base class for {@linkplain Coverage coverage} processor implementations. * * @since 2.2 * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) */ public abstract class AbstractProcessor { /** * The logger for coverage processing operations. */ public static final Logger LOGGER = Logging.getLogger("org.geotools.coverage.processing"); /** * The logging level for reporting coverage operations. * This level is equals or slightly lower than {@link Level#INFO}. */ public static final Level OPERATION = new LogLevel("OPERATION", 780); /** * The grid coverage logging level type. */ private static final class LogLevel extends Level { protected LogLevel(final String name, final int level) { super(name, level); } } /** * The default coverage processor. Will be constructed only when first requested. * * @todo This is a temporary field, to be removed when a GeoAPI interfaces for coverage * processing while be redesigned along the lines of ISO 19123. */ private static AbstractProcessor DEFAULT; /** * Constructs a coverage processor. */ public AbstractProcessor() { super(); } /** * Returns a default processor instance. * <p> * <strong>Note:</strong> this is a temporary method, until we have GeoAPI interface for * coverage processor and a factory finder for their implementations. */ public static synchronized AbstractProcessor getInstance() { if (DEFAULT == null) { DEFAULT = new DefaultProcessor((RenderingHints) null); DEFAULT.setAsDefault(); } return DEFAULT; } /** * Notifies this processor that it is going to be used as the application-wide default * processor. */ void setAsDefault() { } /** * Retrieves grid processing operations information. Each operation information contains * the name of the operation as well as a list of its parameters. */ public abstract Collection<Operation> getOperations(); /** * Returns the operation for the specified name. * * @param name Name of the operation. * @return The operation for the given name. * @throws OperationNotFoundException if there is no operation for the specified name. */ public abstract Operation getOperation(String name) throws OperationNotFoundException; /** * Applies an operation. * * @param parameters Parameters required for the operation. * @return The result as a coverage. * @throws OperationNotFoundException if there is no operation for the parameter group name. */ public abstract Coverage doOperation(final ParameterValueGroup parameters) throws OperationNotFoundException; /** * The locale for logging message or reporting errors. The default implementations * returns the {@linkplain Locale#getDefault default locale}. Subclasses can override * this method if a different locale is wanted. */ public Locale getLocale() { return Locale.getDefault(); } /** * Logs a message for an operation. The message will be logged only if the source grid * coverage is different from the result (i.e. if the operation did some work). * * @param source The source grid coverage. * @param result The resulting grid coverage. * @param operationName the operation name. * @param fromCache {@code true} if the result has been fetch from the cache. */ final void log(final Coverage source, final Coverage result, final String operationName, final boolean fromCache) { if (source != result) { String interp = "Nearest"; if (result instanceof Interpolator2D) { interp = ImageUtilities.getInterpolationName( ((Interpolator2D) result).getInterpolation()); } final Locale locale = getLocale(); final LogRecord record = Loggings.getResources(locale).getLogRecord( OPERATION, LoggingKeys.APPLIED_OPERATION_$4, getName((source!=null) ? source : result, locale), operationName, interp, Integer.valueOf(fromCache ? 1 : 0)); // Note: DefaultProcessor is the class that will use this method. record.setSourceClassName("org.geotools.coverage.processing.DefaultProcessor"); record.setSourceMethodName("doOperation"); record.setLoggerName(LOGGER.getName()); LOGGER.log(record); } } /** * Returns the primary source coverage from the specified parameters, or {@code null} if none. */ static Coverage getPrimarySource(final ParameterValueGroup parameters) { try { return (Coverage) parameters.parameter("Source").getValue(); } catch (ParameterNotFoundException exception) { /* * "Source" parameter may not exists. Conservatively * assumes that the operation will do some usefull work. */ return null; } } /** * Returns the operation name for the specified parameters. */ static String getOperationName(final ParameterValueGroup parameters) { return parameters.getDescriptor().getName().getCode().trim(); } /** * Returns the coverage name in the specified locale. */ private static String getName(final Coverage coverage, final Locale locale) { if (coverage instanceof AbstractCoverage) { final InternationalString name = ((AbstractCoverage) coverage).getName(); if (name != null) { return name.toString(locale); } } return Vocabulary.getResources(locale).getString(VocabularyKeys.UNTITLED); } /** * Makes sure that an argument is non-null. * * @param name Argument name. * @param object User argument. * @throws IllegalArgumentException if {@code object} is null. */ static void ensureNonNull(final String name, final Object object) throws IllegalArgumentException { if (object == null) { throw new IllegalArgumentException(Errors.format(ErrorKeys.NULL_ARGUMENT_$1, name)); } } /** * Lists a summary of all operations to the specified stream. * * @param out The destination stream. * @throws IOException if an error occured will writing to the stream. */ public void listOperations(final Writer out) throws IOException { final Collection operations = getOperations(); final CoverageParameterWriter writer = new CoverageParameterWriter(out); final List descriptors = new ArrayList(operations.size()); for (final Iterator it=operations.iterator(); it.hasNext();) { final Operation operation = (Operation) it.next(); if (operation instanceof AbstractOperation) { descriptors.add(((AbstractOperation) operation).descriptor); } } writer.summary(descriptors, null); } /** * Prints a description of operations to the specified stream. If the {@code names} array * is non-null, then only the specified operations are printed. Otherwise, all operations * are printed. The description details include operation names and lists of parameters. * * @param out The destination stream. * @param names The operation to print, or an empty array for none, or {@code null} for all. * @throws IOException if an error occured will writing to the stream. * @throws OperationNotFoundException if an operation named in {@code names} was not found. */ public void printOperations(final Writer out, final String[] names) throws OperationNotFoundException, IOException { final CoverageParameterWriter writer = new CoverageParameterWriter(out); final String lineSeparator = System.getProperty("line.separator", "\n"); if (names != null) { for (int i=0; i<names.length; i++) { final Operation operation = getOperation(names[i]); if (operation instanceof AbstractOperation) { out.write(lineSeparator); writer.format(((AbstractOperation) operation).descriptor); } } } else { final Collection operations = getOperations(); for (final Iterator it=operations.iterator(); it.hasNext();) { final Operation operation = (Operation) it.next(); if (operation instanceof AbstractOperation) { out.write(lineSeparator); writer.format(((AbstractOperation) operation).descriptor); } } } } /** * Dumps to the {@linkplain System#out standard output stream} a list of operations for the * default processor. If no argument is provided, then only a summary of operations is printed. * If arguments are provided, then the operation parameters are printed for all operation names * given in arguments. This method can been invoked from the command line. For example: * * <blockquote><pre> * java org.geotools.coverage.processing.DefaultProcessor Interpolate * </pre></blockquote> * * <strong>Note for Windows users:</strong> If the output contains strange * symbols, try to supply an "{@code -encoding}" argument. Example: * * <blockquote><pre> * java org.geotools.coverage.processing.DefaultProcessor -encoding Cp850 * </pre></blockquote> * * The codepage number (850 in the previous example) can be fetch from the DOS * command line by entering the "{@code chcp}" command with no arguments. */ public static void main(String[] args) { final Arguments arguments = new Arguments(args); final boolean all = arguments.getFlag("-all"); args = arguments.getRemainingArguments(Integer.MAX_VALUE); final AbstractProcessor processor = getInstance(); try { if (args.length == 0) { processor.listOperations(arguments.out); } else { processor.printOperations(arguments.out, all ? null : args); } } catch (OperationNotFoundException exception) { arguments.out.println(exception.getLocalizedMessage()); } catch (IOException exception) { // Should not occurs exception.printStackTrace(arguments.out); } arguments.out.flush(); } }