/* Copyright (c) 2001 - 2007 TOPP - 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.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.xml.datatype.XMLGregorianCalendar; import net.opengis.ows11.CodeType; import net.opengis.wps10.ComplexDataType; import net.opengis.wps10.DataType; import net.opengis.wps10.DocumentOutputDefinitionType; import net.opengis.wps10.ExecuteResponseType; import net.opengis.wps10.ExecuteType; import net.opengis.wps10.InputReferenceType; import net.opengis.wps10.InputType; import net.opengis.wps10.LiteralDataType; import net.opengis.wps10.MethodType; import net.opengis.wps10.OutputDataType; import net.opengis.wps10.OutputDefinitionsType; import net.opengis.wps10.OutputReferenceType; import net.opengis.wps10.ProcessBriefType; import net.opengis.wps10.ProcessFailedType; import net.opengis.wps10.ProcessOutputsType1; import net.opengis.wps10.Wps10Factory; import org.geoserver.config.GeoServerInfo; import org.geoserver.ows.Ows11Util; import org.geoserver.ows.URLMangler.URLType; import org.geoserver.ows.util.RequestUtils; import org.geoserver.ows.util.ResponseUtils; import org.geoserver.platform.ServiceException; import org.geoserver.wps.ppio.ComplexPPIO; import org.geoserver.wps.ppio.LiteralPPIO; import org.geoserver.wps.ppio.ProcessParameterIO; import org.geoserver.wps.ppio.ReferencePPIO; import org.geoserver.wps.ppio.XMLPPIO; import org.geotools.data.Parameter; import org.geotools.feature.NameImpl; import org.geotools.process.Process; import org.geotools.process.ProcessFactory; import org.geotools.process.Processors; import org.geotools.util.Converters; import org.geotools.xml.EMFUtils; import org.opengis.feature.type.Name; import org.springframework.context.ApplicationContext; /** * Main class used to handle Execute requests * * @author Lucas Reed, Refractions Research Inc */ public class Execute { WPSInfo wps; GeoServerInfo gs; ApplicationContext context; public Execute(WPSInfo wps, GeoServerInfo gs, ApplicationContext context) { this.wps = wps; this.gs = gs; this.context = context; } /** * Main method for performing decoding, execution, and response * * @param object * @param output * @throws IllegalArgumentException */ public ExecuteResponseType run(ExecuteType request) { //note the current time Date started = Calendar.getInstance().getTime(); //load the process factory CodeType ct = request.getIdentifier(); Name processName = Ows11Util.name(ct); ProcessFactory pf = Processors.createProcessFactory(processName); if ( pf == null ) { throw new WPSException( "No such process: " + processName ); } //parse the inputs for the request Map<String, Object> inputs = new HashMap(); for ( Iterator i = request.getDataInputs().getInput().iterator(); i.hasNext(); ) { InputType input = (InputType) i.next(); //locate the parameter for this request Parameter p = pf.getParameterInfo(processName).get( input.getIdentifier().getValue() ); if ( p == null ) { throw new WPSException( "No such parameter: " + input.getIdentifier().getValue() ); } //find the ppio ProcessParameterIO ppio = ProcessParameterIO.find( p, context ); if ( ppio == null ) { throw new WPSException( "Unable to decode input: " + input.getIdentifier().getValue() ); } //read the data Object decoded = null; if ( input.getReference() != null ) { //this is a reference InputReferenceType ref = input.getReference(); //grab the location and method String href = ref.getHref(); MethodType meth = ref.getMethod() != null ? ref.getMethod() : MethodType.GET_LITERAL; //handle get vs post if ( meth == MethodType.POST_LITERAL ) { //post, handle the body } else { //get, parse kvp } } else { //actual data, figure out which type DataType data = input.getData(); if ( data.getLiteralData() != null ) { LiteralDataType literal = data.getLiteralData(); decoded = ((LiteralPPIO)ppio).decode( literal.getValue() ); } else if ( data.getComplexData() != null ) { ComplexDataType complex = data.getComplexData(); decoded = complex.getData().get( 0 ); try { decoded = ((ComplexPPIO)ppio).decode( decoded ); } catch (Exception e) { throw new WPSException( "Unable to decode input: " + input.getIdentifier().getValue() ); } } } //decode the input inputs.put( p.key, decoded ); } //execute the process Map<String,Object> result = null; Throwable error = null; try { Process p = pf.create(processName); result = p.execute( inputs, null ); } catch( Throwable t ) { //save the error to report back error = t; } //build the response Wps10Factory f = Wps10Factory.eINSTANCE; ExecuteResponseType response = f.createExecuteResponseType(); response.setLang("en"); response.setServiceInstance(ResponseUtils.appendQueryString(ResponseUtils.buildURL(request.getBaseUrl(), "ows", null, URLType.SERVICE), "")); //process final ProcessBriefType process = f.createProcessBriefType(); response.setProcess( process ); process.setIdentifier(ct); process.setProcessVersion(pf.getVersion(processName)); process.setTitle( Ows11Util.languageString( pf.getTitle(processName).toString() ) ); process.setAbstract( Ows11Util.languageString( pf.getDescription(processName).toString() ) ); //status response.setStatus( f.createStatusType() ); response.getStatus().setCreationTime( Converters.convert( started, XMLGregorianCalendar.class )); if ( error != null ) { ProcessFailedType failure = f.createProcessFailedType(); response.getStatus().setProcessFailed( failure ); failure.setExceptionReport( Ows11Util.exceptionReport( new ServiceException( error ), wps.getGeoServer().getGlobal().isVerboseExceptions()) ); } else { response.getStatus().setProcessSucceeded( "Process succeeded."); } //inputs response.setDataInputs( f.createDataInputsType1() ); for ( Iterator i = request.getDataInputs().getInput().iterator(); i.hasNext(); ) { InputType input = (InputType) i.next(); response.getDataInputs().getInput().add( EMFUtils.clone( input, f, true ) ); } //output definitions OutputDefinitionsType outputs = f.createOutputDefinitionsType(); response.setOutputDefinitions( outputs ); Map<String,Parameter<?>> outs = pf.getResultInfo(processName, null); Map<String,ProcessParameterIO> ppios = new HashMap(); for ( String key : result.keySet() ) { Parameter p = pf.getResultInfo(processName, null).get( key ); if ( p == null ) { throw new WPSException( "No such output: " + key ); } //find the ppio ProcessParameterIO ppio = ProcessParameterIO.find( p, context ); if ( ppio == null ) { throw new WPSException( "Unable to encode output: " + p.key ); } ppios.put( p.key, ppio ); DocumentOutputDefinitionType output = f.createDocumentOutputDefinitionType(); outputs.getOutput().add( output ); output.setIdentifier( Ows11Util.code( p.key ) ); if ( ppio instanceof ComplexPPIO ) { output.setMimeType( ((ComplexPPIO) ppio).getMimeType() ); } //TODO: encoding + schema } //process outputs ProcessOutputsType1 processOutputs = f.createProcessOutputsType1(); response.setProcessOutputs( processOutputs ); for ( String key : result.keySet() ) { OutputDataType output = f.createOutputDataType(); output.setIdentifier(Ows11Util.code(key)); output.setTitle(Ows11Util.languageString(pf.getResultInfo(processName, null).get( key ).description)); processOutputs.getOutput().add( output ); final Object o = result.get( key ); ProcessParameterIO ppio = ppios.get( key ); if ( ppio instanceof ReferencePPIO ) { //encode as a reference OutputReferenceType ref = f.createOutputReferenceType(); output.setReference( ref ); //TODO: mime type ref.setHref( ((ReferencePPIO) ppio).encode(o).toString() ); } else { //encode as data DataType data = f.createDataType(); output.setData( data ); if ( ppio instanceof LiteralPPIO ) { LiteralDataType literal = f.createLiteralDataType(); data.setLiteralData( literal ); literal.setValue( ((LiteralPPIO) ppio).encode( o ) ); } else if ( ppio instanceof ComplexPPIO ) { ComplexDataType complex = f.createComplexDataType(); data.setComplexData( complex ); ComplexPPIO cppio = (ComplexPPIO) ppio; complex.setMimeType( cppio.getMimeType() ); if ( cppio instanceof XMLPPIO ) { //encode directly complex.getData().add( new ComplexDataEncoderDelegate( (XMLPPIO) cppio, o ) ); } else { //TODO: handle other content types, perhaps as CDATA } } } } return response; } // @SuppressWarnings("unchecked") // private void outputs(Map<String, Object> outputs) { // ProcessFactory pf = this.executor.getProcessFactory(); // ProcessOutputsType1 processOutputs = WpsFactory.eINSTANCE.createProcessOutputsType1(); // // for(String outputName : outputs.keySet()) { // Parameter<?> param = (pf.getResultInfo(null)).get(outputName); // // OutputDataType output = WpsFactory.eINSTANCE.createOutputDataType(); // // CodeType identifier = Ows11Factory.eINSTANCE.createCodeType(); // identifier.setValue(param.key); // output.setIdentifier(identifier); // // LanguageStringType title = Ows11Factory.eINSTANCE.createLanguageStringType(); // title.setValue(param.title.toString(this.locale)); // output.setTitle(title); // // DataType data = WpsFactory.eINSTANCE.createDataType(); // // // Determine the output type, Complex or Literal // Object outputParam = outputs.get(outputName); // // final Transmuter transmuter = this.dataTransformer.getDefaultTransmuter(outputParam.getClass()); // // // Create appropriate response document node for given type // if (transmuter instanceof ComplexTransmuter) { // data.setComplexData(this.complexData((ComplexTransmuter)transmuter, outputParam)); // } else { // if (transmuter instanceof LiteralTransmuter) { // data.setLiteralData(this.literalData((LiteralTransmuter)transmuter, outputParam)); // } else { // throw new WPSException("NoApplicableCode", "Could not find transmuter for output " + outputName); // } // } // // output.setData(data); // // processOutputs.getOutput().add(output); // } // // this.response.setProcessOutputs(processOutputs); // } // // private LiteralDataType literalData(LiteralTransmuter transmuter, Object value) { // LiteralDataType data = WpsFactory.eINSTANCE.createLiteralDataType(); // // data.setValue( transmuter.encode(value)); // data.setDataType(transmuter.getEncodedType()); // // return data; // } // // @SuppressWarnings("unchecked") // private ComplexDataType complexData(ComplexTransmuter transmuter, Object value) { // ComplexDataType data = WpsFactory.eINSTANCE.createComplexDataType(); // // data.setSchema( transmuter.getSchema(this.request.getBaseUrl())); // data.setMimeType(transmuter.getMimeType()); // data.getData().add(value); // // return data; // } // // private void processBrief() { // ProcessFactory pf = this.executor.getProcessFactory(); // ProcessBriefType brief = WpsFactory.eINSTANCE.createProcessBriefType(); // LanguageStringType title = Ows11Factory.eINSTANCE.createLanguageStringType(); // // brief.setProcessVersion(pf.getVersion()); // brief.setIdentifier(this.request.getIdentifier()); // title.setValue(pf.getTitle().toString(this.locale)); // brief.setTitle(title); // // this.response.setProcess(brief); // } // // private void status() { // StatusType status = WpsFactory.eINSTANCE.createStatusType(); // // status.setProcessSucceeded("Process completed successfully."); // // XMLGregorianCalendar calendar; // // try { // calendar = DatatypeFactory.newInstance().newXMLGregorianCalendar( // new GregorianCalendar(TimeZone.getTimeZone("UTC"))); // } catch(Exception e) { // throw new WPSException("NoApplicableCode", e.getMessage()); // } // // status.setCreationTime(calendar); // // this.response.setStatus(status); // } }