org.n52.wps.ags.GenericAGSProcessDelegator.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.wps.ags.GenericAGSProcessDelegator.java

Source

/**
 * Copyright (C) 2009 - 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.ags;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import net.opengis.wps.x100.InputDescriptionType;
import net.opengis.wps.x100.OutputDescriptionType;
import net.opengis.wps.x100.ProcessDescriptionType;

import org.apache.commons.io.FileUtils;
import org.n52.wps.ags.workspace.AGSWorkspace;
import org.n52.wps.io.data.GenericFileDataWithGT;
import org.n52.wps.io.data.GenericFileDataConstants;
import org.n52.wps.io.data.IData;
import org.n52.wps.io.data.binding.complex.GenericFileDataWithGTBinding;
import org.n52.wps.io.data.binding.literal.LiteralBooleanBinding;
import org.n52.wps.io.data.binding.literal.LiteralDoubleBinding;
import org.n52.wps.io.data.binding.literal.LiteralFloatBinding;
import org.n52.wps.io.data.binding.literal.LiteralIntBinding;
import org.n52.wps.io.data.binding.literal.LiteralStringBinding;
import org.n52.wps.server.IAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Matthias Mueller, TU Dresden
 *
 */
public class GenericAGSProcessDelegator implements IAlgorithm {

    private static Logger LOGGER = LoggerFactory.getLogger(GenericAGSProcessDelegator.class);
    private final String processID;
    private List<String> errors;
    private AGSWorkspace workspace;
    protected final ToolParameter[] parameterDescriptions;
    private String[] toolParameters;
    private final int parameterCount;
    private final ProcessDescriptionType processDescription;
    private final File instanceWorkspace;

    public GenericAGSProcessDelegator(File workspace, String processID, ToolParameter[] legacyParameters,
            ProcessDescriptionType processDescription) {
        errors = new ArrayList<String>();
        this.processID = processID;
        this.parameterDescriptions = legacyParameters;
        this.parameterCount = legacyParameters.length;
        this.processDescription = processDescription;
        this.toolParameters = new String[this.parameterCount];
        this.instanceWorkspace = workspace;

    }

    public ProcessDescriptionType getDescription() {
        return processDescription;
    }

    public List<String> getErrors() {
        return errors;
    }

    public Class<?> getInputDataType(String id) {
        InputDescriptionType[] inputs = this.getDescription().getDataInputs().getInputArray();

        for (InputDescriptionType input : inputs) {

            //Literal Input
            if (input.isSetLiteralData()) {
                String datatype = input.getLiteralData().getDataType().getStringValue();
                if (datatype.equalsIgnoreCase("string")) {
                    return LiteralStringBinding.class;
                } else if (datatype.equalsIgnoreCase("boolean")) {
                    return LiteralBooleanBinding.class;
                } else if (datatype.equalsIgnoreCase("float")) {
                    return LiteralFloatBinding.class;
                } else if (datatype.equalsIgnoreCase("double")) {
                    return LiteralDoubleBinding.class;
                } else if (datatype.equalsIgnoreCase("int")) {
                    return LiteralIntBinding.class;
                } else if (datatype.equalsIgnoreCase("integer")) {
                    return LiteralIntBinding.class;
                }
            }

            //Complex Output
            else if (input.isSetComplexData()) {
                return GenericFileDataWithGTBinding.class;
            }
        }

        return null;
    }

    public Class<?> getOutputDataType(String id) {
        OutputDescriptionType[] outputs = this.getDescription().getProcessOutputs().getOutputArray();

        for (OutputDescriptionType output : outputs) {

            //Literal Output
            if (output.isSetLiteralOutput()) {
                String datatype = output.getLiteralOutput().getDataType().getStringValue();
                if (datatype.equalsIgnoreCase("string")) {
                    return LiteralStringBinding.class;
                } else if (datatype.equalsIgnoreCase("boolean")) {
                    return LiteralBooleanBinding.class;
                } else if (datatype.equalsIgnoreCase("float")) {
                    return LiteralFloatBinding.class;
                } else if (datatype.equalsIgnoreCase("double")) {
                    return LiteralDoubleBinding.class;
                } else if (datatype.equalsIgnoreCase("int")) {
                    return LiteralIntBinding.class;
                } else if (datatype.equalsIgnoreCase("integer")) {
                    return LiteralIntBinding.class;
                }
            }

            //Complex Output
            else if (output.isSetComplexOutput()) {
                return GenericFileDataWithGTBinding.class;
            }
        }
        return null;
    }

    public String getWellKnownName() {
        return processID;
    }

    public boolean processDescriptionIsValid() {
        return this.getDescription().validate();
    }

    public Map<String, IData> run(Map<String, List<IData>> inputData) {

        //initialize arcObjects
        AGSProperties.getInstance().bootstrapArcobjectsJar();

        //create the workspace
        this.workspace = new AGSWorkspace(instanceWorkspace);

        //Assign the parameters
        for (int i = 0; i < this.parameterCount; i++) {

            ToolParameter currentParam = this.parameterDescriptions[i];

            // input parameters
            if (currentParam.isInput) {
                if (inputData.containsKey(currentParam.wpsInputID)) {
                    //open the IData list and iterate through it
                    List<IData> dataItemList = inputData.get(currentParam.wpsInputID);
                    Iterator<IData> it = dataItemList.iterator();
                    ArrayList<String> valueList = new ArrayList<String>();
                    while (it.hasNext()) {
                        IData currentItem = it.next();
                        valueList.add(this.loadSingleDataItem(currentItem));
                    }

                    String[] valueArray = valueList.toArray(new String[0]);

                    //TODO verify: isnt the input separator acutally an " ; "?
                    this.toolParameters[i] = this.calcToolParameterString(" ", valueArray);
                } else {
                    if (currentParam.isOptional) {
                        this.toolParameters[i] = null;
                    } else {
                        errors.add("Error while allocating input parameter " + currentParam.wpsInputID);
                        throw new RuntimeException(
                                "Error while allocating input parameter " + currentParam.wpsInputID);

                    }
                }
            }

            //output only parameters
            else if (currentParam.isOutput && !currentParam.isInput) {
                if (currentParam.isComplex) {
                    String extension = "";
                    if (currentParam.schema != null && currentParam.schema.length() > 0) {
                        //we have vector data. So use a shp file.
                        extension = "shp";
                    } else {
                        extension = GenericFileDataConstants.mimeTypeFileTypeLUT().get(currentParam.mimeType);
                    }
                    String fileName = UUID.randomUUID().toString().substring(0, 7) + "." + extension; // geoprocessor can't handle points, dashes etc in output file name

                    fileName = this.addOutputFile(fileName);
                    this.toolParameters[i] = fileName;
                }
            }
        }

        //execute
        String toolName = this.processDescription.getTitle().getStringValue();
        LOGGER.info("Executing ArcGIS tool " + toolName + " . Parameter array contains " + this.parameterCount
                + " parameters.");
        try {
            workspace.executeGPTool(toolName, null, this.toolParameters);
        } catch (IOException e1) {
            LOGGER.error(e1.getMessage());
            errors.add(e1.getMessage());
            throw new RuntimeException(e1.getMessage()); // otherwise WPS tries to zip and return non-existing files => null pointer
        }

        //create the output
        HashMap<String, IData> result = new HashMap<String, IData>();

        for (int i = 0; i < this.parameterCount; i++) {
            ToolParameter currentParam = this.parameterDescriptions[i];

            if (currentParam != null // Otherwise, nullpointer exception when trying to process outputs!
                    && currentParam.isOutput) {

                if (currentParam.isComplex) {
                    String fileName = this.toolParameters[i];
                    //GenericFileData outputFileData = new GenericFileData(this.workspace.getFileAsStream(fileName), currentParam.mimeType);

                    File currentFile = new File(fileName);
                    GenericFileDataWithGT outputFileData;
                    try {
                        if (currentParam.schema != null && currentParam.schema.length() > 0) {
                            //we have vector data. So use a shp file.

                            outputFileData = new GenericFileDataWithGT(currentFile,
                                    GenericFileDataConstants.MIME_TYPE_ZIPPED_SHP);
                        } else {
                            outputFileData = new GenericFileDataWithGT(currentFile, currentParam.mimeType);
                        }
                        result.put(currentParam.wpsOutputID, new GenericFileDataWithGTBinding(outputFileData));
                    } catch (FileNotFoundException e) {
                        LOGGER.error("Could not read output file: " + fileName);
                        errors.add("Could not read output file: " + fileName);
                        throw new RuntimeException(
                                "No files found. Probably the process did not create any output files.");
                    } catch (IOException e) {
                        LOGGER.error("Could not create output file from: " + fileName);
                        errors.add("Could not create output file from: " + fileName);
                        e.printStackTrace();
                    }
                }

                if (currentParam.isLiteral) {
                    // not implemented
                }
                if (currentParam.isCRS) {
                    // not implemented
                }
            }
        }

        //Handle if no result was created
        if (result.isEmpty()) {
            String message = "";
            for (String error : errors) {
                message = message.concat(error + " - ");
            }
            message = message.concat("ArcGIS Backend Process " + this.processID + " did not return any output"
                    + " data or the output data could not be processed.");
            throw new RuntimeException(message);
        }
        return result;
    }

    private String loadSingleDataItem(IData dataItem) {

        Object payload = dataItem.getPayload();
        String value = null;

        //File
        if (payload instanceof GenericFileDataWithGT) {
            GenericFileDataWithGT gfd = (GenericFileDataWithGT) payload;
            value = gfd.writeData(this.workspace.getWorkspace());
        }

        //String
        else if (payload instanceof String)
            value = (String) payload;

        //Float
        else if (payload instanceof Float)
            value = ((Float) payload).toString();

        //Integer
        else if (payload instanceof Integer)
            value = ((Integer) payload).toString();

        //Double
        else if (payload instanceof Double)
            value = ((Double) payload).toString();

        return value;
    }

    private String calcToolParameterString(String valueSeparator, String[] valueArray) {

        String returnValue = null;
        boolean firstrun = true;

        for (String currentValue : valueArray) {
            if (firstrun) {
                firstrun = false;
                returnValue = currentValue;
            } else {
                returnValue = returnValue + valueSeparator + currentValue;
            }
        }

        return returnValue;
    }

    private final String addOutputFile(String fileName) {
        String newFileName = this.workspace.getWorkspace().getAbsolutePath() + "\\" + fileName;
        return newFileName;
    }

    //delete the current workspace
    protected void finalize() {
        try {
            FileUtils.deleteDirectory(instanceWorkspace);
        } catch (IOException e) {
            LOGGER.error("Could not delete dead workspace:\n" + instanceWorkspace.getAbsolutePath());
            e.printStackTrace();
        }
    }
}