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 }