What is Mvel dialect in Drools? - drools

I am new to Drools. I am creating a rule but I get a compile time error
"field is not visible'.
I've tried to check with Jboss examples, where they use dialect "mvel". It compiled. I didn't understand about dialect. So what is dialect=mvel?

mvel, or the MVFLEX Expression Language has a rich syntax, many of which allow for more concise and expressive code (and less imperative) than java, e.g.
Shorthand for get()ters / set()ters (e.g. encapsulating private fields) to be accessed in an alternative property style syntax (similar to VB or C# properties in .Net)
ie. instead of
myObject.setSomeField("SomeValue");
int x = myObject.getSomeIntField();
You can use the syntax (note the subtle capitalization switch as well):
myObject.someField = "SomeValue"
x = myObject.someIntField // Type inferrence
The return statement is optional (a convention found in many functional languages like Scala), as is the semi-colon, unless you have multiple statements per line:
x // i.e. return x;
Shorthand array creation and indexing by ordinal
foos = {2, 4, 6, 8, 10}
foos[3] // foos.get(3)
Similarly for Maps (Dictionaries)
bars = ["a" : "Apple", "b" : "Basket"] // Hashmap, with put
bars["a"]
bars.a // Similar to dynamically typed object e.g. in javascript, if key is a string.
Null Safe navigation operator (like the null-conditional operator in Rosyln)
foo.?bar.baz // if (foo.bar != null) { return foo.bar.baz; } else { return null; }

Based on
Drools JBoss Rules 5.0 Developer's Guide
Dialect is used to specify the syntax in any code expression that is in a condition or consequence. The default value is Java. Drools currently supports one more dialect called mvel.
Specifically mvel is an expression language for Java-based applications. And it's based on Java syntax. more info about mvel

rule "validate holiday"
dialect "mvel"
dialect "java"
when
$h1 : Holiday( month == "july" )
then
System.out.println($h1.name + ":" + $h1.month);
end
The purpose of dialect "mvel" is to point the Getter and Setters of the variables of your Plain Old Java Object (POJO) classes. Consider the above example, in which a Holiday class is used and inside the circular brackets (parentheses) "month" is used. So with the help dialect "mvel" the getter and setters of the variable "month" can be accessed.
Dialect "java" is used to help us write our Java code in our rules. There is one restriction or characteristic on this. We cannot use Java code inside "when" part of the rule but we can use Java code in "then" part.
We can also declare a Reference variable $h1 without the $ symbol. There is no restriction on this. The main purpose of putting the $ symbol before the variable is to mark the difference between variables of POJO classes and Rules.
Regards.

if you use dialect mvel - will fix your error.
Otherwise the scope of that variable is private by default, so use the default getter.
getField(). replace "Field" with yoru fieldname.
You can see the source code of the class in Data Objects -> class -> source tab in Business Central.

I found some thing on this.I shared with that.Drools was supported Java or MVEL scripting language.To get object properties values.For Example,The Fibonacci has bean and having multiple properties i.e.,sequence
rule Recurse
salience 10
when
not ( Fibonacci ( sequence == 1 ) )
f : Fibonacci ( value == -1 )
then
insert( new Fibonacci( f.sequence - 1 ) );
System.out.println( "recurse for " + f.sequence ); end
we need to check the if sequence ==1 then value is -1 .The sequence values are setting into Fibonacci object.We are checked the values based on MVEL or java.MVEL is a superset of Java.

Related

Ada: Importing the inequality operator "/="

I don't want to use an entire package, but I do want to import a few features, such as the "/=" operator. I know that renames allows me to do this with most functions, but with the inequality operator I get the error, explicit definition of inequality not allowed. How do I import this operator without raising the error?
package Integer_Maps is new Ada.Containers.Ordered_Maps
(
Key_Type => Integer,
Element_Type => Integer
);
-- the next line fails!
function "/=" ( Left, Right: Integer_Maps.Cursor ) return Boolean
renames Integer_Maps."/=";
You could do a use type Integer_Maps.Cursor; which gives visibility of the operators on the type.
For the container cursors, it might also be practical to do a use all type Integer_Maps.Cursor; which gives visibility of all the primitive operations on the type, like Key and Element.
I usually put use type and use all type clauses in the innermost enclosing scope (i.e. inside subprograms) where they're needed, like so:
procedure Foo is
use all type Integer_Maps.Cursor;
begin
for Cursor in My_Map.Iterate loop
Ada.Text_IO.Put_Line
(Integer'Image(Key(Cursor)) & " ->" & Integer'Image(Element(Cursor)));
end loop;
end Foo;
You don't! not directly, at any rate. Renaming the equality operator "=", and you get inequality for free.
-- this line succeeds!
function "=" ( Left, Right: Integer_Maps.Cursor ) return Boolean
renames Integer_Maps."=";
This is similar to overriding the operators. See ARM 6.6, in particular Static Semantics.

Usage of #TestCaseName with #FileParameters in JUnitParams

I use JUnit4 with JUnitParams for testing and I want to know more about the usage of the #TestCaseName annotation. I understand the usage of #TestCaseName with the #Parameters annotation, but I want to know about how to use #TestCaseName with the #FileParmeters annotation.
#TestCaseName allows you to modify how the name of the test case is presented in reports (eg. in your IDE or in the Maven Surefire report). The default naming is {method}({params}) [{index}]. You can use placeholders to create your own test case names. See Javadoc of junitparams.naming.TestCaseName#value:
A template of the individual test case name. This template can contain
macros, which will be substituted by their actual values at runtime.
Supported macros are: {index} - index of
parameters set (starts from zero). Hint: use it to avoid names
duplication. {params} - parameters set joined by
comma. {method} - testing method name.
{0}, {1}, {2} - single parameter by index in current parameters set.
If there is no parameter with such index, it will use empty string. Lets assume, that we are testing Fibonacci
sequence generator. We have a test with the following signature
#Parameters({ "0,1", "8,34" })
public void testFibonacci(int indexInSequence, int expectedNumber) { ... }
Here are some examples, that can be used as a test name template:
{method}({params}) => testFibonacci(0, 1), testFibonacci(8, 34)
fibonacci({0}) = {1} => fibonacci(0) = 1, fibonacci(8) = 34
{0} element should be {1} => 0 element should be 1, 8 element should be 34
Fibonacci sequence test #{index} => Fibonacci sequence test #0, Fibonacci sequence test #1
#FileParameters does not have any relation to #TestCaseName - it's simply a way to provide parameters to a test method from a file. Using the example above, instead of #Parameters you could use #FileParameters("/path/to/file.txt") and have a /path/to/file.txt with content
0,1
8,34
to achieve the same results.

Scala: how do I get the annotations on an expression?

In the Scala language specification, ยง6.14 Annotated Expressions:
An annotated expression e: #a1 ... #an attaches annotations a1, ..., an to the expression e.
While I can get annotations just fine on classes (and their member values and methods), I can't find a way to get the annotations on an expression at runtime.
Say I have val x = C(f1 = v1 : #a1, f2 = v2 : #a2), how do I get annotations #a1 and #a2 from x's fields? (where C is a case class and #aX may be custom annotations)
Using runtime reflection I don't believe you can access any expressions (except for annotation values and default parameter values; there may be something else I am overlooking) at all, and so you can't access any annotations on them.
You need C or C.apply to be a macro (or use a compiler plugin).

Returning query results within rules (when clause of drl file) in drools

I need help in retrieving query results within when clause of drl file in drools.
Example rule file having query:
query getUsersForCard (Long ipCardNumber)
$listOfUsers : UsersList()
$listOfUserCards : User(cardNumber == ipCardNumber, $cardNum : cardNumber) from $listOfUsers.user_list
end
rule "matchUser"
when
getUsersForCard("4444333322221112L";)
then
System.out.println( "$$$card number in VisaMessage matched with card number in UsersList$$$" );
end
How to obtain $cardNum aftergetUsersForCard query call so that then clause gets printed? I don't want to retrieve $cardNum in Java code from Working Memory but rather should be able to do it within the drl file itself.
Help is much appreciated!
Going back to the original question: "Can query results be accessed from the LHS of a rule?", the answer is: "Yes, using unification (Sections 8.8.3.3.6 and 8.9)".
A query in Drools can have input and output parameters. Input parameters are those that have a value (are bound) when the query is invoked. Those parameters that don't have a value (unbound) are considered output parameters.
The first thing to do is to rewrite your query using unification:
query getUsersForCard (Long ipCardNumber, Long $cardNum)
$listOfUsers : UsersList()
$listOfUserCards : User(
cardNumber == ipCardNumber,
$cardNum := cardNumber
) from $listOfUsers.user_list
end
The important thing to notice is the := (unification) sign being used. This operator is basically saying: "If the variable has a value, then I'll act as an == operator. Otherwise I'll act as a variable binding.
When invoking your query from a rule, you need to make sure you don't provide any value for the second parameter in the query. Given that you are already using positional arguments, that's easy to do:
rule "matchUser"
when
getUsersForCard("4444333322221112L", $cardNum;)
then
System.out.println( "$$$card number in VisaMessage matched with card number in UsersList$$$: "+$cardNum );
end
When the query is invoked, $cardNum will not have a value and it will set by the query because of the unification mechanism.
Hope it helps,
You cannot retrieve query results within the when clause the way I think you think it can be done. But there is no need to do so, simply write the rule as
rule "match card number"
when
$listOfUsers: UsersList()
$user: User(cardNumber == "4444333322221112L") from $listOfUsers
then ... end
Assuming the text of the println indicates what you really want to do, you might use
rule "match card number"
when
VisaMessage( $cardNo: cardNumber )
$listOfUsers: UsersList()
$user: User(cardNumber == $cardNo) from $listOfUsers
then ... end

Matching a list (of tags) with another and detecting presence of common elements

My requirement is to match tags. In the example, this particular HourConstraint checks the TeacherHour assigned to Hour(23).
Specifically, it checks TeacherHour.attributes["tags"] for the values ["asst_ct","teacher_john_smith"] and detects atleast one match, two in this case (both "asst_ct" and "teacher_john_smith") .
TeacherHour:
id: 47
assigned_hour: Null
attributes:Map<List<String>>
"tags":["asst_ct","no_strenuous_duties","kinda_boring","teacher_john_smith"]
"another_attribute":[...]
HourConstraint:
hour: Hour(23)
attribute: "tags"
values_list: ["asst_ct","teacher_john_smith"]
Question: How do I detect the presence (true or false) of common elements between two lists?
Drools Expert has memberOf and contains, but they check a scalar vs a collection, never a collection vs a collection.
I see two potential ways:
introduce a function boolean isIntersecting(list,list) and tell Drools to use that for truth checking
Implement TeacherHour.attributes[] as a string instead of a list and HourConstraint.valueslist as a regular expression that can match that list
There are a few options. Most straight forward is to use the Collections class to do that for you:
rule X
when
$t: TeacherHour( )
HourConstraint( Collections.disjoint( $t.attributes["tags"], values_list ) == false )
...
If this is something you would use often in your rules, then I recommend wrapping that function in a pluggable operator, supported by Drools. Lets say you name the operator "intersect", you can then write your rules like this:
rule X
when
$t: TeacherHour( )
HourConstraint( values_list intersect $t.attributes["tags"] )
...
A third option, is to use "from", but that is less efficient in runtime as it causes iterations on the first list:
rule X
when
$t: TeacherHour( )
$tag : String() from $t.attributes["tags"]
exists( HourConstraint( values_list contains $tag ) )
...