4.15. User Task calls

The User Task service exposes a Java API for managing the life cycle of its User Tasks via the TaskClient class. The API is intended for developers to allow direct managing of the lifecycle of User Tasks. End users are advised to use the Business Central web application for User Task management.
To manage user tasks via a public API use the methods of the org.kie.api.task.TaskService class. The methods of this interface take the following arguments:
  • taskId: ID of the target Task instance usually extracted from the currently selected User Task in the user task list in the user interface
  • userId: ID of the user that is executing the action called by the method; usually the ID of the user that is logged in
The following is a subset of methods provided by the org.kie.api.task.TaskService class:
void start(long taskId, String userId);
void stop(long taskId, String userId);
void release(long taskId, String userId);
void suspend(long taskId, String userId);
void resume(long taskId, String userId);
void skip(long taskId, String userId);
void delegate(long taskId, String userId, String targetUserId);
void complete(long taskId, String userId, Map<String, Object> results);

Example 4.13. Starting and completing a simple user task

import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.manager.RuntimeManager;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.api.task.TaskService;
import org.kie.api.task.model.TaskSummary;

....		
KieSession ksession = runtimeEngine.getKieSession();
TaskService taskService = runtimeEngine.getTaskService();
ProcessInstance processInstance = ksession.startProcess("com.sample.bpmn.hello");

// John is assigned a task and he completes it
List<TaskSummary> list = taskService.getTasksAssignedAsPotentialOwner("john", "en-UK");
TaskSummary task = list.get(0);

logger.info("John is executing task {}", task.getName());

taskService.start(task.getId(), "john");
taskService.complete(task.getId(), "john", null);

...

4.15.1. Actor assignment calls

User Tasks must define either the ActorID or the GroupID parameter, which define the users who can or should execute the User Tasks. It is in the Task List of these users the Task appears.
If the User Task element defines exactly one user, the User Task appears only in the Task List of that particular user. If a User Task is assigned to more than one user, that is, to multiple actors or to a group, it appears in the Task List of all the users and any of the users can claim and execute the User Task.
End users define these properties in the Process Designer. However, the provided actor and group IDs needs to be registered with the User Task service before they can be used by User Tasks.
You can manage actors dynamically on the TaskService.

Example 4.14. Adding user Kris and group Developers on taskSession

EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.jbpm.task");
TaskService taskService = new TaskService(emf, SystemEventListenerFactory.getSystemEventListener());
TaskServiceSession taskSession = taskService.createSession();

// registering new user and group:
taskSession.addUser(new User("Kris"));
taskSession.addGroup(new Group("Developers"));
Also, you can specify the groups a user is a member of, such as, the default admin roles as well as your custom roles.

Example 4.15. Requesting the list of tasks the user is a potential owner of

List<String> groups = new ArrayList<String>();

groups.add("sales");

taskClient.getTasksAssignedAsPotentialOwner("sales-rep", groups, "en-UK", taskSummaryHandler);

Important

The Administrator can manipulate the life cycle of all Tasks, even if not being their potential owner. By default, a special user with userId Administrator is the administrator of each Task. It is therefore recommended to always define at least user Administrator when registering the list of valid users with the User Task service.

4.15.2. Connecting to custom directory information services

It is often necessary to establish connection and transfer data from existing systems and services, such as LDAP, to acquire data on actors and groups for User Tasks. This can be done by implementing the UserGroupInfoProducer interface which allows you to create your own implementation for user and group management, and then configuring it over CDI for Business Central. These are the steps required to implement and make this interface active:
  1. Create an implementation of the UserGroupInfoProducer interface and provide your own custom callback (see Section 4.15.3.1, “Connecting to LDAP”) and user info implementations according to the needs from the producer.
    This implementation must be annotated with the @Selectable qualifier for it to be found by Business Central. The listing below shows an example LDAP implementation:
    import javax.enterprise.context.ApplicationScoped;
    import javax.enterprise.inject.Alternative;
    import javax.enterprise.inject.Produces;
    
    import org.jbpm.services.task.identity.LDAPUserGroupCallbackImpl;
    import org.jbpm.services.task.identity.LDAPUserInfoImpl;
    import org.jbpm.shared.services.cdi.Selectable;
    import org.kie.api.task.UserGroupCallback;
    import org.kie.internal.task.api.UserInfo;
    
    @ApplicationScoped
    @Alternative
    @Selectable
    public class LDAPUserGroupInfoProducer implements UserGroupInfoProducer {
    
      private UserGroupCallback callback = new LDAPUserGroupCallbackImpl(true);
      private UserInfo userInfo = new LDAPUserInfoImpl(true);
      
      @Override
      @Produces
      public UserGroupCallback produceCallback() {
        return callback;
      }
    
      @Override
      @Produces
      public UserInfo produceUserInfo() {
        return userInfo;
      }
    
    }
  2. Package your custom implementations (the LDAPUserGroupInfoProducer, the LDAPUserGroupCallbackImpl and the LDAPUserInfoImpl classes from the example above) into a bean archive (jar with META-INF/beans.xml so it can be found by CDI container). Add this jar file to business-central.war/WEB-INF/lib.
  3. Modify business-central.war/WEB-INF/beans.xml and add the implementation (LDAPUserGroupInfoProducer from the example above) as an alternative to be used by Business Central.
    <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd">
    
        <alternatives>
            <class>com.test.services.producer.LDAPUserGroupInfoProducer</class>
        </alternatives>
        <interceptors>
            <class>org.uberfire.security.server.authz.cdi.RolesInterceptor</class>
            <class>org.uberfire.security.server.authz.cdi.TraitInterceptor</class>
        </interceptors>
    </beans>
    
  4. Restart your server and your custom callback implementation should now be used by Business Central.

4.15.3. LDAP connection

A dedicated UserGroupCallback implementation for LDAP servers is provided with the product to allow the User Task service to retrieve information on users, and groups and roles directly from an LDAP service.
The LDAP UserGroupCallback implementation takes the following properties:
  • ldap.bind.user: username used to connect to the LDAP server (optional if LDAP server accepts anonymous access)
  • ldap.bind.pwd: password used to connect to the LDAP server (optional if LDAP server accepts anonymous access)
  • ldap.user.ctx: context in LDAP with user information (mandatory)
  • ldap.role.ctx: context in LDAP with group and role information (mandatory)
  • ldap.user.roles.ctx: context in LDAP with user group and role membership information (optional; if not specified, ldap.role.ctx is used)
  • ldap.user.filter: filter used to search for user information; usually contains substitution keys {0}, which are replaced with parameters (mandatory)
  • ldap.role.filter: filter used to search for group and role information, usually contains substitution keys {0}, which are replaced with parameters (mandatory)
  • ldap.user.roles.filter: filter used to search for user group and role membership information, usually contains substitution keys {0}, which are replaced with parameters (mandatory)
  • ldap.user.attr.id: attribute name of the user ID in LDAP (optional; if not specified, uid is used)
  • ldap.roles.attr.id: attribute name of the group and role ID in LDAP (optional; if not specified cn is used)
  • ldap.user.id.dn: user ID in a DN, instructs the callback to query for user DN before searching for roles (optional, by default false)
  • java.naming.factory.initial: initial conntext factory class name (by default com.sun.jndi.ldap.LdapCtxFactory)
  • java.naming.security.authentication: authentication type (possible values are none, simple, strong; by default simple)
  • java.naming.security.protocol: security protocol to be used; for instance ssl
  • java.naming.provider.url: LDAP url (by default ldap://localhost:389; if the protocol is set to ssl then ldap://localhost:636)

4.15.3.1. Connecting to LDAP

To be able to use the LDAP UserGroupCallback implementation configure the respective LDAP properties (refer to Section 4.15.3, “LDAP connection”) in one of the following ways:
  • programatically: build a Properties object with the respective LDAPUserGroupCallbackImpl properties and create LDAPUserGroupCallbackImpl with the Properties object as its parameter.

    Example 4.16. 

    import org.kie.api.PropertiesConfiguration;
    import org.kie.api.task.UserGroupCallback;
    ...
    Properties properties = new Properties();
    properties.setProperty(LDAPUserGroupCallbackImpl.USER_CTX, "ou=People,dc=my-domain,dc=com");
    properties.setProperty(LDAPUserGroupCallbackImpl.ROLE_CTX, "ou=Roles,dc=my-domain,dc=com");
    properties.setProperty(LDAPUserGroupCallbackImpl.USER_ROLES_CTX, "ou=Roles,dc=my-domain,dc=com");
    properties.setProperty(LDAPUserGroupCallbackImpl.USER_FILTER, "(uid={0})");
    properties.setProperty(LDAPUserGroupCallbackImpl.ROLE_FILTER, "(cn={0})");
    properties.setProperty(LDAPUserGroupCallbackImpl.USER_ROLES_FILTER, "(member={0})");
    
    UserGroupCallback ldapUserGroupCallback = new LDAPUserGroupCallbackImpl(properties);
    
    UserGroupCallbackManager.getInstance().setCallback(ldapUserGroupCallback);
  • declaratively: create the jbpm.usergroup.callback.properties file in the root of your application or specify the file location as a system property: -Djbpm.usergroup.callback.properties=FILE_LOCATION_ON_CLASSPATH
    Make sure to register the LDAP callback when starting the User Task server.
    #ldap.bind.user=
    #ldap.bind.pwd=
    ldap.user.ctx=ou\=People,dc\=my-domain,dc\=com
    ldap.role.ctx=ou\=Roles,dc\=my-domain,dc\=com
    ldap.user.roles.ctx=ou\=Roles,dc\=my-domain,dc\=com
    ldap.user.filter=(uid\={0})
    ldap.role.filter=(cn\={0})
    ldap.user.roles.filter=(member\={0})
    #ldap.user.attr.id=
    #ldap.roles.attr.id=