/*
* Copyright (c) 2009, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wso2.carbon.bpel.b4p.extension;
import org.apache.ode.bpel.o.OPartnerLink;
import org.apache.ode.bpel.o.OProcess;
import org.apache.ode.bpel.runtime.BpelRuntimeContext;
import org.apache.ode.bpel.runtime.extension.ExtensionContext;
import org.apache.ode.bpel.common.FaultException;
import org.apache.ode.bpel.dd.DeployDocument;
import org.apache.ode.bpel.dd.TDeployment;
import org.apache.ode.bpel.dd.TInvoke;
import org.apache.ode.bpel.dd.TProvide;
import org.apache.ode.store.DeploymentUnitDir;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axiom.om.OMElement;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import javax.xml.namespace.QName;
import javax.wsdl.Definition;
import javax.wsdl.Service;
import javax.wsdl.Port;
import javax.wsdl.Operation;
import java.io.File;
import java.util.List;
import com.ibm.wsdl.extensions.soap.SOAPAddressImpl;
public class PeopleActivity {
protected final Log log = LogFactory.getLog(PeopleActivity.class);
private String name;
private String inputVarName;
private String outputVarName;
private boolean isSkipable = false;
private String partnerLinkName;
private String operation;
private String responseOperation;
private EndpointReference targetEPR;
private String serviceURI;
private String servicePort;
private String callbackServicePort;
private OMElement payload = null;
private ExtensionContext extensionContext;
private Element element;
private DeploymentUnitDir du;
private InteractionType activityType;
public InteractionType getActivityType() {
return activityType;
}
public QName getCallbackServiceName() {
return callbackServiceName;
}
public String getCallbackServicePort() {
return callbackServicePort;
}
QName serviceName;
QName callbackServiceName;
Definition hiWSDL;
public PeopleActivity (ExtensionContext extensionContext, Element element) throws FaultException {
this.extensionContext = extensionContext;
this.element = element;
init();
deriveServiceEPR();
}
public Element getInputMessage() throws FaultException {
Node inputNode = extensionContext.readVariable(inputVarName);
if (inputNode.getNodeType() == Node.ELEMENT_NODE) {
return (Element)inputNode;
} else {
log.error("The node type of the variable is not ELEMENT");
throw new FaultException(new QName(B4PExtensionBundle.NS, "Unsupported variable type"));
}
}
public Operation getOperation() {
BpelRuntimeContext runTimeContext = extensionContext.getInternalInstance();
OProcess process = runTimeContext.getProcessModel();
OPartnerLink partnerLink = process.getPartnerLink(partnerLinkName);
return partnerLink.getPartnerRoleOperation(operation);
}
public Operation getCallbackOperation() {
BpelRuntimeContext runTimeContext = extensionContext.getInternalInstance();
OProcess process = runTimeContext.getProcessModel();
OPartnerLink partnerLink = process.getPartnerLink(partnerLinkName);
return partnerLink.getMyRoleOperation(responseOperation);
}
public String getOperationName() {
return operation;
}
public String getEPRURL() {
return serviceURI;
}
public String getServicePort() {
return servicePort;
}
public String getOutputVarName() {
return outputVarName;
}
public DeploymentUnitDir getDu() {
return du;
}
public QName getServiceName() {
return serviceName;
}
public Definition getHiWSDL() {
return hiWSDL;
}
public Definition getCallbackWSDL() {
return du.getDefinitionForService(callbackServiceName);
}
private void init() throws FaultException {
if (!element.getLocalName().equals("peopleActivity") || !element.getNamespaceURI().equals(B4PExtensionBundle.NS)) {
throw new FaultException(new QName(B4PExtensionBundle.NS, "no peopleActivity found"));
}
name = element.getAttribute("name");
inputVarName = element.getAttribute("inputVariable");
outputVarName = element.getAttribute("outputVariable");
isSkipable = element.getAttribute("isSkipable").equalsIgnoreCase("yes");
NodeList taskList = element.getChildNodes();
Node task = null;
int elementNodeCount = 0;
for (int i = 0; i < taskList.getLength(); i++) {
if (taskList.item(i).getNodeType() == Node.ELEMENT_NODE) {
elementNodeCount++;
if (elementNodeCount > 1) {
break;
}
task = taskList.item(i);
}
}
if (elementNodeCount != 1 || task == null) {
log.error("Invalid peopleActivity definition");
throw new FaultException(new QName(B4PExtensionBundle.NS, "Invalid peopleActivity definition"));
}
/*TODO this only checks for b4p namespace, we need to check for <htd:task>...</htd:task> and
<htd:notification>...</htd:notification> which r in ht namespace*/
if (!task.getNamespaceURI().equals(B4PExtensionBundle.NS)) {
throw new FaultException(new QName(B4PExtensionBundle.NS, "Invalid namespace uri for the task. " +
"The valid namespace: " + B4PExtensionBundle.NS));
}
//TODO is it required to read through the element per task type? cant we jst do it once? what about null elements
if (task.getLocalName().equals("remoteTask")) {
activityType = InteractionType.TASK;
if (task.getNodeType() == Node.ELEMENT_NODE) {
Element remoteTaskEle = (Element)task;
partnerLinkName = remoteTaskEle.getAttribute("partnerLink");
operation = remoteTaskEle.getAttribute("operation");
responseOperation = remoteTaskEle.getAttribute("responseOperation");
if (log.isDebugEnabled()) {
log.debug("name: " + name + " inputVarName: " + inputVarName + " outPutVarName: " + outputVarName +
" isSkipable: " + isSkipable + " partnerLinkName: " + partnerLinkName + " operation: " +
operation + " responseOperation: " + responseOperation);
}
} //TODO what if NODE type is not ELEMENT_NODE
} else if (task.getLocalName().equals("remoteNotification")) {
activityType = InteractionType.NOTIFICATION;
if (task.getNodeType() == Node.ELEMENT_NODE) {
Element remoteTaskEle = (Element)task;
partnerLinkName = remoteTaskEle.getAttribute("partnerLink");
operation = remoteTaskEle.getAttribute("operation");
if (log.isDebugEnabled()) {
log.debug("name: " + name + " inputVarName: " + inputVarName + " partnerLinkName: " +
partnerLinkName + " operation: " + operation);
}
} //TODO what if NODE type is not ELEMENT_NODE
} else if (task.getLocalName().equals("localNotification")) {
activityType = InteractionType.NOTIFICATION;
log.warn(task.getLocalName() + " is not supported yet!");
throw new RuntimeException(task.getLocalName() + " is not supported yet!");
} else if (task.getLocalName().equals("localTask")) {
activityType = InteractionType.TASK;
log.warn(task.getLocalName() + " is not supported yet!");
throw new RuntimeException(task.getLocalName() + " is not supported yet!");
}
du = new DeploymentUnitDir(new File(extensionContext.getDUDir()));
}
private void deriveServiceEPR () throws FaultException {
DeployDocument deployDocument = du.getDeploymentDescriptor();
BpelRuntimeContext runTimeContext = extensionContext.getInternalInstance();
//TODO neeed to extend ExtentionContext
OProcess oProcess = runTimeContext.getProcessModel();
TDeployment.Process hiProcess = null;
List<TDeployment.Process> processList = deployDocument.getDeploy().getProcessList();
for (TDeployment.Process process : processList) {
if (process.getName().equals(oProcess.getQName())) {
hiProcess = process;
break;
}
}
if (hiProcess == null) {
throw new FaultException(new QName(B4PExtensionBundle.NS, "related process not found"));
}
List<TInvoke> tInvokeList = hiProcess.getInvokeList();
for (TInvoke tInvoke : tInvokeList) {
if (tInvoke.getPartnerLink().equals(partnerLinkName)) {
serviceName = tInvoke.getService().getName();
servicePort = tInvoke.getService().getPort();
break;
}
}
if (serviceName == null || servicePort == null) {
log.error("service and port for human interaction is not found in the deploy.xml");
throw new FaultException(new QName(B4PExtensionBundle.NS,
"service and port for human interaction is not found in the deploy.xml"));
}
//get the callback information for the TASK
if (activityType.equals(InteractionType.TASK)) {
List<TProvide> tProvideList = hiProcess.getProvideList();
for (TProvide tProvide : tProvideList) {
if (tProvide.getPartnerLink().equals(partnerLinkName)) {
callbackServiceName = tProvide.getService().getName();
callbackServicePort = tProvide.getService().getPort();
break;
}
}
if (callbackServiceName == null || callbackServicePort == null) {
throw new FaultException(new QName(B4PExtensionBundle.NS,
"service and port for human task callback is not found in the deploy.xml"));
}
}
hiWSDL = du.getDefinitionForService(serviceName);
Service service = hiWSDL.getService(serviceName);
Port port = service.getPort(servicePort);
List extList = port.getExtensibilityElements();
for (Object extEle : extList) {
if (extEle instanceof SOAPAddressImpl) {
SOAPAddressImpl soapAddress = (SOAPAddressImpl)extEle;
serviceURI = soapAddress.getLocationURI();
break;
}
}
if (serviceURI == null) {
throw new FaultException(new QName(B4PExtensionBundle.NS, "Service URI is not available"));
}
}
}