/*
* Copyright (c) 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.coordination.event.listeners;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.bpel.b4p.coordination.CoordinationTask;
import org.wso2.carbon.bpel.b4p.coordination.configuration.CoordinationConfiguration;
import org.wso2.carbon.bpel.b4p.coordination.context.ExitProtocolMessage;
import org.wso2.carbon.bpel.b4p.coordination.context.WSConstants;
import org.wso2.carbon.bpel.b4p.coordination.dao.HTCoordinationDAOConnection;
import org.wso2.carbon.bpel.b4p.coordination.dao.HTProtocolHandlerDAO;
import org.wso2.carbon.bpel.b4p.coordination.dao.TaskProtocolHandler;
import org.wso2.carbon.bpel.b4p.internal.B4PContentHolder;
import org.wso2.carbon.bpel.core.ode.integration.BPELServerImpl;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import java.util.List;
import java.util.concurrent.Callable;
/**
* Thread that used to terminate tasks.
*/
public class TerminationTask implements CoordinationTask {
private static final Log log = LogFactory.getLog(TerminationTask.class);
private static final String REG_TASK_COORDINATION = "TaskCoordination";
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
private String instanceID;
private int tenantID;
public TerminationTask(String instanceID) {
this.instanceID = instanceID;
}
public void setTenantID(int tenantID) {
this.tenantID = tenantID;
}
@Override
public void run() {
PrivilegedCarbonContext.startTenantFlow();
PrivilegedCarbonContext privilegedCarbonContext =
PrivilegedCarbonContext.getThreadLocalCarbonContext();
privilegedCarbonContext.setTenantId(tenantID, true);
try {
List<TaskProtocolHandler> taskProtocolHandlers = null;
try {
taskProtocolHandlers = getHTProtocolHandlerURLWithTasks(instanceID);
} catch (Exception e) {
log.error("Error occurred while retrieving coordination data", e);
}
String currentProtocolHandler = "";
ExitProtocolMessage currentExitMessage = null;
for (TaskProtocolHandler taskProtocolHandler : taskProtocolHandlers) {
// Task Protocol Handler and Task ID should be not null
if (taskProtocolHandler.getProtocolHandlerURL() != null && taskProtocolHandler.getTaskID() != null) {
// Note: Result set is pre-sorted using protocolHandler URL.
// So we can retrieve a list of task id for that particular protocol handler URL using few
// iterations.
// Here we are building that taskID list and store them in exitMessage.
// If it found new URL, do invoke using old exit message and create a new exit message
if (!currentProtocolHandler.equals(taskProtocolHandler.getProtocolHandlerURL())) {
// found a new protocol handler URL, so invoking old exit message.
if (currentExitMessage != null) { // To ignore initial condition, we do null check here.
invokeProtocolHandler(currentExitMessage);
}
currentExitMessage = new ExitProtocolMessage(taskProtocolHandler.getProtocolHandlerURL());
currentProtocolHandler = taskProtocolHandler.getProtocolHandlerURL();
}
currentExitMessage.getTaskIDs().add(taskProtocolHandler.getTaskID());
if (log.isDebugEnabled()) {
log.debug("building exit protocol message for task id:" + taskProtocolHandler.getTaskID());
}
}
}
if (currentExitMessage != null) { // Here we do last invocation.
invokeProtocolHandler(currentExitMessage);
}
//Cleaning coordination data.
boolean deleted = false;
try {
deleted = deleteCoordinationData(instanceID);
} catch (Exception e) {
log.error("Error occurred while cleaning coordination data for process instance id " + instanceID, e);
}
if (deleted && log.isDebugEnabled()) {
log.debug("Coordination data are removed from database for process instance id " + instanceID);
}
} finally {
PrivilegedCarbonContext.endTenantFlow();
}
}
private List<HTProtocolHandlerDAO> getHtProtocolHandlerDAOList(final String instanceID) throws Exception {
List<HTProtocolHandlerDAO> htProtocolHandlerDAOList = ((BPELServerImpl) B4PContentHolder.getInstance()
.getBpelServer())
.getScheduler().execTransaction(new Callable<List<HTProtocolHandlerDAO>>() {
@Override
public List<HTProtocolHandlerDAO> call() throws Exception {
HTCoordinationDAOConnection daoConnection = B4PContentHolder.getInstance()
.getCoordinationController()
.getDaoConnectionFactory().getConnection();
return daoConnection.getProtocolHandlers(instanceID);
}
});
return htProtocolHandlerDAOList;
}
private List<TaskProtocolHandler> getHTProtocolHandlerURLWithTasks(final String instanceID) throws Exception {
List<TaskProtocolHandler> htProtocolURLWithTasks = ((BPELServerImpl) B4PContentHolder.getInstance()
.getBpelServer())
.getScheduler().execTransaction(new Callable<List<TaskProtocolHandler>>() {
@Override
public List<TaskProtocolHandler> call() throws Exception {
HTCoordinationDAOConnection daoConnection = B4PContentHolder.getInstance()
.getCoordinationController()
.getDaoConnectionFactory().getConnection();
return daoConnection.getProtocolHandlerURLsWithTasks(instanceID);
}
});
return htProtocolURLWithTasks;
}
private boolean deleteCoordinationData(final String instanceID) throws Exception {
boolean success = (Boolean) ((BPELServerImpl) B4PContentHolder.getInstance().getBpelServer()).getScheduler()
.execTransaction(new Callable<Object>() {
@Override
public Object call() throws Exception {
HTCoordinationDAOConnection daoConnection = B4PContentHolder.getInstance()
.getCoordinationController()
.getDaoConnectionFactory().getConnection();
return daoConnection.deleteCoordinationData(instanceID);
}
});
return success;
}
private synchronized void invokeProtocolHandler(ExitProtocolMessage message) {
OMElement payload = message.toOM();
Options options = new Options();
options.setTo(new EndpointReference(message.getTaskProtocolHandlerURL()));
options.setAction(WSConstants.WS_HT_COORDINATION_PROTOCOL_EXIT_ACTION);
options.setTransportInProtocol(org.apache.axis2.Constants.TRANSPORT_HTTPS);
ServiceClient serviceClient = null;
try {
serviceClient = new ServiceClient();
serviceClient.setOptions(options);
//Setting basic auth headers.
String tenantDomain = MultitenantUtils.getTenantDomainFromUrl(message.getTaskProtocolHandlerURL());
if (message.getTaskProtocolHandlerURL().equals(tenantDomain)) {
//this is a Super tenant registration service
CarbonUtils.setBasicAccessSecurityHeaders(CoordinationConfiguration.getInstance()
.getProtocolHandlerAdminUser()
, CoordinationConfiguration.getInstance().getProtocolHandlerAdminPassword(), serviceClient);
} else {
if (log.isDebugEnabled()) {
log.debug("Sending exit protocol message to tenant domain: " + tenantDomain);
}
// Tenant's registration service
String username = "";
String password = "";
try {
UserRegistry configSystemRegistry = B4PContentHolder.getInstance().getRegistryService()
.getConfigSystemRegistry(tenantID);
Resource taskCoordination = configSystemRegistry.get(REG_TASK_COORDINATION);
if (taskCoordination != null) {
username = taskCoordination.getProperty(USERNAME);
password = taskCoordination.getProperty(PASSWORD);
} else {
log.error("Task coordination is not configured for tenant : " + tenantDomain +
". Dropping Exit Coordination message. Affected Tasks ids : " + message.getTaskIDs());
return;
}
} catch (RegistryException e) {
log.warn("Error while accessing Registry Service for tenant : " + tenantDomain +
". Dropping Exit Coordination message. Affected Tasks ids : " + message.getTaskIDs(), e);
return;
}
CarbonUtils.setBasicAccessSecurityHeaders(username, password, serviceClient);
}
serviceClient.fireAndForget(payload);
if (log.isDebugEnabled()) {
log.debug("Sent exit protocol message to " + message.getTaskProtocolHandlerURL());
}
} catch (AxisFault axisFault) {
log.error("Error occurred while invoking HT Protocol Handler " + message.getTaskProtocolHandlerURL() +
". Affected Tasks ids : " + message.getTaskIDs(), axisFault);
}
}
}