org.geoserver.wps.DescribeProcess.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.wps.DescribeProcess.java

Source

/* Copyright (c) 2001 - 2013 OpenPlans - www.openplans.org. All rights reserved.
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.wps;

import java.math.BigInteger;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.opengis.ows11.AllowedValuesType;
import net.opengis.ows11.CodeType;
import net.opengis.ows11.Ows11Factory;
import net.opengis.ows11.ValueType;
import net.opengis.wps10.CRSsType;
import net.opengis.wps10.ComplexDataDescriptionType;
import net.opengis.wps10.DataInputsType;
import net.opengis.wps10.DefaultType;
import net.opengis.wps10.DescribeProcessType;
import net.opengis.wps10.InputDescriptionType;
import net.opengis.wps10.LiteralInputType;
import net.opengis.wps10.LiteralOutputType;
import net.opengis.wps10.OutputDescriptionType;
import net.opengis.wps10.ProcessDescriptionType;
import net.opengis.wps10.ProcessDescriptionsType;
import net.opengis.wps10.ProcessOutputsType;
import net.opengis.wps10.SupportedCRSsType;
import net.opengis.wps10.SupportedComplexDataInputType;
import net.opengis.wps10.SupportedComplexDataType;
import net.opengis.wps10.Wps10Factory;

import org.geoserver.ows.Ows11Util;
import org.geoserver.wfs.xml.XSProfile;
import org.geoserver.wps.ppio.BoundingBoxPPIO;
import org.geoserver.wps.ppio.ComplexPPIO;
import org.geoserver.wps.ppio.LiteralPPIO;
import org.geoserver.wps.ppio.ProcessParameterIO;
import org.geoserver.wps.ppio.RawDataPPIO;
import org.geoserver.wps.process.AbstractRawData;
import org.geoserver.wps.process.GeoServerProcessors;
import org.geotools.data.Parameter;
import org.geotools.process.ProcessFactory;
import org.opengis.feature.type.Name;
import org.springframework.context.ApplicationContext;

/**
 * First-call DescribeProcess class
 *
 * @author Lucas Reed, Refractions Research Inc
 * @author Justin Deoliveira, OpenGEO
 */
public class DescribeProcess {
    static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(DescribeProcess.class);

    WPSInfo wps;
    ApplicationContext context;
    Locale locale;
    XSProfile xsp;

    Wps10Factory wpsf = Wps10Factory.eINSTANCE;
    Ows11Factory owsf = Ows11Factory.eINSTANCE;

    /**
     * Maps the primitive types that can still be used in process input/output descriptions to
     * object wrappers that we can use in process descriptions
     */
    static final Map<Class, Class> PRIMITIVE_TO_WRAPPER;

    static {
        PRIMITIVE_TO_WRAPPER = new HashMap<Class, Class>();
        PRIMITIVE_TO_WRAPPER.put(byte.class, Byte.class);
        PRIMITIVE_TO_WRAPPER.put(short.class, Short.class);
        PRIMITIVE_TO_WRAPPER.put(int.class, Integer.class);
        PRIMITIVE_TO_WRAPPER.put(long.class, Long.class);
        PRIMITIVE_TO_WRAPPER.put(float.class, Float.class);
        PRIMITIVE_TO_WRAPPER.put(double.class, Double.class);
        PRIMITIVE_TO_WRAPPER.put(boolean.class, Boolean.class);
    }

    public DescribeProcess(WPSInfo wps, ApplicationContext context) {
        this.wps = wps;
        this.context = context;
        locale = Locale.getDefault();

        //TODO: creating this ever time this operation is performed is sort of silly
        // some sort of singleton would be nice
        xsp = new XSProfile();
    }

    public ProcessDescriptionsType run(DescribeProcessType request) {

        ProcessDescriptionsType pds = wpsf.createProcessDescriptionsType();
        pds.setLang("en");

        for (Iterator i = request.getIdentifier().iterator(); i.hasNext();) {
            CodeType id = (CodeType) i.next();
            processDescription(id, pds);
        }

        return pds;
    }

    void processDescription(CodeType id, ProcessDescriptionsType pds) {
        Name name = Ows11Util.name(id);
        ProcessFactory pf = GeoServerProcessors.createProcessFactory(name);
        if (pf == null || pf.create(name) == null) {
            throw new WPSException("No such process: " + id.getValue());
        }

        ProcessDescriptionType pd = wpsf.createProcessDescriptionType();
        pds.getProcessDescription().add(pd);

        pd.setProcessVersion("1.0.0");
        pd.setIdentifier(Ows11Util.code(id.getValue()));
        pd.setTitle(Ows11Util.languageString(pf.getTitle(name)));
        pd.setAbstract(Ows11Util.languageString(pf.getDescription(name)));
        pd.setStatusSupported(true);
        pd.setStoreSupported(true);

        //data inputs
        DataInputsType inputs = wpsf.createDataInputsType();
        pd.setDataInputs(inputs);
        dataInputs(inputs, pf, name);

        //process outputs
        ProcessOutputsType outputs = wpsf.createProcessOutputsType();
        pd.setProcessOutputs(outputs);
        processOutputs(outputs, pf, name);
    }

    void dataInputs(DataInputsType inputs, ProcessFactory pf, Name name) {
        Collection<String> outputMimeParameters = AbstractRawData.getOutputMimeParameters(name, pf).values();
        for (Parameter<?> p : pf.getParameterInfo(name).values()) {
            // skip the output mime choice params, they will be filled automatically by WPS
            if (outputMimeParameters.contains(p.key)) {
                continue;
            }

            InputDescriptionType input = wpsf.createInputDescriptionType();
            inputs.getInput().add(input);

            input.setIdentifier(Ows11Util.code(p.key));
            input.setTitle(Ows11Util.languageString(p.title));
            input.setAbstract(Ows11Util.languageString(p.description));

            // WPS spec specifies non-negative for unlimited inputs, so -1 -> 0
            input.setMaxOccurs(
                    p.maxOccurs == -1 ? BigInteger.valueOf(Long.MAX_VALUE) : BigInteger.valueOf(p.maxOccurs));

            input.setMinOccurs(BigInteger.valueOf(p.minOccurs));

            List<ProcessParameterIO> ppios = ProcessParameterIO.findAll(p, context);
            if (ppios.isEmpty()) {
                throw new WPSException("Could not find process parameter for type " + p.key + "," + p.type);
            }

            //handle the literal case
            if (ppios.get(0) instanceof LiteralPPIO) {
                LiteralPPIO lppio = (LiteralPPIO) ppios.get(0);

                LiteralInputType literal = wpsf.createLiteralInputType();
                input.setLiteralData(literal);

                // map the java class to an xml type name
                if (!String.class.equals(lppio.getType())) {
                    Class type = lppio.getType();
                    if (PRIMITIVE_TO_WRAPPER.containsKey(type)) {
                        type = PRIMITIVE_TO_WRAPPER.get(type);
                    }
                    Name typeName = xsp.name(type);
                    if (typeName != null) {
                        literal.setDataType(Ows11Util.type("xs:" + typeName.getLocalPart()));
                    }
                }
                if (p.metadata.get(Parameter.OPTIONS) != null) {
                    List<Object> options = (List<Object>) p.metadata.get(Parameter.OPTIONS);
                    Object[] optionsArray = (Object[]) options.toArray(new Object[options.size()]);
                    addAllowedValues(literal, optionsArray);
                } else if (lppio.getType().isEnum()) {
                    Object[] enumValues = lppio.getType().getEnumConstants();
                    addAllowedValues(literal, enumValues);
                } else {
                    literal.setAnyValue(owsf.createAnyValueType());
                }

                try {
                    if (p.sample != null) {
                        literal.setDefaultValue(lppio.encode(p.sample));
                    }
                } catch (Exception e) {
                    LOGGER.log(Level.WARNING,
                            "Failed to fill the default value for input " + p.key + " of process " + name, e);
                }
            } else if (ppios.get(0) instanceof BoundingBoxPPIO) {
                input.setBoundingBoxData(buildSupportedCRSType());
            } else {
                //handle the complex data case
                SupportedComplexDataInputType complex = wpsf.createSupportedComplexDataInputType();
                input.setComplexData(complex);

                complex.setSupported(wpsf.createComplexDataCombinationsType());
                for (ProcessParameterIO ppio : ppios) {
                    ComplexPPIO cppio = (ComplexPPIO) ppio;

                    ComplexDataDescriptionType format = null;

                    if (ppio instanceof RawDataPPIO) {
                        String[] mimeTypes = AbstractRawData.getMimeTypes(p);
                        for (String mimeType : mimeTypes) {
                            ComplexDataDescriptionType ddt = wpsf.createComplexDataDescriptionType();
                            ddt.setMimeType(mimeType);
                            complex.getSupported().getFormat().add(ddt);
                            if (format == null) {
                                format = ddt;
                            }
                        }
                    } else {
                        format = wpsf.createComplexDataDescriptionType();
                        format.setMimeType(cppio.getMimeType());
                        // add to supported
                        complex.getSupported().getFormat().add(format);
                    }

                    //handle the default    
                    if (complex.getDefault() == null) {
                        ComplexDataDescriptionType def = wpsf.createComplexDataDescriptionType();
                        def.setMimeType(format.getMimeType());

                        complex.setDefault(wpsf.createComplexDataCombinationType());
                        complex.getDefault().setFormat(def);
                    }
                }
            }
        }
    }

    private void addAllowedValues(LiteralInputType literal, Object[] values) {
        AllowedValuesType allowed = owsf.createAllowedValuesType();
        for (Object value : values) {
            ValueType vt = owsf.createValueType();
            vt.setValue(value.toString());
            allowed.getValue().add(vt);
        }
        literal.setAllowedValues(allowed);
    }

    private SupportedCRSsType buildSupportedCRSType() {
        SupportedCRSsType supportedCRS = wpsf.createSupportedCRSsType();
        DefaultType def = wpsf.createDefaultType();
        def.setCRS("EPSG:4326");
        supportedCRS.setDefault(def);
        // TODO: redo the bindings, supported crs should contain a list, not a single value
        CRSsType crss = wpsf.createCRSsType();
        crss.setCRS("EPSG:4326");
        supportedCRS.setSupported(crss);
        return supportedCRS;
    }

    void processOutputs(ProcessOutputsType outputs, ProcessFactory pf, Name name) {
        Map<String, Parameter<?>> outs = pf.getResultInfo(name, null);
        for (Parameter p : outs.values()) {
            OutputDescriptionType output = wpsf.createOutputDescriptionType();
            outputs.getOutput().add(output);

            output.setIdentifier(Ows11Util.code(p.key));
            output.setTitle(Ows11Util.languageString(p.title));

            List<ProcessParameterIO> ppios = ProcessParameterIO.findAll(p, context);
            if (ppios.isEmpty()) {
                throw new WPSException("Could not find process parameter for type " + p.key + "," + p.type);
            }

            //handle the literal case
            if (ppios.get(0) instanceof LiteralPPIO) {
                LiteralPPIO lppio = (LiteralPPIO) ppios.get(0);

                LiteralOutputType literal = wpsf.createLiteralOutputType();
                output.setLiteralOutput(literal);

                //map the java class to an xml type name
                if (!String.class.equals(lppio.getType())) {
                    Class type = lppio.getType();
                    if (PRIMITIVE_TO_WRAPPER.containsKey(type)) {
                        type = PRIMITIVE_TO_WRAPPER.get(type);
                    }
                    Name typeName = xsp.name(type);
                    if (typeName != null) {
                        literal.setDataType(Ows11Util.type(typeName.getLocalPart()));
                    }
                }
            } else if (ppios.get(0) instanceof BoundingBoxPPIO) {
                output.setBoundingBoxOutput(buildSupportedCRSType());
            } else {
                //handle the complex data case
                SupportedComplexDataType complex = wpsf.createSupportedComplexDataType();
                output.setComplexOutput(complex);

                complex.setSupported(wpsf.createComplexDataCombinationsType());
                for (ProcessParameterIO ppio : ppios) {
                    ComplexPPIO cppio = (ComplexPPIO) ppio;

                    ComplexDataDescriptionType format = null;

                    if (ppio instanceof RawDataPPIO) {
                        String[] mimeTypes = AbstractRawData.getMimeTypes(p);
                        for (String mimeType : mimeTypes) {
                            ComplexDataDescriptionType ddt = wpsf.createComplexDataDescriptionType();
                            ddt.setMimeType(mimeType);
                            complex.getSupported().getFormat().add(ddt);
                            if (format == null) {
                                format = ddt;
                            }
                        }
                    } else {
                        format = wpsf.createComplexDataDescriptionType();
                        format.setMimeType(cppio.getMimeType());
                        // add to supported
                        complex.getSupported().getFormat().add(format);
                    }

                    //handle the default    
                    if (complex.getDefault() == null) {
                        ComplexDataDescriptionType def = wpsf.createComplexDataDescriptionType();
                        def.setMimeType(format.getMimeType());

                        complex.setDefault(wpsf.createComplexDataCombinationType());
                        complex.getDefault().setFormat(def);
                    }
                }
            }
        }
    }
}