cancel
Showing results for 
Search instead for 
Did you mean: 

User/membership creation programmatically fails in 5.11

oops
Champ in-the-making
Champ in-the-making
Hi guys,

I faced a problem in 5.11, it was OK with Activiti 5.10.

I am creating user and membership programmatically - and it fails with "Referential integrity constraint violation"

The code is simple:

        String username = "someName";
        User user = identityService.newUser(username);
        user.setPassword("123");
        user.setFirstName("Manually");
        user.setLastName("created");
        identityService.saveUser(user);

        identityService.createMembership(username, "admin"); // other groups also tried..

The default users/memberships ("kermit", etc) are created successfully.

What I noticed (I am not sure that it definitely the reason of the problem, but providing it just in case).
I.
1. In a case of initial ("kermit" etc) users/memberships creation: CommandContextInterceptor.execute() flag contextReused stays false (due to context == null at that stage).
2. In a case of my users/memberships creation - this flag is true (due to not null context).
II.
javadoc for ProcessEngineConfiguration says "One transaction per service method." Just in case we tried ProcessEngineConfiguration.setTransactionsExternallyManaged(false); This did not help also.

So, I am asking for some directives from you..
Thanks in advance.
5 REPLIES 5

mariusz_cwikla
Champ in-the-making
Champ in-the-making
Hi,
I did not have problems with users/group in 5.11. Did you create groups first (newGroup/saveGroup methods in IdentityService)?

oops
Champ in-the-making
Champ in-the-making
Yep - a group exists.
(I tried either already existing grousp like "admin" etc or manually created by newGroup()/saveGroup()).
And I guess the error happens at commit stage: likely a user is not commited prior to membership committing.
The error does not happen right after a call to identityService.createMembership(..) - the persistent objects (for users)/queries (for memberships) are cashed after it - and only at commit stage it fails.. More then - if I query a user membership after identityService.createMembership(..) - it will display me it.. (but everything crashes in the end of my procedure).

I used the same trivial logic with 5.10 - it did not raise the problems..

This happens with all databases I tried - Oracle, MSSQL and supplied h2 also.

Did you modify some settings - ? May be I am not familiar with some version-specific settings..
The only attracting setting for me were:
- in activiti-standalone-context.xml -> defaultAutoCommit - I played with it already - did not help
- ProcessEngineConfiguration.setTransactionsExternallyManaged(false) - also did not help
Do you know, is there some possibilities for "manual commit" doing?

trademak
Star Contributor
Star Contributor
Hi,

This is exactly what we do in the DemoDataGenerator class of the Activiti Explorer, so this definitely works.
I also created a simple unit test that does exactly what you posted and it works fine.
The only thing that's important is that the Group exists.
You can easily test this with the identityService.createGroupQuery() call.
If it's still failing, can you create a unit test of it?

Best regards,

oops
Champ in-the-making
Champ in-the-making
Tijs,

I am doing this from Activiti Process. As I could not upload bar/jar to here, I dare insert it here in plain code, sorry..

My Service task calls this:

package com.trials;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
import org.activiti.engine.identity.User;

public class CreateUserDaveWershAndMembership  implements JavaDelegate {

Logger LOGGER = Logger.getLogger(CreateUserDaveWershAndMembership.class.getName());

@Override
public void execute(DelegateExecution execution) throws Exception {
 
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        IdentityService identityService = processEngine.getIdentityService();
       
        String username = "DaveWersh";
        User user = identityService.newUser(username);
        user.setPassword("123");
        user.setFirstName("Manually");
        user.setLastName("created");
        identityService.saveUser(user);

        // just in case check "admin" group existance
        if (identityService.createGroupQuery().groupId("admin").list().size() > 0) {
         LOGGER.log(Level.INFO, "   >>> admin group found");
         identityService.createMembership(username, "admin");
         LOGGER.log(Level.INFO, "   >>> membership created");
        } else {
         LOGGER.log(Level.INFO, "   >>> No admin group found");
        }
}

}

The process definition looks like this (simply calls the above execute in server task):

<?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:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:smileysurprised:mgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:smileysurprised:mgdi="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/test">
  <process id="CreateUserDaveWershAndMembership" name="Create User Dave Wersh And Membership">
    <startEvent id="startevent1" name="Start"></startEvent>
    <endEvent id="endevent1" name="End"></endEvent>
    <serviceTask id="servicetask1" name="Create User Dave Wersh And Membership" activiti:class="com.trials.CreateUserDaveWershAndMembership"></serviceTask>
    <sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="servicetask1"></sequenceFlow>
    <sequenceFlow id="flow2" name="" sourceRef="servicetask1" targetRef="endevent1"></sequenceFlow>
  </process>
</definitions>

If I split it into two separate processes (with two dedicated delegates): one for user creation, second for membership creation - it goes well..
Also - the above was OK with 5.10..

jbarrez
Star Contributor
Star Contributor
I looked into your issue and found that ,indeed, you found a bug.

In Activiti 5.11 we fixed the transactions when calling service tasks inside a JavaDelegate. But the issue here is actually not transaction related, it just made another bug visible which was always there but never visible. More specifically, in Activiti, every insert in the database is kept in memory and only flushed at the end of the service invocation (for performance). This is good for users and groups, but apparantly it was not the case for memberships. Membership creation would hit the database immediately, but the user and group wasn't yet flushed to the database. Hence the error. In Activiti 5.10 the transaction would have been flushed already and the data would already be in the database

Also - the above was OK with 5.10..

It worked, yes, but it was not correct: there were actually 4 transactions going on: one for the process, one for the user creation, one for the membership and one for the group. In Activiti 5.11 there is now a single transaction. I pushed a fix for the bug on the master branch: https://github.com/Activiti/Activiti/commit/87e6d82f37a1a94ab9cd193a43cdee590721c46e