    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_testing/src/org/deegree/ogcwebservices/wps/execute/ExecuteRequestHandler.java $
    002    /*----------------------------------------------------------------------------
    003     This file is part of deegree, http://deegree.org/
    004     Copyright (C) 2001-2009 by:
    005       Department of Geography, University of Bonn
    006     and
    007       lat/lon GmbH
    008
    009     This library is free software; you can redistribute it and/or modify it under
    010     the terms of the GNU Lesser General Public License as published by the Free
    011     Software Foundation; either version 2.1 of the License, or (at your option)
    012     any later version.
    013     This library is distributed in the hope that it will be useful, but WITHOUT
    014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
    016     details.
    017     You should have received a copy of the GNU Lesser General Public License
    018     along with this library; if not, write to the Free Software Foundation, Inc.,
    019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    020
    021     Contact information:
    022
    023     lat/lon GmbH
    024     Aennchenstr. 19, 53177 Bonn
    025     Germany
    026     http://lat-lon.de/
    027
    028     Department of Geography, University of Bonn
    029     Prof. Dr. Klaus Greve
    030     Postfach 1147, 53001 Bonn
    031     Germany
    032     http://www.geographie.uni-bonn.de/deegree/
    033
    034     e-mail: info@deegree.org
    035    ----------------------------------------------------------------------------*/
    036    package org.deegree.ogcwebservices.wps.execute;
    037
    038    import java.io.DataOutputStream;
    039    import java.io.InputStream;
    040    import java.io.InputStreamReader;
    041    import java.net.HttpURLConnection;
    042    import java.net.URL;
    043    import java.util.HashMap;
    044    import java.util.List;
    045    import java.util.Map;
    046
    047    import org.deegree.datatypes.Code;
    048    import org.deegree.datatypes.values.TypedLiteral;
    049    import org.deegree.framework.log.ILogger;
    050    import org.deegree.framework.log.LoggerFactory;
    051    import org.deegree.model.feature.FeatureCollection;
    052    import org.deegree.model.feature.GMLFeatureCollectionDocument;
    053    import org.deegree.model.spatialschema.Envelope;
    054    import org.deegree.ogcwebservices.InvalidParameterValueException;
    055    import org.deegree.ogcwebservices.MissingParameterValueException;
    056    import org.deegree.ogcwebservices.OGCWebServiceException;
    057    import org.deegree.ogcwebservices.wps.ServerBusyException;
    058    import org.deegree.ogcwebservices.wps.WPService;
    059    import org.deegree.ogcwebservices.wps.configuration.WPSConfiguration;
    060    import org.deegree.ogcwebservices.wps.describeprocess.ComplexData;
    061    import org.deegree.ogcwebservices.wps.describeprocess.InputDescription;
    062    import org.deegree.ogcwebservices.wps.describeprocess.OutputDescription;
    063    import org.deegree.ogcwebservices.wps.describeprocess.ProcessDescription;
    064    import org.deegree.ogcwebservices.wps.describeprocess.ProcessDescription.DataInputs;
    065    import org.deegree.ogcwebservices.wps.describeprocess.ProcessDescription.ProcessOutputs;
    066    import org.deegree.ogcwebservices.wps.execute.IOValue.ComplexValueReference;
    067
    068    /**
    069     * WPSExecuteRequestHandler.java
    070     *
    071     * Created on 10.03.2006. 12:11:28h
    072     *
    073     * @author <a href="mailto:christian@kiehle.org">Christian Kiehle</a>
    074     * @author <a href="mailto:christian.heier@gmx.de">Christian Heier</a>
    075     * @author last edited by: $Author: mschneider $
    076     *
    077     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
    078     */
    079    public class ExecuteRequestHandler {
    080
    081        private static final ILogger LOG = LoggerFactory.getLogger( ExecuteRequestHandler.class );
    082
    083        private WPService wpService = null;
    084
    085        private static WPSConfiguration wpsConfiguration = null;
    086
    087        /**
    088         *
    089         * @param wpService
    090         */
    091        public ExecuteRequestHandler( WPService wpService ) {
    092            this.wpService = wpService;
    093            // Get configuration from current wps instance
    094            wpsConfiguration = this.wpService.getConfiguration();
    095        }
    096
    097        /**
    098         *
    099         * @param executeRequest
    100         * @return the response
    101         * @throws OGCWebServiceException
    102         */
    103        public ExecuteResponse handleRequest( ExecuteRequest executeRequest )
    104                                throws OGCWebServiceException {
    105
    106            // Get the map of registered Processes from wps configuration
    107            Map<String, Process> registeredProcessesMap = wpsConfiguration.getRegisteredProcesses();
    108
    109            // Get the identifier of the process to be executed from the
    110            // ExecuteRequest
    111            Code executeProcessIdentifier = executeRequest.getIdentifier();
    112
    113            // Get the requested process from the registered processes
    114            Process process = registeredProcessesMap.get( executeProcessIdentifier.getCode().toUpperCase() );
    115
    116            if ( null == process ) {
    117
    118                // Unknown process was requested
    119                String msg = "A process with identifier '" + executeRequest.getIdentifier().getCode()
    120                             + "' is not known to this wpserver.";
    121                LOG.logDebug( msg );
    122                throw new InvalidParameterValueException( getClass().getName(), msg );
    123            }
    124
    125            // Get request queue manager from configuration
    126            RequestQueueManager requestQueueManager = wpsConfiguration.getDeegreeParams().getRequestQueueManager();
    127
    128            // add current request to queue
    129            boolean success = requestQueueManager.addRequestToQueue( executeRequest );
    130
    131            Status status = null;
    132
    133            if ( success ) {
    134                status = new Status();
    135                String msg = "Your execute request has been successfully added to the RequestQueue. The current length of the RequestQueue is "
    136                             + requestQueueManager.getLengthOfQueue();
    137                LOG.logDebug( msg );
    138                status.setProcessAccepted( msg );
    139            } else {
    140                String msg = "The server is too busy to accept and queue the request at this time.";
    141                LOG.logError( msg );
    142                throw new ServerBusyException( msg );
    143            }
    144
    145            // TODO implement multiple threads handling
    146            if ( 0 < requestQueueManager.getLengthOfQueue() ) {
    147                executeRequest = requestQueueManager.getRequestFromQueue();
    148            }
    149
    150            // Instantiate new execute response
    151            // this response will be populated during the following workflow
    152            ExecuteResponse executeResponse = new ExecuteResponse();
    153
    154            // Set identifier in response according to requested process
    155            executeResponse.setIdentifier( process.getProcessDescription().getIdentifier() );
    156
    157            // Add current status to response
    158            executeResponse.setStatus( status );
    159
    160            // Set version in response according to configuration
    161            executeResponse.setVersion( wpsConfiguration.getVersion() );
    162
    163            // Copy inputs from request to response
    164            ExecuteDataInputs executeDataInputs = executeRequest.getDataInputs();
    165            if ( null != executeDataInputs ) {
    166                executeResponse.setDataInputs( executeDataInputs );
    167            }
    168
    169            // Copy outputdefinitions from request to response
    170            OutputDefinitions outputDefinitions = executeRequest.getOutputDefinitions();
    171            if ( null != outputDefinitions ) {
    172                executeResponse.setOutputDefinitions( outputDefinitions );
    173            }
    174
    175            handleStoreParameter( process, executeRequest, executeResponse );
    176
    177            return executeResponse;
    178        }
    179
    180        /**
    181         *
    182         * @param process
    183         * @param executeRequest
    184         * @param executeResponse
    185         * @throws OGCWebServiceException
    186         */
    187        private static void handleStoreParameter( Process process, ExecuteRequest executeRequest,
    188                                                  ExecuteResponse executeResponse )
    189                                throws OGCWebServiceException {
    190
    191            boolean store = executeRequest.isStore();
    192
    193            if ( store ) {
    194
    195                // TODO store (optional) currently not supported
    196                // @see OGC 05-007r4 Table 27
    197                // @see OGC 05-007r4 Subclauses 10.3.1 and 10.3.2
    198                throw new InvalidParameterValueException( "store", "Store is not supported by this WPServer instance." );
    199                // handleStatusParameter(process, executeRequest, executeResponse);
    200
    201            }
    202
    203            // Get configured process outputs
    204            ProcessOutputs configuredProcessOutputs = process.getProcessDescription().getProcessOutputs();
    205
    206            // Get list of outputdescriptions from configured process outputs
    207            List<OutputDescription> outputDescriptionsList = configuredProcessOutputs.getOutput();
    208
    209            /*
    210             * @see OGC 05-007r4 Subclauses 10.3.1 and 10.3.2
    211             * @see OGC 05-007r4 Table 27: If the store parameter is false, there is only one output,
    212             *      and that output has a ComplexValue, then this ComplexValue shall be returned to the
    213             *      client outside of any ExecuteResponse document.
    214             *
    215             */
    216            if ( 1 == outputDescriptionsList.size() ) {
    217                OutputDescription outputDescription = outputDescriptionsList.get( 0 );
    218
    219                ComplexData complexOutput = outputDescription.getComplexOutput();
    220
    221                if ( null != complexOutput ) {
    222                    executeResponse.setDirectResponse( true );
    223                    startProcess( process, executeRequest, executeResponse );
    224                } else {
    225                    handleStatusParameter( process, executeRequest, executeResponse );
    226                }
    227            } else {
    228                handleStatusParameter( process, executeRequest, executeResponse );
    229            }
    230
    231        }
    232
    233        /**
    234         *
    235         * @param process
    236         * @param executeRequest
    237         * @param executeResponse
    238         * @throws OGCWebServiceException
    239         */
    240        private static void handleStatusParameter( Process process, ExecuteRequest executeRequest,
    241                                                   ExecuteResponse executeResponse )
    242                                throws OGCWebServiceException {
    243
    244            boolean status = executeRequest.isStatus();
    245
    246            if ( status ) {
    247
    248                // TODO status currently not supported (optional)
    249                // @see OGC 05-007r4 Table 27
    250                // @see OGC 05-007r4 Subclauses 10.3.1 and 10.3.2
    251
    252                throw new InvalidParameterValueException( "status", "Status is not supported by this WPServer instance." );
    253
    254                // save passed response at web accessible location, get full path
    255                // and add it as statuslocation to response
    256                // saveExecuteResponse();
    257                // executeResponse.setStatusLocation(fullpath);
    258
    259                // return response to client
    260
    261                // startProcess(process, executeRequest, executeResponse);
    262
    263                // update status to process started
    264
    265                // updateSavedExecuteResponse();
    266
    267            }
    268            startProcess( process, executeRequest, executeResponse );
    269
    270        }
    271
    272        /**
    273         *
    274         * @param process
    275         * @param executeRequest
    276         * @param executeResponse
    277         * @throws OGCWebServiceException
    278         */
    279        private static void startProcess( Process process, ExecuteRequest executeRequest, ExecuteResponse executeResponse )
    280                                throws OGCWebServiceException {
    281
    282            // Extract map of provided inputs from request
    283            Map<String, IOValue> inputs = extractProcessInputs( process.getProcessDescription(), executeRequest );
    284
    285            // Extract outputDefinitions from request
    286            OutputDefinitions outputDefinitions = executeRequest.getOutputDefinitions();
    287
    288            ExecuteResponse.ProcessOutputs processOutputs = process.execute( inputs, outputDefinitions );
    289
    290            if ( null != processOutputs ) {
    291
    292                // Update status in response to successfull
    293                Status status = executeResponse.getStatus();
    294                status.setProcessSucceeded( "The " + process.getProcessDescription().getIdentifier().getCode()
    295                                            + " process has been successfully completed" );
    296                executeResponse.setStatus( status );
    297
    298                // Add processOutputs to response
    299                executeResponse.setProcessOutputs( processOutputs );
    300            }
    301        }
    302
    303        /**
    304         * Extract required process inputs from <code>ExecuteRequest</code>
    305         *
    306         * @param executeRequest
    307         * @return processInputs
    308         * @throws OGCWebServiceException
    309         */
    310        private static Map<String, IOValue> extractProcessInputs( ProcessDescription processDescription,
    311                                                                  ExecuteRequest executeRequest )
    312                                throws OGCWebServiceException {
    313
    314            // TODO if complexvaluereferences are included --> load data via a new
    315            // threaded method
    316
    317            // Get inputs provided in executerequest
    318            ExecuteDataInputs executeDataInputs = executeRequest.getDataInputs();
    319            Map<String, IOValue> providedInputs = executeDataInputs.getInputs();
    320
    321            // Prepare result map
    322            Map<String, IOValue> processInputs = null;
    323
    324            // Get required process inputs from processDescription
    325            DataInputs configuredDataInputs = processDescription.getDataInputs();
    326            List<InputDescription> inputDescriptions = configuredDataInputs.getInputDescriptions();
    327
    328            // Get inputDescription for each configured input
    329            int size = inputDescriptions.size();
    330
    331            if ( 0 < size ) {
    332                processInputs = new HashMap<String, IOValue>( size );
    333
    334                for ( int i = 0; i < size; i++ ) {
    335
    336                    InputDescription inputDescription = inputDescriptions.get( i );
    337                    String identifier = inputDescription.getIdentifier().getCode();
    338                    int minOccurs = inputDescription.getMinimumOccurs();
    339
    340                    IOValue ioValue = providedInputs.get( identifier );
    341
    342                    if ( null == ioValue && 1 == minOccurs ) {
    343                        throw new MissingParameterValueException( identifier, "A required process input is missing" );
    344                    }
    345
    346                    if ( inputDescription.isBoundingBoxData() ) {
    347                        Envelope boundingBoxValue = ioValue.getBoundingBoxValue();
    348                        if ( null == boundingBoxValue ) {
    349                            throw new InvalidParameterValueException( identifier,
    350                                                                      "The type of the provided process input is wrong" );
    351                        }
    352
    353                    } else if ( inputDescription.isLiteralData() ) {
    354                        TypedLiteral literalValue = ioValue.getLiteralValue();
    355                        if ( null == literalValue ) {
    356                            throw new InvalidParameterValueException( identifier,
    357                                                                      "The type of the provided process input is wrong" );
    358                        }
    359
    360                    } else if ( inputDescription.isComplexData() ) {
    361                        ComplexValue complexValue = ioValue.getComplexValue();
    362                        ComplexValueReference complexValuereference = ioValue.getComplexValueReference();
    363                        if ( null == complexValue && null == complexValuereference ) {
    364                            throw new InvalidParameterValueException( identifier,
    365                                                                      "The type of the provided process input is wrong" );
    366                        }
    367                        // complexValuereference Implementation provided by Beate Stollberg
    368                        if ( complexValuereference != null ) {
    369
    370                            try {
    371                                LOG.logInfo( "complexValuereference.reference.toString() "
    372                                             + complexValuereference.reference.toString() );
    373                                String sReference = complexValuereference.reference.toString();
    374                                int nIndexQuestionmark = sReference.indexOf( "?" );
    375                                LOG.logInfo( "nIndexQuestionmark " + nIndexQuestionmark );
    376
    377                                FeatureCollection result = null;
    378
    379                                if ( nIndexQuestionmark != -1 ) {
    380                                    String[] asReference = new String[2];
    381                                    asReference[0] = sReference.substring( 0, nIndexQuestionmark );
    382                                    asReference[1] = sReference.substring( nIndexQuestionmark + 1 );
    383                                    URL url = new URL( asReference[0] );
    384                                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    385                                    conn.setRequestMethod( "GET" );
    386                                    conn.setUseCaches( false );
    387                                    conn.setDoInput( true );
    388                                    conn.setDoOutput( true );
    389                                    DataOutputStream dos = new DataOutputStream( conn.getOutputStream() );
    390                                    dos.writeBytes( asReference[1] );
    391                                    dos.close();
    392                                    InputStream in = conn.getInputStream();
    393                                    InputStreamReader isr = new InputStreamReader( in );
    394                                    GMLFeatureCollectionDocument doc = new GMLFeatureCollectionDocument();
    395                                    doc.load( isr, url.toString() );
    396                                    result = doc.parse();
    397                                } else {
    398                                    GMLFeatureCollectionDocument doc = new GMLFeatureCollectionDocument();
    399                                    doc.load( new URL( sReference ) );
    400                                    result = doc.parse();
    401                                }
    402                                ComplexValue cv = new ComplexValue( complexValuereference.format,
    403                                                                    complexValuereference.encoding,
    404                                                                    complexValuereference.schema, result );
    405                                IOValue ioValueNew = new IOValue( ioValue.getIdentifier(), ioValue.getTitle(),
    406                                                                  ioValue.getAbstract(), ioValue.getBoundingBoxValue(), cv,
    407                                                                  null, null );
    408                                ioValue = ioValueNew;
    409                            } catch ( Exception e ) {
    410                                throw new OGCWebServiceException(
    411                                                                  "Error occured while requesting ComplexData from ComplexValueReference! "
    412                                                                                          + e.getMessage() );
    413                            }
    414                        }
    415                    }
    416
    417                    LOG.logDebug( "Found required process input '" + identifier + "' in execute request." );
    418                    processInputs.put( identifier, ioValue );
    419                }
    420            }
    421            return processInputs;
    422        }
    423    }