/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 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.data.wps; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import net.opengis.wps10.ComplexDataCombinationsType; import net.opengis.wps10.ComplexDataDescriptionType; import net.opengis.wps10.ComplexDataType; import net.opengis.wps10.DataInputsType; import net.opengis.wps10.DataType; import net.opengis.wps10.DescriptionType; import net.opengis.wps10.ExecuteResponseType; import net.opengis.wps10.InputDescriptionType; import net.opengis.wps10.LiteralDataType; import net.opengis.wps10.LiteralInputType; import net.opengis.wps10.LiteralOutputType; import net.opengis.wps10.OutputDataType; import net.opengis.wps10.OutputDescriptionType; import net.opengis.wps10.ProcessDescriptionType; import net.opengis.wps10.ProcessOutputsType; import net.opengis.wps10.SupportedComplexDataInputType; import net.opengis.wps10.SupportedComplexDataType; import net.opengis.wps10.Wps10Factory; import org.eclipse.emf.common.util.EList; import org.geotools.data.Parameter; import org.geotools.text.Text; import org.geotools.util.Converters; import org.opengis.util.InternationalString; import com.vividsolutions.jts.geom.Geometry; /** * Contains helpful static util methods for the WPS module * * @author gdavis * * * * @source $URL$ */ public class WPSUtils { /** * static ints representing the input types */ public static final int INPUTTYPE_LITERAL = 1; public static final int INPUTTYPE_COMPLEXDATA = 2; /** * Creates a DataType input object from the given object and InputDescriptionType (from a * describeprocess) and decides if the input is a literal or complex data based on its type. * * @param obj * the base input object * @param idt * input description type defining the input * @return the created DataType input object */ public static DataType createInputDataType(Object obj, InputDescriptionType idt) { int inputtype = 0; // first try to figure out if the input is a literal or complex based // on the data in the idt LiteralInputType literalData = idt.getLiteralData(); SupportedComplexDataInputType complexData = idt.getComplexData(); if (literalData != null) { inputtype = INPUTTYPE_LITERAL; } else if (complexData != null) { inputtype = INPUTTYPE_COMPLEXDATA; } else { // is the value a literal? Do a very basic test here for common // literal types. TODO: figure out a more thorough test here if (obj instanceof String || obj instanceof Double || obj instanceof Float || obj instanceof Integer) { inputtype = INPUTTYPE_LITERAL; } else { // assume complex data inputtype = INPUTTYPE_COMPLEXDATA; } } // now create the input based on its type String schema = null; if (inputtype == INPUTTYPE_COMPLEXDATA) { ComplexDataCombinationsType supported = complexData.getSupported(); ComplexDataDescriptionType cddt = (ComplexDataDescriptionType) supported.getFormat() .get(0); schema = cddt.getSchema(); } return createInputDataType(obj, inputtype, schema); } /** * Creates a DataType input object from the given object, schema and type (complex or literal). * * @param obj * the base input object * @param type * the input type (literal or complexdata) * @param schema * only used for type complexdata * @return the created DataType input object */ public static DataType createInputDataType(Object obj, int type, String schema) { DataType dt = Wps10Factory.eINSTANCE.createDataType(); if (type == INPUTTYPE_LITERAL) { LiteralDataType ldt = Wps10Factory.eINSTANCE.createLiteralDataType(); ldt.setValue(obj.toString()); dt.setLiteralData(ldt); } else { // assume complex data ComplexDataType cdt = Wps10Factory.eINSTANCE.createComplexDataType(); // do I need to add a FeatureMap object, or Entry object, or what? // EStructuralFeature eStructuralFeature = null; // Entry createEntry = FeatureMapUtil.createEntry(eStructuralFeature, obj); // cdt.getMixed().add(obj); cdt.getData().add(obj); if (schema != null) { cdt.setSchema(schema); } dt.setComplexData(cdt); } return dt; } /** * Create a map of <String name, Parameter> inputs for a process based on its describeProcess. * * @param processDesc * @param map * add the inputs to the given map (create it if null) * @return map of name,Parameter representing the input params for this process */ public static Map<String, Parameter<?>> createInputParamMap(ProcessDescriptionType processDesc, Map<String, Parameter<?>> map) { if (map == null) { map = new TreeMap<String, Parameter<?>>(); } // loop through the process desc and setup each input param DataInputsType dataInputs = processDesc.getDataInputs(); if (dataInputs == null) return null; EList inputs = dataInputs.getInput(); if (inputs == null || inputs.isEmpty()) return null; Iterator iterator = inputs.iterator(); while (iterator.hasNext()) { InputDescriptionType idt = (InputDescriptionType) iterator.next(); // determine if the input is a literal or complex data, and from that // find out what type the object should be LiteralInputType literalData = idt.getLiteralData(); SupportedComplexDataInputType complexData = idt.getComplexData(); Class type = Object.class; if (literalData != null) { String reference = literalData.getDataType().getReference(); type = getLiteralTypeFromReference(reference); } else if (complexData != null) { // TODO: get all supported types and determine how to handle that, not just the // default. ComplexDataDescriptionType format = complexData.getDefault().getFormat(); String encoding = format.getEncoding(); String mimetype = format.getMimeType(); String schema = format.getSchema(); if (encoding == null) encoding = ""; if (mimetype == null) mimetype = ""; if (schema == null) schema = ""; type = getComplexType(encoding, mimetype, schema); } // create the parameter boolean required = true; if (idt.getMinOccurs().intValue() < 1){ required = false; } String identifier = idt.getIdentifier().getValue(); InternationalString title = Text.text(idt .getTitle().getValue()); InternationalString description = Text.text( isAbstractNull(idt) ? "" : idt.getAbstract().getValue()); Parameter<?> param = new Parameter(identifier, type, title, description, required, idt .getMinOccurs().intValue(), idt.getMaxOccurs().intValue(), null, null); map.put(identifier, param); } return map; } /** * Create a map of <String name, Parameter> outputs for a process based on its describeProcess. * * @param processDesc * @param map * add the outputs to the given map (create it if null) * @return map of name,Parameter representing the output results for this process */ public static Map<String, Parameter<?>> createOutputParamMap( ProcessDescriptionType processDesc, Map<String, Parameter<?>> map) { if (map == null) { map = new TreeMap<String, Parameter<?>>(); } // loop through the process desc and setup each output param ProcessOutputsType processOutputs = processDesc.getProcessOutputs(); if (processOutputs == null) return null; EList outputs = processOutputs.getOutput(); if (outputs == null || outputs.isEmpty()) return null; Iterator iterator = outputs.iterator(); while (iterator.hasNext()) { OutputDescriptionType odt = (OutputDescriptionType) iterator.next(); // determine if the output is a literal or complex data, and from that // find out what type the object should be LiteralOutputType literalOutput = odt.getLiteralOutput(); SupportedComplexDataType complexOutput = odt.getComplexOutput(); Class type = Object.class; if (literalOutput != null) { String reference = literalOutput.getDataType().getReference(); type = getLiteralTypeFromReference(reference); } else if (complexOutput != null) { // TODO: get all supported types and determine how to handle that, not just the // default. ComplexDataDescriptionType format = complexOutput.getDefault().getFormat(); String encoding = format.getEncoding(); String mimetype = format.getMimeType(); String schema = format.getSchema(); if (encoding == null) encoding = ""; if (mimetype == null) mimetype = ""; if (schema == null) schema = ""; type = getComplexType(encoding, mimetype, schema); } // create the parameter InternationalString description = Text.text(isAbstractNull(odt)? "" : odt.getAbstract().getValue()); Parameter param = new Parameter(odt.getIdentifier().getValue(), type, Text.text(odt .getTitle().getValue()), description); map.put(odt.getIdentifier().getValue(), param); } return map; } /** * Returns whether the abstract or its value of the given DescriptionType is null * @param description * @return */ public static boolean isAbstractNull(DescriptionType description ) { if( description.getAbstract() == null ) return true; if( description.getAbstract().getValue() == null ) return true; return false; } /** * Take a reference string and determine the literal type based from that * * @param reference * string * @return class type it maps to */ private static Class getLiteralTypeFromReference(String reference) { if ((reference.toUpperCase()).contains("DOUBLE")) { return Double.class; } else if ((reference.toUpperCase()).contains("INTEGER")) { return Integer.class; } else if ((reference.toUpperCase()).contains("FLOAT")) { return Float.class; } else if ((reference.toUpperCase()).contains("BOOLEAN")) { return boolean.class; } else if ((reference.toUpperCase()).contains("CHAR")) { return Character.class; } else if ((reference.toUpperCase()).contains("STRING")) { return String.class; } // default to string return String.class; } /** * Take the encoding, mimetype and schema and determine the complex type based from that * * @param encoding * string * @param mimetype * string * @param schema * string * @return class type it maps to */ private static Class getComplexType(String encoding, String mimetype, String schema) { if ((encoding.toUpperCase()).contains("GML") || (mimetype.toUpperCase()).contains("GML") || (schema.toUpperCase()).contains("GML")) { return Geometry.class; } else if ((encoding.toUpperCase()).contains("POLYGON") || (mimetype.toUpperCase()).contains("POLYGON") || (schema.toUpperCase()).contains("POLYGON")) { return Geometry.class; } else if ((encoding.toUpperCase()).contains("POINT") || (mimetype.toUpperCase()).contains("POINT") || (schema.toUpperCase()).contains("POINT")) { return Geometry.class; } else if ((encoding.toUpperCase()).contains("LINE") || (mimetype.toUpperCase()).contains("LINE") || (schema.toUpperCase()).contains("LINE")) { return Geometry.class; } else if ((encoding.toUpperCase()).contains("RING") || (mimetype.toUpperCase()).contains("RING") || (schema.toUpperCase()).contains("RING")) { return Geometry.class; } // default to big O return Object.class; } /** * Go through the ExecuteResponseType response object and put all the output results into a * result map. * * @param ert * the execute response object * @param map * the map to store the results in (will be created if null) * @return the results in a key,Object map */ public static Map<String, Object> createResultMap(ExecuteResponseType ert, Map<String, Object> map) { if (map == null) { map = new TreeMap<String, Object>(); } EList outputs = ert.getProcessOutputs().getOutput(); if (outputs == null) return null; Iterator iterator = outputs.iterator(); while (iterator.hasNext()) { OutputDataType odt = (OutputDataType) iterator.next(); DataType data = odt.getData(); ComplexDataType complexData = data.getComplexData(); LiteralDataType literalData = data.getLiteralData(); if (literalData != null) { // use the converters api to try and create an object of the type // we want (default to the String value if it failed). Object value = literalData.getValue(); if (literalData.getDataType() != null) { Class type = getLiteralTypeFromReference(literalData.getDataType()); Object convertedValue = Converters.convert(literalData.getValue(), type); if (convertedValue != null) value = convertedValue; } map.put(odt.getIdentifier().getValue(), value); } else if (complexData != null) { // if we have a list of values for this output, store it as a arraylist EList datas = complexData.getData(); if (datas.size() > 1) { Iterator iterator2 = datas.iterator(); List<Object> values = new ArrayList<Object>(); while (iterator2.hasNext()) { Object value = iterator2.next(); values.add(value); } map.put(odt.getIdentifier().getValue(), values); } else { map.put(odt.getIdentifier().getValue(), datas.get(0)); } } } return map; } }