cancel
Showing results for 
Search instead for 
Did you mean: 

Switching Persistence layer

byr
Champ in-the-making
Champ in-the-making
Hi!

I'm playing with Activiti 6 Beta2 Snapshot (got the sources yesterday) to completely switch the Persistence layer from Mybatis / native SQL to our in-house solution.

It seems to work fine, however I faces some problems and I have also some questions regarding this:

1.) I run in the HistoricActivityInstanceQueryImpl.java into a problem, that the fields tenantId, tenantIdLike and withoutTenantId do not have a getter, so I'm unable to get the values and set into my query (except with reflection, but I don't want to do this). Is this on purpose or just a mistake? (I saw in the entity mapping xml, that all 3 fields are used to filter the query)

2.) If I completely switch to a different persistence layer is there any possibility to get a ProcessEngineConfiguration implementation where no Datasource and Database type is required? I saw in the code, that even if I create new DataManagers to all entities, some native SQL-s are still run through DbSqlSession. I do not want that, since our persistence layer can support databases, which are not supported by Activiti. It would be nice, to have a ProcessEngineConfiguration, where no Datasource is needed and if the Engine requires data (like schema.version or similar data) would obtain them through the proper DataManager. Our persistence layer will handle database structure changes, so no need to do this via Activiti Engine.

Should I run into similar problems like in 1.) should I write it here, or is there some other forum or JIRA or something where I could fire bug reports?

Thanks!

Regards,

byr
10 REPLIES 10

jbarrez
Star Contributor
Star Contributor
1. This seems to be a mistake. I've added those: https://github.com/Activiti/Activiti/commit/b8f7e0fe685d2f36e02b5831078eb6a6af80cb4c

2. That should not be the case. Which SQL queries are you talking about here?  The engine should be able to run without Datasource at all.

Bug reports should go into Jira (https://activiti.atlassian.net/secure/Dashboard.jspa)

byr
Champ in-the-making
Champ in-the-making
Hi!

Thanks for the reply and the fix. Meanwhile I found some other missing getters in different QueryImpl classes. I will fire a bug report as soon as I'm finished with the DataManager transition.

2. OK, thanks, honestly I did not checked too carefully, but it seemed that the DB type and the activiti schema version is read anyway with Sql (if there is a Datasource of course). But I did not try to omit the datasource yet, but will see Smiley Happy

Thanks!

Regards

byr

byr
Champ in-the-making
Champ in-the-making
Hi!

Another problem I came across:

trying to create a DataManager for the JobEntity. This has the exceptionMessage content stored as a ByteArrayRef. How should I initialize when loading the JobEntity this ByteArrayRef? The exceptionByteArrayRef is final, and is created already. The ByteArrayRef has no setter for the Id, so I cannot set the Id (foreign key) in the ByteArrayRef for the loaded JobEntity. Using the ByteArrayRef.setValue is not good, since it will create (insert) a new ByteArray into the Database. The ByteArrayRefTypeHandler is also not good, since it deals with ResultSet or Statement, what I do not have here.

So I did not found any solution yet to set the ByteArrayRef into an entity. It should be enough to set the Id loaded from the JobEntity as it will trigger the loading of the ByteArrayEntity from the ByteArrayRef, but there is no setter for the Id.

Can anyone enlighten me?

Thanks!

Regards

byr

byr
Champ in-the-making
Champ in-the-making
Hi!
I faced an other problem, and have a question. Given following code:
<code>
ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");

activitiRule.getRuntimeService().setVariable(processInstance.getId(), "variable1", "value1");
activitiRule.getRuntimeService().setVariable(processInstance.getId(), "variable2", "value2");
activitiRule.getRuntimeService().setVariable(processInstance.getId(), "variable3", "value3");

List<Task> tasks = activitiRule.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).list();

activitiRule.getTaskService().setVariable(tasks.get(0).getId(), "taskVar1", 5d);

tasks = activitiRule.getTaskService().createTaskQuery().includeProcessVariables().includeTaskLocalVariables().list();

Assert.assertEquals(1, tasks.size());
Assert.assertEquals(3, tasks.get(0).getProcessVariables().size()); // assert fails here
Assert.assertEquals(1, tasks.get(0).getTaskLocalVariables().size());
</code>

fails. I can see in my DataManager implementation, that the local variables are inserted, however the executionId (when adding process instance variables) and the taskId (when adding task local variables) are empty, and then the query does not return anything. The Variables are there in the Database, just the executionId and the taskId is empty.

I saw in the code (VariableScopeImpl) that these informations are set after the call to createAndInsert, but then an update never called to update the set values in the database.

Is there any special call to persist the current state into database?
Or do I add the variables in a wrong way?

Thanks!

Regards

byr

vasile_dirla
Star Contributor
Star Contributor
Hi,
Would be great if you can provide a unit test to show what exactly happens.

byr
Champ in-the-making
Champ in-the-making
Hi!

Thanks for reply! Here is the full testing code:

<code>
        ProcessEngine activitiRule = (ProcessEngine) context.getBean("processEngine");

        BpmnModel model = new BpmnModel();
        Process process = new Process();
        model.addProcess(process);
        process.setId("my-process");

        process.addFlowElement(createStartEvent());
        process.addFlowElement(createUserTask("task1", "First task", "fred"));
        process.addFlowElement(createUserTask("task2", "Second task", "john"));
        process.addFlowElement(createEndEvent());

        process.addFlowElement(createSequenceFlow("start", "task1"));
        process.addFlowElement(createSequenceFlow("task1", "task2"));
        process.addFlowElement(createSequenceFlow("task2", "end"));

        Deployment deployment = activitiRule.getRepositoryService().createDeployment()
                .addBpmnModel("dynamic-model.bpmn", model).name("Dynamic process deployment")
                .deploy();

        ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process");

        activitiRule.getRuntimeService().setVariable(processInstance.getId(), "variable1", "value1");
        activitiRule.getRuntimeService().setVariable(processInstance.getId(), "variable2", "value2");
        activitiRule.getRuntimeService().setVariable(processInstance.getId(), "variable3", "value3");

        List<Task> tasks = activitiRule.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).list();

        Assert.assertEquals(1, tasks.size());
        Assert.assertEquals("First task", tasks.get(0).getName());
        Assert.assertEquals("fred", tasks.get(0).getAssignee());

        long count = activitiRule.getTaskService().createTaskQuery().processInstanceId(processInstance.getId()).count();

        Assert.assertEquals(1, count);

        activitiRule.getTaskService().setVariable(tasks.get(0).getId(), "taskVar1", 5d);

        tasks = activitiRule.getTaskService().createTaskQuery().includeProcessVariables().includeTaskLocalVariables().list();

        Assert.assertEquals(1, tasks.size());
        Assert.assertEquals(3, tasks.get(0).getProcessVariables().size());
        Assert.assertEquals(1, tasks.get(0).getTaskLocalVariables().size());
</code>

Spring context:

<code>
<bean id="processEngineConfiguration" class="org.jbaf.server.workflow.processengine.JBAFProcessEngineConfiguration" lazy-init="true">
        <property name="databaseType" value="h2"/>
        <property name="dataSource" ref="jbafDS" />
        <property name="dataAccessService" ref="dataAccessService"/>
        <property name="databaseSchemaUpdate" value="false" />
        <property name="history" value="audit" />
        <property name="jobExecutorActivate" value="false" />
        <property name="asyncExecutorEnabled" value="true" />
        <property name="asyncExecutorActivate" value="true" />
    </bean>

    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean" lazy-init="true">
        <property name="processEngineConfiguration" ref="processEngineConfiguration" />
    </bean>
</code>

ProcessEngineConfiguration impl:

<code>
public class JBAFProcessEngineConfiguration extends ProcessEngineConfigurationImpl implements ApplicationContextAware
{
    private ApplicationContext applicationContext;
    private IDataAccessService dataAccessService;

    public void setApplicationContext(ApplicationContext applicationContext)
    {
        this.applicationContext = applicationContext;
    }

    @Override
    protected CommandInterceptor createTransactionInterceptor()
    {
        return null;
    }

    @Override
    protected void initIdGenerator()
    {
        idGenerator = new JBAFIdGenerator(this);
    }

    @Override
    protected void initDataManagers()
    {
        super.initDataManagers();

        this.attachmentDataManager = new ActivitiAttachmentDataManager(this);
        this.byteArrayDataManager = new ActivitiByteArrayDataManager(this);
        this.commentDataManager = new ActivitiCommentDataManager(this);
        this.deploymentDataManager = new ActivitiDeploymentDataManager(this);
        this.eventLogEntryDataManager = new ActivitiEventLogEntryDataManager(this);
        this.executionDataManager = new ActivitiExecutionDataManager(this);
        this.groupDataManager = new ActivitiGroupDataManager(this);

        this.historicActivityInstanceDataManager = new ActivitiHistoricActivityInstanceDataManager(this);
        this.historicDetailDataManager = new ActivitiHistoricDetailDataManager(this);
        this.historicIdentityLinkDataManager = new ActivitiHistoricIdentityLinkDataManager(this);

        this.identityInfoDataManager = new ActivitiIdentityInfoDataManager(this);
        this.jobDataManager = new ActivitiJobDataManager(this);

        this.membershipDataManager = new ActivitiMembershipDataManager(this);
        this.modelDataManager = new ActivitiModelDataManager(this);

        this.processDefinitionDataManager = new ActivitiProcessDefinitionDataManager(this);
        this.processDefinitionInfoDataManager = new ActivitiProcessDefinitionInfoDataManager(this);
        this.propertyDataManager = new ActivitiPropertyDataManager(this);
        this.resourceDataManager = new ActivitiResourceDataManager(this);
        this.taskDataManager = new ActivitiTaskDataManager(this);
        this.userDataManager = new ActivitiUserDataManager(this);
        this.variableInstanceDataManager = new ActivitiVariableDataManager(this);
    }

    public void setDataAccessService(IDataAccessService dataAccessService)
    {
        this.dataAccessService = dataAccessService;
    }

    public IDataAccessService getDataAccessService()
    {
        return dataAccessService;
    }
}
</code>

Let me know if you need something else.

Regards,

byr

vasile_dirla
Star Contributor
Star Contributor
Hi,

Why do you expect to have 3 variables here ?
<code>
Assert.assertEquals(3, tasks.get(0).getProcessVariables().size());
</code>

There will be 4 variables in the process instance.
<code>
    runtimeService.setVariable(processInstance.getId(), "variable1", "value1");
    runtimeService.setVariable(processInstance.getId(), "variable2", "value2");
    runtimeService.setVariable(processInstance.getId(), "variable3", "value3");
     …
   taskService.setVariable(tasks.get(0).getId(), "taskVar1", 5d);
</code>

in the TaskService.java you can see this comment for setVariable method:
<code>
/** set variable on a task.  If the variable is not already existing, it will be created in the
   * most outer scope.  This means the process instance in case this task is related to an
   * execution. */
void setVariable(String taskId, String variableName, Object value);
</code>

which means all 4 variables will be at process instance level.

if you want to have a variable at TaskLevel then you have to call:
<code>
taskService.setVariableLocal(tasks.get(0).getId(), "taskVar1", 5d);
</code>

and this way your unit test will pass. (without other changes)

<code>
  /** set variable on a task.  If the variable is not already existing, it will be created in the
   * task.  */
  void setVariableLocal(String taskId, String variableName, Object value);
</code>

byr
Champ in-the-making
Champ in-the-making
Hi!

Thanks the explanation. However the assert does not fail because I have 4 in the list, but because I have 0 in the list. Like I wrote, the variables are INSERTED into the database, but the EXECUTION ID is not filled (NULL), therefore it is unable to list back to the specified process Instance, means the Query does not find a single variable!

Quote: "I saw in the code (VariableScopeImpl) that these informations are set after the call to createAndInsert, but then an update never called to update the set values in the database. "

Problem is that I'm changing the Persistence layer, and with a different layer the above code is not working, and I don't know if I missed something (wrong impl of DataManager) or there is some other error.
All I can see, that the createAndInsert is called, It gets to my persistence layer (however without an executionId set) and gets inserted into the database. The next line in VariableScopeImpl calls a method (initializeVariableInstanceBackPointer(variableInstance):smileywink: which sets the executionId on the variable (and may be other properties), but then this update never gets to my persistence layer to be saved to the Database (eg. no update is called to update the variable's data).

I attached the SQL statements I'm generating and executing from my Persistence layer.

Is this normal behaviour?
Should I query the variables in a different way in the TaskDataManager?
Should I call some service method which triggers the update event on the Variables before I try to list them?
Are the variables cached in case of Mybatis solution and are they retrieved from cache instead of the Database?

byr
Champ in-the-making
Champ in-the-making
Hi!

I tried the last 6.0.0.Beta2 but still no change, the Execution ID is still not updated in the Variable table.

What am I missing? Can anyone help?

Thanks!

Regards

byr