Package org.geoserver.script.py

Source Code of org.geoserver.script.py.PyWpsHook

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.script.py;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Logger;

import javax.script.ScriptEngine;
import javax.script.ScriptException;

import org.geoserver.script.wps.WpsHook;
import org.geotools.data.Parameter;
import org.geotools.text.Text;
import org.geotools.util.Converters;
import org.geotools.util.logging.Logging;
import org.python.core.Py;
import org.python.core.PyDictionary;
import org.python.core.PyList;
import org.python.core.PyObject;
import org.python.core.PyTuple;
import org.python.core.PyType;

/**
* Python wps hook.
*
* @author Justin Deoliveira, OpenGeo
*/
public class PyWpsHook extends WpsHook {

    static Logger LOGGER = Logging.getLogger(PyWpsHook.class);

    public PyWpsHook(PythonPlugin plugin) {
        super(plugin);
    }

    @Override
    public String getTitle(ScriptEngine engine) throws ScriptException {
        return str(process(engine).__getattr__("title"));
    }

    @Override
    public String getDescription(ScriptEngine engine) throws ScriptException {
        return str(process(engine).__getattr__("description"));
    }

    @Override
    public Map<String, Parameter<?>> getInputs(ScriptEngine engine)
            throws ScriptException {
        engine.eval("import inspect");
        PyList args = (PyList) engine.eval("inspect.getargspec(run.func_closure[0].cell_contents)[0]");
        PyTuple defaults = (PyTuple) engine
                .eval("inspect.getargspec(run.func_closure[0].cell_contents)[3]");
        PyDictionary inputs = (PyDictionary) process(engine).__getattr__("inputs");

        if (args.size() != inputs.size()) {
            throw new RuntimeException(String.format("process function specified %d arguments but"+
                " describes %d inputs", args.size(), inputs.size()));
        }

        Map<String, Parameter<?>> map = new LinkedHashMap<String, Parameter<?>>();
        for (int i = 0; i < args.size(); i++) {
            String arg = args.get(i).toString();
            PyTuple input = (PyTuple) inputs.get(arg);
            if (input == null) {
                throw new RuntimeException(String.format("process function specified argument %s" +
                    " but does not specify it as an input", arg));
            }
            int min = 1;
            int max = 1;
            Object defaultValue = null;
            Map metadata = null;
            if (input.size() == 3) {
                PyDictionary meta = (PyDictionary) input.get(2);
                min = getParameter(meta, "min", Integer.class, 1);
                max = getParameter(meta, "max", Integer.class, 1);
                List<String> options = getParameter(meta, "domain", List.class, null);
                if (options != null) {
                    metadata = new HashMap();
                    metadata.put(Parameter.OPTIONS, options);
                }
                // map every other key as parameter metadata entry
                HashSet<String> otherKeys = new HashSet<String>(meta.keySet());
                otherKeys.remove("min");
                otherKeys.remove("max");
                otherKeys.remove("domain");
                if(!otherKeys.isEmpty()) {
                    if (metadata == null) {
                        metadata = new HashMap();
                    }
                    for (String key : otherKeys) {
            metadata.put(key, meta.get(key));
          }
                }
            }
            if (defaults != null) {
                // from the python guide:
                // defaults is a tuple of default argument values or None if there are no
                // default arguments; if this tuple has n elements,
                // they correspond to the last n elements listed in args.
                int defaultIdx = defaults.size() - (args.size() - i);
                if (defaultIdx >= 0) {
                    defaultValue = defaults.get(defaultIdx);
                }
            }
            Parameter parameter = parameter(arg, input.__getitem__(0), min, max,
                    input.__getitem__(1),
                    defaultValue, metadata);
            map.put(arg, parameter);
        }
        return map;
    }
   
    private <T> T getParameter(PyDictionary meta, String key, Class<T> targetType, T defaultValue) {
        if (!meta.containsKey(key)) {
            return defaultValue;
        }

        Object value = meta.get(key);
        return (T) Converters.convert(value, targetType);
    }

    @Override
    public Map<String, Parameter<?>> getOutputs(ScriptEngine engine)
            throws ScriptException {
   
        PyDictionary outputs = (PyDictionary) process(engine).__getattr__("outputs");
        Map<String,Parameter<?>> map = new TreeMap<String, Parameter<?>>();

        for (String name : (List<String>)outputs.keys()) {
          PyTuple output = (PyTuple) outputs.get(name);

            Object type = output.__getitem__(0);
            Object desc = output.__getitem__(1);

            // map every key in the optional dictionary as parameter metadata entry
            Map<String, Object> metadata = null;
            if (output.size() == 3) {
                PyDictionary meta = (PyDictionary) output.get(2);
                if(meta != null && !meta.isEmpty()) {
                  metadata = new HashMap<String, Object>();
                  for (Object key : meta.keySet()) {
            metadata.put((String) key, meta.get(key));
          }
                }
            }

            map.put(name, parameter(name, type, 1, 1, desc, null, metadata));
        }

        return map;
    }

    @Override
    public Map<String, Object> run(Map<String, Object> inputs, ScriptEngine engine)
            throws ScriptException {
        PyObject run = process(engine);
       
        List<PyObject> args = new ArrayList();
        List<String> kw = new ArrayList();
       
        for (Map.Entry<String,Object> input : inputs.entrySet()) {
            args.add(Py.java2py(input.getValue()));
            kw.add(input.getKey());
        }
       
        PyObject r = run.__call__(args.toArray(new PyObject[args.size()]),
            kw.toArray(new String[kw.size()]));

        Map<String,Parameter<?>> outputs = getOutputs(engine);

        Map<String,?> result = null;
        if (r instanceof Map) {
            result = (Map<String, ?>) r;
        }
        else {
            result = Collections.singletonMap(outputs.keySet().iterator().next(), r);
        }

        if (result.size() != outputs.size()) {
            throw new IllegalStateException(String.format("Process returned %d values, should have " +
                "returned %d", result.size(), outputs.size()));
        }
       
        Map<String,Object> results = new LinkedHashMap<String, Object>();

        for (Map.Entry<String, Parameter<?>> e : outputs.entrySet()) {
            String key = e.getKey();
            Parameter output = e.getValue();
           
            Object obj = result.get(key);

            if (obj instanceof PyObject) {
                obj = ((PyObject) obj).__tojava__(output.type);
            }
            if (obj != null && !output.type.isInstance(obj)) {
                LOGGER.warning(String.format("Output %s declared type %s but returned %s",
                    output.getName(), output.getType().getSimpleName(), obj.getClass().getSimpleName()));
            }
           
            results.put(output.key, obj);
        }

        return results;
    }

    PyObject process(ScriptEngine engine) {
        return (PyObject) engine.get("run");
    }

    String str(Object obj) {
        return obj != null ? obj.toString() : null;
    }

    Parameter parameter(String name, Object type, int min, int max, Object desc,
            Object defaultValue, Map metadata) {
        Class clazz = null;
        if (type != null && type instanceof PyType) {
            clazz = PythonPlugin.toJavaClass((PyType)type);
        }
        if (clazz == null) {
            clazz = Object.class;
        }

        desc = desc != null ? desc : name;
        return new Parameter(name, clazz, Text.text(name), Text.text(desc.toString()),
                min > 0, min, max, defaultValue, metadata);
    }
}
TOP

Related Classes of org.geoserver.script.py.PyWpsHook

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.