0

Using the rules for one entity, is it possible in drools to invoke the methods related to a second entity?

Using Spring boot, I have the following Task entity.

@Entity
public class Task extends AbstractPersistable<Long> {

    private String title;
    private String description;

    @ManyToOne
    @JoinColumn(name = "assignee_group_id")
    private UserGroup assigneeGroup;

    @Enumerated(EnumType.STRING)
    private TaskType type;

    //getters and setters
}

And the UserGroup entity

@Entity
public class UserGroup extends AbstractPersistable<Long> {

    private String name;

    @OneToMany(targetEntity = Task.class, mappedBy = "assigneeGroup", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Set<Task> tasks;

    //getters and setters
}

The TaskType enum is defined as

public enum TaskType {

    STORE("Store"), ACCOUNTS("Accounts");

    private String formattedName;

    TaskType(String formattedName) {
        this.formattedName = formattedName;
    }

    public String getFormattedName() {
        return formattedName;
    }

}

I also have two UserGroups Store and Accounts in the database. Now what I want to do is when a user creates a Task of type Accounts, I would like to set the assignee group as the Accounts group, and similarly for the Task of type Store.

I have defined the rules as

rule "Task for Store"
    when 
        taskObject: Task(type.formattedName=="Store")
    then
        System.out.println("task for store invoked");
    end

rule "Task for Accounts"
    when 
        taskObject: Task(type.formattedName=="Accounts")
    then
        System.out.println("task for accounts invoked");
    end

This works perfectly fine. But now, I want to do something like

rule "Task for Store"
    when 
        taskObject: Task(type.formattedName=="Store")
    then
        //find user group with name Store
        //set this user group as the assignee group
    end

rule "Task for Accounts"
    when 
        taskObject: Task(type.formattedName=="Accounts")
    then
        //find user group with name Accounts
        //set this user group as the assignee group
    end

So far I've only found examples that either print out message in drools rule file like I've done above or invoke setters for fields of primitive data type. How can I (or is it even possible) to invoke setters for fields referring to a different entity? Please let me know if this is not even considered as best practice. I am just starting on drools so I don't have much idea here.

Kshitij Bajracharya
  • 811
  • 2
  • 14
  • 37

1 Answers1

0

I've solved the problem after some research. This post was really helpful. I defined a findByNameOrCreate method in UserGroupService that accepts the userGroup name and returns a userGroup instance. Then where I defined the kieSession, I set a global to UserGroupService like the following:

public Task save(Task task) {
    KieSession kieSession = kieContainer.newKieSession("rulesSession");
    KieRuntime kieRuntime = (KieRuntime) kieSession;
    kieRuntime.setGlobal("userGroupService", userGroupService);
    kieSession.insert(task);
    kieSession.fireAllRules();
    kieSession.dispose();
    return taskRepository.save(task);
}

Then I defined the rules as

package rules

import com.packagename.domain.Task
import com.packagename.service.UserGroupService

global UserGroupService userGroupService;

rule "Task for Store"
    when
        taskObject: Task(type.formattedName=="Store");
    then
        taskObject.setAssigneeGroup(userGroupService.findByNameOrCreate("Store"));
    end

rule "Task for Accounts"
    when
        taskObject: Task(type.formattedName=="Accounts");
    then
        taskObject.setAssigneeGroup(userGroupService.findByNameOrCreate("Accounts"));
    end

Now whenever the save method is invoked, using the name, the task is assigned to the correct userGroup.

Kshitij Bajracharya
  • 811
  • 2
  • 14
  • 37