content: /**
   * ﻿Copyright (C) 2007 - 2019 52°North Initiative for Geospatial Open Source
   * Software GmbH
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *    http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.n52.wps.client;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.UnsupportedEncodingException;
  import java.net.URLEncoder;
  import java.util.Arrays;
  
  import net.opengis.ows.x11.DomainMetadataType;
  import net.opengis.wps.x100.ComplexDataDescriptionType;
  import net.opengis.wps.x100.ComplexDataType;
  import net.opengis.wps.x100.DocumentOutputDefinitionType;
  import net.opengis.wps.x100.ExecuteDocument;
  import net.opengis.wps.x100.ExecuteDocument.Execute;
  import net.opengis.wps.x100.InputDescriptionType;
  import net.opengis.wps.x100.InputReferenceType;
  import net.opengis.wps.x100.InputType;
  import net.opengis.wps.x100.LiteralDataType;
  import net.opengis.wps.x100.OutputDefinitionType;
  import net.opengis.wps.x100.OutputDescriptionType;
  import net.opengis.wps.x100.ProcessDescriptionType;
  import net.opengis.wps.x100.ResponseDocumentType;
  import net.opengis.wps.x100.ResponseFormType;
  
  import org.apache.xmlbeans.XmlException;
  import org.apache.xmlbeans.XmlObject;
  import org.apache.xmlbeans.XmlString;
  import org.n52.wps.io.GeneratorFactory;
  import org.n52.wps.io.IGenerator;
  import org.n52.wps.io.IOHandler;
  import org.n52.wps.io.data.IData;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * @author foerster
   */
  public class ExecuteRequestBuilder {
  	ProcessDescriptionType processDesc;
  	ExecuteDocument execute;
  	String SUPPORTED_VERSION = "1.0.0";
  	
  	private static Logger LOGGER = LoggerFactory.getLogger(ExecuteRequestBuilder.class);
  	
  
  	public ExecuteRequestBuilder(ProcessDescriptionType processDesc) {
  		this.processDesc = processDesc;
  		execute = ExecuteDocument.Factory.newInstance();
  		Execute ex = execute.addNewExecute();
  		ex.setService("WPS");
  		ex.setVersion(SUPPORTED_VERSION);
  		ex.addNewIdentifier().setStringValue(processDesc.getIdentifier().getStringValue());
  		ex.addNewDataInputs();
  	}
  	
  	public ExecuteRequestBuilder(ProcessDescriptionType processDesc, ExecuteDocument execute) {
  		this.processDesc = processDesc;
  		this.execute = execute;
  	}
  	
  	/**
  	 * add an input element. sets the data in the xml request
  	 * 
  	 * @param parameterID the ID of the input (see process description)
  	 * @param value the actual value (for xml data xml for binary data is should be base64 encoded data)
  	 * @param schema schema if applicable otherwise null
  	 * @param encoding encoding if not the default encoding (for default encoding set it to null) (i.e. binary data, use base64)
  	 * @param mimeType mimetype of the data, has to be set
  	 * @throws WPSClientException
  	 */
  	public void addComplexData(String parameterID, IData value, String schema, String encoding, String mimeType) throws WPSClientException {
  		GeneratorFactory fac = StaticDataHandlerRepository.getGeneratorFactory();
  		InputDescriptionType inputDesc = getParameterDescription(parameterID);
  		if (inputDesc == null) {
  			throw new IllegalArgumentException("inputDesription is null for: " + parameterID);
  		}
  		if (inputDesc.getComplexData() == null) {
  			throw new IllegalArgumentException("inputDescription is not of type ComplexData: " + parameterID);			
  		}
  		
  			
  		LOGGER.debug("Looking for matching Generator ..." + 
  				" schema: " + schema +
  				" mimeType: " + mimeType +
  				" encoding: " + encoding);
  		
  		IGenerator generator = fac.getGenerator(schema, mimeType, encoding, value.getClass());
  		
  		if (generator == null) {
  			// generator is still null
  			throw new IllegalArgumentException("Could not find an appropriate generator for parameter: " + parameterID);
  		}
  		
  		
  		InputStream stream = null;
  
  		InputType input = execute.getExecute().getDataInputs().addNewInput();
  		input.addNewIdentifier().setStringValue(
  				inputDesc.getIdentifier().getStringValue());
  		// encoding is UTF-8 (or nothing and we default to UTF-8)
  		// everything that goes to this condition should be inline xml data
  		try {
  
  			if (encoding == null || encoding.equals("")
  					|| encoding.equalsIgnoreCase(IOHandler.DEFAULT_ENCODING)) {
  				stream = generator.generateStream(value, mimeType, schema);
  
  			} else if (encoding.equalsIgnoreCase("base64")) {
  				stream = generator
  						.generateBase64Stream(value, mimeType, schema);
  			} else {
  				throw new WPSClientException("Encoding not supported");
  			}
  			ComplexDataType data = input.addNewData().addNewComplexData();
  
  			setComplexData(data, stream, schema, mimeType, encoding);
  
  		} catch (IOException e) {
  			throw new IllegalArgumentException(
  					"error reading generator output", e);
  		}
  			
  	}
  
  	/**
  	 * add an input element. sets the data in the xml request
  	 * 
  	 * @param parameterID the ID of the input (see process description)
  	 * @param value the actual value as String (for xml data xml for binary data is should be base64 encoded data)
  	 * @param schema schema if applicable otherwise null
  	 * @param encoding encoding if not the default encoding (for default encoding set it to null) (i.e. binary data, use base64)
  	 * @param mimeType mimetype of the data, has to be set
  	 * @throws WPSClientException
  	 */
  	public void addComplexData(String parameterID, String value, String schema, String encoding, String mimeType) throws WPSClientException {
  		InputDescriptionType inputDesc = getParameterDescription(parameterID);
  		if (inputDesc == null) {
  			throw new IllegalArgumentException("inputDesription is null for: " + parameterID);
  		}
  		if (inputDesc.getComplexData() == null) {
  			throw new IllegalArgumentException("inputDescription is not of type ComplexData: " + parameterID);			
  		}	
  						
  		InputType input = execute.getExecute().getDataInputs().addNewInput();
  		input.addNewIdentifier().setStringValue(inputDesc.getIdentifier().getStringValue());
  		
  		ComplexDataType data = input.addNewData().addNewComplexData();
  		
  		setComplexData(data, value, schema, mimeType, encoding);
  			
  	}
  	
  	/**
  	 * add an input element. sets the data in the xml request
  	 * 
  	 * @param parameterID the ID of the input (see process description)
  	 * @param value the actual value as String (for xml data xml for binary data is should be base64 encoded data)
  	 * @param schema schema if applicable otherwise null
  	 * @param encoding encoding if not the default encoding (for default encoding set it to null) (i.e. binary data, use base64)
  	 * @param mimeType mimetype of the data, has to be set
  	 * @throws WPSClientException
  	 */
  	public void addComplexData(String parameterID, String value, String schema, String encoding, String mimeType, boolean asReference) throws WPSClientException {
  		
  		if(asReference){
  			addComplexDataReference(parameterID, value, schema, encoding, mimeType);
  		} else {
  
  			InputDescriptionType inputDesc = getParameterDescription(parameterID);
  			if (inputDesc == null) {
  				throw new IllegalArgumentException(
  						"inputDescription is null for: " + parameterID);
  			}
  			if (inputDesc.getComplexData() == null) {
  				throw new IllegalArgumentException(
  						"inputDescription is not of type ComplexData: "
  								+ parameterID);
  			}
  
  			InputType input = execute.getExecute().getDataInputs()
  					.addNewInput();
  			input.addNewIdentifier().setStringValue(
  					inputDesc.getIdentifier().getStringValue());
  
  			ComplexDataType data = input.addNewData().addNewComplexData();
  
  			setComplexData(data, value, schema, mimeType, encoding);
  		}
  			
  	}
  	
  	/**
  	 * add an input element. sets the data in the xml request
  	 * 
  	 * @param inputType
  	 * @throws WPSClientException
  	 */
  	public void addComplexData(InputType inputType) {
  		
  		String parameterID = inputType.getIdentifier().getStringValue();
  		
  		InputDescriptionType inputDesc = getParameterDescription(parameterID);
  		if (inputDesc == null) {
  			throw new IllegalArgumentException("inputDescription is null for: " + parameterID);
  		}
  		if (inputDesc.getComplexData() == null) {
  			throw new IllegalArgumentException("inputDescription is not of type ComplexData: " + parameterID);			
  		}	
  		
  		InputType[] newInputTypeArray;
  		
  		InputType[] currentInputTypeArray = execute.getExecute().getDataInputs().getInputArray();
  		
  		if(currentInputTypeArray != null){
  			newInputTypeArray = Arrays.copyOf(currentInputTypeArray, currentInputTypeArray.length + 1);
  		}else{
  			newInputTypeArray = new InputType[1];
  		}
  		
  		newInputTypeArray[newInputTypeArray.length - 1] = inputType;
  		
  		execute.getExecute().getDataInputs().setInputArray(newInputTypeArray);
  			
  	}
  	
  	/**
  	 * Add literal data to the request
  	 * @param parameterID the ID of the input paramter according to the describe process
  	 * @param value the value. other types than strings have to be converted to string. The datatype is automatically determined and set accordingly to the process description
  	 */
  	public void addLiteralData(String parameterID, String value) {
  		InputDescriptionType inputDesc = this.getParameterDescription(parameterID);
  		if (inputDesc == null) {
  			throw new IllegalArgumentException("inputDescription is null for: " + parameterID);
  		}
  		if (inputDesc.getLiteralData() == null) {
  			throw new IllegalArgumentException("inputDescription is not of type literalData: " + parameterID);			
  		}
  		InputType input = execute.getExecute().getDataInputs().addNewInput();
  		input.addNewIdentifier().setStringValue(parameterID);
  		input.addNewData().addNewLiteralData().setStringValue(value);
  		DomainMetadataType dataType = inputDesc.getLiteralData().getDataType();
  		if (dataType != null) {
  			input.getData().getLiteralData().setDataType(dataType.getReference());
  		}
  	}
  
  /**
   * Sets a reference to input data
   * 
   * @param parameterID ID of the input element
   * @param value reference URL
   * @param schema schema if applicable otherwise null
   * @param encoding encoding if applicable (typically not), otherwise null
   * @param mimetype mimetype of the input according to the process description. has to be set
   */
  	public void addComplexDataReference(String parameterID, String value, String schema, String encoding, String mimetype) {
  		InputDescriptionType inputDesc = getParameterDescription(parameterID);
  		if (inputDesc == null) {
  			throw new IllegalArgumentException("inputDescription is null for: " + parameterID);
  		}
  		if (inputDesc.getComplexData() == null) {
  			throw new IllegalArgumentException("inputDescription is not of type complexData: " + parameterID);
  		}
  			
  		InputType input = execute.getExecute().getDataInputs().addNewInput();
  		input.addNewIdentifier().setStringValue(parameterID);
  		input.addNewReference().setHref(value);
  		if (schema != null) {
  			input.getReference().setSchema(schema);
  		}
  
  		if (encoding != null) {
  			input.getReference().setEncoding(encoding);
  		}
  		if (mimetype != null) {
  			input.getReference().setMimeType(mimetype);
  		}
  	}
  
  	/**
  	 * checks, if the execute, which has been build is valid according to the process description.
  	 * @return
  	 */
  	public boolean isExecuteValid() {
  		return true;
  	}
  
  	/**
  	 * this sets store for the specific output.
  	 * @param parentInput
  	 * @return
  	 */
  	public boolean setStoreSupport(String outputName, boolean storeSupport) {
  //		DocumentOutputDefinitionType outputDef = null;		
  		
  		if (!execute.getExecute().isSetResponseForm()) {
  			execute.getExecute().addNewResponseForm();
  		}
  		
  		ResponseFormType responseForm = execute.getExecute().getResponseForm();
  		
  		if (!responseForm.isSetResponseDocument()) {
  			responseForm.addNewResponseDocument();
  		}
  		
  		ResponseDocumentType responseDocument = responseForm.getResponseDocument();
  		
  		responseDocument.setStoreExecuteResponse(storeSupport);
  		
  //		for(DocumentOutputDefinitionType outputDefTemp: responseDocument.getOutputArray()) {
  //			if(outputDefTemp.getIdentifier().getStringValue().equals(outputName)) {
  //				outputDef = outputDefTemp;
  //				break;
  //			}
  //		}
  //		if (outputDef == null) {
  //			outputDef = responseDocument.addNewOutput();
  //		}
  		
  		return true;
  	}
  	
  	/**
  	 * this sets store for the specific output.
  	 * @param parentInput
  	 * @return
  	 */
  	public boolean setAsReference(String outputName, boolean asReference) {
  		DocumentOutputDefinitionType outputDef = null;
  		if (!execute.getExecute().isSetResponseForm()) {
  			execute.getExecute().addNewResponseForm();
  		}
  		if (!execute.getExecute().getResponseForm().isSetResponseDocument()) {
  			execute.getExecute().getResponseForm().addNewResponseDocument();
  		}
  		for(DocumentOutputDefinitionType outputDefTemp: execute.getExecute().getResponseForm().getResponseDocument().getOutputArray()) {
  			if(outputDefTemp.getIdentifier().getStringValue().equals(outputName)) {
  				outputDef = outputDefTemp;
  				break;
  			}
  		}
  		if (outputDef == null) {
  			outputDef = execute.getExecute().getResponseForm()
  					.getResponseDocument().addNewOutput();
  		}
  		for (OutputDescriptionType outputDesc : processDesc.getProcessOutputs().getOutputArray()) {
  			if (outputDesc.getIdentifier().getStringValue().equals(outputName)) {
  				outputDef.setAsReference(asReference);
  			}
  		}
  		return true;
  	}
  
  	/**
  	 * this sets store for the specific output.
  	 * @param parentInput
  	 * @return
  	 */
  	public boolean setStatus(String outputName, boolean status) {
  		if (!execute.getExecute().isSetResponseForm()) {
  			execute.getExecute().addNewResponseForm();
  		}
  		
  		ResponseFormType responseForm = execute.getExecute().getResponseForm();
  		
  		if (!responseForm.isSetResponseDocument()) {
  			responseForm.addNewResponseDocument();
  		}
  		
  		ResponseDocumentType responseDocument = responseForm.getResponseDocument();
  		
  		responseDocument.setStatus(status);
  		
  		return true;
  	}
  	
  	/**
  	 * Set this if you want the data to a schema offered in the process description
  	 * @param schema
  	 * @param outputName
  	 * @return
  	 */
  	public boolean setSchemaForOutput(String schema, String outputName) {
  		if (!execute.getExecute().isSetResponseForm()) {
  			execute.getExecute().addNewResponseForm();
  		}
  		if (!execute.getExecute().getResponseForm().isSetResponseDocument()) {
  			execute.getExecute().getResponseForm().addNewResponseDocument();
  		}
  		OutputDescriptionType outputDesc = getOutputDescription(outputName);
  		DocumentOutputDefinitionType outputDef = getOutputDefinition(outputName);
  		if (outputDef == null) {
  			outputDef = execute.getExecute().getResponseForm()
  					.getResponseDocument().addNewOutput();
  			outputDef.setIdentifier(outputDesc.getIdentifier());
  		}
  		String defaultSchema = outputDesc.getComplexOutput().getDefault()
  				.getFormat().getSchema();
  		if ((defaultSchema != null && defaultSchema.equals(schema))
  				|| (defaultSchema == null && schema == null)) {
  			outputDef.setSchema(schema);
  			return true;
  		} else {
  			for (ComplexDataDescriptionType data : outputDesc
  					.getComplexOutput().getSupported().getFormatArray()) {
  				if (data.getSchema() != null && data.getSchema().equals(schema)) {
  					outputDef.setSchema(schema);
  					return true;
  				} else if ((data.getSchema() == null && schema == null)) {
  					return true;
  				}
  			}
  		}
  
  		return false;
  	}
  
  	/**
  	 * sets the desired mimetype of the output. if not set, the default mimetype will be used as stated in the process description
  	 * @param mimeType the name of the mimetype as announced in the processdescription
  	 * @param outputName the Identifier of the output element
  	 * @return success
  	 */
  	public boolean setMimeTypeForOutput(String mimeType, String outputName) {
  		if (!execute.getExecute().isSetResponseForm()) {
  			execute.getExecute().addNewResponseForm();
  		}
  		if (!execute.getExecute().getResponseForm().isSetResponseDocument()) {
  			execute.getExecute().getResponseForm().addNewResponseDocument();
  		}
  		OutputDescriptionType outputDesc = getOutputDescription(outputName);
  		DocumentOutputDefinitionType outputDef = getOutputDefinition(outputName);
  		if (outputDef == null) {
  			outputDef = execute.getExecute().getResponseForm()
  					.getResponseDocument().addNewOutput();
  			outputDef.setIdentifier(outputDesc.getIdentifier());
  		}
  
  		String defaultMimeType = outputDesc.getComplexOutput().getDefault()
  				.getFormat().getMimeType();
  		if (defaultMimeType == null) {
  			defaultMimeType = "text/xml";
  		}
  		if (defaultMimeType.equals(mimeType)) {
  			outputDef.setMimeType(mimeType);
  			return true;
  		} else {
  			for (ComplexDataDescriptionType data : outputDesc
  					.getComplexOutput().getSupported().getFormatArray()) {
  				String m = data.getMimeType();
  				if (m != null && m.equals(mimeType)) {
  					outputDef.setMimeType(mimeType);
  					return true;
  				}
  			}
  		}
  
  		return false;
  	}
  
  	/**
  	 * sets the encoding. necessary if data should not be retrieved in the default encoding (i.e. binary data in XML responses not raw data responses)
  	 * @param encoding use base64
  	 * @param outputName ID of the output
  	 * @return
  	 */
  	public boolean setEncodingForOutput(String encoding, String outputName) {
  		if (!execute.getExecute().isSetResponseForm()) {
  			execute.getExecute().addNewResponseForm();
  		}
  		if (!execute.getExecute().getResponseForm().isSetResponseDocument()) {
  			execute.getExecute().getResponseForm().addNewResponseDocument();
  		}
  		OutputDescriptionType outputDesc = getOutputDescription(outputName);
  		DocumentOutputDefinitionType outputDef = getOutputDefinition(outputName);
  		if (outputDef == null) {
  			outputDef = execute.getExecute().getResponseForm()
  					.getResponseDocument().addNewOutput();
  			outputDef.setIdentifier(outputDesc.getIdentifier());
  		}
  
  		String defaultEncoding = outputDesc.getComplexOutput().getDefault()
  				.getFormat().getEncoding();
  		if (defaultEncoding == null) {
  			defaultEncoding = IOHandler.DEFAULT_ENCODING;
  		}
  		if (defaultEncoding.equals(encoding)) {
  			return true;
  		} else {
  			ComplexDataDescriptionType[] supportedFormats = outputDesc
  					.getComplexOutput().getSupported().getFormatArray();
  			for (ComplexDataDescriptionType data : supportedFormats) {
  				String e = data.getEncoding();
  				if (e != null && e.equals(encoding)) {
  					outputDef.setEncoding(encoding);
  					return true;
  				}
  			}
  		}
  
  		return false;
  	}
  
  	private OutputDescriptionType getOutputDescription(String outputName) {
  		for (OutputDescriptionType outputDesc : processDesc.getProcessOutputs()
  				.getOutputArray()) {
  			if (outputDesc.getIdentifier().getStringValue().equals(outputName)) {
  				return outputDesc;
  			}
  		}
  
  		return null;
  	}
  
  	private DocumentOutputDefinitionType getOutputDefinition(String outputName) {
  		DocumentOutputDefinitionType[] outputs = execute.getExecute()
  				.getResponseForm().getResponseDocument().getOutputArray();
  		for (DocumentOutputDefinitionType outputDef : outputs) {
  			if (outputDef.getIdentifier().getStringValue().equals(outputName)) {
  				return outputDef;
  			}
  		}
  
  		return null;
  	}
  
  	public boolean setResponseDocument(String outputIdentifier, String schema, String encoding, String mimeType){
  		
  		if (!execute.getExecute().isSetResponseForm()) {
  			execute.getExecute().addNewResponseForm();
  		}
  		if (!execute.getExecute().getResponseForm().isSetResponseDocument()) {
  			execute.getExecute().getResponseForm().addNewResponseDocument();
  		}
  		OutputDescriptionType outputDesc = getOutputDescription(outputIdentifier);
  		DocumentOutputDefinitionType outputDef = getOutputDefinition(outputIdentifier);
  		if (outputDef == null) {
  			outputDef = execute.getExecute().getResponseForm()
  					.getResponseDocument().addNewOutput();
  			outputDef.setIdentifier(outputDesc.getIdentifier());
  			
  			if(schema != null){
  				outputDef.setSchema(schema);
  			}
  			if(encoding != null){
  				outputDef.setEncoding(encoding);
  			}
  			if(mimeType != null){
  				outputDef.setMimeType(mimeType);
  			}
  		}
  		
  		return false;
  	}
  	
  	/**
  	 * Asks for data as raw data, i.e. without WPS XML wrapping
  	 * @param schema if applicable otherwise null
  	 * @param encoding if default encoding = null, otherwise base64
  	 * @param mimeType requested mimetype of the output according to the process description. if not set, default mime type is used.
  	 * @return
  	 */
  	public boolean setRawData(String outputIdentifier, String schema, String encoding, String mimeType) {
  		
  		OutputDefinitionType output = execute.getExecute().addNewResponseForm().addNewRawDataOutput();
  		output.addNewIdentifier().setStringValue(outputIdentifier);
  		
  		if (schema != null) {
  			output.setSchema(schema);
  		}
  		if (mimeType != null) {
  			output.setMimeType(mimeType);
  		}
  		if (encoding != null) {
  			output.setEncoding(encoding);
  		}
  		return true;
  	}
  
  	/**
  	 * XML representation of the created request.
  	 * @return
  	 */
  	public ExecuteDocument getExecute() {
  		return execute;
  	}
  
  	/**
  	 * return a KVP representation for the created execute document.
  	 * @return KVP request string
  	 * @throws UnsupportedEncodingException if the URL encoding using UTF-8 fails
  	 */
  	public String getExecuteAsGETString() throws UnsupportedEncodingException {
  		String request = "?service=wps&request=execute&version=1.0.0&identifier=";
  		request = request + processDesc.getIdentifier().getStringValue();
  		request = request + "&DataInputs=";
  		InputType[] inputs = execute.getExecute().getDataInputs().getInputArray();
  		int inputCounter = 0;
  		for(InputType input : inputs){
  			
  			request = request + input.getIdentifier().getStringValue();
  			
  			if(input.isSetReference()){
  				//reference
  				InputReferenceType reference = input.getReference();
  				request = request + "="+"@xlink:href="+ URLEncoder.encode(reference.getHref(), "UTF-8");
  				if(reference.isSetEncoding()){
  					request = request + "@encoding="+reference.getEncoding();
  				}
  				if(reference.isSetMimeType()){
  					request = request + "@format="+reference.getMimeType();
  				}
  				if(reference.isSetEncoding()){
  					request = request + "@schema="+reference.getSchema();
  				}
  			}
  			if(input.isSetData()){
  				if(input.getData().isSetComplexData()){
  					//complex
  					ComplexDataType complexData = input.getData().getComplexData();
  					request = request + "=" + URLEncoder.encode(input.getData().getComplexData().xmlText(), "UTF-8");
  					if(complexData.isSetEncoding()){
  						request = request + "@encoding="+complexData.getEncoding();
  					}
  					if(complexData.isSetMimeType()){
  						request = request + "@format="+complexData.getMimeType();
  					}
  					if(complexData.isSetEncoding()){
  						request = request + "@schema="+complexData.getSchema();
  					}
  				}
  				if(input.getData().isSetLiteralData()){
  					//literal
  					LiteralDataType literalData = input.getData().getLiteralData();
  					request = request + "=" + literalData.getStringValue();
  					if(literalData.isSetDataType()){
  						request = request + "@datatype="+literalData.getDataType();
  					}
  					if(literalData.isSetUom()){
  						request = request + "@datatype="+literalData.getUom();
  					}
  				}
  			}
  			//concatenation for next input element
  			inputCounter = inputCounter +1;
  			if(inputCounter<inputs.length){
  				request = request + ";";
  			}
  			
  		}
  		if(execute.getExecute().getResponseForm().getResponseDocument()==null){
  			throw new RuntimeException("ResponseDocument missing");
  		}
  		DocumentOutputDefinitionType[] outputs = execute.getExecute().getResponseForm().getResponseDocument().getOutputArray();
  		int outputCounter = 0;
  		if(execute.getExecute().getResponseForm().isSetRawDataOutput()){
  			request = request + "&rawdataoutput=";
  		}else{
  			request = request + "&responsedocument=";
  		}
  		for(DocumentOutputDefinitionType output : outputs){
  			request = request + output.getIdentifier().getStringValue();
  			if(output.isSetEncoding()){
  				request = request + "@encoding="+output.getEncoding();
  			}
  			if(output.isSetMimeType()){
  				request = request + "@format="+output.getMimeType();
  			}
  			if(output.isSetEncoding()){
  				request = request + "@schema="+output.getSchema();
  			}
  			if(output.isSetUom()){
  				request = request + "@datatype="+output.getUom();
  			}
  			//concatenation for next output element
  			outputCounter = outputCounter +1;
  			if(outputCounter<outputs.length){
  				request = request + ";";
  			}
  		}
  		
  		if( execute.getExecute().getResponseForm().getResponseDocument().isSetStoreExecuteResponse()){
  			request = request + "&storeExecuteResponse=true";
  		}
  		if( execute.getExecute().getResponseForm().getResponseDocument().isSetStatus()){
  			request = request + "&status=true";
  		}
  		if( execute.getExecute().getResponseForm().getResponseDocument().isSetLineage()){
  			request = request + "&lineage=true";
  		}
  		
  		return request;
  	}
  
  	
  	/**
  	 * 
  	 * @param id
  	 * @return the specified parameterdescription. if not available it returns null.
  	 */
  	private InputDescriptionType getParameterDescription(String id) {
  		InputDescriptionType[] inputDescs = processDesc.getDataInputs().getInputArray();
  		for (InputDescriptionType inputDesc : inputDescs) {
  			if(inputDesc.getIdentifier().getStringValue().equals(id))
  			{
  				return inputDesc;
  			}
  		}
  		return null;
  	}
  	
  	private void setComplexData(ComplexDataType data, Object value,
  			String schema, String mimeType, String encoding) {
  
  		if (value instanceof String) {
  
  			String valueString = (String) value;
  
  			try {
  				data.set(XmlObject.Factory.parse(valueString));
  			} catch (XmlException e) {
  
  				LOGGER.warn("error parsing data String as xml node, trying to parse data as xs:string");
  
  				XmlString xml = XmlString.Factory.newInstance();
  
  				xml.setStringValue(valueString);
  
  				data.set(xml);
  
  			}
  
  		} else if (value instanceof InputStream) {
  
  			InputStream stream = (InputStream) value;
  
  			try {
  				data.set(XmlObject.Factory.parse(stream));
  			} catch (XmlException e) {
  
  				LOGGER.warn("error parsing data stream as xml node, trying to parse data as xs:string");
  
  				String text = "";
  
  				int i = -1;
  
  				try {
  					while ((i = stream.read()) != -1) {
  						text = text + (char) i;
  					}
  				} catch (IOException e1) {
  					LOGGER.error("error parsing stream", e);
  				}
  
  				XmlString xml = XmlString.Factory.newInstance();
  
  				xml.setStringValue(text);
  
  				data.set(xml);
  			} catch (IOException e) {
  				LOGGER.error("error parsing stream", e);
  			}
  
  		}
  		if (schema != null) {
  			data.setSchema(schema);
  		}
  		if (mimeType != null) {
  			data.setMimeType(mimeType);
  		}
  		if (encoding != null) {
  			data.setEncoding(encoding);
  		}
  
  	}
  }
  