001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_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    }