/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.portal.workflow.kaleo.runtime.internal;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.model.Group;
import com.liferay.portal.kernel.service.GroupLocalService;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.transaction.Isolation;
import com.liferay.portal.kernel.transaction.Propagation;
import com.liferay.portal.kernel.transaction.TransactionCommitCallbackUtil;
import com.liferay.portal.kernel.transaction.Transactional;
import com.liferay.portal.kernel.util.OrderByComparator;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.kernel.workflow.WorkflowDefinition;
import com.liferay.portal.kernel.workflow.WorkflowException;
import com.liferay.portal.kernel.workflow.WorkflowInstance;
import com.liferay.portal.spring.extender.service.ServiceReference;
import com.liferay.portal.workflow.kaleo.KaleoWorkflowModelConverter;
import com.liferay.portal.workflow.kaleo.definition.Definition;
import com.liferay.portal.workflow.kaleo.definition.deployment.WorkflowDeployer;
import com.liferay.portal.workflow.kaleo.definition.parser.WorkflowModelParser;
import com.liferay.portal.workflow.kaleo.definition.parser.WorkflowValidator;
import com.liferay.portal.workflow.kaleo.model.KaleoDefinition;
import com.liferay.portal.workflow.kaleo.model.KaleoInstance;
import com.liferay.portal.workflow.kaleo.model.KaleoInstanceToken;
import com.liferay.portal.workflow.kaleo.model.KaleoNode;
import com.liferay.portal.workflow.kaleo.model.KaleoTaskInstanceToken;
import com.liferay.portal.workflow.kaleo.model.KaleoTimerInstanceToken;
import com.liferay.portal.workflow.kaleo.model.KaleoTransition;
import com.liferay.portal.workflow.kaleo.runtime.ExecutionContext;
import com.liferay.portal.workflow.kaleo.runtime.KaleoSignaler;
import com.liferay.portal.workflow.kaleo.runtime.WorkflowEngine;
import com.liferay.portal.workflow.kaleo.runtime.internal.node.NodeExecutorFactory;
import com.liferay.portal.workflow.kaleo.runtime.node.NodeExecutor;
import com.liferay.portal.workflow.kaleo.runtime.util.comparator.KaleoInstanceOrderByComparator;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* @author Michael C. Han
*/
@Transactional(
isolation = Isolation.PORTAL, propagation = Propagation.REQUIRED,
rollbackFor = {Exception.class}
)
public class DefaultWorkflowEngineImpl
extends BaseKaleoBean implements WorkflowEngine {
@Override
public void deleteWorkflowDefinition(
String name, int version, ServiceContext serviceContext)
throws WorkflowException {
try {
kaleoDefinitionLocalService.deleteKaleoDefinition(
name, version, serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public void deleteWorkflowInstance(
long workflowInstanceId, ServiceContext serviceContext)
throws WorkflowException {
try {
kaleoInstanceLocalService.deleteKaleoInstance(workflowInstanceId);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public WorkflowDefinition deployWorkflowDefinition(
String title, InputStream inputStream,
ServiceContext serviceContext)
throws WorkflowException {
try {
Definition definition = _workflowModelParser.parse(inputStream);
if (_workflowValidator != null) {
_workflowValidator.validate(definition);
}
WorkflowDefinition workflowDefinition = _workflowDeployer.deploy(
title, definition, serviceContext);
return workflowDefinition;
}
catch (WorkflowException we) {
throw we;
}
catch (PortalException pe) {
throw new WorkflowException(pe);
}
}
@Override
public ExecutionContext executeTimerWorkflowInstance(
long kaleoTimerInstanceTokenId, ServiceContext serviceContext,
Map<String, Serializable> workflowContext)
throws WorkflowException {
try {
KaleoTimerInstanceToken kaleoTimerInstanceToken =
kaleoTimerInstanceTokenLocalService.getKaleoTimerInstanceToken(
kaleoTimerInstanceTokenId);
KaleoInstanceToken kaleoInstanceToken =
kaleoTimerInstanceToken.getKaleoInstanceToken();
final ExecutionContext executionContext = new ExecutionContext(
kaleoInstanceToken, kaleoTimerInstanceToken, workflowContext,
serviceContext);
KaleoTaskInstanceToken kaleoTaskInstanceToken =
kaleoTimerInstanceToken.getKaleoTaskInstanceToken();
executionContext.setKaleoTaskInstanceToken(kaleoTaskInstanceToken);
final KaleoNode currentKaleoNode =
kaleoInstanceToken.getCurrentKaleoNode();
NodeExecutor nodeExecutor = _nodeExecutorFactory.getNodeExecutor(
currentKaleoNode.getType());
nodeExecutor.executeTimer(currentKaleoNode, executionContext);
TransactionCommitCallbackUtil.registerCallback(
new Callable<Void>() {
@Override
public Void call() throws Exception {
_kaleoSignaler.signalExecute(
currentKaleoNode, executionContext);
return null;
}
});
return executionContext;
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public List<String> getNextTransitionNames(
long workflowInstanceId, ServiceContext serviceContext)
throws WorkflowException {
try {
KaleoInstance kaleoInstance =
kaleoInstanceLocalService.getKaleoInstance(workflowInstanceId);
KaleoInstanceToken rootKaleoInstanceToken =
kaleoInstance.getRootKaleoInstanceToken(null, serviceContext);
List<String> transitionNames = new ArrayList<>();
getNextTransitionNames(rootKaleoInstanceToken, transitionNames);
return transitionNames;
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public WorkflowInstance getWorkflowInstance(
long workflowInstanceId, ServiceContext serviceContext)
throws WorkflowException {
try {
KaleoInstance kaleoInstance =
kaleoInstanceLocalService.getKaleoInstance(workflowInstanceId);
KaleoInstanceToken rootKaleoInstanceToken =
kaleoInstance.getRootKaleoInstanceToken(serviceContext);
return _kaleoWorkflowModelConverter.toWorkflowInstance(
kaleoInstance, rootKaleoInstanceToken);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public int getWorkflowInstanceCount(
Long userId, String assetClassName, Long assetClassPK,
Boolean completed, ServiceContext serviceContext)
throws WorkflowException {
try {
return kaleoInstanceLocalService.getKaleoInstancesCount(
userId, assetClassName, assetClassPK, completed,
serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public int getWorkflowInstanceCount(
Long userId, String[] assetClassNames, Boolean completed,
ServiceContext serviceContext)
throws WorkflowException {
try {
return kaleoInstanceLocalService.getKaleoInstancesCount(
userId, assetClassNames, completed, serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public int getWorkflowInstanceCount(
String workflowDefinitionName, int workflowDefinitionVersion,
boolean completed, ServiceContext serviceContext)
throws WorkflowException {
try {
return kaleoInstanceLocalService.getKaleoInstancesCount(
workflowDefinitionName, workflowDefinitionVersion, completed,
serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public List<WorkflowInstance> getWorkflowInstances(
Long userId, String assetClassName, Long assetClassPK,
Boolean completed, int start, int end,
OrderByComparator<WorkflowInstance> orderByComparator,
ServiceContext serviceContext)
throws WorkflowException {
try {
List<KaleoInstance> kaleoInstances =
kaleoInstanceLocalService.getKaleoInstances(
userId, assetClassName, assetClassPK, completed, start, end,
KaleoInstanceOrderByComparator.getOrderByComparator(
orderByComparator, _kaleoWorkflowModelConverter,
serviceContext),
serviceContext);
return toWorkflowInstances(kaleoInstances, serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public List<WorkflowInstance> getWorkflowInstances(
Long userId, String[] assetClassNames, Boolean completed, int start,
int end, OrderByComparator<WorkflowInstance> orderByComparator,
ServiceContext serviceContext)
throws WorkflowException {
try {
List<KaleoInstance> kaleoInstances =
kaleoInstanceLocalService.getKaleoInstances(
userId, assetClassNames, completed, start, end,
KaleoInstanceOrderByComparator.getOrderByComparator(
orderByComparator, _kaleoWorkflowModelConverter,
serviceContext),
serviceContext);
return toWorkflowInstances(kaleoInstances, serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public List<WorkflowInstance> getWorkflowInstances(
String workflowDefinitionName, int workflowDefinitionVersion,
boolean completed, int start, int end,
OrderByComparator<WorkflowInstance> orderByComparator,
ServiceContext serviceContext)
throws WorkflowException {
try {
List<KaleoInstance> kaleoInstances =
kaleoInstanceLocalService.getKaleoInstances(
workflowDefinitionName, workflowDefinitionVersion,
completed, start, end,
KaleoInstanceOrderByComparator.getOrderByComparator(
orderByComparator, _kaleoWorkflowModelConverter,
serviceContext),
serviceContext);
return toWorkflowInstances(kaleoInstances, serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public List<WorkflowInstance> search(
Long userId, String assetType, String nodeName,
String kaleoDefinitionName, Boolean completed, int start, int end,
OrderByComparator<WorkflowInstance> orderByComparator,
ServiceContext serviceContext)
throws WorkflowException {
try {
List<KaleoInstance> kaleoInstances =
kaleoInstanceLocalService.search(
userId, assetType, nodeName, kaleoDefinitionName, completed,
start, end,
KaleoInstanceOrderByComparator.getOrderByComparator(
orderByComparator, _kaleoWorkflowModelConverter,
serviceContext),
serviceContext);
return toWorkflowInstances(kaleoInstances, serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public int searchCount(
Long userId, String assetType, String nodeName,
String kaleoDefinitionName, Boolean completed,
ServiceContext serviceContext)
throws WorkflowException {
try {
return kaleoInstanceLocalService.searchCount(
userId, assetType, nodeName, kaleoDefinitionName, completed,
serviceContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
public void setKaleoSignaler(KaleoSignaler kaleoSignaler) {
_kaleoSignaler = kaleoSignaler;
}
@Override
public WorkflowInstance signalWorkflowInstance(
long workflowInstanceId, final String transitionName,
Map<String, Serializable> workflowContext,
ServiceContext serviceContext)
throws WorkflowException {
try {
KaleoInstance kaleoInstance = doUpdateContext(
workflowInstanceId, workflowContext, serviceContext);
KaleoInstanceToken kaleoInstanceToken =
kaleoInstance.getRootKaleoInstanceToken(serviceContext);
if (Validator.isNotNull(transitionName)) {
// Validate that the transition actually exists before moving
// forward
KaleoNode currentKaleoNode =
kaleoInstanceToken.getCurrentKaleoNode();
currentKaleoNode.getKaleoTransition(transitionName);
}
serviceContext.setScopeGroupId(kaleoInstanceToken.getGroupId());
final ExecutionContext executionContext = new ExecutionContext(
kaleoInstanceToken, workflowContext, serviceContext);
TransactionCommitCallbackUtil.registerCallback(
new Callable<Void>() {
@Override
public Void call() throws Exception {
try {
_kaleoSignaler.signalExit(
transitionName, executionContext);
}
catch (Exception e) {
throw new WorkflowException(
"Unable to signal next transition", e);
}
return null;
}
});
return _kaleoWorkflowModelConverter.toWorkflowInstance(
kaleoInstance, kaleoInstanceToken, workflowContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public WorkflowInstance startWorkflowInstance(
String workflowDefinitionName, Integer workflowDefinitionVersion,
final String transitionName,
Map<String, Serializable> workflowContext,
ServiceContext serviceContext)
throws WorkflowException {
try {
KaleoDefinition kaleoDefinition =
kaleoDefinitionLocalService.getKaleoDefinition(
workflowDefinitionName, workflowDefinitionVersion,
serviceContext);
if (!kaleoDefinition.isActive()) {
throw new WorkflowException(
"Inactive workflow definition with name " +
workflowDefinitionName + " and version " +
workflowDefinitionVersion);
}
KaleoNode kaleoStartNode = kaleoDefinition.getKaleoStartNode();
if (Validator.isNotNull(transitionName)) {
// Validate that the transition actually exists before moving
// forward
kaleoStartNode.getKaleoTransition(transitionName);
}
long scopeGroupId = serviceContext.getScopeGroupId();
if (scopeGroupId != WorkflowConstants.DEFAULT_GROUP_ID) {
Group group = _groupLocalService.getGroup(scopeGroupId);
if (group.isLayout()) {
group = _groupLocalService.getGroup(
group.getParentGroupId());
serviceContext.setScopeGroupId(group.getGroupId());
}
}
KaleoInstance kaleoInstance =
kaleoInstanceLocalService.addKaleoInstance(
kaleoDefinition.getKaleoDefinitionId(),
kaleoDefinition.getName(), kaleoDefinition.getVersion(),
workflowContext, serviceContext);
KaleoInstanceToken rootKaleoInstanceToken =
kaleoInstance.getRootKaleoInstanceToken(
workflowContext, serviceContext);
rootKaleoInstanceToken.setCurrentKaleoNode(kaleoStartNode);
kaleoLogLocalService.addWorkflowInstanceStartKaleoLog(
rootKaleoInstanceToken, serviceContext);
final ExecutionContext executionContext = new ExecutionContext(
rootKaleoInstanceToken, workflowContext, serviceContext);
TransactionCommitCallbackUtil.registerCallback(
new Callable<Void>() {
@Override
public Void call() throws Exception {
try {
_kaleoSignaler.signalEntry(
transitionName, executionContext);
}
catch (Exception e) {
throw new WorkflowException(
"Unable to start workflow", e);
}
return null;
}
});
return _kaleoWorkflowModelConverter.toWorkflowInstance(
kaleoInstance, rootKaleoInstanceToken, workflowContext);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public WorkflowInstance updateContext(
long workflowInstanceId, Map<String, Serializable> workflowContext,
ServiceContext serviceContext)
throws WorkflowException {
try {
KaleoInstance kaleoInstance = doUpdateContext(
workflowInstanceId, workflowContext, serviceContext);
KaleoInstanceToken rootKaleoInstanceToken =
kaleoInstance.getRootKaleoInstanceToken(serviceContext);
return _kaleoWorkflowModelConverter.toWorkflowInstance(
kaleoInstance, rootKaleoInstanceToken);
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
@Override
public void validateWorkflowDefinition(InputStream inputStream)
throws WorkflowException {
try {
Definition definition = _workflowModelParser.parse(inputStream);
if (_workflowValidator != null) {
_workflowValidator.validate(definition);
}
}
catch (Exception e) {
throw new WorkflowException(e);
}
}
protected KaleoInstance doUpdateContext(
long workflowInstanceId, Map<String, Serializable> workflowContext,
ServiceContext serviceContext)
throws Exception {
return kaleoInstanceLocalService.updateKaleoInstance(
workflowInstanceId, workflowContext, serviceContext);
}
protected void getNextTransitionNames(
KaleoInstanceToken kaleoInstanceToken, List<String> transitionNames)
throws Exception {
if (kaleoInstanceToken.hasIncompleteChildrenKaleoInstanceToken()) {
List<KaleoInstanceToken> incompleteChildrenKaleoInstanceTokens =
kaleoInstanceToken.getIncompleteChildrenKaleoInstanceTokens();
for (KaleoInstanceToken incompleteChildrenKaleoInstanceToken :
incompleteChildrenKaleoInstanceTokens) {
getNextTransitionNames(
incompleteChildrenKaleoInstanceToken, transitionNames);
}
}
else {
KaleoNode kaleoNode = kaleoInstanceToken.getCurrentKaleoNode();
List<KaleoTransition> kaleoTransitions =
kaleoNode.getKaleoTransitions();
for (KaleoTransition kaleoTransition : kaleoTransitions) {
transitionNames.add(kaleoTransition.getName());
}
}
}
protected List<WorkflowInstance> toWorkflowInstances(
List<KaleoInstance> kaleoInstances, ServiceContext serviceContext)
throws PortalException {
List<WorkflowInstance> workflowInstances = new ArrayList<>(
kaleoInstances.size());
for (KaleoInstance kaleoInstance : kaleoInstances) {
KaleoInstanceToken rootKaleoInstanceToken =
kaleoInstance.getRootKaleoInstanceToken(serviceContext);
workflowInstances.add(
_kaleoWorkflowModelConverter.toWorkflowInstance(
kaleoInstance, rootKaleoInstanceToken));
}
return workflowInstances;
}
@ServiceReference(type = GroupLocalService.class)
private GroupLocalService _groupLocalService;
private KaleoSignaler _kaleoSignaler;
@ServiceReference(type = KaleoWorkflowModelConverter.class)
private KaleoWorkflowModelConverter _kaleoWorkflowModelConverter;
@ServiceReference(type = NodeExecutorFactory.class)
private NodeExecutorFactory _nodeExecutorFactory;
@ServiceReference(type = WorkflowDeployer.class)
private WorkflowDeployer _workflowDeployer;
@ServiceReference(type = WorkflowModelParser.class)
private WorkflowModelParser _workflowModelParser;
@ServiceReference(type = WorkflowValidator.class)
private WorkflowValidator _workflowValidator;
}