001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2005, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.coverage.processing;
018:
019: // Collections
020: import java.util.List;
021: import java.util.Locale;
022: import java.util.Iterator;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.logging.Level;
026: import java.util.logging.Logger;
027: import java.util.logging.LogRecord;
028: import java.awt.RenderingHints;
029: import java.io.IOException;
030: import java.io.Writer;
031:
032: // OpenGIS dependencies
033: import org.opengis.coverage.Coverage;
034: import org.opengis.coverage.processing.Operation;
035: import org.opengis.coverage.processing.OperationNotFoundException;
036: import org.opengis.parameter.ParameterNotFoundException;
037: import org.opengis.parameter.ParameterValueGroup;
038:
039: // Geotools dependencies
040: import org.geotools.coverage.AbstractCoverage;
041: import org.geotools.coverage.grid.Interpolator2D;
042: import org.geotools.resources.image.ImageUtilities;
043: import org.geotools.resources.Arguments;
044: import org.geotools.resources.i18n.Errors;
045: import org.geotools.resources.i18n.ErrorKeys;
046: import org.geotools.resources.i18n.Logging;
047: import org.geotools.resources.i18n.LoggingKeys;
048: import org.geotools.resources.i18n.Vocabulary;
049: import org.geotools.resources.i18n.VocabularyKeys;
050:
051: /**
052: * Base class for {@linkplain Coverage coverage} processor implementations.
053: *
054: * @since 2.2
055: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/main/java/org/geotools/coverage/processing/AbstractProcessor.java $
056: * @version $Id: AbstractProcessor.java 27862 2007-11-12 19:51:19Z desruisseaux $
057: * @author Martin Desruisseaux
058: */
059: public abstract class AbstractProcessor {
060: /**
061: * The logger for coverage processing operations.
062: */
063: public static final Logger LOGGER = org.geotools.util.logging.Logging
064: .getLogger("org.geotools.coverage.processing");
065:
066: /**
067: * The logging level for reporting coverage operations.
068: * This level is equals or slightly lower than {@link Level#INFO}.
069: */
070: public static final Level OPERATION = new LogLevel("OPERATION", 780);
071:
072: /**
073: * The grid coverage logging level type.
074: */
075: private static final class LogLevel extends Level {
076: protected LogLevel(final String name, final int level) {
077: super (name, level);
078: }
079: }
080:
081: /**
082: * The default coverage processor. Will be constructed only when first requested.
083: *
084: * @todo This is a temporary field, to be removed when a GeoAPI interfaces for coverage
085: * processing while be redesigned along the lines of ISO 19123.
086: */
087: private static AbstractProcessor DEFAULT;
088:
089: /**
090: * Constructs a coverage processor.
091: */
092: public AbstractProcessor() {
093: super ();
094: }
095:
096: /**
097: * Returns a default processor instance.
098: * <p>
099: * <strong>Note:</strong> this is a temporary method, until we have GeoAPI interface for
100: * coverage processor and a factory finder for their implementations.
101: */
102: public static synchronized AbstractProcessor getInstance() {
103: if (DEFAULT == null) {
104: DEFAULT = new BufferedProcessor((RenderingHints) null);
105: DEFAULT.setAsDefault();
106: }
107: return DEFAULT;
108: }
109:
110: /**
111: * Notifies this processor that it is going to be used as the application-wide default
112: * processor.
113: */
114: void setAsDefault() {
115: }
116:
117: /**
118: * Retrieves grid processing operations information. Each operation information contains
119: * the name of the operation as well as a list of its parameters.
120: */
121: public abstract Collection/*<Operation>*/getOperations();
122:
123: /**
124: * Returns the operation for the specified name.
125: *
126: * @param name Name of the operation.
127: * @return The operation for the given name.
128: * @throws OperationNotFoundException if there is no operation for the specified name.
129: */
130: public abstract Operation getOperation(String name)
131: throws OperationNotFoundException;
132:
133: /**
134: * Applies an operation.
135: *
136: * @param parameters Parameters required for the operation.
137: * @return The result as a coverage.
138: * @throws OperationNotFoundException if there is no operation for the parameter group name.
139: */
140: public abstract Coverage doOperation(
141: final ParameterValueGroup parameters)
142: throws OperationNotFoundException;
143:
144: /**
145: * The locale for logging message or reporting errors. The default implementations
146: * returns the {@linkplain Locale#getDefault default locale}. Subclasses can override
147: * this method if a different locale is wanted.
148: */
149: public Locale getLocale() {
150: return Locale.getDefault();
151: }
152:
153: /**
154: * Logs a message for an operation. The message will be logged only if the source grid
155: * coverage is different from the result (i.e. if the operation did some work).
156: *
157: * @param source The source grid coverage.
158: * @param result The resulting grid coverage.
159: * @param operationName the operation name.
160: * @param fromCache {@code true} if the result has been fetch from the cache.
161: */
162: final void log(final Coverage source, final Coverage result,
163: final String operationName, final boolean fromCache) {
164: if (source != result) {
165: String interp = "Nearest";
166: if (result instanceof Interpolator2D) {
167: interp = ImageUtilities
168: .getInterpolationName(((Interpolator2D) result)
169: .getInterpolation());
170: }
171: final Locale locale = getLocale();
172: final LogRecord record = Logging.getResources(locale)
173: .getLogRecord(
174: OPERATION,
175: LoggingKeys.APPLIED_OPERATION_$4,
176: getName((source != null) ? source : result,
177: locale), operationName, interp,
178: new Integer(fromCache ? 1 : 0));
179: // Note: DefaultProcessor is the class that will use this method.
180: record
181: .setSourceClassName("org.geotools.coverage.processing.DefaultProcessor");
182: record.setSourceMethodName("doOperation");
183: LOGGER.log(record);
184: }
185: }
186:
187: /**
188: * Returns the primary source coverage from the specified parameters, or {@code null} if none.
189: */
190: static Coverage getPrimarySource(
191: final ParameterValueGroup parameters) {
192: try {
193: return (Coverage) parameters.parameter("Source").getValue();
194: } catch (ParameterNotFoundException exception) {
195: /*
196: * "Source" parameter may not exists. Conservatively
197: * assumes that the operation will do some usefull work.
198: */
199: return null;
200: }
201: }
202:
203: /**
204: * Returns the operation name for the specified parameters.
205: */
206: static String getOperationName(final ParameterValueGroup parameters) {
207: return parameters.getDescriptor().getName().getCode().trim();
208: }
209:
210: /**
211: * Returns the coverage name in the specified locale.
212: */
213: private static String getName(final Coverage coverage,
214: final Locale locale) {
215: if (coverage instanceof AbstractCoverage) {
216: return ((AbstractCoverage) coverage).getName().toString(
217: locale);
218: } else {
219: return Vocabulary.getResources(locale).getString(
220: VocabularyKeys.UNTITLED);
221: }
222: }
223:
224: /**
225: * Makes sure that an argument is non-null.
226: *
227: * @param name Argument name.
228: * @param object User argument.
229: * @throws IllegalArgumentException if {@code object} is null.
230: */
231: static void ensureNonNull(final String name, final Object object)
232: throws IllegalArgumentException {
233: if (object == null) {
234: throw new IllegalArgumentException(Errors.format(
235: ErrorKeys.NULL_ARGUMENT_$1, name));
236: }
237: }
238:
239: /**
240: * Lists a summary of all operations to the specified stream.
241: *
242: * @param out The destination stream.
243: * @throws IOException if an error occured will writing to the stream.
244: */
245: public void listOperations(final Writer out) throws IOException {
246: final Collection operations = getOperations();
247: final CoverageParameterWriter writer = new CoverageParameterWriter(
248: out);
249: final List descriptors = new ArrayList(operations.size());
250: for (final Iterator it = operations.iterator(); it.hasNext();) {
251: final Operation operation = (Operation) it.next();
252: if (operation instanceof AbstractOperation) {
253: descriptors
254: .add(((AbstractOperation) operation).descriptor);
255: }
256: }
257: writer.summary(descriptors, null);
258: }
259:
260: /**
261: * Prints a description of operations to the specified stream. If the {@code names} array
262: * is non-null, then only the specified operations are printed. Otherwise, all operations
263: * are printed. The description details include operation names and lists of parameters.
264: *
265: * @param out The destination stream.
266: * @param names The operation to print, or an empty array for none, or {@code null} for all.
267: * @throws IOException if an error occured will writing to the stream.
268: * @throws OperationNotFoundException if an operation named in {@code names} was not found.
269: */
270: public void printOperations(final Writer out, final String[] names)
271: throws OperationNotFoundException, IOException {
272: final CoverageParameterWriter writer = new CoverageParameterWriter(
273: out);
274: final String lineSeparator = System.getProperty(
275: "line.separator", "\n");
276: if (names != null) {
277: for (int i = 0; i < names.length; i++) {
278: final Operation operation = getOperation(names[i]);
279: if (operation instanceof AbstractOperation) {
280: out.write(lineSeparator);
281: writer
282: .format(((AbstractOperation) operation).descriptor);
283: }
284: }
285: } else {
286: final Collection operations = getOperations();
287: for (final Iterator it = operations.iterator(); it
288: .hasNext();) {
289: final Operation operation = (Operation) it.next();
290: if (operation instanceof AbstractOperation) {
291: out.write(lineSeparator);
292: writer
293: .format(((AbstractOperation) operation).descriptor);
294: }
295: }
296: }
297: }
298:
299: /**
300: * Dumps to the {@linkplain System#out standard output stream} a list of operations for the
301: * default processor. If no argument is provided, then only a summary of operations is printed.
302: * If arguments are provided, then the operation parameters are printed for all operation names
303: * given in arguments. This method can been invoked from the command line. For example:
304: *
305: * <blockquote><pre>
306: * java org.geotools.coverage.processing.DefaultProcessor Interpolate
307: * </pre></blockquote>
308: *
309: * <strong>Note for Windows users:</strong> If the output contains strange
310: * symbols, try to supply an "{@code -encoding}" argument. Example:
311: *
312: * <blockquote><pre>
313: * java org.geotools.coverage.processing.DefaultProcessor -encoding Cp850
314: * </pre></blockquote>
315: *
316: * The codepage number (850 in the previous example) can be fetch from the DOS
317: * command line by entering the "{@code chcp}" command with no arguments.
318: */
319: public static void main(String[] args) {
320: final Arguments arguments = new Arguments(args);
321: final boolean all = arguments.getFlag("-all");
322: args = arguments.getRemainingArguments(Integer.MAX_VALUE);
323: final AbstractProcessor processor = getInstance();
324: try {
325: if (args.length == 0) {
326: processor.listOperations(arguments.out);
327: } else {
328: processor.printOperations(arguments.out, all ? null
329: : args);
330: }
331: } catch (OperationNotFoundException exception) {
332: arguments.out.println(exception.getLocalizedMessage());
333: } catch (IOException exception) {
334: // Should not occurs
335: exception.printStackTrace(arguments.out);
336: }
337: arguments.out.flush();
338: }
339: }
|