/**
* Copyright (C) 2009 - 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.ags.algorithmpackage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URI;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import net.opengis.wps.x100.InputDescriptionType;
import net.opengis.wps.x100.OutputDescriptionType;
import net.opengis.wps.x100.ProcessDescriptionType;
import net.opengis.wps.x100.ProcessDescriptionsDocument;
/**
* @author Matthias Mueller, TU Dresden
*
*/
public class AlgorithmPackage {
private final File algorithmWorkspace;
private ProcessDescriptionType processDescription;
private AlgorithmDescription algorithmDescription;
static Logger LOGGER = LoggerFactory.getLogger(AlgorithmPackage.class);
public AlgorithmPackage (ProcessDescriptionType pd, AlgorithmDescription ad, File algorithmWorkspace){
// create descriptions
algorithmDescription = ad;
processDescription = pd;
// assign workspace
this.algorithmWorkspace = algorithmWorkspace;
}
public AlgorithmPackage (File processDescriptionXML, File workspaceTemplateRoot){
// create descriptions
processDescription = createProcessDescription(processDescriptionXML);
algorithmDescription = createAlgorithmDescription(processDescriptionXML);
// assemble template workspace
String wsDirString = workspaceTemplateRoot.getAbsolutePath() + File.separator + getWorkspacePathFragment();
try {
wsDirString = new File(wsDirString).getCanonicalPath();
} catch (IOException e) {
LOGGER.warn("Could not determine the workspace's canonical path. Possibly a malformed AlgorithmDescription.\n"
+ "rootDirectory is: " + workspaceTemplateRoot.getAbsolutePath() + "\n"
+ "workspacePathFragment is: " + getWorkspacePathFragment());
}
algorithmWorkspace = new File(wsDirString);
}
public AlgorithmPackage createChild (File destinationRoot) throws IOException{
FileUtils.copyDirectoryToDirectory(algorithmWorkspace, destinationRoot);
File wsDir = new File(destinationRoot.getAbsolutePath() + File.separator + getWorkspacePathFragment());
AlgorithmPackage child = new AlgorithmPackage(processDescription, algorithmDescription, wsDir);
return child;
}
public String getProcessID(){
return processDescription.getIdentifier().getStringValue();
}
public boolean isContainer(URI containerURN){
String str = containerURN.toString();
if (str.equalsIgnoreCase(algorithmDescription.getContainerType())){
return true;
} else {
return false;
}
}
public boolean isContainer(URI[] containerURNs){
for(URI currentContainer : containerURNs){
if (isContainer(currentContainer)){
return true;
}
}
return false;
}
public boolean isSufficientRuntimeEnvironment (URI[] runtimeURNs){
boolean doublecheck = true;
for (String myCurrentRuntime : algorithmDescription.getRequiredRuntimeComponent()){
boolean check = false;
for (URI yourCurrentRuntime : runtimeURNs){
if (yourCurrentRuntime.toString().equalsIgnoreCase(myCurrentRuntime)){
check = true;
}
}
doublecheck = check && doublecheck;
}
return doublecheck;
}
public ProcessDescriptionType getProcessDescription(){
return processDescription;
}
public File getInstanceWorkspace(){
return algorithmWorkspace;
}
public AlgorithmURL getAlgorithmURL(){
return new AlgorithmURL(algorithmDescription.getAlgorithmLocation());
}
public List<AlgorithmParameterType> getParameters(){
return algorithmDescription.getAlgorithmParameters().getParameter();
}
public String getDefaultMimeType(String paramID){
String mimeType = null;
// check inputs for a match
for (InputDescriptionType currentInput : processDescription.getDataInputs().getInputArray()){
if (currentInput.getIdentifier().getStringValue().equalsIgnoreCase(paramID)){
mimeType = currentInput.getComplexData().getDefault().getFormat().getMimeType();
}
}
for (OutputDescriptionType currentOutput : processDescription.getProcessOutputs().getOutputArray()){
if (currentOutput.getIdentifier().getStringValue().equalsIgnoreCase(paramID)){
mimeType = currentOutput.getComplexOutput().getDefault().getFormat().getMimeType();
}
}
return mimeType;
}
private String getWorkspacePathFragment(){
return algorithmDescription.getWorkspaceLocation();
}
private static AlgorithmDescription createAlgorithmDescription (File xmlFile) {
// create the AlgorithmDescription document from DescribeProcess file
StringReader adReader = generateAlgorithmDescription(xmlFile);
try {
JAXBContext jc = JAXBContext.newInstance(AlgorithmDescription.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
AlgorithmDescription ad = (AlgorithmDescription) unmarshaller.unmarshal(adReader);
return ad;
} catch (JAXBException e) {
LOGGER.error("Unable to create AlgorithmDescription from xmlFile: " + xmlFile.getAbsolutePath());
e.printStackTrace();
return null;
}
}
private static ProcessDescriptionType createProcessDescription (File describeProcessFile){
try {
InputStream xmlDesc = new FileInputStream(describeProcessFile);
XmlOptions option = new XmlOptions();
option.setLoadTrimTextBuffer();
ProcessDescriptionsDocument doc = ProcessDescriptionsDocument.Factory.parse(xmlDesc, option);
if(doc.getProcessDescriptions().getProcessDescriptionArray().length == 0) {
LOGGER.warn("ProcessDescription is empty!");
return null;
}
return doc.getProcessDescriptions().getProcessDescriptionArray(0);
}
catch(IOException e) {
LOGGER.warn("Could not initialize algorithm, parsing error! ", e);
}
catch(XmlException e) {
LOGGER.warn("Could not initialize algorithm, parsing error! ", e);
}
return null;
}
/**
* Generates an XML file. Uses a ProcessDescription file and a XSLT file to generate an
* AlgorithmDescription.
*
* @param xmlFile - the ProcessDescription in XML
* @param xsltFile - the transformation rules in XSLT
* @throws Exception - the exceptions
*/
private static StringReader generateAlgorithmDescription(File xmlFile) {
Source xmlSource = new StreamSource(xmlFile);
TransformerFactory transFact = TransformerFactory.newInstance();
StringWriter sw = new StringWriter();
StreamResult transformResult = new StreamResult(sw);
try {
Source xsltSource = transFact.getAssociatedStylesheet(xmlSource, null, null, null);
Transformer trans = transFact.newTransformer(xsltSource);
trans.transform(xmlSource, transformResult);
StringReader sr = new StringReader(sw.toString());
return sr;
} catch (TransformerException e) {
LOGGER.error("Error evaluating ProcessDescription XML.");
e.printStackTrace();
}
return null;
}
}