/**
* Copyright (C) 2007 - 2014 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.transactional.deploy.bpel.apache;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import net.opengis.wps.x100.DataInputsType;
import net.opengis.wps.x100.ExecuteDocument;
import net.opengis.wps.x100.InputType;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.util.Base64;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.OperationClient;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.saaj.util.SAAJUtil;
import org.n52.wps.PropertyDocument.Property;
import org.n52.wps.commons.WPSConfig;
import org.n52.wps.server.ITransactionalAlgorithmRepository;
import org.n52.wps.transactional.deploy.AbstractProcessManager;
import org.n52.wps.transactional.deploymentprofiles.BPELDeploymentProfile;
import org.n52.wps.transactional.deploymentprofiles.DeploymentProfile;
import org.n52.wps.transactional.request.DeployProcessRequest;
import org.n52.wps.transactional.request.UndeployProcessRequest;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public class ApacheBPELManager extends AbstractProcessManager {
private ODEServiceClient _client;
private OMFactory _factory;
private String deploymentEndpoint;
private String processManagerEndpoint;
public ApacheBPELManager(ITransactionalAlgorithmRepository repository) {
super(repository);
Property[] properties = WPSConfig.getInstance().getPropertiesForRepositoryClass(repository.getClass().getName());
//TODO think of multiple instance of this class registered (yet not possible since singleton)
Property deployEndpointProperty = WPSConfig.getInstance().getPropertyForKey(properties, "ODE-Engine_DeploymentEndpoint");
if(deployEndpointProperty==null){
throw new RuntimeException("Error. Could not find ODE-Engine_DeploymentEndpoint");
}
deploymentEndpoint = deployEndpointProperty.getStringValue();
Property processManagerEndpointProperty = WPSConfig.getInstance().getPropertyForKey(properties, "ODE-Engine_ProcessManagerEndpoint");
if(processManagerEndpointProperty==null){
throw new RuntimeException("Error. Could not find ODE-Engine_ProcessManagerEndpoint");
}
processManagerEndpoint = processManagerEndpointProperty.getStringValue();
try{
_factory = OMAbstractFactory.getOMFactory();
_client = new ODEServiceClient();
}catch(Exception e){
e.printStackTrace();
}
}
public boolean deployProcess(DeployProcessRequest request) throws Exception {
boolean blnresult = false;
// WPS-T preparation
DeploymentProfile profile = request.getDeploymentProfile();
if(! (profile instanceof BPELDeploymentProfile)){
throw new Exception("Requested Deployment Profile not supported");
}
BPELDeploymentProfile deploymentProfile = (BPELDeploymentProfile) profile;
String processID = deploymentProfile.getProcessID();
Node suitcase = deploymentProfile.getSuitCase();
System.out.println(nodeToString(suitcase));
Node workflow = deploymentProfile.getBPEL();
System.out.println(nodeToString(workflow));
Node clientWSDL = deploymentProfile.getClientWSDL();
System.out.println(nodeToString(clientWSDL));
Map<Integer, Node> wsdlList = deploymentProfile.getWSDLList();
//ODE preparation
OMElement result = null;
try{
OMNamespace pmapi = _factory.createOMNamespace("http://www.apache.org/ode/pmapi", "pmapi");
OMElement root = _factory.createOMElement("deploy", null); // qualified operation name
OMElement namePart = _factory.createOMElement("name", null);
namePart.setNamespace(pmapi);
namePart.setText(processID);
//OMElement zipPart = _factory.createOMElement("package", null);
OMElement zipPart = _factory.createOMElement("package", pmapi);
//OMElement zipElmt = _factory.createOMElement("zip", null);
OMElement zipElmt = _factory.createOMElement("zip", pmapi);
File zipFile = File.createTempFile("wpsbpel", ".zip", null);
int res = ZipCreator.makeZIP(processID, suitcase, workflow, clientWSDL, wsdlList, zipFile);
try{
InputStream is = new BufferedInputStream(new FileInputStream(zipFile));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try{
for (int b = is.read(); b >= 0; b = is.read()) {
outputStream.write((byte) b);
}
String base64Enc = Base64.encode(outputStream.toByteArray());
OMText zipContent = _factory.createOMText(base64Enc, "application/zip", true);
root.addChild(namePart);
root.addChild(zipPart);
zipPart.addChild(zipElmt);
zipElmt.addChild(zipContent);
}catch (Exception e){
e.printStackTrace();
}
}catch(FileNotFoundException e){
e.printStackTrace();
}
// Deploy
try{
result = sendToDeployment(root);
}catch(Exception e){
e.printStackTrace();
blnresult = false;
}
}catch(NullPointerException npe){
npe.printStackTrace();
}
//if (result != null){
if (result.toString().contains("response"))
blnresult = true;
//}
return blnresult;
//throw new UnsupportedOperationException("Not supported yet.");
}
public boolean unDeployProcess(String processID) throws Exception {
// Prepare undeploy message
OMNamespace pmapi = _factory.createOMNamespace("http://www.apache.org/ode/pmapi", "pmapi");
OMElement root = _factory.createOMElement("undeploy", pmapi); // qualified operation name
OMElement part = _factory.createOMElement("processName", pmapi);
part.setText(processID);
root.addChild(part);
// Undeploy
sendToDeployment(root);
return true;
}
public Document invoke(ExecuteDocument doc, String algorithmID) throws Exception {
Node domNode = doc.getDomNode();
//doc.save(new File("d:\\tmp\\execdoc.xml"));
//String serializedXML = writeXMLToStream(new DOMSource(domNode)).toString();
// serializedXML = serializedXML.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>","");
// serializedXML = serializedXML.replace("<Execute xmlns=\"http://www.opengis.net/wps/1.0.0\">","<Execute xmlns=\"http://www.opengis.net/wps/1.0.0\" version=\"1.0.0\" service=\"WPS\">");
// serializedXML = serializedXML.replace(" href"," xmlns:xlin=\"http://www.w3.org/1999/xlink\" xlin:href");
ServiceClient client = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
SOAPEnvelope response = null;
try{
client = new ServiceClient();
OperationClient operationClient = client.createClient(ServiceClient.ANON_OUT_IN_OP);
//creating message context
MessageContext outMsgCtx = new MessageContext();
//assigning message context's option object into instance variable
Options opts = outMsgCtx.getOptions();
//setting properties into option
//TODO is this correct?
opts.setTo(new EndpointReference(deploymentEndpoint.replace("DeploymentService", algorithmID)));
opts.setAction("");
outMsgCtx.setEnvelope(createSOAPEnvelope(doc));
operationClient.addMessageContext(outMsgCtx);
operationClient.execute(true);
MessageContext inMsgtCtx = operationClient.getMessageContext("In");
response = inMsgtCtx.getEnvelope();
}catch(AxisFault af){
}finally{
// if (client != null){
// try{
// client.cleanupTransport();
//
// }catch(Exception e){
// e.printStackTrace();
// }
// try{
// client.cleanup();
// }catch(Exception e){
// e.printStackTrace();
// }
// }
}
//TODO: Parse SoapEnvelope to DOM Document
Document result = SAAJUtil.getDocumentFromSOAPEnvelope(response);
if (client != null) {
try {
client.cleanupTransport();
} catch (Exception e) {
e.printStackTrace();
}
try {
client.cleanup();
} catch (Exception e) {
e.printStackTrace();
}
}
//Document result = builder.parse((InputStream)response.getXMLStreamReader());
//System.out.print(result.toString());
return result;
//throw new UnsupportedOperationException("Not supported yet.");
}
public Collection<String> getAllProcesses() throws Exception {
try{
List<String> allProcesses = new ArrayList<String>();
//ServiceClient sc = new ServiceClient(null, null);
OMElement listRoot = _client.buildMessage("listAllProcesses", new String[] {}, new String[] {});
OMElement result = sendToPM(listRoot);
Iterator<OMElement> pi = result.getFirstElement().getChildrenWithName(
new QName("http://www.apache.org/ode/pmapi/types/2006/08/02/","process-info"));
while (pi.hasNext()) {
OMElement omPID = pi.next();
String fullName = omPID.getFirstChildWithName(
new QName("http://www.apache.org/ode/pmapi/types/2006/08/02/","pid")).getText();
/*just take the name as defined by the user...
* whats returned originally was something like
* {http://xy.z}ProcessName-XXX (-XXX is attached due to the ODE-versioning)
* this lead to problems with the processdescription, which
* has the name "ProcessName"
*/
allProcesses.add(fullName.substring(fullName.indexOf("}") + 1, fullName.indexOf("-")));
}
return allProcesses;
}catch(Exception e){
return new ArrayList<String>();
}
}
public boolean containsProcess(String processID) throws Exception {
boolean containsProcess = false;
//need to filter out the namespace if it is passed in.
if (processID.contains("}"))
processID = processID.split("}")[1];
try{
OMElement listRoot = _client.buildMessage("listProcesses", new String[] {"filter", "orderKeys"},
new String[] {"name="+processID+"", ""});
OMElement result = sendToPM(listRoot);
if (result.toString().contains(processID))
containsProcess = true;
}catch(AxisFault af){
containsProcess = false;
af.printStackTrace();
}catch(Exception e){
containsProcess = false;
e.printStackTrace();
}
//return getAllProcesses().contains(processID);
return containsProcess;
//throw new UnsupportedOperationException("Not supported yet.");
}
public boolean unDeployProcess(UndeployProcessRequest request) throws Exception {
//unDeployProcess(String processID) is implemented though...
return unDeployProcess((String)request.getProcessID());
//return false;
//throw new UnsupportedOperationException("Not supported yet.");
}
private OMElement sendToPM(OMElement msg) throws AxisFault {
return _client.send(msg,this.processManagerEndpoint);
//return _PMclient.send(msg, this.processManagerEndpoint,10000);
}
private OMElement sendToDeployment(OMElement msg) throws AxisFault {
return _client.send(msg,this.deploymentEndpoint);
//return _DEPclient.send(msg,this.deploymentEndpoint,10000);
}
private ByteArrayOutputStream writeXMLToStream(Source source) throws TransformerException {
// Prepare the DOM document for writing
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Prepare the output file
Result result = new StreamResult(out);
//System.etProperty("javax.xml.transform.TransformerFactory","com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
// Write the DOM document to the file
TransformerFactory x = TransformerFactory.newInstance();
Transformer xformer = x.newTransformer();
xformer.transform(source, result);
return out;
}
private String nodeToString(Node node) throws TransformerFactoryConfigurationError, TransformerException {
StringWriter stringWriter = new StringWriter();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(node), new StreamResult(stringWriter));
return stringWriter.toString();
}
public SOAPEnvelope createSOAPEnvelope(Node domNode) {
SOAPFactory fac = OMAbstractFactory.getSOAP11Factory();
SOAPEnvelope envelope = fac.getDefaultEnvelope();
NamespaceContext ctx = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
String uri;
if (prefix.equals("wps"))
uri = "http://www.opengis.net/wps/1.0.0";
else if (prefix.equals("ows"))
uri = "http://www.opengis.net/ows/1.1";
else
uri = null;
return uri;
}
public String getPrefix(String namespaceURI) {
return null;
}
public Iterator getPrefixes(String namespaceURI) {
return null;
}
};
XPathFactory xpathFact =
XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
xpath.setNamespaceContext(ctx);
String identifier = null;
String input = null;
String xpathidentifier = "//ows:Identifier";
String xpathinput = "//wps:DataInputs/wps:Input/wps:Data/wps:LiteralData";
try{
identifier = xpath.evaluate(xpathidentifier, domNode);
input = xpath.evaluate(xpathinput, domNode);
}catch(Exception e){
e.printStackTrace();
}
//OMNamespace wpsNs = fac.createOMNamespace("http://scenz.lcr.co.nz/wpsHelloWorld", "wps");
OMNamespace wpsNs = fac.createOMNamespace("http://scenz.lcr.co.nz/"+ identifier, "wps");
// creating the payload
//TODO: parse the domNode to a request doc
//OMElement method = fac.createOMElement("wpsHelloWorldRequest", wpsNs);
OMElement method = fac.createOMElement(identifier + "Request", wpsNs);
OMElement value = fac.createOMElement("input", wpsNs);
//value.setText("Niels");
value.setText(input);
method.addChild(value);
envelope.getBody().addChild(method);
return envelope;
}
@SuppressWarnings("unchecked")
private SOAPEnvelope createSOAPEnvelope(ExecuteDocument execDoc) {
SOAPFactory fac = OMAbstractFactory.getSOAP11Factory();
SOAPEnvelope envelope = fac.getDefaultEnvelope();
NamespaceContext ctx = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
String uri;
if (prefix.equals("wps"))
uri = "http://www.opengis.net/wps/1.0.0";
else if (prefix.equals("ows"))
uri = "http://www.opengis.net/ows/1.1";
else
uri = null;
return uri;
}
public String getPrefix(String namespaceURI) {
return null;
}
public Iterator getPrefixes(String namespaceURI) {
return null;
}
};
_client = new ODEServiceClient();
HashMap<String, String> allProcesses = new HashMap<String, String>();
OMElement listRoot = _client.buildMessage("listAllProcesses",
new String[] {}, new String[] {});
OMElement result = null;
try {
result = sendToPM(listRoot);
} catch (AxisFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Iterator<OMElement> pi = result.getFirstElement().getChildrenWithName(
new QName("http://www.apache.org/ode/pmapi/types/2006/08/02/",
"process-info"));
while (pi.hasNext()) {
OMElement omPID = pi.next();
String fullName = omPID
.getFirstChildWithName(
new QName(
"http://www.apache.org/ode/pmapi/types/2006/08/02/",
"pid")).getText();
allProcesses.put(
fullName.substring(fullName.indexOf("}") + 1,
fullName.indexOf("-")),
fullName.substring(1, fullName.indexOf("}")));
}
String identifier = execDoc.getExecute().getIdentifier()
.getStringValue();
OMNamespace wpsNs = null;
for (String string : allProcesses.keySet()) {
if (string.equals(identifier)) {
wpsNs = fac.createOMNamespace(allProcesses.get(string), "nas");
break;
}
}
// creating the payload
// TODO: parse the domNode to a request doc
// OMElement method = fac.createOMElement("wpsHelloWorldRequest",
// wpsNs);
OMElement method = fac.createOMElement(identifier + "Request", wpsNs);
envelope.getBody().addChild(method);
DataInputsType datainputs = execDoc.getExecute().getDataInputs();
for (InputType input1 : datainputs.getInputArray()) {
String inputIdentifier = input1.getIdentifier().getStringValue();
OMElement value = fac.createOMElement(inputIdentifier, "", "");
if (input1.getData() != null
&& input1.getData().getLiteralData() != null) {
value.setText(input1.getData().getLiteralData()
.getStringValue());
} else {
// Node no =
// input1.getData().getComplexData().getDomNode().getChildNodes().item(1);
// value.setText("<![CDATA[" + nodeToString(no) + "]>");
// value.addChild(no);
OMElement reference = fac.createOMElement("Reference",
"http://www.opengis.net/wps/1.0.0", "wps");
OMNamespace xlin = fac.createOMNamespace(
"http://www.w3.org/1999/xlink", "xlin");
OMAttribute attr = fac.createOMAttribute("href", xlin, input1
.getReference().getHref());
reference.addAttribute(attr);
reference.addAttribute("schema", input1.getReference()
.getSchema(), fac.createOMNamespace("", ""));
value.addChild(reference);
}
method.addChild(value);
}
return envelope;
}
}