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 }