/*
* 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 com.ibm.wsdl.extensions.soap.SOAPAddressImpl;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ode.bpel.common.FaultException;
import org.apache.ode.bpel.dao.AttachmentDAO;
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.bpel.engine.MessageExchangeImpl;
import org.apache.ode.bpel.epr.WSDL11Endpoint;
import org.apache.ode.bpel.iapi.MessageExchange;
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.PartnerLinkInstance;
import org.apache.ode.bpel.runtime.extension.ExtensionContext;
import org.apache.ode.store.DeploymentUnitDir;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.bpel.b4p.coordination.B4PCoordinationException;
import org.wso2.carbon.bpel.b4p.coordination.configuration.CoordinationConfiguration;
import org.wso2.carbon.bpel.b4p.coordination.dao.HTCoordinationDAOConnection;
import org.wso2.carbon.bpel.b4p.coordination.dao.HTProtocolHandlerDAO;
import org.wso2.carbon.bpel.b4p.internal.B4PContentHolder;
import org.wso2.carbon.bpel.b4p.internal.B4PServiceComponent;
import org.wso2.carbon.bpel.b4p.utils.SOAPHelper;
import org.wso2.carbon.bpel.common.config.EndpointConfiguration;
import org.wso2.carbon.bpel.core.ode.integration.BPELMessageContext;
import org.wso2.carbon.bpel.core.ode.integration.BPELServerImpl;
import org.wso2.carbon.bpel.core.ode.integration.store.ProcessConfigurationImpl;
import org.wso2.carbon.bpel.core.ode.integration.utils.AxisServiceUtils;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.unifiedendpoint.core.UnifiedEndpoint;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.NetworkUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import javax.wsdl.Binding;
import javax.wsdl.Definition;
import javax.wsdl.Operation;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.http.HTTPBinding;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.wsdl.extensions.soap12.SOAP12Binding;
import javax.xml.namespace.QName;
/**
* ws-HumanTask PeopleActivity implementation.
*/
public class PeopleActivity {
private static final long serialVersionUID = -89894857418738012L;
private 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 callbackOperationName;
private String serviceURI;
private String servicePort;
private String callbackServicePort;
private InteractionType activityType;
private QName processId;
private boolean isRPC = false;
private boolean isTwoWay = true;
private QName serviceName;
private QName callbackServiceName;
private Definition hiWSDL;
private AttachmentPropagation attachmentPropagation;
public PeopleActivity(ExtensionContext extensionContext, Element element) throws FaultException {
init(extensionContext, element);
}
public Operation getOperation(ExtensionContext extensionContext) {
BpelRuntimeContext runTimeContext = extensionContext.getInternalInstance();
OProcess process = runTimeContext.getProcessModel();
OPartnerLink partnerLink = process.getPartnerLink(partnerLinkName);
return partnerLink.getPartnerRoleOperation(operation);
}
public String getOperationName() {
return operation;
}
public String getServicePort() {
return servicePort;
}
public String getOutputVarName() {
return outputVarName;
}
public QName getServiceName() {
return serviceName;
}
public QName getProcessId() {
return processId;
}
/**
* Parse a localTask node and extract the information
*
* @param localTaskNode Node reference of the localTask
*/
private void parseLocalTask(Node localTaskNode) {
activityType = InteractionType.NOTIFICATION;
String warnMsg = localTaskNode.getLocalName() + " is not supported yet!";
log.warn(warnMsg);
throw new RuntimeException(warnMsg);
}
/**
* Parse a localNotification node and extract the information
*
* @param localNotificationNode Node reference of the localNotification
*/
private void parseLocalNotification(Node localNotificationNode) {
activityType = InteractionType.NOTIFICATION;
String warnMsg = localNotificationNode.getLocalName() + " is not supported yet!";
log.warn(warnMsg);
throw new RuntimeException(warnMsg);
}
/**
* Parse a remoteNotification node and extract the information eg - <b4p:remoteNotification
* partnerLink="b4pNPartnerLink" operation="notify"></b4p:remoteNotification>
*
* @param remoteNotificationNode Node reference of the remoteNotification
*/
private void parseRemoteNotification(Node remoteNotificationNode) {
activityType = InteractionType.NOTIFICATION;
if (remoteNotificationNode.getNodeType() == Node.ELEMENT_NODE) {
Element remoteTaskEle = (Element) remoteNotificationNode;
partnerLinkName = remoteTaskEle.
getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_PARTNER_LINK);
operation = remoteTaskEle.
getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_OPERATION);
if (log.isDebugEnabled()) {
log.debug("name: " + name + " inputVarName: " + inputVarName + " partnerLinkName: " +
partnerLinkName + " operation: " + operation);
}
} //TODO what if NODE type is not ELEMENT_NODE
}
/**
* Parse a remoteTask node and extract the information eg - <b4p:remoteTask partnerLink="b4pPartnerLink"
* operation="approve" responseOperation="approvalResponse"> </b4p:remoteTask>
*
* @param remoteTaskNode Node reference of the remoteTask
*/
private void parseRemoteTask(Node remoteTaskNode) {
activityType = InteractionType.TASK;
if (remoteTaskNode.getNodeType() == Node.ELEMENT_NODE) {
Element remoteTaskEle = (Element) remoteTaskNode;
partnerLinkName =
remoteTaskEle.getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_PARTNER_LINK);
operation = remoteTaskEle.getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_OPERATION);
callbackOperationName = remoteTaskEle.getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_RESPONSE_OPERATION);
if (log.isDebugEnabled()) {
log.debug("name: " + name + " inputVarName: " + inputVarName +
" outPutVarName: " + outputVarName + " isSkipable: " +
isSkipable + " partnerLinkName: " + partnerLinkName + " operation: " +
operation + " responseOperation: " + callbackOperationName);
}
} //TODO what if NODE type is not ELEMENT_NODE
}
/**
* Determine the type of the standard element
*
* @param element element to be processed.
* @return the type of Standard Element
* @throws FaultException if the given element is not a standard element
*/
private String getTypeOfStandardElement(Node element) throws FaultException {
if (element.getLocalName().equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY_REMOTE_TASK)) {
return BPEL4PeopleConstants.PEOPLE_ACTIVITY_REMOTE_TASK;
} else if (element.getLocalName().equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY_REMOTE_NOTIFICATION)) {
return BPEL4PeopleConstants.PEOPLE_ACTIVITY_REMOTE_NOTIFICATION;
} else if (element.getLocalName().equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY_LOCAL_NOTIFICATION)) {
return BPEL4PeopleConstants.PEOPLE_ACTIVITY_LOCAL_NOTIFICATION;
} else if (element.getLocalName().equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY_LOCAL_TASK)) {
return BPEL4PeopleConstants.PEOPLE_ACTIVITY_LOCAL_TASK;
} else {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"The given element:" + element.getLocalName() +
" is not a standard Element.");
}
}
/**
* In a peopleActivity element there can be exist only one standard element. eg - Standard Elements are 1. task 2.
* localTask 3. remoteTask 4. remoteNotification etc.
* <p/>
* This method verify there's only one standard element exist and return the type of that standard element
*
* @return
*/
private String extractStandardElementType(Element parentElement) throws FaultException {
NodeList taskList = parentElement.getChildNodes();
String elementType = null;
int standardElementCounter = 0;
for (int i = 0; i < taskList.getLength(); i++) {
if (taskList.item(i).getNodeType() == Node.ELEMENT_NODE) {
try {
elementType = getTypeOfStandardElement(taskList.item(i));
standardElementCounter++;
if (standardElementCounter > 1) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"There is exist more than one standard child elements in " +
BPEL4PeopleConstants.PEOPLE_ACTIVITY);
}
} catch (FaultException e) {
//Do nothing
}
}
}
if (elementType != null) {
return elementType;
} else {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"There is no standard child elements defined in " +
BPEL4PeopleConstants.PEOPLE_ACTIVITY);
}
}
/**
* Determine what the standard element is and process it
*
* @param peopleActivityElement
* @throws FaultException
*/
private void processStandardElement(Element peopleActivityElement) throws FaultException {
try {
String elementType = extractStandardElementType(peopleActivityElement);
if (elementType.equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY_REMOTE_TASK)) {
Node node = peopleActivityElement.getElementsByTagNameNS(BPEL4PeopleConstants.B4P_NAMESPACE,
BPEL4PeopleConstants
.PEOPLE_ACTIVITY_REMOTE_TASK).item(0);
if (node == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Namespace for element:" + elementType + " is not " +
BPEL4PeopleConstants.B4P_NAMESPACE);
}
parseRemoteTask(node);
} else if (elementType.equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY_REMOTE_NOTIFICATION)) {
Node node = peopleActivityElement.getElementsByTagNameNS(BPEL4PeopleConstants
.B4P_NAMESPACE, BPEL4PeopleConstants
.PEOPLE_ACTIVITY_REMOTE_NOTIFICATION).item(0);
if (node == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Namespace for element:" + elementType + " is not " +
BPEL4PeopleConstants.B4P_NAMESPACE);
}
parseRemoteNotification(node);
} else if (elementType.equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY_LOCAL_NOTIFICATION)) {
Node node = peopleActivityElement.getElementsByTagNameNS(BPEL4PeopleConstants
.B4P_NAMESPACE, BPEL4PeopleConstants
.PEOPLE_ACTIVITY_LOCAL_NOTIFICATION).item(0);
if (node == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Namespace for element:" + elementType + " is not " +
BPEL4PeopleConstants.B4P_NAMESPACE);
}
parseLocalNotification(node);
} else if (elementType.equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY_LOCAL_TASK)) {
Node node = peopleActivityElement.getElementsByTagNameNS(BPEL4PeopleConstants.B4P_NAMESPACE,
BPEL4PeopleConstants
.PEOPLE_ACTIVITY_LOCAL_TASK).item(0);
if (node == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Namespace for element:" + elementType + " is not " +
BPEL4PeopleConstants.B4P_NAMESPACE);
}
parseLocalTask(node);
}
} catch (FaultException fex) {
throw fex;
}
}
/**
* Process the <attachmentPropagation/> element defined under peopleActivity
*
* @param peopleActivityElement peopleActivity (parent element) where the <attachmentPropagation/> resides
* @throws FaultException can be raised if there are more than one <attachmentPropagation/> elements defined
* or the namespace for the <attachmentPropagation/> element is not defined correctly
*/
private void processAttachmentPropagationElement(Element peopleActivityElement)
throws FaultException {
NodeList attachmentElementList =
peopleActivityElement.getElementsByTagNameNS(BPEL4PeopleConstants.B4P_NAMESPACE,
BPEL4PeopleConstants
.ATTACHMENT_PROPAGATION_ACTIVITY);
if (attachmentElementList.getLength() > 1) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"More than one elements defined for:" + BPEL4PeopleConstants
.ATTACHMENT_PROPAGATION_ACTIVITY + " inside " +
BPEL4PeopleConstants.PEOPLE_ACTIVITY);
} else if (attachmentElementList.getLength() == 1) {
// <attachmentPropagation/> element processing logic
Node attachmentPropagationElement = attachmentElementList.item(0);
this.attachmentPropagation =
new AttachmentPropagation((Element) attachmentPropagationElement);
} else if (attachmentElementList.getLength() == 0) {
//As the BPEL4PeopleConstants.ATTACHMENT_PROPAGATION_ACTIVITY is not declared. So handling the default
// behavior
if (log.isDebugEnabled()) {
log.debug("No " + BPEL4PeopleConstants.ATTACHMENT_PROPAGATION_ACTIVITY + " " +
"activities found. Hence " +
"assuming the default values defined by specification.");
}
this.attachmentPropagation = new AttachmentPropagation();
} else {
if (peopleActivityElement.
getElementsByTagName(BPEL4PeopleConstants.ATTACHMENT_PROPAGATION_ACTIVITY)
.getLength() > 0) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Namespace defined for :" + BPEL4PeopleConstants
.ATTACHMENT_PROPAGATION_ACTIVITY + " inside " +
BPEL4PeopleConstants.PEOPLE_ACTIVITY + " is wrong.");
}
}
}
private void init(ExtensionContext extensionContext, Element element) throws FaultException {
if (!element.getLocalName().equals(BPEL4PeopleConstants.PEOPLE_ACTIVITY) ||
!element.getNamespaceURI().equals(BPEL4PeopleConstants.B4P_NAMESPACE)) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"No " + BPEL4PeopleConstants.PEOPLE_ACTIVITY + " activity found");
}
name = element.getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_NAME);
inputVarName = element.getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_INPUT_VARIABLE);
outputVarName = element.getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_OUTPUT_VARIABLE);
isSkipable = "yes".equalsIgnoreCase(
element.getAttribute(BPEL4PeopleConstants.PEOPLE_ACTIVITY_IS_SKIPABLE));
processStandardElement(element);
processAttachmentPropagationElement(element);
String duDir = extensionContext.getDUDir().toString();
String duVersion = duDir.substring(duDir.lastIndexOf('-') + 1);
if (duVersion.endsWith("/")) {
duVersion = duVersion.substring(0, duVersion.lastIndexOf("/"));
} else if (duVersion.endsWith("\\")) {
duVersion = duVersion.substring(0, duVersion.lastIndexOf("\\"));
}
// //Commenting this logic to fix memory issues.
// DeploymentUnitDir du = new DeploymentUnitDir(new File(extensionContext.getDUDir()));
// processId = new QName(extensionContext.getProcessModel().getQName().getNamespaceURI(),
// extensionContext.getProcessModel().getQName().getLocalPart() + "-" +
// du.getStaticVersion());
processId = new QName(extensionContext.getProcessModel().getQName().getNamespaceURI(),
extensionContext.getProcessModel().getQName().getLocalPart() + "-" +
duVersion);
Integer tenantId = B4PServiceComponent.getBPELServer().getMultiTenantProcessStore().getTenantId(processId);
DeploymentUnitDir du = B4PServiceComponent.getBPELServer().getMultiTenantProcessStore()
.getTenantsProcessStore(tenantId).getDeploymentUnitDir(processId);
isTwoWay = activityType.equals(InteractionType.TASK);
deriveServiceEPR(du, extensionContext);
}
private void deriveServiceEPR(DeploymentUnitDir du, ExtensionContext extensionContext)
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(BPEL4PeopleConstants.B4P_FAULT, "Related process: " +
oProcess.getQName() + " 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(BPEL4PeopleConstants.B4P_FAULT,
"Service or 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(BPEL4PeopleConstants.B4P_FAULT,
"Service or 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(BPEL4PeopleConstants.B4P_FAULT, "Service URI is not available");
}
}
public Binding getBinding() throws FaultException {
Service serviceDef = hiWSDL.getService(serviceName);
if (serviceDef == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Service definition is not available for service " + serviceName);
}
Port port = serviceDef.getPort(getServicePort());
if (port == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Service port is not available for service " + serviceName + " and port " +
getServicePort());
}
Binding binding = port.getBinding();
if (binding == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Service binding is not available for service " + serviceName + " and port " +
getServicePort());
}
return binding;
}
public SOAPFactory getSoapFactory() throws FaultException {
Binding binding = getBinding();
ExtensibilityElement bindingType = SOAPHelper.getBindingExtension(binding);
if (!(bindingType instanceof SOAPBinding || bindingType instanceof SOAP12Binding ||
bindingType instanceof HTTPBinding)) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Service binding is not supported for service " + serviceName + " and port " +
getServicePort());
}
if (bindingType instanceof SOAPBinding) {
return OMAbstractFactory.getSOAP11Factory();
} else {
return OMAbstractFactory.getSOAP12Factory();
}
}
public UnifiedEndpoint getUnifiedEndpoint() throws FaultException {
int tenantId = B4PServiceComponent.getBPELServer().getMultiTenantProcessStore().
getTenantId(processId);
ProcessConfigurationImpl processConf = (ProcessConfigurationImpl) B4PServiceComponent.
getBPELServer().getMultiTenantProcessStore().getTenantsProcessStore(tenantId).
getProcessConfiguration(processId);
EndpointConfiguration epConf = processConf.
getEndpointConfiguration(new WSDL11Endpoint(serviceName, servicePort));
try {
return epConf.getUnifiedEndpoint();
} catch (AxisFault axisFault) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Error occurred while reading UnifiedEndpoint for service " + serviceName,
axisFault);
}
}
public ConfigurationContext getConfigurationContext() throws FaultException {
int tenantId = B4PServiceComponent.getBPELServer().getMultiTenantProcessStore().
getTenantId(processId);
ProcessConfigurationImpl processConf = (ProcessConfigurationImpl) B4PServiceComponent.
getBPELServer().getMultiTenantProcessStore().getTenantsProcessStore(tenantId).
getProcessConfiguration(processId);
return processConf.getTenantConfigurationContext();
}
/**
* Process the current runtime context and generate a list of attachment ids bind to the current runtime context.
*
* @return a list of attachment ids
*/
private Collection<Long> getAttachmentIDs(ExtensionContext extensionContext) {
Collection<Long> attachmentIDs = new ArrayList<Long>();
Collection<MessageExchange> mexList =
extensionContext.getInternalInstance().getMessageExchangeDAOs();
for (MessageExchange mex : mexList) {
//extract the available mex references
MessageExchangeImpl mexImpl = (MessageExchangeImpl) mex;
Collection<AttachmentDAO> attachmentDAOList = mexImpl.getDAO().getAttachments();
for (AttachmentDAO dao : attachmentDAOList) {
attachmentIDs.add(dao.getId());
}
}
//TODO log.warn("Here we return a one level list, so the client doesn't knows which " +
// "attachment ids are bind to which message exchanges");
return attachmentIDs;
}
/**
* Generate an attachment id list to be sent to the human-task based on the fromProcess attribute defined inside
* <attachmentPropagation/> element
*
* @param extensionContext
* @param taskMessageContext
* @return a list of attachment ids. The list can be empty if attachment propagation is not allowed from process to
* human task
*/
private List<Long> extractAttachmentIDsToBeSentToHumanTask(ExtensionContext extensionContext,
BPELMessageContext taskMessageContext) {
List<Long> attachmentIDList = new ArrayList<Long>();
if (attachmentPropagation != null && attachmentPropagation.isInitialized) {
if (FromProcessSpec.all.toString().equals(attachmentPropagation.getFromProcess())) {
attachmentIDList = (List<Long>) getAttachmentIDs(extensionContext);
taskMessageContext.setAttachmentIDList(attachmentIDList);
} else if (FromProcessSpec.none.toString().equals(attachmentPropagation.getFromProcess())) {
if (log.isDebugEnabled()) {
log.debug("No attachments will be propagated to the human-task as attribute value of " +
BPEL4PeopleConstants.ATTACHMENT_PROPAGATION_ACTIVITY_FROM_PROCESS +
" is " + FromProcessSpec.none);
}
}
} else {
if (log.isDebugEnabled()) {
log.debug("AttachmentPropagation element is not initialized yet." +
" So attachments are ignored by the BPEL4People extension runtime.");
}
}
return attachmentIDList;
}
public String invoke(ExtensionContext extensionContext) throws FaultException {
BPELMessageContext taskMessageContext = new BPELMessageContext(hiWSDL);
UUID messageID = null;
int tenantId = B4PServiceComponent.getBPELServer().getMultiTenantProcessStore().
getTenantId(processId);
String tenantDomain = null;
try {
tenantDomain = B4PContentHolder.getInstance().getRealmService().getTenantManager().getDomain(tenantId);
} catch (UserStoreException e) {
log.error(" Cannot find the tenant domain " + e.toString());
}
if (tenantDomain == null) {
tenantDomain = MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
}
PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain);
try {
//Setting the attachment id attachmentIDList
List<Long> attachmentIDList = extractAttachmentIDsToBeSentToHumanTask(extensionContext,
taskMessageContext);
taskMessageContext.setOperationName(getOperationName());
SOAPHelper soapHelper = new SOAPHelper(getBinding(), getSoapFactory(), isRPC);
MessageContext messageContext = new MessageContext();
/*
Adding attachment ID list as a method input to createSoapRequest makes no sense.
Have to fix. Here we can't embed attachments in MessageContext, as we have only a
list of attachment ids.
*/
soapHelper.createSoapRequest(messageContext,
(Element) extensionContext.readVariable(inputVarName),
getOperation(extensionContext), attachmentIDList);
// Coordination Context and skipable attribute is only valid for a Task.
if (InteractionType.TASK.equals(activityType)) {
//Adding HumanTask Coordination context.
//Note: If registration service is not enabled, we don't need to send coor-context.
if (CoordinationConfiguration.getInstance().isHumantaskCoordinationEnabled() &&
CoordinationConfiguration.getInstance().isRegistrationServiceEnabled()) {
messageID = UUID.randomUUID();
soapHelper.addCoordinationContext(messageContext, messageID.toString(), getRegistrationServiceURL
());
}
// Adding HumanTask Context overriding attributes.
soapHelper.addOverridingHumanTaskAttributes(messageContext, isSkipable);
}
taskMessageContext.setInMessageContext(messageContext);
taskMessageContext.setPort(getServicePort());
taskMessageContext.setService(getServiceName());
taskMessageContext.setRPCStyleOperation(isRPC);
taskMessageContext.setTwoWay(isTwoWay);
taskMessageContext.setSoapFactoryForCurrentMessageFlow(getSoapFactory());
taskMessageContext.setWsdlBindingForCurrentMessageFlow(getBinding());
taskMessageContext.setUep(getUnifiedEndpoint());
taskMessageContext.setCaller(processId.getLocalPart());
AxisServiceUtils.invokeService(taskMessageContext, getConfigurationContext());
} catch (AxisFault axisFault) {
log.error(axisFault, axisFault);
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Error occurred while invoking service " + serviceName,
axisFault);
} catch (B4PCoordinationException coordinationFault) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Error occurred while generating Registration Service URL" + serviceName,
coordinationFault);
}
// it seems the WSDLAwareMessage is not required.
// taskMessageContext.setRequestMessage();
if (taskMessageContext.getFaultMessageContext() != null ||
taskMessageContext.getOutMessageContext().isFault()) {
MessageContext faultContext = taskMessageContext.getFaultMessageContext() != null ?
taskMessageContext.getFaultMessageContext() :
taskMessageContext.getOutMessageContext();
log.warn("SOAP Fault: " + faultContext.getEnvelope().toString());
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
faultContext.getEnvelope().toString());
}
String taskID = SOAPHelper.parseResponseFeedback(
taskMessageContext.getOutMessageContext().getEnvelope().getBody());
// HT-Coordination - Persisting taskID against message ID
// Ignore Notifications, since we are ignore coordination context for notification.
if (CoordinationConfiguration.getInstance().isHumantaskCoordinationEnabled() && InteractionType.TASK.equals
(activityType)) {
Long instanceID = extensionContext.getProcessId();
if (CoordinationConfiguration.getInstance().isRegistrationServiceEnabled()) {
try { // Already coordinated with Registration service.
updateCoordinationData(messageID.toString(), Long.toString(instanceID), taskID);
} catch (Exception e) {
log.error("Error occurred while updating humantask coordination data.", e);
}
} else {
// This is an special case. Registration service is disabled. So we are calculating Task engine protocol
// Handler URL by manually.
try {
messageID = UUID.randomUUID();
String protocolHandlerURL = generateTaskProtocolHandlerURL(taskMessageContext);
if (log.isDebugEnabled()) {
log.debug("Generated Protocol Handler URL : " + protocolHandlerURL);
}
createCoordinationData(messageID.toString(), protocolHandlerURL, Long.toString(instanceID), taskID);
} catch (Exception e) {
log.error("Error occurred while creating humantask coordination data for coordinated task.", e);
}
}
}
return taskID;
}
public String inferCorrelatorId(ExtensionContext extensionContext) throws FaultException {
PartnerLinkInstance plink;
plink = extensionContext.getPartnerLinkInstance(partnerLinkName);
return plink.partnerLink.getName() + "." + callbackOperationName;
}
private void updateCoordinationData(final String messageID, final String instanceID, final String taskID) throws
Exception {
((BPELServerImpl) B4PContentHolder.getInstance().getBpelServer()).getScheduler()
.execTransaction(new Callable<Object>() {
@Override
public Object call() throws Exception {
HTCoordinationDAOConnection daoConnection = B4PContentHolder.getInstance()
.getCoordinationController
().getDaoConnectionFactory().getConnection();
daoConnection.updateProtocolHandler(messageID, instanceID, taskID);
return null;
}
});
}
private HTProtocolHandlerDAO createCoordinationData(final String messageID, final String participantProtocolService,
final String instanceID, final String taskID) throws Exception {
HTProtocolHandlerDAO htProtocolHandlerDAO = ((BPELServerImpl) B4PContentHolder.getInstance().getBpelServer())
.getScheduler().execTransaction(new Callable<HTProtocolHandlerDAO>() {
@Override
public HTProtocolHandlerDAO call() throws Exception {
HTCoordinationDAOConnection daoConnection = B4PContentHolder.getInstance()
.getCoordinationController
().getDaoConnectionFactory().getConnection();
return daoConnection.createCoordinatedTask(messageID, participantProtocolService, instanceID,
taskID);
}
});
return htProtocolHandlerDAO;
}
private String generateServiceURLUpToWebContext() throws B4PCoordinationException, FaultException {
String baseURL = "";
if (CoordinationConfiguration.getInstance().isClusteredTaskEngines()) {
baseURL = CoordinationConfiguration.getInstance().getLoadBalancerURL();
} else {
ConfigurationContext serverConfigurationContext = getConfigurationContext();
String scheme = CarbonConstants.HTTPS_TRANSPORT;
String host;
try {
host = NetworkUtils.getLocalHostname();
} catch (SocketException e) {
log.error(e.getMessage(), e);
throw new B4PCoordinationException(e.getLocalizedMessage(), e);
}
int port = 9443;
port = CarbonUtils.getTransportProxyPort(serverConfigurationContext, scheme);
if (port == -1) {
port = CarbonUtils.getTransportPort(serverConfigurationContext, scheme);
}
baseURL = scheme + "://" + host + ":" + port;
}
String webContext = ServerConfiguration.getInstance().getFirstProperty("WebContextRoot");
if (webContext == null || webContext.equals("/")) {
webContext = "";
}
return baseURL + webContext;
}
private String getRegistrationServiceURL() throws B4PCoordinationException, FaultException {
String tenantDomain = "";
try {
tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(true);
} catch (Throwable e) {
tenantDomain = null;
}
String registrationServiceURL = generateServiceURLUpToWebContext() + ((tenantDomain != null &&
!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) ?
"/" + MultitenantConstants.TENANT_AWARE_URL_PREFIX + "/" + tenantDomain : "") +
BPEL4PeopleConstants.CARBON_ADMIN_SERVICE_CONTEXT_ROOT + "/"
+ BPEL4PeopleConstants.B4P_REGISTRATION_SERVICE + "/";
return registrationServiceURL;
}
private String generateTaskProtocolHandlerURL(BPELMessageContext taskMessageContext) throws FaultException,
B4PCoordinationException {
String tenantTaskService = taskMessageContext.getUep().getAddress();
int tenantDelimiterIndex = tenantTaskService.indexOf("/t/");
String tenantIdentifier = "";
if (tenantDelimiterIndex != -1) {
String temp = tenantTaskService.substring(tenantDelimiterIndex + 3); // 3 = length("/t/")
int indexOfSlash = temp.indexOf('/');
tenantIdentifier = "/t/" + ((indexOfSlash != -1) ? temp.substring(0, indexOfSlash) : temp);
}
//Else super tenant. -> tenantIdentifier = ""
String protocolHandlerURL = generateServiceURLUpToWebContext() + tenantIdentifier +
BPEL4PeopleConstants.CARBON_ADMIN_SERVICE_CONTEXT_ROOT + "/"
+ BPEL4PeopleConstants.HT_ENGINE_COORDINATION_PROTOCOL_HANDLER_SERVICE;
return protocolHandlerURL;
}
enum FromProcessSpec {
all,
none
}
enum ToProcessSpec {
all,
newOnly,
none
}
/**
* Manage the child element of PeopleActivity eg - <b4p:attachmentPropagation fromProcess="all|none"
* toProcess="all|newOnly|none" />
*/
class AttachmentPropagation {
private String fromProcess;
private String toProcess;
private boolean isInitialized;
/**
* Default constructor : specifies the default values for the <attachmentPropagation/> child element
*/
public AttachmentPropagation() throws FaultException {
init();
}
private AttachmentPropagation(Element element) throws FaultException {
init(element);
}
public boolean isInitialized() {
return isInitialized;
}
public String getFromProcess() {
return fromProcess;
}
public String getToProcess() {
return toProcess;
}
/**
* Initializes the default values for the <attachmentPropagation/> child element
*/
private void init() throws FaultException {
this.fromProcess = extractFromProcessValue(FromProcessSpec.all.toString()); //Default value is :
// FromProcessSpec.all
this.toProcess = extractToProcessValue(ToProcessSpec.newOnly.toString()); //Default value is :
// ToProcessSpec.newOnly
isInitialized = true;
}
private void init(Element element) throws FaultException {
if (!element.getLocalName().equals(BPEL4PeopleConstants.ATTACHMENT_PROPAGATION_ACTIVITY) ||
!element.getNamespaceURI().equals(BPEL4PeopleConstants.B4P_NAMESPACE)) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"No " + BPEL4PeopleConstants.ATTACHMENT_PROPAGATION_ACTIVITY + " found");
}
this.fromProcess = extractFromProcessValue(element.getAttribute(BPEL4PeopleConstants
.ATTACHMENT_PROPAGATION_ACTIVITY_FROM_PROCESS));
this.toProcess = extractToProcessValue(element.getAttribute(BPEL4PeopleConstants
.ATTACHMENT_PROPAGATION_ACTIVITY_TO_PROCESS));
isInitialized = true;
}
private String extractFromProcessValue(String fromProcessValue) throws FaultException {
if (FromProcessSpec.all.toString().equals(fromProcessValue) ||
FromProcessSpec.none.toString().equals(fromProcessValue)) {
return fromProcessValue;
} else {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Assigned value for " +
BPEL4PeopleConstants.ATTACHMENT_PROPAGATION_ACTIVITY_FROM_PROCESS +
" attribute is not compliant with the specification.");
}
}
private String extractToProcessValue(String toProcessValue) throws FaultException {
if (ToProcessSpec.all.toString().equals(toProcessValue) ||
ToProcessSpec.none.toString().equals(toProcessValue) ||
ToProcessSpec.newOnly.toString().equals(toProcessValue)) {
return toProcessValue;
} else {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Assigned value for " +
BPEL4PeopleConstants.ATTACHMENT_PROPAGATION_ACTIVITY_TO_PROCESS +
" attribute is not compliant with the specification.");
}
}
}
}