Giter Club home page Giter Club logo

flowable / flowable-engine Goto Github PK

View Code? Open in Web Editor NEW
7.5K 265.0 2.5K 222.05 MB

A compact and highly efficient workflow and Business Process Management (BPM) platform for developers, system admins and business users.

Home Page: https://www.flowable.org

License: Apache License 2.0

Shell 0.02% Java 93.53% HTML 0.12% CSS 0.22% JavaScript 5.30% Batchfile 0.01% PLSQL 0.39% Groovy 0.01% Dockerfile 0.01% TSQL 0.02% SQLPL 0.38% Handlebars 0.01%
bpmn java workflow workflow-engine

flowable-engine's People

Contributors

arthware avatar balsarori avatar bertmatthys avatar carlosalbertomjr avatar cdeneux avatar dbmalkovsky avatar dependabot[bot] avatar filiphr avatar frederikheremans avatar h7kanna avatar henryyan avatar jbarrez avatar marcus-nl avatar martin-grofcik avatar mikedias avatar mkiener avatar motorina0 avatar pascalschumacher avatar paulhh avatar qiudaoke avatar robhafner avatar robsoncardosoti avatar smirzai avatar tiesebarrell avatar tijsrademakers avatar tombaeyens avatar vasiledirla avatar vzickner avatar welschchristopher avatar yvoswillens avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flowable-engine's Issues

Local collection updated but never queried (part 2)

Here is another occurrence; see org.flowable.app.rest.editor.EditorGroupsResource and the variable result in the getGroups method where it is added to but not used:

  @RequestMapping(value = "/rest/editor-groups", method = RequestMethod.GET)
  public ResultListDataRepresentation getGroups(@RequestParam(required = false, value = "filter") String filter) {
    List<GroupRepresentation> result = new ArrayList<GroupRepresentation>();
    List<RemoteGroup> groups = remoteIdmService.findGroupsByNameFilter(filter);
    for (RemoteGroup group : groups) {
      result.add(new GroupRepresentation(group));
    }
    return new ResultListDataRepresentation(groups);
  }

CountingTask (similar to the CountingExecution)

Purpose:

  • provide performance improvements by reducing the number of calls to the DB

Counting Execution approach:

  • has been implemented in this issue: Activiti/Activiti#971
  • keep a count on executions to avoid deletes
  • an ExecutionEntityImpl holds references to lists of:
List<EventSubscriptionEntity>
List<JobEntity>
List<TimerJobEntity>
List<TaskEntity>
List<IdentityLinkEntity>
List<VariableInstanceEntity>
  • for each of these lists a count flag is kept separately (the List.size() can not be used since the lists are not populated in every scenario):
int eventSubscriptionCount
int jobCount
int timerJobCount
int taskCount
int identityLinkCount
int variableCount
  • two extra counts (no corresponding lists) are kept for
int suspendedJobCount
int deadLetterJobCount
  • these 8 counts are persisted to the ACT_RU_EXECUTION table (which now has 30 columns!)
  • the counts are increased/decreased in the insert()/delete() methods of their corresponding XXXXEntityManagerImpl
  • the counts are ONLY checked in the ExecutionEntityManagerImpl.deleteDataForExecution() method. Basically the delete is called for an entity only when we are sure that there is something to delete:
if (...((CountingExecutionEntity) executionEntity).getXXXXCount() > 0)) {
   //call delete
  • the "counting" performance improvement can be enabled/disabled by setting the enableExecutionRelationshipCounts property:
 	<bean id="processEngineConfiguration" class="...">
		<property name="enableExecutionRelationshipCounts" value="true" />
		...

Counting Tasks approach:

  • will follow the Counting Execution style
  • an TaskEntityImpl hold references to lists of:
List<IdentityLinkEntity> getIdentityLinks() 
List<VariableInstanceEntity> getQueryVariables()
  • TaskEntityImpl also has a Set of candidates (not sure how to be handled):
    public Set<IdentityLink> getCandidates()
  • A TaskEntityImpl can have sub-tasks. Let ExecutionEntityManager handle the sub-tasks count (together with normal task count)?

Implementation

  • add CountingTaskEntity interface (implemented by TaskEntityImpl)
  • add the two count fields (identityLinkCount and variableCount) to TaskEntityImpl
  • update the DB scripts and the persistence logic
  • add the enableTaskRelationshipCounts
  • benchmark performance before/after
  • add unit tests

AbstractAsyncExecutor modifications cause an NPE when Spring is used

Using the latest 6.0.0 snapshot, I get an NPE when using the SpringAsyncExecutor, e.g.

Exception in thread "flowable-acquire-async-jobs" java.lang.NullPointerException
at org.flowable.engine.impl.asyncexecutor.DefaultAsyncJobExecutor.getRemainingCapacity(DefaultAsyncJobExecutor.java:254)
at org.flowable.engine.impl.asyncexecutor.AcquireAsyncJobsDueRunnable.run(AcquireAsyncJobsDueRunnable.java:53)
at java.lang.Thread.run(Thread.java:745)

I believe this is a result of the recent commit 3c22315 - pull request #44. It introduced two additional methods that are called from the start() method in AbstractAsyncExecutor:

  • initializeRunnables();
  • startAdditionalComponents();

The problem is that the SpringAsyncExecutor overrides initAsyncJobExecutionThreadPool() to do nothing, since it relies on the spring executor framework. However, startAdditionalComponents (which is not overridden) requires certain data structures to be initialised that would have been done in the initAsyncJobExecutionThreadPool method.

I have thrown together a "fix" which at least resolves the problem but it is a little bit messy - the SpringAsyncExecutor does need to ensure that the timer acquisition thread is created so it cannot simply override the startAdditionalComponents method to do nothing.

It does appear that the inheritance hierarchy is not really correct - should SpringAsyncExecutor really inherit from DefaultAsyncJobExecutor?

I am happy to submit a pull request with what I have done but not sure it is a great fix!

Call to equals() with different types

In the flowable-ui-task module there is a class, org.flowable.app.service.runtime.PermissionService. The class has a method, canDeleteProcessInstance():

public boolean canDeleteProcessInstance(User currentUser, HistoricProcessInstance processInstance) {
    boolean canDelete = false;
    if (processInstance.getStartUserId() != null) {
      try {
        Long starterId = Long.parseLong(processInstance.getStartUserId());
        canDelete = starterId.equals(currentUser.getId());
      } catch (NumberFormatException nfe) {
        // Ignore illegal starter id value
      }
    }

    return canDelete;
  }

It appears that a String value of the currentUser's id is being compared to a Long value that originally was a String value for the user that started the process.

This just doesn't look right or am I missing something?

Inconsistent Handling of IdentityLinks for tasks

Scenario
When a user is involved in a task an "IdentityLink" is created and it points to the TaskEntity

Identity Links are not handled consistently dough:

  • "candidate" identity link types are persisted in "ACT_RU_IDENTITYLINK" and point to a task "ACT_RU_TASK"
  • "assignee" and "owner" identity link types
    • are persisted in "ACT_RU_IDENTITYLINK" but have TASK_ID null
    • have a "PROC_INSTANCE_ID" value
    • have the type "participant" (in fact they refer to a process participant rather than a task owner or assignee)
    • the actual link between a TaskEntity and a User/Group is kept in the "ACT_RU_TASK" table in column OWNER_, ASSIGNEE_
    • the TaskService.getIdentityLinksForTask(String) method executes GetIdentityLinksForTaskCmd command which adds the two links manually and appends them two whatever it found in the DB

Problems

  • the API is not consistent. TaskService.getIdentityLinksForTask(String) and IdentityLinkEntityManager.findIdentityLinksByTaskId(String) can return different results (depending if the task has an owner or assignee)
    - it affects #123 by making it difficult to keep track (count) of task identity links
    - the Historic Identity Links are incomplete. The updates regarding task assignee and task ownership are not present in ACT_HI_IDENTITYLINK. Only the entries regarding process participation are kept.

Classcast exception in org.flowable.test.ldap.LdapGroupCacheTest

I was running tests and ran across an issue in org.flowable.test.ldap.LdapGroupCacheTest.java where IdmIdentityServiceImpl cannot be cast to LDAPIdentityServiceImpl. I assume this is result of the refactoring of the IDM modules.

Here is the top of the traceback.

-------------------------------------------------------------------------------
Test set: org.flowable.test.ldap.LdapGroupCacheTest
-------------------------------------------------------------------------------
Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 9.673 sec <<< FAILURE!
testLdapGroupCacheExpiration(org.flowable.test.ldap.LdapGroupCacheTest)  Time elapsed: 6.307 sec  <<< ERROR!
java.lang.ClassCastException: org.flowable.idm.engine.impl.IdmIdentityServiceImpl cannot be cast to org.flowable.ldap.LDAPIdentityServiceImpl
	at org.flowable.test.ldap.LdapGroupCacheTest.setUp(LdapGroupCacheTest.java:33)
	at junit.framework.TestCase.runBare(TestCase.java:139)

I will leave it to the main authors as to decide the proper changes.

IdentityService does not correctly create membership when used in TaskListener::notify()

This is my first issue report on github. I hope the description contains enough details and is structured in a way to add value to your project.

I have recently migrated a project from activiti 6.0.0.Beta2 to 6.0.0.Beta3. The new version breaks a functionality which is using the IdentityService to create groups and group memberships from within the notify(DelegateTask delegateTask) function of a TaskListener.

The attached test project (reproduce-issue.tar.gz) reproduces the issue.
The test project:

  • is a spring-boot project integrating activiti 6.0.0.Beta4 with a H2 database.
  • contains a test class showing that using the IdentityService directly to create a group and group memberships is working as expected.
  • contains a test class showing that creating a group and group memberships through a TaskListener::notify(DelegateTask delegateTask) does not persist all group members.
  • can be executed with "mvn clean verify"

It seems to me that, if calling IdentityService::createMembership(), only the last member is persisted in the failing scenario.

Process definition name is not copied into process instance upon start

Attached code is slightly modified Flowable sample which throws exception to diagnose the issue.
HollidayApp.zip

Modifying ExecutionEntityManagerImpl.createProcessInstanceExecution line 218 resolves this issue.

public ExecutionEntity createProcessInstanceExecution(ProcessDefinition processDefinition, String businessKey, String tenantId, String initiatorVariableName) {
ExecutionEntity processInstanceExecution = executionDataManager.create();    

if (isExecutionRelatedEntityCountEnabledGlobally()) {
  ((CountingExecutionEntity) processInstanceExecution).setCountEnabled(true);
}    

processInstanceExecution.setProcessDefinitionId(processDefinition.getId());
processInstanceExecution.setProcessDefinitionKey(processDefinition.getKey());
// FIX
processInstanceExecution.setProcessDefinitionName(processDefinition.getName());

Ignore databaseTablePrefix in 6 version

not start
ERROR: relation "act_id_property" does not exist
in the database to "Activiti" assigned to a separate scheme "activiti"
config
<bean id="processEngineConfiguration" class="org.flowable.spring.SpringProcessEngineConfiguration"> <property name="databaseTablePrefix" value="activiti." /> <property name="tablePrefixIsSchema" value="true" />
...
a request that is trying to query "select VALUE_ from ACT_ID_PROPERTY where NAME_ = 'schema.version'"
specified in the config file prefix does not substitute
but it work in 5.22.0 version

Running Crystallball tests

I believe that the class org.flowable.engine.impl.interceptor.CommandConfig has been renamed to org.flowable.engine.common.impl.interceptor.CommandConfig.

In the Crystallball test suites there are two config files with the old names.

See \flowable-crystalball\src\test\resources\org\flowable\crystalball\examples\tutorial\step01\FirstSimulationRunTest.cfg.xml around line 74:

<property name="defaultCommandConfig">
          <bean class="org.flowable.engine.impl.interceptor.CommandConfig">
            <constructor-arg name="contextReusePossible" value="false"/>
          </bean>
 </property>

And \flowable-crystalball\src\test\resources\org\flowable\crystalball\simulator\impl\ScriptEventHandlerTest.cfg.xml around line 77 that has a similar construct.

FWIW, there are references to a databases that include activiti in the name. For xample in flowable.cfg.xml file in the same module.

initiator is null

When I'm trying to start the process via REST call initiator is null inside the process

curl "http://localhost:8080/flowable-task/process-api/runtime/process-instances"
-H "Accept: application/json"
-H "Content-Type: application/json;charset=utf-8"
--user admin:test
-X POST -d '{"processDefinitionKey":"PilotFlow", "variables": [{"name":"startParameter","value":"startParameter value"}]}'

When I start same process via flowable-task web UI, initiator is correct.

Also the processes started via previous REST call are not appearing in flowable-task web UI.

My process is just 3 service tasks (no user tasks).

Thanks,
--MG

HistoricActivityInstanceQuery search unfinished activities - always zero results

Query for all unfinished Historyc Activity Instances using HistoricActivityInstanceQuery.

Actual result:

  • always get zero result

Expected result:

  • should return the entries that do NOT have an END_TIME (END_TIME is null)

    HistoryService historyService = activitiRule.getHistoryService();
    HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();

    long finishedActivityInstanceCount = historicActivityInstanceQuery.finished().count();
    assertEquals("The Start event is completed", 1, finishedActivityInstanceCount);
    
    //select count(RES.ID_) from ACT_HI_ACTINST RES WHERE RES.END_TIME_ is null and RES.END_TIME_ is not null 
    long unfinishedActivityInstanceCount = historicActivityInstanceQuery.unfinished().count();
    assertEquals("There is one active task", 1, unfinishedActivityInstanceCount);

The generated SQL query is:
select count(RES.ID_) from ACT_HI_ACTINST RES WHERE RES.END_TIME_ is null and RES.END_TIME_ is not null

A helper class for basic EL operations is needed. Ex build a map in EL, build an array or list

Here are some examples:

build map:
${

op.asMap()
  .put("key1", "value1")
  .put("key2", "value2")
  .done()

}

build list:
${

op.asList("item1", "item2")

}

build array:
${

op.asArray("item1", "item2")

}


concat strings:
${

"str1".concat("str2")

}

package org.flowable.app.service.addon;

import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Component("op")
public class Operation
{
    public <T> T[] asArray(T... objects)
    {
        return objects;
    }

    public <T> List<T> asList(T... objects)
    {
        return Arrays.asList(objects);
    }

    public <K, V> MapBuilder<K, V> asMap()
    {
        return new MapBuilder();
    }
}
package org.flowable.app.service.addon;

import java.util.HashMap;
import java.util.Map;

public class MapBuilder<K, V>
{
    private Map<K, V> map = new HashMap<K, V>();

    public MapBuilder<K, V> put(K key, V value)
    {
        map.put(key, value);
        return this;
    }

    public Map<K, V> done()
    {
        return map;
    }
}

I think it would be useful to have such utility class and have it documented in flowable documentation.
EL is lacking those basic operations, but they can be a part from library.

Thanks

Asynchronous history

Currently, historical data is written in the same transaction as the runtime data. Benchmark profiling has shown that in many use cases, a significant amount of time is spent processing and persisting the historical data whilst the user has to wait for the transaction to finish. By making this asynchronous, a performance improvement is expected.

Test queries that depend on the order of date/times

Depending how, where, and when I run the suite of unit tests I often get some set of the same errors. When examining the errors they all have the same common trait: there is an SQL query that is sorting on some date/time field. Because of the speed of the machine and the lack of resolution in Java date/time values some operations appear as the executed exactly at the same time even though executed sequentially. The unit tests depend on explicit ordering as the assert statements are fetching and comparing to specific values in the returned result sets. The SQL query when seeing exactly the same ordering is free to return the values in any order thus the errors.

There are 4 main tests that exhibit this behavior and they are:

  • AdhocSubProcessTest - see (1) below
  • HistoricProcessInstanceTest - see (2) below
  • HistoricTaskQueryEscapeClauseTest - see (3) -> (12) below; only annotated a few as the pattern became clear
  • FullHistoryTest - see (13) below

I see 3 possible solutions:

  • always run on a slow machine :)
  • add sleep statements to force different dates/time values so the ordering is correct
  • use contains type test logic instead of comparing to specific values in the returned result set list

I lean towards the last option as we really aren't testing the ability of SQL engines to sort the data but rather the presence or absence of specific records.

Comments?

I'll provide a pull request when a decision is made.

Thanks

Details

testSimpleCompletionCondition(org.activiti.engine.test.bpmn.subprocess.adhoc.AdhocSubProcessTest)
junit.framework.ComparisonFailure: expected:<subProcessTask[]> but was:<subProcessTask[2]>
at org.activiti.engine.test.bpmn.subprocess.adhoc.AdhocSubProcessTest.testSimpleCompletionCondition(AdhocSubProcessTest.java:112)

The query includes: .orderByHistoricTaskInstanceEndTime()

The returned data values are:

2016-10-18 06:19:28.716
2016-10-18 06:19:28.716
2016-10-18 06:19:28.732

(2)

testHistoricProcessInstanceSorting(org.activiti.engine.test.history.HistoricProcessInstanceTest)
junit.framework.ComparisonFailure: expected:<15[898]> but was:<15[903]>
at org.activiti.engine.test.history.HistoricProcessInstanceTest.testHistoricProcessInstanceSorting(HistoricProcessInstanceTest.java:353)

The query includes: .orderByProcessInstanceEndTime()

(3)

testQueryByTaskNameLikeIgnoreCase(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)
junit.framework.ComparisonFailure: expected:<1[1]> but was:<1[6]>
at org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest.testQueryByTaskNameLikeIgnoreCase(HistoricTaskQueryEscapeClauseTest.java:269)

The query includes: .orderByHistoricTaskInstanceStartTime()

The returned date values are:

2016-10-18 06:21:19.996
2016-10-18 06:21:19.996

(4)

testQueryByProcessDefinitionNameLike(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)
junit.framework.ComparisonFailure: expected:<1[1]> but was:<1[6]>
at org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest.testQueryByProcessDefinitionNameLike(HistoricTaskQueryEscapeClauseTest.java:148)

which has: .orderByHistoricTaskInstanceStartTime()

(5)

testQueryByTaskDescriptionLike(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)
junit.framework.ComparisonFailure: expected:<1[1]> but was:<1[6]>
at org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest.testQueryByTaskDescriptionLike(HistoricTaskQueryEscapeClauseTest.java:296)

which has: .orderByHistoricTaskInstanceStartTime()

(6)

testQueryByTaskNameLike(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)

(7)

testQueryByTaskAssigneeLike(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)

(8)

testQueryLikeByQueryVariableValue(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)

(9)

testQueryLikeIgnoreCaseByQueryVariableValue(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)

(10)

testQueryByProcessInstanceBusinessKeyLikeIgnoreCase(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)

(11)

testQueryByTenantIdLike(org.activiti.standalone.escapeclause.HistoricTaskQueryEscapeClauseTest)

(12)

testQueryByProcessDefinitionNameLike(org.activiti.standalone.escapeclause.TaskQueryEscapeClauseTest)

(13)

testHistoricVariableRemovedWhenRuntimeVariableIsRemoved(org.activiti.standalone.history.FullHistoryTest)
junit.framework.AssertionFailedError
at org.activiti.standalone.history.FullHistoryTest.testHistoricVariableRemovedWhenRuntimeVariableIsRemoved(FullHistoryTest.java:1392)

which has: .orderByTime()

Add a documentation chapter on using EL in workflow definition

Add a documentation chapter on using EL in workflow definition.
It should cover most commonly used predefined spring beans their use,
and explain how EL can be written. How to concatenate strings EL, how to call functions, how to refer to constants. More examples please.

Thanks

Create common CSS for all flowable web apps for easy styling

Flowable 6 UI consists of 5 separate web applications each with its own CSS.
Why don't they have common CSS? It seems the is no style re-use and it makes difficult to integrate with other websites requiring consistent look and feel.

It would be nice if that common CSS override would be in some well documented location on classpath so to change look and feel a developer would just include additional CSS into well known location on a classpath.

Thanks

Local collection queried but never updated

In org.flowable.engine.impl.cmd.GetDecisionTablesForProcessDefinitionCmd there is a local collection variable that is queried but it is never updated.

The variable is decisionTableKeys and the method in question starts around line 74:

protected List<DecisionTable> getDecisionTablesFromModel(BpmnModel bpmnModel, ProcessDefinition processDefinition) {
    Set<String> decisionTableKeys = new HashSet<>();
    List<DecisionTable> decisionTables = new ArrayList<>();
    List<ServiceTask> serviceTasks = bpmnModel.getMainProcess().findFlowElementsOfType(ServiceTask.class, true);

    for (ServiceTask serviceTask : serviceTasks) {
      if ("dmn".equals(serviceTask.getType())) {
        if (serviceTask.getFieldExtensions() != null && serviceTask.getFieldExtensions().size() > 0) {
          for (FieldExtension fieldExtension : serviceTask.getFieldExtensions()) {
            if ("decisionTableReferenceKey".equals(fieldExtension.getFieldName())) {
              String decisionTableReferenceKey = fieldExtension.getStringValue();
              if (!decisionTableKeys.contains(decisionTableReferenceKey)) {
                addDecisionTableToCollection(decisionTables, decisionTableReferenceKey, processDefinition);
              }
              break;
            }
          }
        }
      }
    }

Local collection updated but never queried

In org.flowable.editor.dmn.converter.DmnJsonConverter.java there appears that in two occasions where there is a mismatch between the updating and querying of a collection.

In the first case inputClauseMap is added to but never queried; starting around line 100:

        Map<String, InputClause> inputClauseMap = new HashMap<>();
        ArrayNode inputExpressionsNode = objectMapper.createArrayNode();

        for (InputClause clause : definition.getCurrentDecisionTable().getInputs()) {

            LiteralExpression inputExpression = clause.getInputExpression();
            inputClauseMap.put(inputExpression.getId(), clause);

            ObjectNode inputExpressionNode = objectMapper.createObjectNode();
            inputExpressionNode.put("id", inputExpression.getId());
            inputExpressionNode.put("type", inputExpression.getTypeRef());
            inputExpressionNode.put("label", inputExpression.getLabel());
            inputExpressionNode.put("variableId", inputExpression.getText());

            inputExpressionsNode.add(inputExpressionNode);
        }

The second case is for the variable outputClauseMap starting around line 120:

        Map<String, OutputClause> outputClauseMap = new HashMap<>();
        ArrayNode outputExpressionsNode = objectMapper.createArrayNode();

        for (OutputClause clause : definition.getCurrentDecisionTable().getOutputs()) {

            outputClauseMap.put(clause.getId(), clause);

            ObjectNode outputExpressionNode = objectMapper.createObjectNode();
            outputExpressionNode.put("id", clause.getId());
            outputExpressionNode.put("type", clause.getTypeRef());
            outputExpressionNode.put("label", clause.getLabel());
            outputExpressionNode.put("variableId", clause.getName());

            outputExpressionsNode.add(outputExpressionNode);
        }

This should be reviewed to see if the code is unneeded or there is some other error.

Call Activity Does not start referenced process

I have created application with two processes, one calling into another. When token of the parent process passes into the call activity, no tasks of the called process appear in the task application. Below is BPMN files:

<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef"> <process id="learning_Subprocess" name="Learning Subprocess" isExecutable="true"> <startEvent id="startEvent1"></startEvent> <userTask id="subprocessTask" name="Subprocess Task"></userTask> <sequenceFlow id="sid-2A367ED3-5718-4C47-8EF5-C1E811E7F8ED" sourceRef="startEvent1" targetRef="subprocessTask"></sequenceFlow> <endEvent id="sid-BF7D8ACD-837F-4F3F-9370-15510C8EE5B3"></endEvent> <sequenceFlow id="sid-4A22B10B-F5FC-4C78-AC95-9B3F7B27EF80" sourceRef="subprocessTask" targetRef="sid-BF7D8ACD-837F-4F3F-9370-15510C8EE5B3"></sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_learning_Subprocess"> <bpmndi:BPMNPlane bpmnElement="learning_Subprocess" id="BPMNPlane_learning_Subprocess"> <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1"> <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="subprocessTask" id="BPMNShape_subprocessTask"> <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="sid-BF7D8ACD-837F-4F3F-9370-15510C8EE5B3" id="BPMNShape_sid-BF7D8ACD-837F-4F3F-9370-15510C8EE5B3"> <omgdc:Bounds height="28.0" width="28.0" x="320.0" y="164.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="sid-2A367ED3-5718-4C47-8EF5-C1E811E7F8ED" id="BPMNEdge_sid-2A367ED3-5718-4C47-8EF5-C1E811E7F8ED"> <omgdi:waypoint x="130.0" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="175.0" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="sid-4A22B10B-F5FC-4C78-AC95-9B3F7B27EF80" id="BPMNEdge_sid-4A22B10B-F5FC-4C78-AC95-9B3F7B27EF80"> <omgdi:waypoint x="275.0" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="320.0" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>

<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef"> <process id="learning_ContainerProcess" name="Learning Container Process" isExecutable="true"> <startEvent id="startEvent1"></startEvent> <userTask id="containerUserTask" name="User Task"></userTask> <sequenceFlow id="sid-F76B057D-2A41-45D6-B449-711BBC4AFBB8" sourceRef="startEvent1" targetRef="containerUserTask"></sequenceFlow> <callActivity id="callSubprocess" name="Call Subprocess" calledElement="learning_Subprocess" activiti:inheritVariables="false"></callActivity> <sequenceFlow id="sid-3DB8F357-0A51-44B7-ACFA-3E9A41B5E9E3" sourceRef="containerUserTask" targetRef="callSubprocess"></sequenceFlow> <endEvent id="sid-679B0ACA-2BE6-4DF4-B264-6952E3349EFD"></endEvent> <sequenceFlow id="sid-9E287818-BCD7-474A-9B1B-F5BAD5DF42D8" sourceRef="callSubprocess" targetRef="sid-679B0ACA-2BE6-4DF4-B264-6952E3349EFD"></sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_learning_ContainerProcess"> <bpmndi:BPMNPlane bpmnElement="learning_ContainerProcess" id="BPMNPlane_learning_ContainerProcess"> <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1"> <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="containerUserTask" id="BPMNShape_containerUserTask"> <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="callSubprocess" id="BPMNShape_callSubprocess"> <omgdc:Bounds height="80.0" width="100.0" x="360.0" y="138.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="sid-679B0ACA-2BE6-4DF4-B264-6952E3349EFD" id="BPMNShape_sid-679B0ACA-2BE6-4DF4-B264-6952E3349EFD"> <omgdc:Bounds height="28.0" width="28.0" x="505.0" y="164.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="sid-3DB8F357-0A51-44B7-ACFA-3E9A41B5E9E3" id="BPMNEdge_sid-3DB8F357-0A51-44B7-ACFA-3E9A41B5E9E3"> <omgdi:waypoint x="275.0" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="360.0" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="sid-9E287818-BCD7-474A-9B1B-F5BAD5DF42D8" id="BPMNEdge_sid-9E287818-BCD7-474A-9B1B-F5BAD5DF42D8"> <omgdi:waypoint x="460.0" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="505.0" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="sid-F76B057D-2A41-45D6-B449-711BBC4AFBB8" id="BPMNEdge_sid-F76B057D-2A41-45D6-B449-711BBC4AFBB8"> <omgdi:waypoint x="130.0" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="175.0" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>

DynamicBpmnService only works when the enableProcessDefinitionInfoCache is enabled

Hi,

While testing the functionality of the DynamicBpmnService I noticed that this does not work unless you enable the ProcessDefinitionInfoCache on the ProcessEngine.

/**
 * Created by Pardo David on 28/11/2016.
 */
public class DynamicBpmnServiceTest {
	private ProcessEngine processEngine;

	@Before
	public void setup(){
		ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
		configuration.setEnableProcessDefinitionInfoCache(true);
		//configuration.setJdbcUrl("jdbc:h2:mem:DynamicBpmnServiceTest;DB_CLOSE_DELAY=1000");
		configuration.setJobExecutorActivate(false);

		processEngine = configuration.buildProcessEngine();
	}

	@After
	public void teardown(){
		processEngine.close();
	}

	@Test
	public void itShouldBePossibleToUpdateTheCandidateUser(){
		InputStream resourceAsStream = this.getClass().getResourceAsStream("/activiti/dynamic-bpmn-test-process.bpmn20.xml");
		RepositoryService repositoryService = processEngine.getRepositoryService();
		Deployment deploy = repositoryService.createDeployment()
				.addInputStream("dynamic-bpmn-test-process.bpmn20.xml", resourceAsStream)
				.deploy();


		RuntimeService runtimeService = processEngine.getRuntimeService();
		String processDefinitionId = repositoryService.createProcessDefinitionQuery().active().singleResult().getId();

		IdentityService identityService = processEngine.getIdentityService();
		User david = identityService.newUser("david");
		identityService.saveUser(david);

		runtimeService.startProcessInstanceById(processDefinitionId);
		TaskService taskService = processEngine.getTaskService();
		Task task = taskService.createTaskQuery().taskCandidateUser("david").singleResult();
		assertThat(task,is(not(nullValue())));

		DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService();
		ObjectNode processInfo = dynamicBpmnService.changeUserTaskCandidateUser("sid-B94D5D22-E93E-4401-ADC5-C5C073E1EEB4", "bob", true);
		dynamicBpmnService.saveProcessDefinitionInfo(processDefinitionId,processInfo);

		ObjectNode infoNode = dynamicBpmnService.getProcessDefinitionInfo(processDefinitionId);
		assertThat(infoNode,is(not(nullValue())));


		runtimeService.startProcessInstanceById(processDefinitionId);
		task = taskService.createTaskQuery().taskCandidateUser("bob").singleResult();
		assertThat(task,is(not(nullValue())));
	}


}
<?xml version='1.0' encoding='UTF-8'?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef">
  <process id="dynamicServiceTest" name="dynamic-bpmn-test-process" isExecutable="true">
    <startEvent id="sid-0B5FF4AC-12C5-4202-BBB5-BB54E866FE09"/>
    <userTask id="sid-B94D5D22-E93E-4401-ADC5-C5C073E1EEB4" name="Taak 1" activiti:candidateUsers="david"/>
    <sequenceFlow id="sid-CD26A84F-7A62-46CB-A6F4-58B264B71E52" sourceRef="sid-0B5FF4AC-12C5-4202-BBB5-BB54E866FE09" targetRef="sid-B94D5D22-E93E-4401-ADC5-C5C073E1EEB4"/>
    <sequenceFlow id="sid-652E5401-70F4-4136-8BE5-40ECD02C7936" sourceRef="sid-B94D5D22-E93E-4401-ADC5-C5C073E1EEB4" targetRef="sid-A403BAE0-E367-449A-90B2-48834FCAA2F9"/>
    <userTask id="sid-B1C37EBE-A273-4DDE-B909-89302638526A" name="Taak 2" activiti:candidateUsers="david"/>
    <sequenceFlow id="sid-68FC6555-6D0A-4546-80CA-852F05E69B5D" sourceRef="sid-A403BAE0-E367-449A-90B2-48834FCAA2F9" targetRef="sid-B1C37EBE-A273-4DDE-B909-89302638526A"/>
    <endEvent id="sid-1723AC22-2ABB-427A-82F5-01CAEB338783"/>
    <sequenceFlow id="sid-6B2BCC2A-FA7B-4F68-8739-E7C3BE0DB4DB" sourceRef="sid-B1C37EBE-A273-4DDE-B909-89302638526A" targetRef="sid-1723AC22-2ABB-427A-82F5-01CAEB338783"/>
    <scriptTask id="sid-A403BAE0-E367-449A-90B2-48834FCAA2F9" name="Service 1" activiti:autoStoreVariables="false">
      <script><![CDATA[var test = "hallo";]]></script>
    </scriptTask>
  </process>
</definitions>

Im scratching my head a bit here. In the example unit tests: https://github.com/flowable/flowable-engine/tree/master/modules/flowable5-test/src/test/java/org/activiti5/engine/test/bpmn/usertask
The cache is never enabled.

A read of the processDefinitionInfo is always done trough the cache: https://github.com/flowable/flowable-engine/blob/master/modules/flowable5-engine/src/main/java/org/activiti5/engine/impl/cmd/GetProcessDefinitionInfoCmd.java

Is this behavior by design to have more performant lookups or should both scenario's work?

Use of modified version of JUEL

In the user guide, ch04-API.adoc, in the first paragraph under Expressions is the statement:

To support all features of latest UEL spec on ALL environments, we use a modified version of JUEL.

I believe that @tijsrademakers removed the JUEL classes from the Version 6 engine in July, 2016.

This statement should thus be removed or qualified that it is only true for the Version 5 compatibility engine.

Given the appropriate direction I will submit a pull request.

variable instance lost because RuntimeService#setVariable behaves like VariableScope#setVariable(_,_,false)

We're trying to upgrade from activiti 5.9 to flowable 5.22.0 but our test-cases fail with 5.22.0. We depend on RuntimeService#setVariable to set a variable instance for a nested workflow. Unfortunately the variable is gone by the time we need it. Our method works with 5.9.

When debugging we see that SetExecutionVariablesCmd#execute is called which executes VariableScope#setVariable(String variableName, Object value, boolean fetchAllVariables) with fetchAllVariables == false. This is counter-intuitive to me because the documentation of RuntimeService#setVariable refers to VariableScope#setVariable(String, Object) which defaults to fetchAllVariables == true.

As a consequence of fetchAllVariables == false we end up in VariableScopeImpl#createVariableInstance with variableInstances == null, the put operation doesn't take place and the variable only gets written to the VariableScopeImpl#usedVariablesCache.

Is there a call to VariableScopeImpl#ensureVariableInstancesInitialized() missing in VariableScopeImpl#createVariableInstance or should SetExecutionVariablesCmd use fetchAllVariables == true or is this a new expected behavior and we should use another method to set our variables?

Implement fix that was also suggeste to Activiti-project

My comment at Activiti/Activiti@40ae7ef#commitcomment-20433801 probably also applies to Flowable.

Basically, in https://github.com/flowable/flowable-engine/blob/master/modules/flowable5-test/src/test/java/org/activiti/standalone/cfg/CustomMybatisMapperTest.java#L103, replace

Long variableValue = (Long) result.get("VARIABLEVALUE");

with

Long variableValue = ((Number)result.get("VARIABLEVALUE").longValue()

(The reason for the original problem is that Oracle returns a BigDecimal rather than a Long).

Possible null pointer exception

In org.flowable.engine.impl.persistence.entity.VariableScopeImpl (in both the version 6 engine module and the flowable5-engine module) it appears that a NPE can be generated at line 870 if the variableInstance variable is null:

    if ((variableInstance != null) && (!variableInstance.getType().equals(newType))) {
      variableInstance.setValue(null);
      variableInstance.setType(newType);
      variableInstance.forceUpdate();
      variableInstance.setValue(value);
    } else {
      variableInstance.setValue(value);
    }

add a maven project to allow starting all flowable 5 web apps in single tomcat via maven plugin

Here is the pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <artifactId>flowable-ui-root</artifactId>
    <packaging>pom</packaging>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-parent</artifactId>
        <version>6.0.0-SNAPSHOT</version>
    </parent>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <path>/</path>
                    <port>8080</port>
                    <protocol>org.apache.coyote.http11.Http11NioProtocol</protocol>
                    <addWarDependenciesInClassloader>true</addWarDependenciesInClassloader>
                    <useSeparateTomcatClassLoader>false</useSeparateTomcatClassLoader>
                    <systemProperties>
                        <com.sun.management.jmxremote.port>4000</com.sun.management.jmxremote.port>
                    </systemProperties>
                    <webapps>
                        <webapp>
                            <groupId>org.flowable</groupId>
                            <artifactId>flowable-ui-idm-app</artifactId>
                            <version>${project.version}</version>
                            <type>war</type>
                            <asWebapp>true</asWebapp>
                        </webapp>
                        <webapp>
                            <groupId>org.flowable</groupId>
                            <artifactId>flowable-ui-modeler-app</artifactId>
                            <version>${project.version}</version>
                            <type>war</type>
                            <asWebapp>true</asWebapp>
                        </webapp>
                        <webapp>
                            <groupId>org.flowable</groupId>
                            <artifactId>flowable-ui-admin</artifactId>
                            <version>${project.version}</version>
                            <type>war</type>
                            <asWebapp>true</asWebapp>
                        </webapp>
                        <webapp>
                            <groupId>org.flowable</groupId>
                            <artifactId>flowable-app-rest</artifactId>
                            <version>${project.version}</version>
                            <type>war</type>
                            <asWebapp>true</asWebapp>
                        </webapp>
                        <webapp>
                            <groupId>org.flowable</groupId>
                            <artifactId>flowable-ui-task-app</artifactId>
                            <version>${project.version}</version>
                            <type>war</type>
                            <asWebapp>true</asWebapp>
                        </webapp>
                        <!--
                        <webapp>
                            <contextPath>/</contextPath>
                            <groupId>org.flowable</groupId>
                            <artifactId>flowable-home</artifactId>
                            <version>${project.version}</version>
                            <type>war</type>
                            <asWebapp>true</asWebapp>
                        </webapp>
                        -->
                    </webapps>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Expand child process for a call activity in the visual editor

I have been fooling around with the modeler and am trying out the call activity.

I create the child element first and name it.
I then create the parent that calls the child.

The image presented on the overall process view page on http://localhost:8080/flowable-modeler/#/processes
shows the parent calling the child element with the '+' on the call activity. However if I click into the parent process visual editor, the call activity just looks like every other task. I am not able to expand it to see the child contents. I would have to back out and look at the child separately.

Stems from a forum posting:

http://forum.flowable.org/t/flowable-ui-getting-started/205/3

Add taskAssigneeIn method for searching/filtering tasks

The TaskQuery interface provides for retrieving/filtering tasks that are assigned to a specific user, but if one wants to search for tasks assigned to several users, individual queries must be done and the results merged together. It would be much more convenient if there was a taskAssigneeIn method that took a list of users.

Provide Transaction depentent EventListeners

Just as with the new TransactionDependent Task/Execution Listener (as nicely demonstrated by Yvo in his blogpost: http://blog.mark-it-zero.com/transaction-dependent-listeners/), it might make sense to have the same kind of functionality for EventListeners.

e.g. I want to notify on a Kafka topic each time a process instance has started / ended, but do not want to clutter the BPMN xml with that. The current implementation (if I'm not mistaking) will notify the EventListeners even when the transaction has not yet been committed. I want to be notified only when I'm sure that the process instance really started / ended.

In the project I'm currently working on, we implemented this functionality on top of Flowable (/Activiti). Do you guys think it makes sense to move this closer to the core?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.