/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.identity.workflow.impl;
import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.impl.llom.OMElementImpl;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.bpel.stub.mgt.PackageManagementException;
import org.wso2.carbon.bpel.stub.mgt.ProcessManagementException;
import org.wso2.carbon.bpel.stub.mgt.types.DeployedPackagesPaginated;
import org.wso2.carbon.bpel.stub.mgt.types.PackageType;
import org.wso2.carbon.bpel.stub.mgt.types.Version_type0;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.humantask.stub.types.TSimpleQueryCategory;
import org.wso2.carbon.humantask.stub.types.TSimpleQueryInput;
import org.wso2.carbon.humantask.stub.types.TStatus;
import org.wso2.carbon.humantask.stub.types.TTaskSimpleQueryResultRow;
import org.wso2.carbon.humantask.stub.types.TTaskSimpleQueryResultSet;
import org.wso2.carbon.humantask.stub.ui.task.client.api.IllegalAccessFault;
import org.wso2.carbon.humantask.stub.ui.task.client.api.IllegalArgumentFault;
import org.wso2.carbon.humantask.stub.ui.task.client.api.IllegalOperationFault;
import org.wso2.carbon.humantask.stub.ui.task.client.api.IllegalStateFault;
import org.wso2.carbon.identity.workflow.impl.bean.BPSProfile;
import org.wso2.carbon.identity.workflow.impl.dao.BPSProfileDAO;
import org.wso2.carbon.identity.workflow.impl.internal.WorkflowImplServiceDataHolder;
import org.wso2.carbon.identity.workflow.impl.listener.WorkflowImplServiceListener;
import org.wso2.carbon.identity.workflow.impl.util.BPELPackageManagementServiceClient;
import org.wso2.carbon.identity.workflow.impl.util.HumanTaskClientAPIAdminClient;
import org.wso2.carbon.identity.workflow.impl.util.ProcessManagementServiceClient;
import org.wso2.carbon.identity.workflow.mgt.WorkflowManagementService;
import org.wso2.carbon.identity.workflow.mgt.bean.Parameter;
import org.wso2.carbon.identity.workflow.mgt.bean.Workflow;
import org.wso2.carbon.identity.workflow.mgt.bean.WorkflowRequest;
import org.wso2.carbon.identity.workflow.mgt.exception.WorkflowException;
import org.wso2.carbon.identity.workflow.mgt.util.WFConstant;
import org.wso2.carbon.identity.workflow.mgt.util.WorkflowManagementUtil;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.rmi.RemoteException;
import java.util.Iterator;
import java.util.List;
public class WorkflowImplServiceImpl implements WorkflowImplService {
private static final Log log = LogFactory.getLog(WorkflowImplServiceImpl.class);
BPSProfileDAO bpsProfileDAO = new BPSProfileDAO();
@Override
public void addBPSProfile(BPSProfile bpsProfileDTO, int tenantId)
throws WorkflowImplException {
List<WorkflowImplServiceListener> workflowListenerList =
WorkflowImplServiceDataHolder.getInstance().getWorkflowListenerList();
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPreAddBPSProfile(bpsProfileDTO, tenantId);
}
}
bpsProfileDAO.addProfile(bpsProfileDTO, tenantId);
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPostAddBPSProfile(bpsProfileDTO, tenantId);
}
}
}
@Override
public List<BPSProfile> listBPSProfiles(int tenantId) throws WorkflowImplException {
List<WorkflowImplServiceListener> workflowListenerList =
WorkflowImplServiceDataHolder.getInstance().getWorkflowListenerList();
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPreListBPSProfiles(tenantId);
}
}
List<BPSProfile> bpsProfiles = bpsProfileDAO.listBPSProfiles(tenantId);
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPostListBPSProfiles(tenantId, bpsProfiles);
}
}
return bpsProfiles;
}
@Override
public void removeBPSProfile(String profileName) throws WorkflowImplException {
List<WorkflowImplServiceListener> workflowListenerList =
WorkflowImplServiceDataHolder.getInstance().getWorkflowListenerList();
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPreRemoveBPSProfile(profileName);
}
}
bpsProfileDAO.removeBPSProfile(profileName);
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPostRemoveBPSProfile(profileName);
}
}
}
@Override
public BPSProfile getBPSProfile(String profileName, int tenantId) throws WorkflowImplException {
List<WorkflowImplServiceListener> workflowListenerList =
WorkflowImplServiceDataHolder.getInstance().getWorkflowListenerList();
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPreGetBPSProfile(profileName, tenantId);
}
}
BPSProfile bpsProfile = bpsProfileDAO.getBPSProfile(profileName, tenantId, true);
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPostGetBPSProfile(profileName, tenantId, bpsProfile);
}
}
return bpsProfile;
}
@Override
public void updateBPSProfile(BPSProfile bpsProfileDTO, int tenantId) throws WorkflowImplException {
List<WorkflowImplServiceListener> workflowListenerList =
WorkflowImplServiceDataHolder.getInstance().getWorkflowListenerList();
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPreUpdateBPSProfile(bpsProfileDTO, tenantId);
}
}
BPSProfile currentBpsProfile = bpsProfileDAO.getBPSProfile(bpsProfileDTO.getProfileName(), tenantId, true);
if (ArrayUtils.isEmpty(bpsProfileDTO.getPassword())) {
bpsProfileDTO.setPassword(currentBpsProfile.getPassword());
}
bpsProfileDAO.updateProfile(bpsProfileDTO, tenantId);
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPostUpdateBPSProfile(bpsProfileDTO, tenantId);
}
}
}
@Override
public void deleteHumanTask(WorkflowRequest workflowRequest) throws WorkflowImplException {
BPSProfileDAO bpsProfileDAO = new BPSProfileDAO();
List<WorkflowImplServiceListener> workflowListenerList =
WorkflowImplServiceDataHolder.getInstance().getWorkflowListenerList();
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPreDeleteHumanTask(workflowRequest);
}
}
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
List<BPSProfile> bpsProfiles = bpsProfileDAO.listBPSProfiles(tenantId);
HumanTaskClientAPIAdminClient client = null;
TSimpleQueryInput input = new TSimpleQueryInput();
TStatus reservedState = new TStatus();
reservedState.setTStatus(WFImplConstant.HT_STATE_RESERVED);
input.addStatus(reservedState);
TStatus readyState = new TStatus();
readyState.setTStatus(WFImplConstant.HT_STATE_READY);
input.addStatus(readyState);
input.setPageSize(WFImplConstant.DEFAULT_PAGE_SIZE_FOR_HT_LIST);
input.setPageNumber(WFImplConstant.PAGE_0);
input.setSimpleQueryCategory(TSimpleQueryCategory.ALL_TASKS);
for (BPSProfile bpsProfile : bpsProfiles) {
try {
String host = bpsProfile.getWorkerHostURL();
if (bpsProfile.getProfileName().equals(WFImplConstant.DEFAULT_BPS_PROFILE_NAME)) {
client = new HumanTaskClientAPIAdminClient(host, bpsProfile.getUsername());
} else {
client = new HumanTaskClientAPIAdminClient(host, bpsProfile.getUsername(),
bpsProfile.getPassword());
}
TTaskSimpleQueryResultSet results = client.simpleQuery(input);
TTaskSimpleQueryResultRow[] humanTasks = results.getRow();
if (ArrayUtils.isNotEmpty(humanTasks)) {
for (int j = 0; j < humanTasks.length; j++) {
try {
Object task = client.getInput(humanTasks[j].getId());
InputStream stream = new ByteArrayInputStream(task.toString().getBytes(StandardCharsets
.UTF_8));
OMElement taskXML = new StAXOMBuilder(stream).getDocumentElement();
Iterator<OMElementImpl> iterator = taskXML.getChildElements();
while (iterator.hasNext()) {
OMElementImpl child = iterator.next();
checkMatchingTaskAndDelete(workflowRequest.getRequestId(), client, humanTasks, j, child);
}
} catch (IllegalStateFault | XMLStreamException | IllegalArgumentFault | RemoteException |
IllegalOperationFault | IllegalAccessFault e) {
//If exception throws when retrieving and deleting a specific task, it will continue with
// other tasks without terminating.
log.warn("Failed to retrieve information of human task : " + humanTasks[j].getName() + ".");
}
}
}
} catch (IllegalArgumentFault | RemoteException | IllegalStateFault e) {
//If exception throws at one iteration of loop, which is testing 1 BPS profile, it will continue with
// other profiles without terminating.
log.warn("Failed to delete human task associated for this request in BPS profile : " + bpsProfile
.getProfileName());
}
}
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPostDeleteHumanTask(workflowRequest);
}
}
}
/**
* This method is used to remove the BPS Artifacts upon a deletion of
* a Workflow.
*
* @param workflow - Workflow request to be deleted.
* @throws WorkflowImplException
*/
@Override
public void removeBPSPackage(Workflow workflow) throws WorkflowImplException {
List<WorkflowImplServiceListener> workflowListenerList =
WorkflowImplServiceDataHolder.getInstance().getWorkflowListenerList();
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPreRemoveBPSPackage(workflow);
}
}
WorkflowImplService workflowImplService = WorkflowImplServiceDataHolder.getInstance().getWorkflowImplService();
WorkflowManagementService workflowManagementService = WorkflowImplServiceDataHolder.getInstance().
getWorkflowManagementService();
if (workflowImplService == null || workflowManagementService == null) {
throw new WorkflowImplException("Error while deleting the BPS artifacts of: " + workflow.getWorkflowName());
}
try {
List<Parameter> workflowParameters = workflowManagementService.
getWorkflowParameters(workflow.getWorkflowId());
Parameter bpsParameter = WorkflowManagementUtil.getParameter(workflowParameters,
WFImplConstant.ParameterName.BPS_PROFILE, WFConstant.ParameterHolder.WORKFLOW_IMPL);
if (bpsParameter == null) {
throw new WorkflowImplException("Error while deleting the BPS artifacts of: " +
workflow.getWorkflowName());
}
String bpsProfileName = bpsParameter.getParamValue();
if (StringUtils.isEmpty(bpsProfileName)) {
throw new WorkflowImplException("Error while deleting the BPS artifacts of: " +
workflow.getWorkflowName());
}
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
BPSProfile bpsProfile = workflowImplService.getBPSProfile(bpsProfileName, tenantId);
if (log.isDebugEnabled()) {
log.debug("Removing BPS Artifacts of " + bpsProfileName + " " + "for Tenant ID : " + tenantId);
}
BPELPackageManagementServiceClient bpsPackageClient;
ProcessManagementServiceClient bpsProcessClient;
//Authorizing BPS Package Management & BPS Process Management Stubs.
String host = bpsProfile.getManagerHostURL();
if (bpsProfileName.equals(WFImplConstant.DEFAULT_BPS_PROFILE_NAME)) {
//If emebeded_bps, use mutual ssl authentication
bpsPackageClient = new BPELPackageManagementServiceClient(host, bpsProfile
.getUsername());
bpsProcessClient = new ProcessManagementServiceClient(host, bpsProfile
.getUsername());
} else {
//For external BPS profiles, use password authentication
bpsPackageClient = new BPELPackageManagementServiceClient(host, bpsProfile
.getUsername(), bpsProfile.getPassword());
bpsProcessClient = new ProcessManagementServiceClient(host, bpsProfile
.getUsername(), bpsProfile.getPassword());
}
DeployedPackagesPaginated deployedPackagesPaginated =
bpsPackageClient.listDeployedPackagesPaginated(0, workflow.getWorkflowName());
PackageType[] packageTypes = deployedPackagesPaginated.get_package();
if (packageTypes == null || packageTypes.length == 0) {
throw new WorkflowImplException("Error while deleting the BPS artifacts of: " +
workflow.getWorkflowName());
}
int numberOfPackages = packageTypes.length;
for (int i = 0; i < numberOfPackages; i++) {
PackageType packageType = deployedPackagesPaginated.get_package()[i];
int numberOfVersions = packageType.getVersions().getVersion().length;
//Iterating through BPS Packages deployed for the Workflow and retires each associated active processes.
for (int j = 0; j < numberOfVersions; j++) {
Version_type0 versionType = packageType.getVersions().getVersion()[j];
if (versionType.getIsLatest()) {
int numberOfProcesses = versionType.getProcesses().getProcess().length;
if (numberOfProcesses == 0) {
throw new WorkflowImplException("Error while deleting the BPS artifacts of: " +
workflow.getWorkflowName());
}
for (int k = 0; k < numberOfProcesses; k++) {
QName pid = null;
try {
String processStatus = versionType.getProcesses().getProcess()[k].getStatus()
.getValue();
if (StringUtils.equals(processStatus, WFImplConstant.BPS_STATUS_ACTIVE)) {
String processID = versionType.getProcesses().getProcess()[k].getPid();
pid = QName.valueOf(processID);
bpsProcessClient.retireProcess(pid);
}
} catch (RemoteException | ProcessManagementException e) {
//If exception throws at retiring one process, it will continue with
// other processes without terminating.
log.info("Failed to retire BPS process : " + pid);
}
}
}
}
}
if (log.isDebugEnabled()) {
log.debug("BPS Artifacts Successfully removed for Workflow : " + workflow.getWorkflowName());
}
} catch (WorkflowException | PackageManagementException | RemoteException e) {
throw new WorkflowImplException("Error while deleting the BPS Artifacts of the Workflow "
+ workflow.getWorkflowName(), e);
}
for (WorkflowImplServiceListener workflowListener : workflowListenerList) {
if (workflowListener.isEnable()) {
workflowListener.doPostRemoveBPSPackage(workflow);
}
}
}
/*
*
*
* @param requestId Id of the deleting request
* @param stub stub to call HumanTaskClientAPIAdmin
* @param resultsList task list in the current human task engine
* @param resultIndex index of the currently considering rask
* @param taskElement currently considering task
* @throws RemoteException
*/
private void checkMatchingTaskAndDelete(String requestId, HumanTaskClientAPIAdminClient client,
TTaskSimpleQueryResultRow[] resultsList, int resultIndex, OMElementImpl
taskElement) throws RemoteException, IllegalStateFault,
IllegalOperationFault, IllegalArgumentFault, IllegalAccessFault {
if (taskElement.getLocalName().equals(WFImplConstant.HT_PARAMETER_LIST_ELEMENT)) {
Iterator<OMElementImpl> parameters = taskElement.getChildElements();
while (parameters.hasNext()) {
OMElementImpl parameter = parameters.next();
Iterator<OMAttribute> attributes = parameter.getAllAttributes();
while (attributes.hasNext()) {
OMAttribute currentAttribute = attributes.next();
if (currentAttribute.getLocalName().equals(WFImplConstant.HT_ITEM_NAME_ATTRIBUTE) &&
currentAttribute
.getAttributeValue().equals(WFImplConstant.HT_REQUEST_ID_ATTRIBUTE_VALUE)) {
Iterator<OMElementImpl> itemValues = parameter.getChildElements();
if (itemValues.hasNext()) {
String taskRequestId = itemValues.next().getText();
if (taskRequestId.contains(",")) {
taskRequestId = taskRequestId.replaceAll(",", "");
}
if (taskRequestId.equals(requestId)) {
client.skip(resultsList[resultIndex].getId());
}
}
}
}
}
}
}
}