drools 5: NullPointerException when sharing KnowledgeBase across processes - drools

We have a cluster of jboss instances running drools. We generate the KnowledgeBase on one instance, then store it in a database; the other instances can then load it from the database instead of generating it themselves.
This has worked well for some time using drools 4, but we recently upgraded to drools 5.3.0 BRMS and the pattern no longer works. The KnowledgeBase works fine within the app instance in which it was generated, but it fails everywhere else with the following exception. Note that this exception happens upon inserting a fact into working memory.
All instances of the app are identical, they run in the same jvm, etc. The 'other' instance does not need to be on a different physical machine -- it can be on the same hardware, and the failure still occurs.
What is it about a KnowledgeBase that makes it fail in a different jvm instance from the one in which it was generated? Is there some way to avoid this problem? Thanks.
This is the drl in which the failure seems to happen. I've done some debugging through the mvel code, but I'm not familiar with it and I haven't figured out what's going on. I think the expression on which the failure occurs is the 'this.fact.requirementId'.
rule "Find OutOfOrder PredicateSolutions for new LeafPredicateSolution in rule [Become Application Expired : 147]"
ruleflow-group "RuleGroup[Become Application Expired:147]"
agenda-group "leaf"
no-loop
salience -1001
when
EngineDates($rewindToDate: engineEffectiveDate);
lps:LeafPredicateSolution(
ruleId==147,
parent==null,
$candidateId:candidateId,
defunct==false,
fact:fact,
effectiveDate == $rewindToDate,
$programId:programId,
eval(!fact.getReused())); // only solutions created for the fact we're running on can trigger OoO
oops : ArrayList() from accumulate(
PredicateSolution(
$sol:this,
candidateId==$candidateId,
effectiveDate > $rewindToDate,
defunct==false,
programId==$programId,
parent!=null,
solutionType!=SolutionType.RETIRED,
eval(($sol instanceof LeafPredicateSolution) || ($sol instanceof NonCalcProgramSolutionChild))
),
init(ArrayList items = new ArrayList();),
action(items.add($sol);),
reverse(items.remove($sol);),
result(items));
// Find ProgramPredicateSolutions in other programs that refer to this program.
// These need to be rewound.
oopps:ArrayList() from collect(
ProgramPredicateSolution(
this.fact.requirementId == $programId,
candidateId==$candidateId,
effectiveDate > $rewindToDate,
defunct==false,
parent!=null,
solutionType!=SolutionType.RETIRED));
eval((oops.size() > 0) || (oopps.size() > 0));
eval(predicateSolutionFactory.oopEnabled());//Don't run oop if it is disabled (TimeMachine, Whatif)
then
predicateSolutionFactory.addToOutOfOrder(lps, oops, oopps, new Long(65));
end
Stack trace:
java.lang.NullPointerException
at org.mvel2.MVEL.executeExpression(MVEL.java:954)
at org.drools.base.extractors.MVELClassFieldReader.getValue(MVELClassFieldReader.java:100)
at org.drools.base.extractors.BaseObjectClassFieldReader.getHashCode(BaseObjectClassFieldReader.java:196)
at org.drools.core.util.AbstractHashTable$DoubleCompositeIndex.hashCodeOf(AbstractHashTable.java:616)
at org.drools.core.util.RightTupleIndexHashTable.getOrCreate(RightTupleIndexHashTable.java:451)
at org.drools.core.util.RightTupleIndexHashTable.add(RightTupleIndexHashTable.java:332)
at org.drools.reteoo.AccumulateNode.assertObject(AccumulateNode.java:263)
at org.drools.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:458)
at org.drools.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:386)
at org.drools.reteoo.AlphaNode.assertObject(AlphaNode.java:135)
at org.drools.reteoo.SingleObjectSinkAdapter.propagateAssertObject(SingleObjectSinkAdapter.java:59)
at org.drools.reteoo.AlphaNode.assertObject(AlphaNode.java:135)
at org.drools.reteoo.SingleObjectSinkAdapter.propagateAssertObject(SingleObjectSinkAdapter.java:59)
at org.drools.reteoo.AlphaNode.assertObject(AlphaNode.java:135)
at org.drools.reteoo.CompositeObjectSinkAdapter.doPropagateAssertObject(CompositeObjectSinkAdapter.java:458)
at org.drools.reteoo.CompositeObjectSinkAdapter.propagateAssertObject(CompositeObjectSinkAdapter.java:376)
at org.drools.reteoo.ObjectTypeNode.assertObject(ObjectTypeNode.java:214)
at org.drools.reteoo.EntryPointNode.assertObject(EntryPointNode.java:244)
at org.drools.common.NamedEntryPoint.insert(NamedEntryPoint.java:337)
at org.drools.common.NamedEntryPoint.insert(NamedEntryPoint.java:298)
at org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:887)
at org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:846)
at org.drools.impl.StatefulKnowledgeSessionImpl.insert(StatefulKnowledgeSessionImpl.java:267)

Related

Why does Drools re-evaluate and re-trigger rule actions after a persistent session is reloaded?

I have a simple rule like the one below:
package rules
dialect "mvel"
declare MyEvent
#role( event )
#expires( 2d )
id String
value: Double
end
rule "My Rule"
when
MyEvent($value : value)
then
System.out.println("My event with value: " + $value);
end
I create a persistent session and call fireAllRules() on it. Then, I insert a MyEvent fact, and as expected the rule is evaluated, matched and the action is executed. If I call fireAllRules() again the rule is not matched, as expected because it has already matched for the same fact. At this point everything is fine.
Then I kill the JVM and run the app again. At startup the app loads the session like this:
kieSession = kieServices.getStoreServices().loadKieSession(KIE_SESSION_ID, kieBase, kieSessionConfiguration, kieEnvironment);
The session gets loaded successfully, and then fireAllRules() is called again. Since the rule has already matched for the inserted event, I am expecting that it does not match again. However I can see the message in the rule action is printed again. Why does Drools match the rule for the same eventagaian? To me it looks like the session state is not properly saved to database. I mean, the event is saved, but Drools can not recogonize that it has already matched the rule. When I load a persistent session I expect to recover exactly the same state that the session had in the previous running instance. Is my assumption wrong? or Am I doing something wrong for the expected behaviour?
Running:
JavaSE 11
SpringBoot 2.3
Drools 7.53.0

How to compile documents and run Jshop2 in Eclipse?

I am a student who begin to study SHOP2 from China.
My teacher told me to run JSHOP2 in Eclipse.Now I can run original zenotravel problem and generate GUI and plans.Likewise, I want to put other domain and problems to SHOP2 and produce plans.
But the problem is that I don't know how to compile them and My teacher only asked me to run the the main function in Internaldomain but it can't succeed.Follow is the original code:
public static void main(String[] args) throws Exception
{
//compile();
// compile(args);
//-- run the planning algorithm
run(args);
}
This code can run zenotravel.Then I put domain and problems named pfile1 and
tdepots respectively into SHOP2 folder.Change the codes to:
{
compile(domaintdepots);
// compile(args);
//-- run the planning algorithm
run(args);
}
It warns "domainpdfiles cannot be resolved to a variable".
Or
//--compile();
compile(args);
//-- run the planning algorithm
//run(args);
It turns out:
"Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at JSHOP2.InternalDomain.compile(InternalDomain.java:748)
at JSHOP2.InternalDomain.main(InternalDomain.java:720)"
720 is main funcition above.And 748 is compile function:
public static void compile(String[] args) throws Exception
{
//-- The number of solution plans to be returned.
int planNo = -1;
//-- Handle the number of solution plans the user wants to be returned.
if (args.length == 2 || args[0].substring(0, 2).equals("-r")) {
if (args[0].equals("-r"))
planNo = 1;
else if (args[0].equals("-ra"))
planNo = Integer.MAX_VALUE;
else try {
planNo = Integer.parseInt(args[0].substring(2));
} catch (NumberFormatException e) {
}
}
Finally,according to the advice of the friend,I put the two pddls into src folder and use “java Jshop2.InternalDomain domaintdepots”in CMD commad but an error appeared:"the main class Interdomain can't be found or loaded".But I have set the class path accurately and the Zenotravel planning can run.So how
and where can I use the command ?
And what is written in the bracket"compile()" in Eclipse?
I am also not familiar with JAVA so it's better if there is concrete instruction.Thanks a lot.
Please describe what are you trying to build, what is it supposed to do, what is the expected end result.
If you do have a valid PDDL domain and problem file, you could try to load them into the online http://editor.planning.domains/ editor using the File > Load menu. Then press the Solve button and confirm which of the file is the domain and which is problem. If the PDDL model is valid (and the underlying solver can handle the requirements), you will get a plan back.
If you are trying to build a software solution that needs a PDDL-based planning engine as one of its component, perhaps you could use one of the available implementations: https://nergmada.github.io/pddl-reference/guide/whatisplanner.html#list-of-planners
If you are trying to build your own planning engine in Java using the Eclipse IDE, you probably need a Java-based PDDL parser. Here is a tutorial, how to use pddl4j for that purpose:
https://github.com/pellierd/pddl4j/wiki/A-tutorial-to-develop-your-own-planner
If you need to use Jshop2 in particular, it looks from their documentation (http://www.cs.umd.edu/projects/shop/description.html) that you need to indeed compile the domain and problem PDDL into Java code using following commands:
java JSHOP2.InternalDomain domainFileName
java JSHOP2.InternalDomain -r problemFileName
Edited on June 19th
Java package names (e.g. JSHOP2) and class names (InternalDomain) are case sensitive, so make sure you type them as per the documentation. That is probably why you are getting the "main class not found error".
It is difficult to say what the lines numbers 748 and 720 exactly correspond to, because in the GitHub repo https://github.com/mas-group/jshop2/blob/master/src/JSHOP2/InternalDomain.java the code is different from yours. Can you indicate in your questions which lines those are exactly?
The make file shows how to execute an out-of-the-box example in the distribution:
cd examples\blocks
java JSHOP2.InternalDomain blocks
java JSHOP2.InternalDomain -r problem300
Does that work for you?

Debugging test cases when they are combination of Robot framework and python selenium

Currently I'm using Eclipse with Nokia/Red plugin which allows me to write robot framework test suites. Support is Python 3.6 and Selenium for it.
My project is called "Automation" and Test suites are in .robot files.
Test suites have test cases which are called "Keywords".
Test Cases
Create New Vehicle
Create new vehicle with next ${registrationno} and ${description}
Navigate to data section
Those "Keywords" are imported from python library and look like:
#keyword("Create new vehicle with next ${registrationno} and ${description}")
def create_new_vehicle_Simple(self,registrationno, description):
headerPage = HeaderPage(TestCaseKeywords.driver)
sideBarPage = headerPage.selectDaten()
basicVehicleCreation = sideBarPage.createNewVehicle()
basicVehicleCreation.setKennzeichen(registrationno)
basicVehicleCreation.setBeschreibung(description)
TestCaseKeywords.carnumber = basicVehicleCreation.save()
The problem is that when I run test cases, in log I only get result of this whole python function, pass or failed. I can't see at which step it failed- is it at first or second step of this function.
Is there any plugin or other solution for this case to be able to see which exact python function pass or fail? (of course, workaround is to use in TC for every function a keyword but that is not what I prefer)
If you need to "step into" a python defined keyword you need to use python debugger together with RED.
This can be done with any python debugger,if you like to have everything in one application, PyDev can be used with RED.
Follow below help document, if you will face any problems leave a comment here.
RED Debug with PyDev
If you are wanting to know which statement in the python-based keyword failed, you simply need to have it throw an appropriate error. Robot won't do this for you, however. From a reporting standpoint, a python based keyword is a black box. You will have to explicitly add logging messages, and return useful errors.
For example, the call to sideBarPage.createNewVehicle() should throw an exception such as "unable to create new vehicle". Likewise, the call to basicVehicleCreation.setKennzeichen(registrationno) should raise an error like "failed to register the vehicle".
If you don't have control over those methods, you can do the error handling from within your keyword:
#keyword("Create new vehicle with next ${registrationno} and ${description}")
def create_new_vehicle_Simple(self,registrationno, description):
headerPage = HeaderPage(TestCaseKeywords.driver)
sideBarPage = headerPage.selectDaten()
try:
basicVehicleCreation = sideBarPage.createNewVehicle()
except:
raise Exception("unable to create new vehicle")
try:
basicVehicleCreation.setKennzeichen(registrationno)
except:
raise exception("unable to register new vehicle")
...

Problem with DSL and Business Rules creation in Drools

I am using Eclipse with the Drools plugin to create rules.
I want to create business rules and main aim is to try and provide the user a set of options which he can use to create rules.
For eg:If an Apple can have only 3 colors: I want to provide an option like a drop down so that the user can know before hand which are the options he can use in his rules.
Is it possible?
I am creating a dsl but unable to still provide the above functionality for a business rule.
I am having an error implementing a basic dsl also.
The code to add the dsl is as follows in my RuleRunner class()
InputStream ruleSource = RuleRunner.class.getClassLoader().getResourceAsStream("/Rule1.dslr");
InputStream dslSource = RuleRunner.class.getClassLoader().getResourceAsStream("/sample-dsl.dsl");
//Load the rules , using DSL
addRulesToThisPackage.addPackageFromDrl(
new InputStreamReader(ruleSource),new InputStreamReader(dslSource));
I have both the sample-dsl .dsl and Rule1.dslr in my working directory.
Error encountered at adding the dsl to the package (last line)
Error stack:
Exception in thread "main" java.lang.NullPointerException
at java.io.Reader.<init>(Unknown Source)
at java.io.InputStreamReader.<init>(Unknown Source)
at com.org.RuleRunner.loadRuleFile(RuleRunner.java:96)
at com.org.RuleRunner.loadRules(RuleRunner.java:48)
at com.org.RuleRunner.runStatelessRules(RuleRunner.java:109)
at com.org.RulesTest.main(RulesTest.java:41)
my dsl file has basic mapping as per the online documentations.
The dsl rule I created is:
expander sample-dsl.dsl
rule "A status changes B status"
when
There is an A
- has an address
There is a B
- has name
then
- print updated A and Aaddress
End
I have created DSL in eclipse.
Is the code I added for it to be loaded to my package correct?? Or am I missing something????
It seems like my program is unable to find the dsl?
Please help. Can you point me towards the right direction to create a user friendly business rule ??
Thanks.
J
I am not quite familiar with the method you are trying to use to create a knowledge session, but I will show a example of what's used in my applications.
KnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase(<KnowledgeBaseConfiguration>);
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newClassPathResource( "rules/myRuleFile.drl", getClass() ),
ResourceType.DRL );
kbuilder.add( ResourceFactory.newClassPathResource( "rules/myDslFile.dsl", getClass() ),
ResourceType.DSL );
if ( kbuilder.hasErrors() ) {
System.err.println( builder.getErrors().toString() );
}
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
Now as far as giving your users the ability to author rule files, with built in constraints, have you looked at Drools Guvnor?(http://downloads.jboss.com/drools/docs/5.0.1.26597.FINAL/drools-guvnor/html_single/index.html) I have not incorporated it into my project yet, but have researched it a bit. I think it may provide the functionality your seeking for allowing your users to create and edit rule files. Good luck!

Drools related problem

Hi I want to bring a little change in my site. So i have written a set of rules but I dont know how to fire them in the place that i want them to work i.e. the original code of my site.Can anyone plz help me on it?
A little information is missing (like which Drools version, the environment you're running in, etc.), so I'll try to answer in a general way, and if you need something more specific let me know:
In general in Drools you 'assert' objects into the working memory (using methods like, well, assertObject..), this allows the rule engine to be aware of them, and later, when you execute 'fireAllRules' on that working memory, all the rules are executed (so, you explicitly call the fireAllRules method on your working memory when you want to - I think this is what you were asking).
For more detailed information, in case you haven't looked already, you can check this: http://legacy.drools.codehaus.org/Working+Memory .
thanks
Gadi
when you have your abc object, this will be the fact that you insert into the Working Memory. For example:
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newFileSystemResource( fileName ), ResourceType.DRL );
if (kbuilder.hasErrors() ) {
System.out.println( kbuilder.getErrors() );
} else {
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();
ksession.execute( abc );
}
Then you will have your modified abc object when the execute finishes. Take a look at here
You probably dont't want the rules being build everytime (this is really time consumer), so you can use or KnowledgeAgent or have an static KnowledgeBase and recreate it whenever your rules files change.