/**
* Copyright (C) 2007 - 2016 52°North 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.grass;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import net.opengis.wps.x100.ComplexDataDescriptionType;
import net.opengis.wps.x100.InputDescriptionType;
import net.opengis.wps.x100.OutputDescriptionType;
import net.opengis.wps.x100.ProcessDescriptionType;
import net.opengis.wps.x100.ProcessDescriptionsDocument;
import net.opengis.wps.x100.SupportedComplexDataInputType;
import net.opengis.wps.x100.SupportedComplexDataType;
import org.apache.xmlbeans.XmlException;
import org.n52.wps.io.IOHandler;
import org.n52.wps.io.data.GenericFileDataConstants;
import org.n52.wps.io.datahandler.parser.GenericFileDataWithGTParser;
import org.n52.wps.server.grass.io.GrassIOHandler;
import org.n52.wps.server.grass.util.JavaProcessStreamReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Benjamin Pross (bpross-52n)
*
*/
public class GrassProcessDescriptionCreator {
private final String fileSeparator = System.getProperty("file.separator");
private final String lineSeparator = System.getProperty("line.separator");
private String grassHome = "";
private String pythonHome = "";
private String pythonPath = "";
private String addonPath = "";
private String[] envp = null;
private static Logger LOGGER = LoggerFactory.getLogger(GrassProcessDescriptionCreator.class);
private final String wpsProcessDescCmd = " --wps-process-description";
private Runtime rt = Runtime.getRuntime();
private ExecutorService executor = Executors.newFixedThreadPool(10);
private String gisrcDir;
public GrassProcessDescriptionCreator() {
grassHome = GrassProcessRepository.grassHome;
pythonHome = GrassProcessRepository.pythonHome;
pythonPath = GrassProcessRepository.pythonPath;
gisrcDir = GrassProcessRepository.gisrcDir;
addonPath = GrassProcessRepository.addonPath;
}
public ProcessDescriptionType createDescribeProcessType(String identifier, boolean addon)
throws IOException, XmlException {
Process proc = null;
//addons have their own directory and are python scripts
if(addon){
if (!GrassIOHandler.OS_Name.startsWith("Windows")) {
proc = rt.exec(addonPath + fileSeparator +
identifier + wpsProcessDescCmd,
getEnvp());
} else {
proc = rt.exec(pythonHome + fileSeparator + "python.exe " + addonPath
+ fileSeparator + identifier + ".py"
+ wpsProcessDescCmd, getEnvp());
}
} else {
if (!GrassIOHandler.OS_Name.startsWith("Windows")) {
proc = rt.exec(grassHome + fileSeparator + "bin"
+ fileSeparator + identifier + wpsProcessDescCmd,
getEnvp());
} else {
proc = rt.exec(grassHome + fileSeparator + "bin"
+ fileSeparator + identifier + ".exe"
+ wpsProcessDescCmd, getEnvp());
}
}
PipedOutputStream pipedOut = new PipedOutputStream();
PipedInputStream pipedIn = new PipedInputStream(pipedOut);
PipedOutputStream pipedOutError = new PipedOutputStream();
PipedInputStream pipedInError = new PipedInputStream(pipedOutError);
// attach error stream reader
JavaProcessStreamReader errorGobbler = new JavaProcessStreamReader(proc.getErrorStream(),
"ERROR", pipedOutError);
// attach output stream reader
JavaProcessStreamReader outputGobbler = new JavaProcessStreamReader(proc.getInputStream(),
"OUTPUT", pipedOut);
// start them
executor.execute(errorGobbler);
executor.execute(outputGobbler);
BufferedReader xmlReader = new BufferedReader(new InputStreamReader(
pipedIn));
String line = xmlReader.readLine();
String xml = "";
while (line != null) {
xml = xml.concat(line + lineSeparator);
line = xmlReader.readLine();
}
pipedIn.close();
pipedOut.close();
xmlReader.close();
BufferedReader errorReader = new BufferedReader(new InputStreamReader(
pipedInError));
String errorLine = errorReader.readLine();
String errors = "";
while (errorLine != null) {
errors = errors.concat(errorLine + lineSeparator);
errorLine = errorReader.readLine();
}
if (errors != "") {
LOGGER.error("Error while creating processdescription for process "
+ identifier + ": " + errors);
}
pipedInError.close();
pipedOutError.close();
errorReader.close();
try {
proc.waitFor();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
proc.destroy();
ProcessDescriptionsDocument pDoc = ProcessDescriptionsDocument.Factory
.parse(xml);
int i = pDoc.getProcessDescriptions().getProcessDescriptionArray().length;
if (i == 1) {
ProcessDescriptionType result = pDoc.getProcessDescriptions()
.getProcessDescriptionArray()[0];
InputDescriptionType[] inputs = result.getDataInputs().getInputArray();
for (InputDescriptionType inputDescriptionType : inputs) {
checkForBase64Encoding(inputDescriptionType.getComplexData());
checkForKMLMimeType(inputDescriptionType);
addZippedSHPMimeType(inputDescriptionType);
}
SupportedComplexDataType outputType = result.getProcessOutputs()
.getOutputArray(0).getComplexOutput();
if (outputType != null) {
String schema = outputType.getDefault().getFormat().getSchema();
if (schema != null) {
if (schema
.contains("http://schemas.opengis.net/gml/2.0.0/feature.xsd")
|| schema
.contains("http://schemas.opengis.net/gml/2.1.1/feature.xsd")
|| schema
.contains("http://schemas.opengis.net/gml/2.1.2/feature.xsd")
|| schema
.contains("http://schemas.opengis.net/gml/2.1.2.1/feature.xsd")
|| schema
.contains("http://schemas.opengis.net/gml/3.0.0/base/feature.xsd")
|| schema
.contains("http://schemas.opengis.net/gml/3.0.1/base/feature.xsd")
|| schema
.contains("http://schemas.opengis.net/gml/3.1.1/base/gml.xsd")
|| schema
.contains("http://schemas.opengis.net/gml/3.1.1/base/feature.xsd")) {
ComplexDataDescriptionType xZippedShapeType = outputType.getSupported().addNewFormat();
xZippedShapeType.setMimeType(IOHandler.MIME_TYPE_ZIPPED_SHP);
xZippedShapeType.setEncoding(IOHandler.ENCODING_BASE64);
ComplexDataDescriptionType xZippedShapeTypeUTF8 = outputType.getSupported().addNewFormat();
xZippedShapeTypeUTF8.setMimeType(IOHandler.MIME_TYPE_ZIPPED_SHP);
}
}
checkForBase64Encoding(result.getProcessOutputs()
.getOutputArray(0).getComplexOutput());
checkForKMLMimeType(result.getProcessOutputs()
.getOutputArray(0));
}
return result;
}
return null;
}
private void checkForBase64Encoding(SupportedComplexDataType complexData){
if(complexData == null){
return;
}
String[] genericFileParserMimeTypes = new GenericFileDataWithGTParser().getSupportedFormats();
ComplexDataDescriptionType[] supportedTypes = complexData.getSupported().getFormatArray();
for (ComplexDataDescriptionType complexDataDescriptionType : supportedTypes) {
String supportedMimeType = complexDataDescriptionType.getMimeType();
String supportedEncoding = complexDataDescriptionType.getEncoding();
if(supportedMimeType != null && supportedEncoding == null){
for (String mimeType : genericFileParserMimeTypes) {
if(mimeType.equals(IOHandler.MIME_TYPE_ZIPPED_SHP)){
continue;
}
if(mimeType.equals(supportedMimeType)){
ComplexDataDescriptionType base64Format = complexData.getSupported().addNewFormat();
base64Format.setMimeType(supportedMimeType);
base64Format.setEncoding(IOHandler.ENCODING_BASE64);
}
}
}
}
}
private void checkForKMLMimeType(InputDescriptionType inputDescriptionType) {
SupportedComplexDataInputType complexData = inputDescriptionType.getComplexData();
if(complexData == null){
return;
}
if(complexData.getDefault().getFormat().getSchema() != null && complexData.getDefault().getFormat().getSchema().equals("http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd")){
complexData.getDefault().getFormat().setMimeType(GenericFileDataConstants.MIME_TYPE_KML);
return;
}
ComplexDataDescriptionType[] supportedTypes = complexData.getSupported().getFormatArray();
for (ComplexDataDescriptionType complexDataDescriptionType : supportedTypes) {
if(complexDataDescriptionType.getSchema() != null && complexDataDescriptionType.getSchema().equals("http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd")){
complexDataDescriptionType.setMimeType(GenericFileDataConstants.MIME_TYPE_KML);
return;
}
}
}
private void addZippedSHPMimeType(InputDescriptionType inputDescriptionType) {
SupportedComplexDataInputType complexData = inputDescriptionType.getComplexData();
if(complexData == null){
return;
}
ComplexDataDescriptionType[] supportedTypes = complexData.getSupported().getFormatArray();
for (ComplexDataDescriptionType complexDataDescriptionType : supportedTypes) {
if(complexDataDescriptionType.getSchema() != null && complexDataDescriptionType.getSchema().equals("http://schemas.opengis.net/gml/2.1.2/feature.xsd")){
inputDescriptionType.getComplexData().getSupported().addNewFormat().setMimeType(IOHandler.MIME_TYPE_ZIPPED_SHP);
return;
}
}
}
private void checkForKMLMimeType(OutputDescriptionType outputDescriptionType) {
SupportedComplexDataType complexData = outputDescriptionType.getComplexOutput();
if(complexData == null){
return;
}
if(complexData.getDefault().getFormat().getSchema() != null && complexData.getDefault().getFormat().getSchema().equals("http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd")){
complexData.getDefault().getFormat().setMimeType(GenericFileDataConstants.MIME_TYPE_KML);
return;
}
ComplexDataDescriptionType[] supportedTypes = complexData.getSupported().getFormatArray();
for (ComplexDataDescriptionType complexDataDescriptionType : supportedTypes) {
if(complexDataDescriptionType.getSchema() != null && complexDataDescriptionType.getSchema().equals("http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd")){
complexDataDescriptionType.setMimeType(GenericFileDataConstants.MIME_TYPE_KML);
return;
}
}
}
private String[] getEnvp() {
if (envp == null) {
if (GrassIOHandler.OS_Name.startsWith("Windows")) {
envp = new String[] {
"GISRC=" + gisrcDir,
"GDAL_DATA=" + grassHome + fileSeparator + "etc"
+ fileSeparator + "ogr_csv",
"GISBASE=" + grassHome,
"PATH=" + grassHome + fileSeparator + "lib;"
+ grassHome + fileSeparator + "bin;"
+ grassHome + fileSeparator + "scripts;"
+ pythonHome + ";" + grassHome + fileSeparator
+ "extralib;" + grassHome + fileSeparator
+ "extrabin",
"LD_LIBRARY_PATH=" + grassHome + fileSeparator + "lib",
"PWD=" + grassHome,
"PYTHONHOME=" + pythonHome,
"PYTHONPATH=" + grassHome + fileSeparator + "etc"
+ fileSeparator + "python",
"GRASS_CONFIG_DIR=.grass7",
"GRASS_GNUPLOT=gnuplot -persist", "GRASS_PAGER=less",
"GRASS_PYTHON=python", "GRASS_SH=/bin/sh",
"GRASS_VERSION=7.0.svn", "WINGISBASE=" + grassHome };
}else{
envp = new String[] {
"GISRC=" + gisrcDir,
"GDAL_DATA=" + grassHome + fileSeparator + "etc"
+ fileSeparator + "ogr_csv",
"GISBASE=" + grassHome,
"PATH=" + grassHome + fileSeparator + "lib:"
+ grassHome + fileSeparator + "bin:"
+ grassHome + fileSeparator + "scripts:"
+ pythonHome + ":" + grassHome + fileSeparator
+ "extralib:" + grassHome + fileSeparator
+ "extrabin",
"LD_LIBRARY_PATH=" + grassHome + fileSeparator + "lib",
"PWD=" + grassHome,
"PYTHONHOME=" + pythonHome,
"PYTHONPATH=" + grassHome + fileSeparator + "etc"
+ fileSeparator + "python" + ":" + pythonPath,
"GRASS_CONFIG_DIR=.grass7",
"GRASS_GNUPLOT=gnuplot -persist", "GRASS_PAGER=less",
"GRASS_PYTHON=python", "GRASS_SH=/bin/sh",
"GRASS_VERSION=7.0.svn"};
}
}
return envp;
}
}