提交 4cf844c4 编写于 作者: T trademak

ACT-527 Initial development of a businessRuleTask

上级 3af7bbbb
......@@ -53,6 +53,11 @@
<artifactId>drools-core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
......
/* 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.activiti.engine.impl.bpmn;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.activiti.engine.impl.el.Expression;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.pvm.delegate.ActivityExecution;
import org.activiti.engine.impl.repository.DeploymentEntity;
import org.activiti.engine.impl.repository.ProcessDefinitionEntity;
import org.activiti.engine.impl.rules.RulesAgendaFilter;
import org.activiti.engine.impl.rules.RulesHelper;
import org.drools.KnowledgeBase;
import org.drools.runtime.StatefulKnowledgeSession;
/**
* activity implementation of the BPMN 2.0 business rule task.
*
* @author Tijs Rademakers
*/
public class BusinessRuleTaskActivity extends TaskActivity {
protected Set<Expression> variablesInputExpressions = new HashSet<Expression>();
protected Set<Expression> rulesExpressions = new HashSet<Expression>();
protected boolean exclude = false;
protected String resultVariableName;
public BusinessRuleTaskActivity() {}
public void execute(ActivityExecution execution) throws Exception {
String processDefinitionID = execution.getActivity().getProcessDefinition().getId();
ProcessDefinitionEntity definitionEntity = CommandContext.getCurrent()
.getRepositorySession()
.findDeployedProcessDefinitionById(processDefinitionID);
String deploymentID = definitionEntity.getDeploymentId();
DeploymentEntity deploymentEntity = CommandContext.getCurrent()
.getRepositorySession()
.findDeploymentById(deploymentID);
KnowledgeBase knowledgeBase = RulesHelper.findLatestKnowledgeBaseByDeploymentName(
deploymentEntity.getName());
StatefulKnowledgeSession ksession = knowledgeBase.newStatefulKnowledgeSession();
if (variablesInputExpressions != null) {
Iterator<Expression> itVariable = variablesInputExpressions.iterator();
while (itVariable.hasNext()) {
Expression variable = itVariable.next();
ksession.insert(variable.getValue(execution));
}
}
if (rulesExpressions.size() > 0) {
RulesAgendaFilter filter = new RulesAgendaFilter();
Iterator<Expression> itRuleNames = rulesExpressions.iterator();
while (itRuleNames.hasNext()) {
Expression ruleName = itRuleNames.next();
filter.addSuffic(ruleName.getValue(execution).toString());
}
filter.setAccept(exclude);
ksession.fireAllRules(filter);
} else {
ksession.fireAllRules();
}
Collection<Object> ruleOutputObjects = ksession.getObjects();
if (ruleOutputObjects != null && ruleOutputObjects.size() > 0) {
Collection<Object> outputVariables = new ArrayList<Object>();
for (Object object : ruleOutputObjects) {
outputVariables.add(object);
}
execution.setVariable(resultVariableName, outputVariables);
}
ksession.dispose();
leave(execution);
}
public void addRuleVariableInputIdExpression(Expression inputId) {
this.variablesInputExpressions.add(inputId);
}
public void addRuleIdExpression(Expression inputId) {
this.rulesExpressions.add(inputId);
}
public void setExclude(boolean exclude) {
this.exclude = exclude;
}
public void setResultVariableName(String resultVariableName) {
this.resultVariableName = resultVariableName;
}
}
......@@ -28,6 +28,7 @@ import org.activiti.engine.impl.bpmn.Assignment;
import org.activiti.engine.impl.bpmn.BoundaryTimerEventActivity;
import org.activiti.engine.impl.bpmn.BpmnInterface;
import org.activiti.engine.impl.bpmn.BpmnInterfaceImplementation;
import org.activiti.engine.impl.bpmn.BusinessRuleTaskActivity;
import org.activiti.engine.impl.bpmn.CallActivityBehaviour;
import org.activiti.engine.impl.bpmn.ClassDelegate;
import org.activiti.engine.impl.bpmn.ClassStructureDefinition;
......@@ -63,6 +64,8 @@ import org.activiti.engine.impl.bpmn.TaskActivity;
import org.activiti.engine.impl.bpmn.TransformationDataOutputAssociation;
import org.activiti.engine.impl.bpmn.UserTaskActivity;
import org.activiti.engine.impl.bpmn.WebServiceActivityBehavior;
import org.activiti.engine.impl.bpmn.parser.BpmnParseListener;
import org.activiti.engine.impl.bpmn.parser.BpmnParser;
import org.activiti.engine.impl.el.Expression;
import org.activiti.engine.impl.el.ExpressionManager;
import org.activiti.engine.impl.el.FixedValue;
......@@ -652,6 +655,8 @@ public class BpmnParse extends Parse {
parseScriptTask(activityElement, scopeElement);
} else if (activityElement.getTagName().equals("serviceTask")) {
parseServiceTask(activityElement, scopeElement);
} else if (activityElement.getTagName().equals("businessRuleTask")) {
parseBusinessRuleTask(activityElement, scopeElement);
} else if (activityElement.getTagName().equals("task")) {
parseTask(activityElement, scopeElement);
} else if (activityElement.getTagName().equals("manualTask")) {
......@@ -839,6 +844,67 @@ public class BpmnParse extends Parse {
parseListener.parseServiceTask(serviceTaskElement, scope, activity);
}
}
/**
* Parses a businessRuleTask declaration.
*/
public void parseBusinessRuleTask(Element businessRuleTaskElement, ScopeImpl scope) {
ActivityImpl activity = parseAndCreateActivityOnScopeElement(businessRuleTaskElement, scope);
BusinessRuleTaskActivity ruleActivity = new BusinessRuleTaskActivity();
String ruleInputString = businessRuleTaskElement.attributeNS(BpmnParser.ACTIVITI_BPMN_EXTENSIONS_NS, "ruleVariablesInput");
String rulesString = businessRuleTaskElement.attributeNS(BpmnParser.ACTIVITI_BPMN_EXTENSIONS_NS, "rules");
String excludeString = businessRuleTaskElement.attributeNS(BpmnParser.ACTIVITI_BPMN_EXTENSIONS_NS, "exclude");
String resultVariableNameString = businessRuleTaskElement.attributeNS(BpmnParser.ACTIVITI_BPMN_EXTENSIONS_NS, "resultVariableName");
if (ruleInputString != null) {
String[] ruleInputObjects = ruleInputString.split(",");
for (String ruleInputObject : ruleInputObjects) {
ruleActivity.addRuleVariableInputIdExpression(expressionManager.createExpression(ruleInputObject.trim()));
}
}
if (rulesString != null) {
String[] rules = ruleInputString.split(",");
for (String rule : rules) {
ruleActivity.addRuleIdExpression(expressionManager.createExpression(rule.trim()));
}
if (excludeString != null) {
excludeString = excludeString.trim();
if ("true".equalsIgnoreCase(excludeString) == false && "false".equalsIgnoreCase(excludeString) == false) {
addError("'exclude' only supports true or false for business rule tasks", businessRuleTaskElement);
} else {
ruleActivity.setExclude(Boolean.valueOf(excludeString.toLowerCase()));
}
}
} else if (excludeString != null) {
addError("'exclude' not supported for business rule tasks not defining 'rules'", businessRuleTaskElement);
}
if (resultVariableNameString != null) {
resultVariableNameString = resultVariableNameString.trim();
if (resultVariableNameString.length() > 0 == false) {
addError("'resultVariableName' must contain a text value for business rule tasks", businessRuleTaskElement);
} else {
ruleActivity.setResultVariableName(resultVariableNameString);
}
} else {
ruleActivity.setResultVariableName("org.activiti.engine.rules.OUTPUT");
}
activity.setActivityBehavior(ruleActivity);
parseExecutionListenersOnScope(businessRuleTaskElement, activity);
for (BpmnParseListener parseListener: parseListeners) {
parseListener.parseBusinessRuleTask(businessRuleTaskElement, scope, activity);
}
}
/**
* Parses a sendTask declaration.
......
......@@ -33,6 +33,7 @@ public interface BpmnParseListener {
void parseParallelGateway(Element parallelGwElement, ScopeImpl scope, ActivityImpl activity);
void parseScriptTask(Element scriptTaskElement, ScopeImpl scope, ActivityImpl activity);
void parseServiceTask(Element serviceTaskElement, ScopeImpl scope, ActivityImpl activity);
void parseBusinessRuleTask(Element businessRuleTaskElement, ScopeImpl scope, ActivityImpl activity);
void parseTask(Element taskElement, ScopeImpl scope, ActivityImpl activity);
void parseManualTask(Element manualTaskElement, ScopeImpl scope, ActivityImpl activity);
void parseUserTask(Element userTaskElement, ScopeImpl scope, ActivityImpl activity);
......
......@@ -83,6 +83,10 @@ public class HistoryParseListener implements BpmnParseListener {
public void parseServiceTask(Element serviceTaskElement, ScopeImpl scope, ActivityImpl activity) {
addActivityHandlers(serviceTaskElement, activity);
}
public void parseBusinessRuleTask(Element businessRuleTaskElement, ScopeImpl scope, ActivityImpl activity) {
addActivityHandlers(businessRuleTaskElement, activity);
}
public void parseSubProcess(Element subProcessElement, ScopeImpl scope, ActivityImpl activity) {
addActivityHandlers(subProcessElement, activity);
......
/* 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.activiti.engine.impl.rules;
import java.util.ArrayList;
import java.util.List;
import org.drools.runtime.rule.Activation;
import org.drools.runtime.rule.AgendaFilter;
/**
* @author Tijs Rademakers
*/
public class RulesAgendaFilter implements AgendaFilter {
protected List<String> suffixList = new ArrayList<String>();
protected boolean accept;
public RulesAgendaFilter() {}
public boolean accept(Activation activation) {
String ruleName = activation.getRule().getName();
for (String suffix : suffixList) {
if (ruleName.endsWith(suffix)) {
return this.accept;
}
}
return !this.accept;
}
public void addSuffic(String suffix) {
this.suffixList.add(suffix);
}
public void setAccept(boolean accept) {
this.accept = accept;
}
}
/* 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.activiti.standalone.rules;
import java.io.Serializable;
/**
* @author Tijs Rademakers
*/
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
private int itemCount;
private boolean valid;
public int getItemCount() {
return itemCount;
}
public void setItemCount(int itemCount) {
this.itemCount = itemCount;
}
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
}
/* 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.activiti.standalone.rules;
import java.util.List;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.impl.ProcessEngineImpl;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.repository.Deployer;
import org.activiti.engine.impl.rules.RulesDeployer;
import org.activiti.engine.impl.test.ResourceActivitiTestCase;
/**
* @author Tijs Rademakers
*/
public class RulesActivitiTestCase extends ResourceActivitiTestCase {
public RulesActivitiTestCase(String activitiConfigurationResource) {
super(activitiConfigurationResource);
}
@Override
protected void initializeProcessEngine() {
processEngine = cachedProcessEngines.get(activitiConfigurationResource);
if (processEngine==null) {
processEngine = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource(activitiConfigurationResource)
.buildProcessEngine();
List<Deployer> deployersList = ((ProcessEngineConfigurationImpl)
((ProcessEngineImpl) processEngine).getProcessEngineConfiguration()).getDeployers();
deployersList.add(new RulesDeployer());
cachedProcessEngines.put(activitiConfigurationResource, processEngine);
}
}
}
/* 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.activiti.standalone.rules;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.test.Deployment;
/**
* @author Tijs Rademakers
*/
public class RulesDeployerTest extends RulesActivitiTestCase {
public RulesDeployerTest() {
super("org/activiti/standalone/rules/rules.activiti.cfg.xml");
}
@SuppressWarnings("unchecked")
@Deployment(
resources={"org/activiti/standalone/rules/rulesDeploymentTestProcess.bpmn20.xml",
"org/activiti/standalone/rules/simpleRule1.drl"})
public void testRulesDeployment() {
Map<String, Object> variableMap = new HashMap<String, Object>();
Order order = new Order();
order.setItemCount(2);
variableMap.put("order", order);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("rulesDeployment", variableMap);
assertNotNull(processInstance);
assertEquals("rulesDeployment:1", processInstance.getProcessDefinitionId());
Collection<Object> ruleOutputList = (Collection<Object>)
runtimeService.getVariable(processInstance.getId(), "rulesOutput");
assertNotNull(ruleOutputList);
assertEquals(1, ruleOutputList.size());
order = (Order) ruleOutputList.iterator().next();
assertTrue(order.isValid());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<!-- Database configurations -->
<property name="history" value="audit" />
<property name="databaseSchemaUpdate" value="true" />
<!-- job executor configurations -->
<property name="jobExecutorActivate" value="false" />
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="Examples">
<process id="rulesDeployment">
<startEvent id="start"/>
<sequenceFlow id="flow1" sourceRef="start" targetRef="ruleTask" />
<businessRuleTask id="ruleTask" activiti:ruleVariablesInput="${order}" activiti:resultVariableName="rulesOutput"/>
<sequenceFlow id="flow2" sourceRef="ruleTask" targetRef="receiveTask" />
<receiveTask id="receiveTask" />
<sequenceFlow id="flow3" sourceRef="receiveTask" targetRef="end" />
<endEvent id="end" />
</process>
</definitions>
package org.activiti.rules.deploytest;
import org.activiti.standalone.rules.Order
rule "OrderItemCountZeroOrLess"
when
order : Order( itemCount <= 0)
then
order.setValid(false);
end
rule "OrderItemCountGreaterThanZero"
when
order : Order( itemCount > 0)
then
order.setValid(true);
end
\ No newline at end of file
......@@ -230,6 +230,11 @@
<artifactId>drools-core</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册