Package org.geotools.process.factory

Source Code of org.geotools.process.factory.AnnotationDrivenProcessFactory$InvokeMethodProcess

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2009-2011, 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.process.factory;

import java.awt.RenderingHints.Key;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geotools.data.Parameter;
import org.geotools.data.Query;
import org.geotools.process.Process;
import org.geotools.process.ProcessException;
import org.geotools.process.ProcessFactory;
import org.geotools.process.RenderingProcess;
import org.geotools.util.Converters;
import org.geotools.util.SimpleInternationalString;
import org.geotools.util.logging.Logging;
import org.opengis.coverage.grid.GridGeometry;
import org.opengis.feature.type.Name;
import org.opengis.util.InternationalString;
import org.opengis.util.ProgressListener;

/**
* A process factory that uses annotations to determine much of the metadata
* needed to describe a {@link Process}.
* <p>
* The annotations supported are:
* <ul>
* <li>{@link DescribeProcess} - describes the process functionality
* <li>{@link DescribeResult} - describes a process result
* <li>{@link DescribeParameter} - describes a process parameter
* </ul>
*
* @author jody
* @author aaime
*
* @source $URL$
*/
public abstract class AnnotationDrivenProcessFactory implements ProcessFactory {
   
    static final Logger LOGGER = Logging.getLogger(AnnotationDrivenProcessFactory.class);
   
    protected String namespace;

    InternationalString title;
   
    private static Map<Class, Class> PRIMITIVE_MAPPER = new HashMap<Class, Class>() {
        {
            put(boolean.class, Boolean.class);
            put(char.class, Character.class);
            put(byte.class, Byte.class);
            put(short.class, Short.class);
            put(int.class, Integer.class);
            put(long.class, Long.class);
            put(double.class, Double.class);
            put(float.class, Float.class);
        }
    };

    public AnnotationDrivenProcessFactory(InternationalString title, String namespace) {
        this.namespace = namespace;
        this.title = title;
    }

    protected abstract DescribeProcess getProcessDescription(Name name);

    protected abstract Method method(String localPart);

    public InternationalString getTitle() {
        return title;
    }

    public InternationalString getDescription(Name name) {
        DescribeProcess info = getProcessDescription(name);
        if (info != null) {
            return new SimpleInternationalString(info.description());
        } else {
            return null;
        }
    }

    public Map<String, Parameter<?>> getParameterInfo(Name name) {
        // build the parameter descriptions by using the DescribeParameter
        // annotations
        Method method = method(name.getLocalPart());
        Map<String, Parameter<?>> input = new LinkedHashMap<String, Parameter<?>>();
        Annotation[][] params = method.getParameterAnnotations();
        Class<?>[] paramTypes = getMethodParamTypes(method);
        for (int i = 0; i < paramTypes.length; i++) {
            if (!(ProgressListener.class.isAssignableFrom(paramTypes[i]))) {
                Parameter<?> param = paramInfo(method.getDeclaringClass(), i, paramTypes[i], params[i]);
                input.put(param.key, param);
            }
        }
        return input;
    }

    // expand to non primitive, the Process API only allows objects to be passed anyways
    // and using primitives is a source of troubles with converters, since generics cannot
    // deal with primitive values
    private Class<?>[] getMethodParamTypes(Method method) {
        Class<?>[] paramTypes = method.getParameterTypes();
        for (int i = 0; i < paramTypes.length; i++) {
            if(paramTypes[i].isPrimitive()) {
                paramTypes[i] = PRIMITIVE_MAPPER.get(paramTypes[i]);
            }
        }
       
        return paramTypes;
    }

    @SuppressWarnings("unchecked")
    public Map<String, Parameter<?>> getResultInfo(Name name, Map<String, Object> parameters)
            throws IllegalArgumentException {
        Method method = method(name.getLocalPart());
        // look for the DescribeResult annotations (the result could be a
        // key/value
        // map holding multiple results)
        Map<String, Parameter<?>> result = new LinkedHashMap<String, Parameter<?>>();
        for (Annotation annotation : method.getAnnotations()) {
            if (annotation instanceof DescribeResult) {
                DescribeResult info = (DescribeResult) annotation;
                // see if a type has been declared, otherwise use the annotation
                addResult(method, result, info);
            } else if(annotation instanceof DescribeResults) {
                DescribeResults info = (DescribeResults) annotation;
                for (DescribeResult dr : info.value()) {
                    addResult(method, result, dr);
                }
            }
        }
        // if annotation is not found, return a generic description using
        // the method return type
        if (result.isEmpty()) {
            if (!Void.class.equals(method.getReturnType())) {
                Parameter<?> VALUE = new Parameter("result", method.getReturnType(),
                        "Process result", "No description is available");
                result.put(VALUE.key, VALUE);
            }
        }
        return result;
    }

    private void addResult(Method method, Map<String, Parameter<?>> result, DescribeResult info) {
        Class resultType = info.type();
        if (Object.class.equals(resultType)) {
            resultType = method.getReturnType();
        }
       
        // metadata
        Map<String, Object> metadata = null;
        if (info != null && info.meta() != null && info.meta().length > 0) {
            String[] meta = info.meta();
            metadata = new HashMap<String, Object>();
            fillParameterMetadata(meta, metadata);
        }

        int min = info.primary() ? 0 : 1;
        Parameter resultParam = new Parameter(info.name(), resultType,
                new SimpleInternationalString(info.name()), new SimpleInternationalString(
                        info.description()), min > 0, min, 1, null, metadata);
        result.put(resultParam.key, resultParam);
    }

    public InternationalString getTitle(Name name) {
        DescribeProcess info = getProcessDescription(name);
        if (info != null) {
            return new SimpleInternationalString(info.title());
        } else {
            return null;
        }
    }

    public String getVersion(Name name) {
        DescribeProcess info = getProcessDescription(name);
        if (info != null) {
            return info.version();
        } else {
            return null;
        }
    }

    public boolean supportsProgress(Name name) {
        return false;
    }

    public boolean isAvailable() {
        return true;
    }

    public Map<Key, ?> getImplementationHints() {
        return null;
    }

    @SuppressWarnings("unchecked")
    Parameter<?> paramInfo(Class process, int i, Class<?> type, Annotation[] paramAnnotations) {
        DescribeParameter info = null;
        for (Annotation annotation : paramAnnotations) {
            if (annotation instanceof DescribeParameter) {
                info = (DescribeParameter) annotation;
                break;
            }
        }
        // handle collection type and multiplicity
        boolean collection = Collection.class.isAssignableFrom(type);
        int min = 1;
        int max = 1;
        if (collection) {
            if (info != null) {
                type = info.collectionType();
                if (type == null) {
                    type = Object.class;
                }
                min = info.min() > -1 ? info.min() : 0;
                max = info.max() > -1 ? info.max() : Integer.MAX_VALUE;
            } else {
                type = Object.class;
                min = 0;
                max = Integer.MAX_VALUE;
            }
        } else if (type.isArray()) {
            if (info != null) {
                min = info.min() > -1 ? info.min() : 0;
                max = info.max() > -1 ? info.max() : Integer.MAX_VALUE;
            } else {
                min = 0;
                max = Integer.MAX_VALUE;
            }
            type = type.getComponentType();
        } else {
            if (info != null) {
                if (info.min() > 1) {
                    throw new IllegalArgumentException("The non collection parameter at index " + i
                            + " cannot have a min multiplicity > 1");
                }
                min = info.min() > -1 ? info.min() : 1;
                if (info.max() > 1) {
                    throw new IllegalArgumentException("The non collection parameter at index " + i
                            + " cannot have a max multiplicity > 1");
                }
                max = info.max() > -1 ? info.max() : 1;
            }
        }
        if (min > max) {
            throw new IllegalArgumentException(
                    "Min occurrences > max occurrences for parameter at index " + i);
        }
        if (min == 0 && max == 1 && type.isPrimitive()) {
            throw new IllegalArgumentException("Optional values cannot be primitives, " +
                "use the associated object wrapper instead: " + info.name() + " in process " + process.getName());
        }
       
        HashMap<String, Object> metadata = new HashMap<String, Object>();
        if (info != null){
          double minValue = info.minValue();
          if (minValue != Double.NEGATIVE_INFINITY){
            metadata.put(Parameter.MIN, Double.valueOf(minValue));
          }
          double maxValue = info.maxValue();
          if (maxValue != Double.POSITIVE_INFINITY){
            metadata.put(Parameter.MAX, Double.valueOf(maxValue));
          }
        }
   
        Object defaultValue = null;
        if(info != null && !DescribeParameter.DEFAULT_NULL.equals(info.defaultValue())) {
            String strDefault = info.defaultValue();

            // lookup for constant value
            defaultValue = lookupConstant(strDefault, process, type);

            // try a string to target value conversion
            if (defaultValue == null) {
                defaultValue = Converters.convert(strDefault, type);
            }

            if(defaultValue == null) {
                throw new IllegalArgumentException("Default value " + strDefault + " could not be converted to target type " + type);
            }
        }
       
        // other metadata
        if (info != null && info.meta() != null && info.meta().length > 0) {
            String[] meta = info.meta();
            fillParameterMetadata(meta, metadata);
        }
       
       
        // finally build the parameter
        if (info != null) {
            return new Parameter(info.name(), type, new SimpleInternationalString(info.name()),
                    new SimpleInternationalString(info.description()), min > 0, min, max, defaultValue,
                    metadata);
        } else {
            return new Parameter("arg" + i, type, new SimpleInternationalString("Argument " + i),
                    new SimpleInternationalString("Input " + type.getName() + " value"), min > 0,
                    min, max, defaultValue, metadata);
        }
    }

    private void fillParameterMetadata(String[] metas, Map<String, Object> metadata) {
        for (String pair : metas) {
            int idx = pair.indexOf('=');
            String key, value;
            if (idx > 0) {
                key = pair.substring(0, idx);
                value = pair.substring(idx + 1);
            } else {
                key = pair;
                value = null;
            }

            metadata.put(key, value);
        }
    }

    /**
     * Uses the provided path to look up a constant of the specified type.
     * If the path
     *
     * @param strDefault
     * @param type
     * @return
     */
    private Object lookupConstant(String path, Class<?> process, Class<?> type) {
        int hashIdx = path.indexOf("#");
        if(hashIdx == -1) {
            // simple reference into the target type, let's see if the constant is is the
            // process class
            Object result = getConstantValue(path, process, type);
            if(result == null) {
                // see if it's in the target class then
                result = getConstantValue(path, type, type);
            }
            return result;
        } else {
            // an absolute reference
            String className = path.substring(0, hashIdx);
            String field = path.substring(hashIdx + 1);
            try {
                Class holder = Class.forName(className);
                return getConstantValue(field, holder, type);
            } catch(ClassNotFoundException e) {
                throw new IllegalArgumentException("Failed to locate class " + className);
            }
        }
    }

    private Object getConstantValue(String path, Class<?> holder, Class<?> target) {
        Field field = null;
        try {
            field = holder.getDeclaredField(path);
        } catch(NoSuchFieldException e) {
            if(LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "Failed to locate the field " + path + " in class " + holder);
            }
            return null;
        }
       
        // is it a constant?
        if((field.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) == 0) {
            if(LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "Field " + path + " found in class " + holder + ", but it's not a costant");
            }
            return null;
        }
       
        try {
            // make the field accessible, the constant is not necessarily public, especially in the
            // process class
            if(!field.isAccessible()) {
                field.setAccessible(true);
            }
           
            Object result = field.get(null);
            return Converters.convert(result, target);
        } catch (Exception e) {
            if(LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "Field " + path + " found in class " + holder + ", but failed to access it", e);
            }
            return null;
        }
    }

    /**
     * Cerate a process (for the indicated name).
     * <p>
     * Subclasses can control the process using their implementation of:
     * <ul>
     * <li>{@ #method(String)}: must return a non null method</li>
     * <li>{@link #createProcessBean(Name)}: return a bean to use; or null for static methods</li>
     * </ul>
     */
    public Process create(Name name) {
      String methodName = name.getLocalPart();
        Method meth = method(methodName);
      Object process = createProcessBean(name);
      if (process != null && (lookupInvertGridGeometry(process, meth.getName()) != null
              || lookupInvertQuery(process, meth.getName()) != null)) {
        return new InvokeMethodRenderingProcess(meth, process);
      } else {
        return new InvokeMethodProcess(meth, process);
      }
    }

    /**
     * Looks up a method in an object by simple name (restricted to public methods).
     * @param targetObject object, usually a java bean, on which to perform reflection
     * @param methodName
     * @return Method found
     */
    Method lookupMethod(Object targetObject, String methodName) {
        Method method = null;
        for (Method m : targetObject.getClass().getMethods()) {
            if (Modifier.isPublic(m.getModifiers()) &&  methodName.equals(m.getName())) {
                method = m;
                break;
            }
        }
        return method;
    }
   
    /**
     * Used to recognise {@link RenderingProcess} implementations; returns a non null
     * method for {@link RenderingProcess#invertGridGeometry(Map, Query, GridGeometry)}.
     * <p>
     * Used to look up the method to use for "invertGridGeometry"; if a specific method name is
     * not provided "invertGridGeometry" will be used.
     * <p>
     * <ul>
     * <li>For {@literal null} method name "invertGridGeometry" will be used.</li>
     * <li>For {@literal "execute"} method name "invertGridGeometry" will be used.</li>
     * <li>For {@literal "buffer"} method name "bufferInvertGridGeometry" will be used</li>
     * </ul>
     *
     * @param targetObject Target object; may be null for static method lookup
     * @param methodName method to use for "invertGridGeometry"
     * @return method to use for RenderingProcess "invertGridGeometry", or null if not a RenderingProcess
     */
    protected Method lookupInvertGridGeometry( Object targetObject, String methodName ){
        if( methodName == null || "execute".equals(methodName) ){
            methodName = "invertGridGeometry";
        }
        else {
            methodName = methodName + "InvertGridGeometry";
        }
        return lookupMethod( targetObject, methodName );
    }


    /**
     * Used to recognise {@link RenderingProcess} implementations; returns a non null
     * method for {@link RenderingProcess#invertQuery(Map, Query, GridGeometry)}.
     * <p>
     * Used to look up the method to use for "invertQuery"; if a specific method name is not
     * provided "invertGridGeometry" will be used.
     * <p>
     * <ul>
     * <li>For {@literal null} method name "invertQuery" will be used.</li>
     * <li>For {@literal "execute"} method name "invertQuery" will be used.</li>
     * <li>For {@literal "buffer"} method name "bufferInvertQuery" will be used</li>
     * </ul>
     * @param targetObject Target object; may be null for static method lookup
     * @param methodName method to use for "invertQuery"
     * @return method to use for RenderingProcess "invertQuery", or <code>null</code> if not a RenderingProcess
     */
    protected Method lookupInvertQuery( Object targetObject, String methodName ){
        if( methodName == null || "execute".equals(methodName)){
            methodName = "invertQuery";
        }
        else {
            methodName = methodName + "InvertQuery";
        }
        return lookupMethod( targetObject, methodName );
    }

    /**
     * Creates the bean upon which the process execution method will be invoked.
     * <p>
     * Can be null in case the method is a static one
     *
     * @param name Name of the process bean
     * @return intance of process bean; or null if the method is a static method
     */
    protected abstract Object createProcessBean(Name name);

    /**
     * A wrapper which executes the given method as a {@link Process}.
     * When the process {@link #execute(Map, ProgressListener)} is called
     * the method is invoked to produce a result.
     * The mapping from the process parameters to the method parameters
     * is determined by the {@link DescribeParameter} annotations on the method parameters.
     *
     */
    class InvokeMethodProcess implements Process {
        /**
         * Method to invoke.
         */
        Method method;
        /**
         * Target object used to invoke method, may be null when using a static method.
         */
        Object targetObject;

        /**
         * Creates a wrapper for invoking a method as a process
         *
         * @param method method to invoke.  May be static
         * @param targetObject object used to invoke method.  May be null
         */
        public InvokeMethodProcess(Method method, Object targetObject) {
            this.method = method;
            this.targetObject = targetObject;
        }

        @SuppressWarnings("unchecked")
        public Map<String, Object> execute(Map<String, Object> input, ProgressListener monitor)
                throws ProcessException {

            Object[] args = buildProcessArguments(method, input, monitor, false);

            // invoke and grab result
            Object value = null;
            try {
                value = method.invoke(targetObject, args);
            } catch (IllegalAccessException e) {
                // report the exception and exit
                if (monitor != null) {
                    monitor.exceptionOccurred(e);
                }
                throw new ProcessException(e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getTargetException();
                // report the exception and exit
                if (monitor != null) {
                    monitor.exceptionOccurred(t);
                }
                if (t instanceof ProcessException) {
                    throw ((ProcessException) t);
                } else {
                    throw new ProcessException(t);
                }
            }

            // build up the result
            if (value instanceof Object[]) {
                // handle the case the implementor used a positional array for
                // returning multiple outputs
                Object values[] = (Object[]) value;
                Map<String, Object> result = new LinkedHashMap<String, Object>();
                int i = 0;
                for (Annotation annotation : method.getAnnotations()) {
                    if (i >= values.length)
                        break; // no more values to encode
                    Object obj = values[i];

                    if (annotation instanceof DescribeResult) {
                        DescribeResult info = (DescribeResult) annotation;
                        addResult(result, obj, info);
                    }
                    if (annotation instanceof DescribeResults) {
                        DescribeResults info = (DescribeResults) annotation;
                        for (DescribeResult dr : info.value()) {
                            addResult(result, obj, dr);
                        }
                    }
                }
                return result;
            } else if (value instanceof Map) {
                Map<String, Object> result = new LinkedHashMap<String, Object>();
                Map<String, Object> map = (Map<String, Object>) value;
                for (Annotation annotation : method.getAnnotations()) {
                    if (annotation instanceof DescribeResult) {
                        DescribeResult info = (DescribeResult) annotation;
                        Object resultValue = map.get(info.name());
                        if(resultValue != null) {
                            addResult(result, resultValue, info);
                        }
                    }
                    if (annotation instanceof DescribeResults) {
                        DescribeResults info = (DescribeResults) annotation;
                        for (DescribeResult dr : info.value()) {
                            Object resultValue = map.get(dr.name());
                            if(resultValue != null) {
                                addResult(result, resultValue, dr);
                            }
                        }
                    }
                }
                return result;
            } else if (!Void.class.equals(method.getReturnType())) {
                // handle the single result case
                Map<String, Object> result = new LinkedHashMap<String, Object>();
                DescribeResult dr = method.getAnnotation(DescribeResult.class);
                if (dr != null) {
                    result.put(dr.name(), value);
                } else {
                    result.put("result", value);
                }
                return result;
            }
            // handle the case where the method returns void
            return null;
        }

        private void addResult(Map<String, Object> result, Object obj, DescribeResult info) {
            if (info.type().isInstance(obj)) {
                result.put(info.name(), obj);
            } else {
                throw new IllegalArgumentException(method.getName()
                        + " unable to encode result " + obj + " as " + info.type());
            }
        }

        protected Object[] buildProcessArguments(Method method, Map<String, Object> input, ProgressListener monitor, boolean skip)
                throws ProcessException {
            // build the array of arguments we'll use to invoke the method
            Class<?>[] paramTypes = getMethodParamTypes(method);
            Annotation[][] annotations = method.getParameterAnnotations();
            Object args[] = new Object[paramTypes.length];
            for (int i = 0; i < args.length; i++) {
                if (ProgressListener.class.equals(paramTypes[i])) {
                    // pass in the monitor
                    args[i] = monitor;
                } else {
                    // if we can skip and there is no annotation, skip
                    if((annotations[i] == null || annotations[i].length == 0) && skip) {
                        continue;
                    }
                   
                    // find the corresponding argument in the input
                    // map and set it
                    Class<? extends Object> target = targetObject == null ? null : targetObject.getClass();
          Parameter p = paramInfo(target, i, paramTypes[i], annotations[i]);
                    Object value = input.get(p.key);
                   
                    if(value == null && p.getDefaultValue() != null) {
                        value = p.getDefaultValue();
                    }

                    // this takes care of array/collection conversions among
                    // others
                    args[i] = Converters.convert(value, paramTypes[i]);
                    // check the conversion was successful
                    if (args[i] == null && value != null) {
                        throw new ProcessException("Could not convert " + value
                                + " to target type " + paramTypes[i].getName());
                    }

                    // check multiplicity is respected
                    if (p.minOccurs > 0 && value == null) {
                        throw new ProcessException("Parameter " + p.key
                                + " is missing but has min multiplicity > 0");
                    } else if (p.maxOccurs > 1) {
                        int size = -1;
                        if(args[i] == null) {
                            size = 0;
                        } else if (paramTypes[i].isArray()) {
                            size = Array.getLength(args[i]);
                        } else {
                            size = ((Collection) args[i]).size();
                        }
                        if (size < p.minOccurs) {
                            throw new ProcessException("Parameter " + p.key + " has " + size
                                    + " elements but min occurrences is " + p.minOccurs);
                        }
                        if (size > p.maxOccurs) {
                            throw new ProcessException("Parameter " + p.key + " has " + size
                                    + " elements but max occurrences is " + p.maxOccurs);
                        }
                    }
                }
            }
            return args;
        }
    }
   
   
   
    /**
     * A wrapper which executes the given method as a {@linkplain RenderingProcess}.
     * When the process {@link #execute(Map, ProgressListener)} is called
     * the method is invoked to produce a result.
     * The mapping from the process parameters to the method parameters
     * is determined by the {@link DescribeParameter} annotations on the method parameters.
     * <p>
     * This implementation supports the additional methods required for a RenderingProcess:
     * <ul>
     * <li>invertQuery
     * <li>invertGridGeometry
     * </ul>
     * The signature of these methods in the Process class is annotation-driven.
     * Each method must accept a {@link Query} and a {@link GridGeometry} as its final parameters,
     * but may have any number of parameters preceding them.
     * These parameters must be a subset of the parameters of the given execution
     * method, and they use the same annotation to describe them.
     *
     */
    class InvokeMethodRenderingProcess extends InvokeMethodProcess implements RenderingProcess {
       
        /**
         * Creates a wrapper for invoking a method as a process
         *
         * @param method method to invoke.  May be static
         * @param targetObject object used to invoke method.  May be null
         */
        public InvokeMethodRenderingProcess(Method method, Object targetObject) {
            super(method, targetObject);
        }

        public Query invertQuery(Map<String, Object> input, Query targetQuery,
                GridGeometry targetGridGeometry) throws ProcessException {
            Method invertQueryMethod = lookupInvertQuery(targetObject, method.getName() );

            if (invertQueryMethod == null) {
                return targetQuery;
            }

            try {
                Object[] args = buildProcessArguments(invertQueryMethod, input, null, true);
                args[args.length - 2] = targetQuery;
                args[args.length - 1] = targetGridGeometry;


                return (Query) invertQueryMethod.invoke(targetObject, args);
            } catch (IllegalAccessException e) {
                throw new ProcessException(e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getTargetException();
                if (t instanceof ProcessException) {
                    throw ((ProcessException) t);
                } else {
                    throw new ProcessException(t);
                }
            }

        }

        public GridGeometry invertGridGeometry(Map<String, Object> input, Query targetQuery,
                GridGeometry targetGridGeometry) throws ProcessException {
           
           Method invertGridGeometryMethod = lookupInvertGridGeometry(targetObject, this.method.getName() );

            if (invertGridGeometryMethod == null) {
                return targetGridGeometry;
            }

            try {
                Object[] args = buildProcessArguments(invertGridGeometryMethod, input, null, true);
                args[args.length - 2] = targetQuery;
                args[args.length - 1] = targetGridGeometry;

                return (GridGeometry) invertGridGeometryMethod.invoke(targetObject, args);
            } catch (IllegalAccessException e) {
                throw new ProcessException(e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getTargetException();
                if (t instanceof ProcessException) {
                    throw ((ProcessException) t);
                } else {
                    throw new ProcessException(t);
                }
            }
        }
       
    }

}
TOP

Related Classes of org.geotools.process.factory.AnnotationDrivenProcessFactory$InvokeMethodProcess

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.