OnTheRoad
OnTheRoad

Reputation: 613

Why I always got the Unexpected global error from drools?

When I fire the rules I got a strange error.
The error details are

java.lang.RuntimeException: Unexpected global [validateResult]
    at org.drools.core.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:1209)
    at com.hikedu.backend.service.impl.signupproject.SignUpProjectServiceImpl.validate(SignUpProjectServiceImpl.java:190)
    at com.hikedu.backend.service.impl.signupproject.SignUpProjectServiceImpl.validate(SignUpProjectServiceImpl.java:204)
    at com.hikedu.backend.service.impl.signupproject.SignUpProjectServiceImpl.signUp(SignUpProjectServiceImpl.java:102)
    at com.hikedu.backend.controller.ProjectApplicationRecordController.signUp(ProjectApplicationRecordController.java:94)
    at com.hikedu.backend.controller.ProjectApplicationRecordController$$FastClassBySpringCGLIB$$dc339407.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)

Here is my code to fire the rules

    KieSession session = sessionBuilder.build(theDsl);
    ProjectVersion latestVersion = projectVersionService.getLatestVersionIfNotExistsThenThrowException(projectId);
    User user = userService.getUserIfNotExistsThenThrowException(userId);
    ApplicationInfo info = getTheInsertObj(userId, projectId);
    ProjectSignUpValidateResultDTO resultDTO = new ProjectSignUpValidateResultDTO();
    resultDTO.setPass(true);
    session.setGlobal("validateResult", resultDTO);
    session.insert(latestVersion);
    session.insert(info);
    session.insert(user);
    session.fireAllRules(1);
    session.dispose();

    return resultDTO;

I searched a lot about this error. The answers all talking the same thing--The dsl file must declar the global and the declar name and path must be euqal to the code given But I confirmd again and again my dsl and my code there is not found any mistaken.

I tried to change the global name to nother one but still get that error.

So please help me.

Here is my dsl

import com.hikedu.backend.model.User;
import com.hikedu.backend.model.ProjectVersion;
import java.util.Map;
import com.hikedu.backend.dto.signupproject.ApplicationInfo
import java.util.Date
import java.sql.Timestamp

global com.hikedu.backend.dto.project.ProjectSignUpValidateResultDTO validateResult

rule "department not match"
no-loop
when
    $p : ProjectVersion()
    $u : User($p.applicationRequirements.departmentId not contains departmentOfJoined.id)
then
    validateResult.setPass(false);
    validateResult.setTheReasonOfUnPass("some reason");
end

And I did the debug to check the globals of the session. Here is the debug result enter image description here

The drools version I am using is enter image description here

Here is the KieSessionBuilder.build method

@Override
    public KieSession build(String dsl) {
        if (dsl == null) {
            throw new RuntimeException("Dsl cannot be null");
        }
        KieHelper helper = new KieHelper();
        helper.setClassLoader(getClass().getClassLoader());
        helper.addContent(dsl, ResourceType.DSL);
        KieBase base = helper.build();
        return base.newKieSession();
    }

Thanks you all. My english dost not good well please forgive me.

Upvotes: 0

Views: 2969

Answers (2)

user497087
user497087

Reputation: 1591

Coming late to the party, but I had the same error, but for a different reason. I was changing a system using Drools 7.0.12 from using a stateless session to a stateful session. It would appear that in a stateful session Drools is checking that the global is actually defined in at least one .drl file. If there is no "global" definition in a .drl file then the unexpected Global error is thrown. In a stateless session, no such check is made.

Upvotes: 2

OnTheRoad
OnTheRoad

Reputation: 613

I resovled the error by myself. Here is the solution:

Change the way of build drl.

@Override
public KieSession build(String drl) {
    if (drl == null) {
        throw new RuntimeException("Drl cannot be null");
    }

    kieFileSystem.write("src/main/resources/" + drl.hashCode() + ".drl", kieServices.getResources().newReaderResource(new StringReader(drl)));
    KieBuilder builder = kieServices.newKieBuilder(kieFileSystem).buildAll();

    Results results = builder.getResults();
    if (results.hasMessages(Message.Level.ERROR)) {
        throw new IllegalStateException("##errors : " + results.getMessages());
    }

    KieContainer container = kieServices.newKieContainer(builder.getKieModule().getReleaseId());

    return container.newKieSession();
}

After I changed the way of build drl got another error :

java.lang.RuntimeException: Illegal class for global. Expected [com.hikedu.backend.dto.project.ProjectSignUpValidateResultDTO], found [com.hikedu.backend.dto.project.ProjectSignUpValidateResultDTO].
    at org.drools.core.impl.StatefulKnowledgeSessionImpl.setGlobal(StatefulKnowledgeSessionImpl.java:1211)
    at com.hikedu.backend.service.impl.signupproject.SignUpProjectServiceImpl.validate(SignUpProjectServiceImpl.java:190)
    at com.hikedu.backend.service.impl.signupproject.SignUpProjectServiceImpl.validate(SignUpProjectServiceImpl.java:204)
    at com.hikedu.backend.service.impl.signupproject.SignUpProjectServiceImpl.signUp(SignUpProjectServiceImpl.java:102)
    at com.hikedu.backend.controller.ProjectApplicationRecordController.signUp(ProjectApplicationRecordController.java:94)
    at com.hikedu.backend.controller.ProjectApplicationRecordController$$FastClassBySpringCGLIB$$dc339407.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)

I searched a lot about this new error. And finally got the solution. This error because I am using the devtools in my project. And the devtools will use itself classloader to load all class. But the drools load the class by another classloader.

Here is the debug info :

The type is load by drools. enter image description here

The value is load by devtools enter image description here

How to resolve this ? Just add the META-INF/spring-devtools.properties file. The content is

restart.include.drools=/drools-[\\s\\S]+\.jar
restart.include.kie=/kie-[\\s\\S]+\.jar

This will make sure the drools and kie load by devtools itself class loader. And then the error fixed.

Here is some document

https://github.com/spring-projects/spring-boot/issues/3316

https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html

Upvotes: 1

Related Questions