Debugging the right-hand side of a rule

As we already know, the right-hand side of a rule in Drools may contain a combination of the following elements:

  • Java sentences: Any regular Java sentence that is allowed in a Java method can also be used on the right-hand side of a rule in Drools.
  • MVEL expressions: If the dialect of the rule is set to mvel, MVEL expressions are enabled on the right-hand side of the rule in Drools.
  • Predefined variables and methods: Variables such as drools and kcontext and methods such as insert, update, and delete are also allowed. The special modify(){} structure could also be used on the right-hand side of the rule in Drools.

In the previous section, we introduced the notion of how, when compiled, the left-hand side of all the rules in a KIE Base is converted into a network of nodes. For the right-hand side of the rules, the situation is different. When a KIE Base is compiled, the right-hand side of each of the rules that it contains is converted into a Java class. This Java class will basically define a single method containing all the code that was on the right-hand side of the source rule. Inside the PHREAK network, a reference to this class is then added as a terminal node (this will be covered in greater detail in the next chapter).

Even if there is a way to use breakpoints to debug the right-hand side of the rule in a traditional way, this is only possible under some strict circumstances; this is why having a useful set of good practices and techniques to make the right-hand side of a rule easier to debug becomes mandatory.

Tip

There is a Drools Eclipse plugin that can be used, among other things, to debug the right-hand side of the rules in a DRL resource. This capability is only enabled for Drools projects. The scope of this plugin is beyond this book. More information about how to set up this plugin in Eclipse can be found in the following Drools' documentation: http://docs.jboss.org/drools/release/latestF

Right-hand side troubleshooting

The good news about the right-hand side of a rule being converted into a Java class is that the errors that we may experience will look much more familiar to us than the errors found on the left-hand side of it.

Just like with any piece of Java code, two types of errors might be found: compilation errors and runtime errors.

Compilation errors

Compilation errors are caused by invalid syntax or grammar on the right-hand side of a rule. Similar to the compilation errors on the left-hand side of a rule, compilation errors on the right-hand side will create an error containing information about what the error was and where in the corresponding resource it occurred. The same consideration for compilation errors on the left-hand side of a rule also applies here: Drools will not complain about compilation errors in a KIE Base by itself. The verification of a newly created KIE Container is mandatory.

As an example, let's go back to the rule that was used to send suspicious operations to an audit service introduced in Chapter 5, Understanding KIE Sessions:

rule "Send Suspicious Operation to Audit Service"
when
    $so: SuspiciousOperation()
then
    auditServiceXXX.notifySuspiciousOperation($so);
end

In the preceding rule, we have intentionally introduced a compilation error: the name of the global being used as a service was changed from auditService to auditServiceXXX.

When a KIE Container containing the erroneous rule is validated, the following error will be generated:

[ERROR] - chapter05/globals-5/globals-5.drl[26,0]: Rule Compilation error auditServiceXXX cannot be resolved

Similar to the compilation errors on the left-hand side of a rule, the generated error will indicate what the error was (auditServiceXXX cannot be resolved) and resource where the error occurred (chapter05/globals-5/globals-5.drl). An estimated line (26) and column (0) for the error will also be generated.

Using all this information, the identification and resolution of compilation errors in the right-hand side of a rule is, most of the times, trivial.

Runtime errors

Runtime errors on the right-hand side of a rule are caused by unhandled exceptions in the code. This type of errors on the right-hand side of the rule are as potentially harmful as runtime errors on the left-hand side: they can leave a session in an inconsistent and irrecoverable state. Special attention is then required for this type of errors in our knowledge bases. Just like we stated before for runtime errors on the left-hand side of our rules, the best mechanism to mitigate this kind of errors is to provide an extensive set of test scenarios covering all the different situations that our sessions could be exposed to.

Using the same rule from the previous section, now let's see what happens if the audit service used by this rule throws an exception during runtime. In this scenario, IllegalStateException will be thrown if the audit service can't be contacted. The stack trace generated during runtime for this scenario will look similar to the following (the stack trace was shortened to make it easier to read):

Exception executing consequence for rule "Send Suspicious Operation to Audit Service" in chapter05.globals5: java.lang.IllegalStateException: Unable to contact Audit Service: No route to host.
    at o.d.c.r.r.i.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:39)
    at o.d.c.c.DefaultAgenda.fireActivation(DefaultAgenda.java:1083)
... 37 more
Caused by: java.lang.IllegalStateException: Unable to contact Audit Service: No route to host.
    at org.drools.devguide.chapter05.GlobalsTest$4.notifySuspiciousOperation(GlobalsTest.java:286)
    at chapter05.globals5.Rule_Send_Suspicious_Operation_to_Audit_Service1050594099.defaultConsequence(Rule_Send_Suspicious_Operation_to_Audit_Service1050594099.java:7)
... 40 more

The preceding stack trace shows the IllegalStateException being thrown by the service, and where in our code, the exception actually takes place. There are two important things to notice in the stack trace, other than the concrete exception: one is where the exception actually occurred. In this case, the concrete implementation of the service being used is defined as an anonymous class (GlobalsTest$4) in GlobalTest.java. The second thing to notice is where in our rule is the exception thrown. In this case, the class where the exception is thrown is Rule_Send_Suspicious_Operation_to_Audit_Service1050594099. This is the class that Drools generated for the right-hand side of the rule when it was compiled. We will come back to these generated classes later in this chapter.

Right-hand side good practices

Some of the good practices regarding the right-hand side of the rules that were already covered in this chapter and some of the good practices regarding the left-hand side also apply here. The use of global variables to reference services, for example, makes our rules independent of the context. Different context (that is, production, testing, and so on) could use different implementations of these global variables to obtain different behaviors. Using event listeners, we can also be aware of when the right-hand side of a rule modifies the state of the session by inserting, updating, or deleting facts.

As debugging the right-hand side of the rules requires some extra steps (either the Drools Eclipse plug-in or the generation of the corresponding Java classes), creating simple right-hand sides, when possible, is always a good idea. For example, instead of having 10 lines of code in the action part of a rule, we could extract this into a regular Java class and invoke it from the rule. This simplification will allow us to easily debug our Java class and not worry about the rule itself.

Along with keeping the right-hand side of our rules simple, we must also avoid any unhandled exception to happen in it. We already talked about the problems that this kind of exceptions cause in Drools.

Another good practice that should sound obvious for any experienced developer is to use a logger framework. Remember that the right-hand side of our rules is just Java. We could, and should, use a logger in our rules to get a more detailed idea of what is going on in our knowledge bases.

Dumping the generated Java classes

As already mentioned earlier, the right-hand side of our rules is converted, on the fly, into Java classes by Drools. This conversion is, by default, invisible to the application using Drools: we never get to see these generated classes. When dealing with errors on the right-hand side of a rule it is, sometimes, useful to understand which exact Java code is being executed during runtime.

Thankfully, Drools allows us to dump the generated Java classes from our rules into a directory in the filesystem. These classes are not only useful to understand what is the concrete Java code that is being executed by Drools, but they can also be used to attach a debugger to them in order to debug the right-hand side of the rules as a regular class.

Drools provides two simple ways to enable the dump of the generated classes into a directory via a system property or declaratively in the kmodule.xml file.

Using the drools.dump.dir system variable, the directory where we want to dump the generated classes can be specified. For example, if we are using Maven to run our tests and want to dump any generated class, we can invoke the following command:

mvn test -Ddrools.dump.dir
="/tmp/classes"

We could achieve the same result by adding the following property to our <kmodule> section in the kmodule.xml files:

<kmodule>
    <configuration>
        <property key="drools.dump.dir" value="/tmp/classes"/>
    </configuration>
    ...
</kmodule>

If we take a look at the kmodule.xml file present in the code bundle associated with this chapter, we will notice that it is actually using the property that was mentioned earlier.

To get a better understanding of how these classes look and how the code on the right-hand side of our rules is executed inside them, it is highly recommended to execute the tests associated with this chapter. To get an even better understanding, try to use the drools. dump.dir property in other examples of this book.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.97.187