org.n52.wps.server.request.ExecuteRequest.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.wps.server.request.ExecuteRequest.java

Source

/**
 * Copyright (C) 2007 - 2014 52North Initiative for Geospatial Open Source
 * Software GmbH
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 *
 * If the program is linked with libraries which are licensed under one of
 * the following licenses, the combination of the program with the linked
 * library is not considered a "derivative work" of the program:
 *
 *        Apache License, version 2.0
 *        Apache Software License, version 1.0
 *        GNU Lesser General Public License, version 3
 *        Mozilla Public License, versions 1.0, 1.1 and 2.0
 *        Common Development and Distribution License (CDDL), version 1.0
 *
 * Therefore the distribution of the program linked with libraries licensed
 * under the aforementioned licenses, is permitted by the copyright holders
 * if the distribution is compliant with both the GNU General Public
 * License version 2 and the aforementioned licenses.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 */
package org.n52.wps.server.request;

import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilderFactory;

import net.opengis.ows.x11.BoundingBoxType;
import net.opengis.ows.x11.ExceptionType;
import net.opengis.wps.x100.ComplexDataType;
import net.opengis.wps.x100.DataInputsType;
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 net.opengis.wps.x100.StatusType;

import org.apache.commons.collections.map.CaseInsensitiveMap;
import org.apache.commons.io.IOUtils;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.n52.wps.commons.context.ExecutionContext;
import org.n52.wps.commons.context.ExecutionContextFactory;
import org.n52.wps.io.data.IComplexData;
import org.n52.wps.io.data.IData;
import org.n52.wps.server.AbstractTransactionalAlgorithm;
import org.n52.wps.server.ExceptionReport;
import org.n52.wps.server.IAlgorithm;
import org.n52.wps.server.RepositoryManager;
import org.n52.wps.server.database.DatabaseFactory;
import org.n52.wps.server.observerpattern.IObserver;
import org.n52.wps.server.observerpattern.ISubject;
import org.n52.wps.server.response.ExecuteResponse;
import org.n52.wps.server.response.ExecuteResponseBuilder;
import org.n52.wps.server.response.Response;
import org.n52.wps.util.XMLBeansHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * Handles an ExecuteRequest
 */
public class ExecuteRequest extends Request implements IObserver {

    private static Logger LOGGER = LoggerFactory.getLogger(ExecuteRequest.class);
    private ExecuteDocument execDom;
    private Map<String, IData> returnResults;
    private ExecuteResponseBuilder execRespType;

    /**
     * Creates an ExecuteRequest based on a Document (HTTP_POST)
     * 
     * @param doc
     *            The clients submission
     * @throws ExceptionReport
     */
    public ExecuteRequest(Document doc) throws ExceptionReport {
        super(doc);
        try {
            XmlOptions option = new XmlOptions();
            option.setLoadTrimTextBuffer();
            this.execDom = ExecuteDocument.Factory.parse(doc, option);
            if (this.execDom == null) {
                LOGGER.error("ExecuteDocument is null");
                throw new ExceptionReport("Error while parsing post data", ExceptionReport.MISSING_PARAMETER_VALUE);
            }
        } catch (XmlException e) {
            throw new ExceptionReport("Error while parsing post data", ExceptionReport.MISSING_PARAMETER_VALUE, e);
        }

        // validate the client input
        validate();

        // create an initial response
        execRespType = new ExecuteResponseBuilder(this);

        storeRequest(execDom);
    }

    /*
     * Creates an ExecuteRequest based on a Map (HTTP_GET). NOTE: Parameters are
     * treated as non case sensitive. @param ciMap The client input @throws
     * ExceptionReport
     */
    public ExecuteRequest(CaseInsensitiveMap ciMap) throws ExceptionReport {
        super(ciMap);
        initForGET(ciMap);
        // validate the client input
        validate();

        // create an initial response
        execRespType = new ExecuteResponseBuilder(this);

        storeRequest(ciMap);
    }

    public void getKVPDataInputs() {

    }

    /**
     * @param ciMap
     */
    private void initForGET(CaseInsensitiveMap ciMap) throws ExceptionReport {
        String version = getMapValue("version", ciMap, true);
        if (!version.equals(Request.SUPPORTED_VERSION)) {
            throw new ExceptionReport("request version is not supported: " + version,
                    ExceptionReport.VERSION_NEGOTIATION_FAILED);
        }
        this.execDom = ExecuteDocument.Factory.newInstance();
        Execute execute = execDom.addNewExecute();
        String processID = getMapValue("Identifier", true);
        if (!RepositoryManager.getInstance().containsAlgorithm(processID)) {
            throw new ExceptionReport("Process does not exist", ExceptionReport.INVALID_PARAMETER_VALUE);
        }
        execute.addNewIdentifier().setStringValue(processID);
        DataInputsType dataInputs = execute.addNewDataInputs();
        String dataInputString = getMapValue("DataInputs", true);
        dataInputString = dataInputString.replace("&amp;", "&");
        String[] inputs = dataInputString.split(";");

        // Handle data inputs
        for (String inputString : inputs) {
            int position = inputString.indexOf("=");
            if (position == -1) {
                throw new ExceptionReport("No \"=\" supplied for attribute: " + inputString,
                        ExceptionReport.MISSING_PARAMETER_VALUE);
            }
            //get name
            String key = inputString.substring(0, position);
            String value = null;
            if (key.length() + 1 < inputString.length()) {
                // BS int valueDelimiter = inputString.indexOf("@");
                int valueDelimiter = inputString.indexOf("@");
                if (valueDelimiter != -1 && position + 1 < valueDelimiter) {
                    value = inputString.substring(position + 1, valueDelimiter);
                } else {
                    value = inputString.substring(position + 1);
                }
            }
            ProcessDescriptionType description = RepositoryManager.getInstance().getProcessDescription(processID);

            if (description == null) {
                throw new ExceptionReport("Data Identifier not supported: " + key,
                        ExceptionReport.MISSING_PARAMETER_VALUE);
            }
            InputDescriptionType inputDesc = XMLBeansHelper.findInputByID(key, description.getDataInputs());
            if (inputDesc == null) {
                throw new ExceptionReport("Data Identifier not supported: " + key,
                        ExceptionReport.MISSING_PARAMETER_VALUE);
            }
            InputType input = dataInputs.addNewInput();
            input.addNewIdentifier().setStringValue(key);
            // prepare attributes
            String encodingAttribute = null;
            String mimeTypeAttribute = null;
            String schemaAttribute = null;
            String hrefAttribute = null;
            String uom = null;
            String dataType = null;
            String[] inputItemstemp = inputString.split("@");
            String[] inputItems = null;
            if (inputItemstemp.length == 2) {
                inputItems = inputItemstemp[1].split("@");
            } else {
                inputItems = inputString.split("@");
            }
            if (inputItemstemp.length > 1) {
                for (int i = 0; i < inputItems.length; i++) {
                    int attributePos = inputItems[i].indexOf("=");
                    if (attributePos == -1 || attributePos + 1 >= inputItems[i].length()) {
                        continue;
                    }
                    String attributeName = inputItems[i].substring(0, attributePos);
                    String attributeValue = inputItems[i].substring(attributePos + 1);
                    //attribute is input name
                    if (attributeName.equals(key)) {
                        continue;
                    }
                    try {
                        attributeValue = URLDecoder.decode(attributeValue, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        throw new ExceptionReport(
                                "Something went wrong while trying to decode value of " + attributeName,
                                ExceptionReport.NO_APPLICABLE_CODE, e);
                    }
                    if (attributeName.equalsIgnoreCase("encoding")) {
                        encodingAttribute = attributeValue;
                    } else if (attributeName.equalsIgnoreCase("mimeType")) {
                        mimeTypeAttribute = attributeValue;
                    } else if (attributeName.equalsIgnoreCase("schema")) {
                        schemaAttribute = attributeValue;
                    } else if (attributeName.equalsIgnoreCase("href")
                            | attributeName.equalsIgnoreCase("xlink:href")) {
                        hrefAttribute = attributeValue;
                    } else if (attributeName.equalsIgnoreCase("uom")) {
                        uom = attributeValue;
                    } else if (attributeName.equalsIgnoreCase("datatype")) {
                        dataType = attributeValue;
                    } else {
                        throw new ExceptionReport("Attribute is not supported: " + attributeName,
                                ExceptionReport.INVALID_PARAMETER_VALUE);
                    }

                }
            }
            if (inputDesc.isSetComplexData()) {
                // TODO: check for different attributes
                // handling ComplexReference
                if (!(hrefAttribute == null) && !hrefAttribute.equals("")) {
                    InputReferenceType reference = input.addNewReference();
                    reference.setHref(hrefAttribute);
                    if (schemaAttribute != null) {
                        reference.setSchema(schemaAttribute);
                    }
                    if (mimeTypeAttribute != null) {
                        reference.setMimeType(mimeTypeAttribute);
                    }
                    if (encodingAttribute != null) {
                        reference.setEncoding(encodingAttribute);
                    }

                }
                // Handling ComplexData
                else {
                    ComplexDataType data = input.addNewData().addNewComplexData();

                    InputStream stream = new ByteArrayInputStream(value.getBytes());

                    try {
                        data.set(XmlObject.Factory.parse(stream));
                    } catch (Exception e) {
                        LOGGER.warn(
                                "Could not parse value: " + value + " as XMLObject. Trying to create text node.");
                        try {
                            Node textNode = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
                                    .createTextNode(value);
                            data.set(XmlObject.Factory.parse(textNode));
                        } catch (Exception e1) {
                            throw new ExceptionReport("Exception while trying to parse value: " + value,
                                    ExceptionReport.NO_APPLICABLE_CODE, e1);
                        }
                    }

                    if (schemaAttribute != null) {
                        data.setSchema(schemaAttribute);
                    }
                    if (mimeTypeAttribute != null) {
                        data.setMimeType(mimeTypeAttribute);
                    }
                    if (encodingAttribute != null) {
                        data.setEncoding(encodingAttribute);
                    }
                }

            } else if (inputDesc.isSetLiteralData()) {
                LiteralDataType data = input.addNewData().addNewLiteralData();
                if (value == null) {
                    throw new ExceptionReport(
                            "No value provided for literal: " + inputDesc.getIdentifier().getStringValue(),
                            ExceptionReport.MISSING_PARAMETER_VALUE);
                }
                data.setStringValue(value);
                if (uom != null) {
                    data.setUom(uom);
                }
                if (dataType != null) {
                    data.setDataType(dataType);
                }
            } else if (inputDesc.isSetBoundingBoxData()) {
                BoundingBoxType data = input.addNewData().addNewBoundingBoxData();
                String[] values = value.split(",");

                if (values.length < 4) {
                    throw new ExceptionReport(
                            "Invalid Number of BBOX Values: " + inputDesc.getIdentifier().getStringValue(),
                            ExceptionReport.MISSING_PARAMETER_VALUE);
                }
                List<String> lowerCorner = new ArrayList<String>();
                lowerCorner.add(values[0]);
                lowerCorner.add(values[1]);
                data.setLowerCorner(lowerCorner);

                List<String> upperCorner = new ArrayList<String>();
                upperCorner.add(values[2]);
                upperCorner.add(values[3]);
                data.setUpperCorner(upperCorner);

                if (values.length > 4) {
                    data.setCrs(values[4]);
                }

                if (values.length > 5) {
                    data.setDimensions(BigInteger.valueOf(Long.valueOf(values[5])));
                }
            }

        }
        // retrieve status
        boolean status = false;
        String statusString = getMapValue("status", false);
        if (statusString != null) {
            status = Boolean.parseBoolean(statusString);
        }
        boolean store = false;
        String storeString = getMapValue("storeExecuteResponse", false);
        if (storeString != null) {
            store = Boolean.parseBoolean(storeString);
        }
        // Handle ResponseDocument option
        String responseDocument = getMapValue("ResponseDocument", false);
        if (responseDocument != null) {
            String[] outputs = responseDocument.split(";");
            ResponseDocumentType responseDoc = execute.addNewResponseForm().addNewResponseDocument();
            responseDoc.setStatus(status);
            responseDoc.setStoreExecuteResponse(store);
            for (String outputID : outputs) {
                String[] outputDataparameters = outputID.split("@");
                String outputDataInput = "";
                if (outputDataparameters.length > 0) {
                    outputDataInput = outputDataparameters[0];
                } else {
                    outputDataInput = outputID;
                }
                outputDataInput = outputDataInput.replace("=", "");
                ProcessDescriptionType description = RepositoryManager.getInstance()
                        .getProcessDescription(processID);
                OutputDescriptionType outputDesc = XMLBeansHelper.findOutputByID(outputDataInput,
                        description.getProcessOutputs().getOutputArray());
                if (outputDesc == null) {
                    throw new ExceptionReport("Data output Identifier not supported: " + outputDataInput,
                            ExceptionReport.MISSING_PARAMETER_VALUE);
                }
                DocumentOutputDefinitionType output = responseDoc.addNewOutput();
                output.addNewIdentifier().setStringValue(outputDataInput);

                for (int i = 1; i < outputDataparameters.length; i++) {
                    int attributePos = outputDataparameters[i].indexOf("=");
                    if (attributePos == -1 || attributePos + 1 >= outputDataparameters[i].length()) {
                        continue;
                    }
                    String attributeName = outputDataparameters[i].substring(0, attributePos);
                    String attributeValue = outputDataparameters[i].substring(attributePos + 1);
                    try {
                        attributeValue = URLDecoder.decode(attributeValue, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        throw new ExceptionReport(
                                "Something went wrong while trying to decode value of " + attributeName,
                                ExceptionReport.NO_APPLICABLE_CODE, e);
                    }
                    if (attributeName.equalsIgnoreCase("mimeType")) {
                        output.setMimeType(attributeValue);
                    } else if (attributeName.equalsIgnoreCase("schema")) {
                        output.setSchema(attributeValue);
                    } else if (attributeName.equalsIgnoreCase("encoding")) {
                        output.setEncoding(attributeValue);

                    }
                }
            }
        }
        String rawData = getMapValue("RawDataOutput", false);
        if (rawData != null) {
            String[] rawDataparameters = rawData.split("@");
            String rawDataInput = "";
            if (rawDataparameters.length > 0) {
                rawDataInput = rawDataparameters[0];
            } else {
                rawDataInput = rawData;
            }
            ProcessDescriptionType description = RepositoryManager.getInstance().getProcessDescription(processID);
            OutputDescriptionType outputDesc = XMLBeansHelper.findOutputByID(rawDataInput,
                    description.getProcessOutputs().getOutputArray());
            if (outputDesc == null) {
                throw new ExceptionReport("Data output Identifier not supported: " + rawData,
                        ExceptionReport.MISSING_PARAMETER_VALUE);
            }
            ResponseFormType responseForm = execute.addNewResponseForm();
            OutputDefinitionType output = responseForm.addNewRawDataOutput();
            output.addNewIdentifier().setStringValue(outputDesc.getIdentifier().getStringValue());

            if (rawDataparameters.length > 0) {
                for (int i = 0; i < rawDataparameters.length; i++) {
                    int attributePos = rawDataparameters[i].indexOf("=");
                    if (attributePos == -1 || attributePos + 1 >= rawDataparameters[i].length()) {
                        continue;
                    }
                    String attributeName = rawDataparameters[i].substring(0, attributePos);
                    String attributeValue = rawDataparameters[i].substring(attributePos + 1);
                    try {
                        attributeValue = URLDecoder.decode(attributeValue, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        throw new ExceptionReport(
                                "Something went wrong while trying to decode value of " + attributeName,
                                ExceptionReport.NO_APPLICABLE_CODE, e);
                    }
                    if (attributeName.equalsIgnoreCase("mimeType")) {
                        output.setMimeType(attributeValue);
                    } else if (attributeName.equalsIgnoreCase("schema")) {
                        output.setSchema(attributeValue);
                    } else if (attributeName.equalsIgnoreCase("encoding")) {
                        output.setEncoding(attributeValue);

                    } else {
                        throw new ExceptionReport("Attribute is not supported: " + attributeName,
                                ExceptionReport.INVALID_PARAMETER_VALUE);
                    }

                }
            }

        }

    }

    /**
     * Validates the client request
     * 
     * @return True if the input is valid, False otherwise
     */
    public boolean validate() throws ExceptionReport {
        // Identifier must be specified.
        /*
         * Only for HTTP_GET: String identifier = getMapValue("identifier");
         * 
         * try{ // Specifies if all complex valued output(s) of this process
         * should be stored by process // as web-accessible resources store =
         * getMapValue("store").equals("true");
         *  // Specifies if Execute operation response shall be returned quickly
         * with status information status =
         * getMapValue("status").equals("true"); }catch(ExceptionReport e){ //
         * if parameters "store" or "status" are not included, they default to
         * false; }
         *  // just testing if the number of arguments is even... String[]
         * diArray = getMapValue("DataInputs").split(","); if(diArray.length % 2 !=
         * 0) { throw new ExceptionReport("Incorrect number of arguments for
         * parameter dataInputs, please only a even number of parameter values",
         * ExceptionReport.INVALID_PARAMETER_VALUE); }
         * 
         */
        if (!execDom.getExecute().getVersion().equals(SUPPORTED_VERSION)) {
            throw new ExceptionReport("Specified version is not supported.",
                    ExceptionReport.INVALID_PARAMETER_VALUE, "version=" + getExecute().getVersion());
        }

        //Fix for bug https://bugzilla.52north.org/show_bug.cgi?id=906
        String identifier = getAlgorithmIdentifier();

        if (identifier == null) {
            throw new ExceptionReport("No process identifier supplied.", ExceptionReport.MISSING_PARAMETER_VALUE,
                    "identifier");
        }

        // check if the algorithm is in our repository
        if (!RepositoryManager.getInstance().containsAlgorithm(identifier)) {
            throw new ExceptionReport("Specified process identifier does not exist",
                    ExceptionReport.INVALID_PARAMETER_VALUE, "identifier=" + identifier);
        }

        // validate if the process can be executed
        ProcessDescriptionType desc = RepositoryManager.getInstance()
                .getProcessDescription(getAlgorithmIdentifier());
        // We need a description of the inputs for the algorithm
        if (desc == null) {
            LOGGER.warn("desc == null");
            return false;
        }

        // Get the inputdescriptions of the algorithm

        if (desc.getDataInputs() != null) {
            InputDescriptionType[] inputDescs = desc.getDataInputs().getInputArray();

            //prevent NullPointerException for zero input values in execute request (if only default values are used)
            InputType[] inputs;
            if (getExecute().getDataInputs() == null)
                inputs = new InputType[0];
            else
                inputs = getExecute().getDataInputs().getInputArray();

            // For each input supplied by the client
            for (InputType input : inputs) {
                boolean identifierMatched = false;
                // Try to match the input with one of the descriptions
                for (InputDescriptionType inputDesc : inputDescs) {
                    // If found, then process:
                    if (inputDesc.getIdentifier().getStringValue().equals(input.getIdentifier().getStringValue())) {
                        identifierMatched = true;
                        // If it is a literal value,
                        if (input.getData() != null && input.getData().getLiteralData() != null) {
                            // then check if the desription is also of type literal
                            if (inputDesc.getLiteralData() == null) {
                                throw new ExceptionReport("Inputtype LiteralData is not supported",
                                        ExceptionReport.INVALID_PARAMETER_VALUE);
                            }
                            // literalValue.getDataType ist optional
                            if (input.getData().getLiteralData().getDataType() != null) {
                                if (inputDesc.getLiteralData() != null)
                                    if (inputDesc.getLiteralData().getDataType() != null)
                                        if (inputDesc.getLiteralData().getDataType().getReference() != null)
                                            if (!input.getData().getLiteralData().getDataType().equals(
                                                    inputDesc.getLiteralData().getDataType().getReference())) {
                                                throw new ExceptionReport("Specified dataType is not supported "
                                                        + input.getData().getLiteralData().getDataType()
                                                        + " for input " + input.getIdentifier().getStringValue(),
                                                        ExceptionReport.INVALID_PARAMETER_VALUE);
                                            }
                            }
                        }
                        // Excluded, because ProcessDescription validation should be
                        // done on startup!
                        // else if (input.getComplexValue() != null) {
                        // if(ParserFactory.getInstance().getParser(input.getComplexValue().getSchema())
                        // == null) {
                        // LOGGER.warn("Request validation message: schema attribute
                        // null, so the simple one will be used!");
                        // }
                        // }
                        // else if (input.getComplexValueReference() != null) {
                        // // we found a complexvalue input, try to get the parser.
                        // if(ParserFactory.getInstance().getParser(input.getComplexValueReference().getSchema())
                        // == null) {
                        // LOGGER.warn("Request validation message: schema attribute
                        // null, so the simple one will be used!");
                        // }
                        // }
                        break;
                    }
                }
                // if the identifier did not match one of the descriptions, it is
                // invalid
                if (!identifierMatched) {
                    throw new ExceptionReport(
                            "Input Identifier is not valid: " + input.getIdentifier().getStringValue(),
                            ExceptionReport.INVALID_PARAMETER_VALUE, "input identifier");
                }
            }
        }
        return true;
    }

    /**
     * Actually serves the Request.
     * 
     * @throws ExceptionReport
     */
    public Response call() throws ExceptionReport {
        IAlgorithm algorithm = null;
        Map<String, List<IData>> inputMap = null;
        try {
            ExecutionContext context;
            if (getExecute().isSetResponseForm()) {
                context = getExecute().getResponseForm().isSetRawDataOutput()
                        ? new ExecutionContext(getExecute().getResponseForm().getRawDataOutput())
                        : new ExecutionContext(Arrays
                                .asList(getExecute().getResponseForm().getResponseDocument().getOutputArray()));
            } else {
                context = new ExecutionContext();
            }

            // register so that any function that calls ExecuteContextFactory.getContext() gets the instance registered with this thread
            ExecutionContextFactory.registerContext(context);

            LOGGER.debug("started with execution");

            updateStatusStarted();

            // parse the input
            InputType[] inputs = new InputType[0];
            if (getExecute().getDataInputs() != null) {
                inputs = getExecute().getDataInputs().getInputArray();
            }
            InputHandler parser = new InputHandler.Builder(inputs, getAlgorithmIdentifier()).build();

            // we got so far:
            // get the algorithm, and run it with the clients input

            /*
             * IAlgorithm algorithm =
             * RepositoryManager.getInstance().getAlgorithm(getAlgorithmIdentifier());
             * returnResults = algorithm.run((Map)parser.getParsedInputLayers(),
             * (Map)parser.getParsedInputParameters());
             */
            algorithm = RepositoryManager.getInstance().getAlgorithm(getAlgorithmIdentifier());

            if (algorithm instanceof ISubject) {
                ISubject subject = (ISubject) algorithm;
                subject.addObserver(this);

            }

            if (algorithm instanceof AbstractTransactionalAlgorithm) {
                returnResults = ((AbstractTransactionalAlgorithm) algorithm).run(execDom);
            } else {
                inputMap = parser.getParsedInputData();
                returnResults = algorithm.run(inputMap);
            }

            List<String> errorList = algorithm.getErrors();
            if (errorList != null && !errorList.isEmpty()) {
                String errorMessage = errorList.get(0);
                LOGGER.error("Error reported while handling ExecuteRequest for " + getAlgorithmIdentifier() + ": "
                        + errorMessage);
                updateStatusError(errorMessage);
            } else {
                updateStatusSuccess();
            }
        } catch (Throwable e) {
            String errorMessage = null;
            if (algorithm != null && algorithm.getErrors() != null && !algorithm.getErrors().isEmpty()) {
                errorMessage = algorithm.getErrors().get(0);
            }
            if (errorMessage == null) {
                errorMessage = e.toString();
            }
            if (errorMessage == null) {
                errorMessage = "UNKNOWN ERROR";
            }
            LOGGER.error("Exception/Error while executing ExecuteRequest for " + getAlgorithmIdentifier() + ": "
                    + errorMessage);
            updateStatusError(errorMessage);
            if (e instanceof Error) {
                // This is required when catching Error
                throw (Error) e;
            }
            if (e instanceof ExceptionReport) {
                throw (ExceptionReport) e;
            } else {
                throw new ExceptionReport(
                        "Error while executing the embedded process for: " + getAlgorithmIdentifier(),
                        ExceptionReport.NO_APPLICABLE_CODE, e);
            }
        } finally {
            //  you ***MUST*** call this or else you will have a PermGen ClassLoader memory leak due to ThreadLocal use
            ExecutionContextFactory.unregisterContext();
            if (algorithm instanceof ISubject) {
                ((ISubject) algorithm).removeObserver(this);
            }
            if (inputMap != null) {
                for (List<IData> l : inputMap.values()) {
                    for (IData d : l) {
                        if (d instanceof IComplexData) {
                            ((IComplexData) d).dispose();
                        }
                    }
                }
            }
            if (returnResults != null) {
                for (IData d : returnResults.values()) {
                    if (d instanceof IComplexData) {
                        ((IComplexData) d).dispose();
                    }
                }
            }
        }

        ExecuteResponse response = new ExecuteResponse(this);
        return response;
    }

    /**
     * Gets the identifier of the algorithm the client requested
     * 
     * @return An identifier
     */
    public String getAlgorithmIdentifier() {
        //Fix for bug https://bugzilla.52north.org/show_bug.cgi?id=906
        if (getExecute().getIdentifier() != null) {
            return getExecute().getIdentifier().getStringValue();
        }
        return null;
    }

    /**
     * Gets the Execute that is associated with this Request
     * 
     * @return The Execute
     */
    public Execute getExecute() {
        return execDom.getExecute();
    }

    public Map<String, IData> getAttachedResult() {
        return returnResults;
    }

    public boolean isStoreResponse() {
        if (execDom.getExecute().getResponseForm() == null) {
            return false;
        }
        if (execDom.getExecute().getResponseForm().getRawDataOutput() != null) {
            return false;
        }
        return execDom.getExecute().getResponseForm().getResponseDocument().getStoreExecuteResponse();
    }

    public boolean isQuickStatus() {
        if (execDom.getExecute().getResponseForm() == null) {
            return false;
        }
        if (execDom.getExecute().getResponseForm().getRawDataOutput() != null) {
            return false;
        }
        return execDom.getExecute().getResponseForm().getResponseDocument().getStatus();
    }

    public ExecuteResponseBuilder getExecuteResponseBuilder() {
        return this.execRespType;
    }

    public boolean isRawData() {
        if (execDom.getExecute().getResponseForm() == null) {
            return false;
        }
        if (execDom.getExecute().getResponseForm().getRawDataOutput() != null) {
            return true;
        } else {
            return false;
        }
    }

    public void update(ISubject subject) {
        Object state = subject.getState();
        LOGGER.info("Update received from Subject, state changed to : " + state);
        StatusType status = StatusType.Factory.newInstance();

        int percentage = 0;
        if (state instanceof Integer) {
            percentage = (Integer) state;
            status.addNewProcessStarted().setPercentCompleted(percentage);
        } else if (state instanceof String) {
            status.addNewProcessStarted().setStringValue((String) state);
        }
        updateStatus(status);
    }

    public void updateStatusAccepted() {
        StatusType status = StatusType.Factory.newInstance();
        status.setProcessAccepted("Process Accepted");
        updateStatus(status);
    }

    public void updateStatusStarted() {
        StatusType status = StatusType.Factory.newInstance();
        status.addNewProcessStarted().setPercentCompleted(0);
        updateStatus(status);
    }

    public void updateStatusSuccess() {
        StatusType status = StatusType.Factory.newInstance();
        status.setProcessSucceeded("Process successful");
        updateStatus(status);
    }

    public void updateStatusError(String errorMessage) {
        StatusType status = StatusType.Factory.newInstance();
        net.opengis.ows.x11.ExceptionReportDocument.ExceptionReport excRep = status.addNewProcessFailed()
                .addNewExceptionReport();
        excRep.setVersion("1.0.0");
        ExceptionType excType = excRep.addNewException();
        excType.addNewExceptionText().setStringValue(errorMessage);
        excType.setExceptionCode(ExceptionReport.NO_APPLICABLE_CODE);
        updateStatus(status);
    }

    private void updateStatus(StatusType status) {
        getExecuteResponseBuilder().setStatus(status);
        try {
            getExecuteResponseBuilder().update();
            if (isStoreResponse()) {
                ExecuteResponse executeResponse = new ExecuteResponse(this);
                InputStream is = null;
                try {
                    is = executeResponse.getAsStream();
                    DatabaseFactory.getDatabase().storeResponse(getUniqueId().toString(), is);
                } finally {
                    IOUtils.closeQuietly(is);
                }
            }
        } catch (ExceptionReport e) {
            LOGGER.error("Update of process status failed.", e);
            throw new RuntimeException(e);
        }
    }

    private void storeRequest(ExecuteDocument executeDocument) {
        InputStream is = null;
        try {
            is = executeDocument.newInputStream();
            DatabaseFactory.getDatabase().insertRequest(getUniqueId().toString(), is, true);
        } catch (Exception e) {
            LOGGER.error("Exception storing ExecuteRequest", e);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    private void storeRequest(CaseInsensitiveMap map) {

        BufferedWriter w = null;
        ByteArrayOutputStream os = null;
        ByteArrayInputStream is = null;
        try {
            os = new ByteArrayOutputStream();
            w = new BufferedWriter(new OutputStreamWriter(os));
            for (Object key : map.keySet()) {
                Object value = map.get(key);
                String valueString = "";
                if (value instanceof String[]) {
                    valueString = ((String[]) value)[0];
                } else {
                    valueString = value.toString();
                }
                w.append(key.toString()).append('=').append(valueString);
                w.newLine();
            }
            w.flush();
            is = new ByteArrayInputStream(os.toByteArray());
            DatabaseFactory.getDatabase().insertRequest(getUniqueId().toString(), is, false);
        } catch (Exception e) {
            LOGGER.error("Exception storing ExecuteRequest", e);
        } finally {
            IOUtils.closeQuietly(w);
            IOUtils.closeQuietly(os);
            IOUtils.closeQuietly(is);
        }
    }
}