001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wps/execute/ExecuteRequestHandler.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/exse/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstraße 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041     
042     ---------------------------------------------------------------------------*/
043    package org.deegree.ogcwebservices.wps.execute;
044    
045    import java.util.HashMap;
046    import java.util.List;
047    import java.util.Map;
048    
049    import org.deegree.datatypes.Code;
050    import org.deegree.datatypes.values.TypedLiteral;
051    import org.deegree.framework.log.ILogger;
052    import org.deegree.framework.log.LoggerFactory;
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: apoth $
076     * 
077     * @version $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
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
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",
199                                                          "Store is not supported by this WPServer instance." );
200                // handleStatusParameter(process, executeRequest, executeResponse);
201    
202            }
203    
204            // Get configured process outputs
205            ProcessOutputs configuredProcessOutputs = process.getProcessDescription().getProcessOutputs();
206    
207            // Get list of outputdescriptions from configured process outputs
208            List<OutputDescription> outputDescriptionsList = configuredProcessOutputs.getOutput();
209    
210            /*
211             * @see OGC 05-007r4 Subclauses 10.3.1 and 10.3.2
212             * @see OGC 05-007r4 Table 27: If the store parameter is false, there is only one output,
213             *      and that output has a ComplexValue, then this ComplexValue shall be returned to the
214             *      client outside of any ExecuteResponse document.
215             * 
216             */
217            if ( 1 == outputDescriptionsList.size() ) {
218                OutputDescription outputDescription = outputDescriptionsList.get( 0 );
219    
220                ComplexData complexOutput = outputDescription.getComplexOutput();
221    
222                if ( null != complexOutput ) {
223                    executeResponse.setDirectResponse( true );
224                    startProcess( process, executeRequest, executeResponse );
225                } else {
226                    handleStatusParameter( process, executeRequest, executeResponse );
227                }
228            } else {
229                handleStatusParameter( process, executeRequest, executeResponse );
230            }
231    
232        }
233    
234        /**
235         * 
236         * @param process
237         * @param executeRequest
238         * @param executeResponse
239         * @throws OGCWebServiceException
240         */
241        private static void handleStatusParameter( Process process, ExecuteRequest executeRequest,
242                                                   ExecuteResponse executeResponse )
243                                throws OGCWebServiceException {
244    
245            boolean status = executeRequest.isStatus();
246    
247            if ( status ) {
248    
249                // TODO status currently not supported (optional)
250                // @see OGC 05-007r4 Table 27
251                // @see OGC 05-007r4 Subclauses 10.3.1 and 10.3.2
252    
253                throw new InvalidParameterValueException( "status",
254                                                          "Status is not supported by this WPServer instance." );
255    
256                // save passed response at web accessible location, get full path
257                // and add it as statuslocation to response
258                // saveExecuteResponse();
259                // executeResponse.setStatusLocation(fullpath);
260    
261                // return response to client
262    
263                // startProcess(process, executeRequest, executeResponse);
264    
265                // update status to process started
266    
267                // updateSavedExecuteResponse();
268    
269            }
270            startProcess( process, executeRequest, executeResponse );
271    
272        }
273    
274        /**
275         * 
276         * @param process
277         * @param executeRequest
278         * @param executeResponse
279         * @throws OGCWebServiceException
280         */
281        private static void startProcess( Process process, ExecuteRequest executeRequest,
282                                          ExecuteResponse executeResponse )
283                                throws OGCWebServiceException {
284    
285            // Extract map of provided inputs from request
286            Map<String, IOValue> inputs = extractProcessInputs( process.getProcessDescription(),
287                                                                executeRequest );
288    
289            // Extract outputDefinitions from request
290            OutputDefinitions outputDefinitions = executeRequest.getOutputDefinitions();
291    
292            ExecuteResponse.ProcessOutputs processOutputs = process.execute( inputs, outputDefinitions );
293    
294            if ( null != processOutputs ) {
295    
296                // Update status in response to successfull
297                Status status = executeResponse.getStatus();
298                status.setProcessSucceeded( "The "
299                                            + process.getProcessDescription().getIdentifier().getCode()
300                                            + " process has been successfully completed" );
301                executeResponse.setStatus( status );
302    
303                // Add processOutputs to response
304                executeResponse.setProcessOutputs( processOutputs );
305            }
306        }
307    
308        /**
309         * Extract required process inputs from <code>ExecuteRequest</code>
310         * 
311         * @param executeRequest
312         * @return processInputs
313         * @throws MissingParameterValueException
314         * @throws InvalidParameterValueException
315         */
316        private static Map<String, IOValue> extractProcessInputs(
317                                                                  ProcessDescription processDescription,
318                                                                  ExecuteRequest executeRequest )
319                                throws MissingParameterValueException, InvalidParameterValueException {
320    
321            // TODO if complexvaluereferences are included --> load data via a new
322            // threaded method
323    
324            // Get inputs provided in executerequest
325            ExecuteDataInputs executeDataInputs = executeRequest.getDataInputs();
326            Map<String, IOValue> providedInputs = executeDataInputs.getInputs();
327    
328            // Prepare result map
329            Map<String, IOValue> processInputs = null;
330    
331            // Get required process inputs from processDescription
332            DataInputs configuredDataInputs = processDescription.getDataInputs();
333            List<InputDescription> inputDescriptions = configuredDataInputs.getInputDescriptions();
334    
335            // Get inputDescription for each configured input
336            int size = inputDescriptions.size();
337    
338            if ( 0 < size ) {
339                processInputs = new HashMap<String, IOValue>( size );
340    
341                for ( int i = 0; i < size; i++ ) {
342    
343                    InputDescription inputDescription = inputDescriptions.get( i );
344                    String identifier = inputDescription.getIdentifier().getCode();
345                    int minOccurs = inputDescription.getMinimumOccurs();
346    
347                    IOValue ioValue = providedInputs.get( identifier );
348    
349                    if ( null == ioValue && 1 == minOccurs ) {
350                        throw new MissingParameterValueException( identifier,
351                                                                  "A required process input is missing" );
352                    }
353    
354                    if ( inputDescription.isBoundingBoxData() ) {
355                        Envelope boundingBoxValue = ioValue.getBoundingBoxValue();
356                        if ( null == boundingBoxValue ) {
357                            throw new InvalidParameterValueException( identifier,
358                                                                      "The type of the provided process input is wrong" );
359                        }
360    
361                    } else if ( inputDescription.isLiteralData() ) {
362                        TypedLiteral literalValue = ioValue.getLiteralValue();
363                        if ( null == literalValue ) {
364                            throw new InvalidParameterValueException( identifier,
365                                                                      "The type of the provided process input is wrong" );
366                        }
367    
368                    } else if ( inputDescription.isComplexData() ) {
369                        ComplexValue complexValue = ioValue.getComplexValue();
370                        ComplexValueReference complexValuereference = ioValue.getComplexValueReference();
371                        if ( null == complexValue && null == complexValuereference ) {
372                            throw new InvalidParameterValueException( identifier,
373                                                                      "The type of the provided process input is wrong" );
374                        }
375                    }
376    
377                    // TODO load complexvaluereference, add as IOValue to
378                    // ProcessInputsmap
379    
380                    LOG.logDebug( "Found required process input '" + identifier
381                                  + "' in execute request." );
382    
383                    processInputs.put( identifier, ioValue );
384                }
385            }
386    
387            return processInputs;
388        }
389    
390    }