I have such code:
StatefulKnowledgeSession kSession = getKnowledgeBase().newStatefulKnowledgeSession();
this.insertFactsToWorkingMemory(inputCollection, kSession);
kSession.fireAllRules(new NotificationRuleNameFilter(name));
What insertFactsToWorkingMemory does is it takes object attributes and simply does WorkingMemory.insert(fact).
The rules are stored in .drl file and looks like:
rule "USER.PASSWORD_RENEW"
when
$config : UserSettings ( )
eval( true )
then
DroolsNotificationResult fact0 = new DroolsNotificationResult();
fact0.setBusinessRulePassed( true );
insert(fact0 );
end
The name of the rule and name passed in NotificationRuleNameFilter(name) match perfectly. Any clues?
I'm relatively new to Drools. I have those rules :
import models.Demarche;
declare IsMarque
demarche : Demarche
end
rule "Add type Marque taxe"
salience 2
no-loop true
lock-on-active true
when
$d : Demarche( typeDemarche == "Marque" )
then
modify($d){
listTaxes.put(14, 1)
}
insert( new IsMarque( $d ) );
System.out.println("infer marque");
end
And :
rule "Add Marque Polynesie extention taxe"
no-loop true
lock-on-active true
when
$d : Demarche( extPolynesie == true)
IsMarque(demarche == $d)
then
$d.listTaxes.put(17, 1);
System.out.println("marque");
end
rule "Add Not Marque Polynesie extention taxe"
no-loop true
lock-on-active true
when
$d : Demarche( extPolynesie == true)
not(IsMarque(demarche == $d))
then
System.out.println("not marque");
end
For the rules 2 or 3, nothing happens. One of them should be true, but nothing is printed, as if the infered IsMarque cannot be evaluated. If I comment the IsMaqrue evaluation this is working, i can see the messages printed in the console.
Any idea?
This rule needs to be rewritten as
rule "Add type Marque taxe"
when
$d : Demarche( typeDemarche == "Marque", $t: listTaxes) // I AM GUESSING HERE
not IsMarque(demarche == $d)
then
modify($t){
put(14, 1)
}
insert( new IsMarque( $d ) );
System.out.println("infer marque");
end
And no no-loop true and lock-on-active true if you have shown everything there is.
Note that you could write the first rule also as
rule "Add type Marque taxe"
when
$d : Demarche( typeDemarche == "Marque")
then
$d.getListTaxes().put(14, 1);
insert( new IsMarque( $d ) );
System.out.println("infer marque");
end
if (and only if) no other rule as CEs referring to the listTaxes property. Since you have used this "dirty update" in rule "Add Marque Polynesie extention taxe", it seems to be OK.
Please post complete rules - #1 doesn't compile.
I have problems codify this rule in drools which unites the link to the same destination exists and if the inveso then does the union of the latter also.
class Node {
List <Link> out;
List <Link> in;
}
class Link {
Source node;
Target node;
}
they are inserted as facts in working memory.
example.
A - link1 -> B
A - link2 -> B
A - link3 -> C
C - link4 -> D
B - link5 -> A
result
A - link1 + link2 +link5 -> B
A - link3 -> C
C - link4 -> D
Can anyone help me?
To remove all redundant Link objects and assuming that class Link is declared as
class Link {
Node source;
Node target;
}
(and not as given in the original post), the rule:
rule "kill redundant links"
when
$l1: Link( $s: source, $t: target )
$l2: Link( this != $l1,
source == $s && target == $t
||
source == $t && target == $s )
$n1: Node( out contains $l2 )
$n2: Node( in contains $l2 )
then
retract( $l2 );
modify( $n1 ){ getOut().remove( $l2 ) }
modify( $n2 ){ getIn().remove( $l2 ) }
end
removes all redundant Link facts and updates the out and in fields of
the Nodes at either end of these links.
I need a little help with Drools eval and variable assigning.
rule "check that no previously submitted requests exist"
when
$user : UserFormField( name == 'employeeId', value != null )
$repository : Repository( )
$activeRequests : List( ) from $repository.findActiveRequestsByEmployee( $user.getValue() ) # call to repository
eval( $activeRequests.size() > 0 )
then
System.err.println(' You have active requests: ' + ((Request)$activeRequests.get(0)).getTitle);
insert(Boolean.TRUE);
end
In this rule I try to access repository and get active requests for current user. Rule compiles and executes without any exceptions or warnings. In debug mode it can be seen that repository returns non empty list and I expect to see console message 'You have active requests' but this doesn't happen. I think the problem is in this line
$activeRequests : List( ) from $repository.findActiveRequestsByEmployee( $user.getValue() )
because this rule works fine
rule "check that no previously submitted requests exist"
when
$user : UserFormField( name == 'employeeId', value != null )
$repository : Repository( )
eval( $repository.findActiveRequestsByEmployee($user.getValue()).size() > 0 )
then
System.err.println(' You have active requests !' );
insert(Boolean.TRUE);
end
So could someone point me how to solve this problem?
Thanks!
I was helped to find a solution. I should use from collect expression instead simple from to bundle facts into collection :
$activeRequests : ArrayList() from collect ( Request() from $repository.findActiveRequestsByEmployee( $user.getValue() ) )
You have to distinguish (i.e., read the fine print in the
documentation) between "from" and "from collect". If you want the rule
to fire individually for each collection element produced by the
expression after "from", then use "from". If, however, you want to
have it all bundled into a collection you must used "from collect".
$activeRequests : ArrayList() from collect ( Request() from
$repository.findActiveRequestsByEmployee( $user.getValue() ) )
Note that the separate eval isn't necessary. You can put this
constraint into the ArrayList pattern:
ArrayList( size > 0 )
There is something like status changes check logic in our app.
Currently checking is being handled by ugly if statement
I want to replace it by transition matrix:
my %allowed_status_changes = (
1 => (2,5),
2 => (1,2,3,4,5),
3 => (4,2),
4 => (3,2),
5 => (),
);
my $is_allowed_transition =
$submitted_status ~~ $allowed_status_changes {$original_status};
if ($prerequestsites && !$is_allowed_transition) {
return;
}
certain transitions can be allowed only on additional condition, therefore I will need something like
2 => (
(target => 1)
(target => 2, condition => $some_condition)
(target => (3,4), condition => $other_condition),
(target => 5)
),
(in my opinion it is too long)
What structure would you use in this situation if you should focus on readability and maintainability?
How you will parse it to check if transition is allowed?
If the conditions are very prevalent (e.g. almost every allowed transition has them) then your latter structure is perfectly fine, other than your syntax error of representing a hashref with "()" instead of "{}".
If the conditions are rare, I'd suggest going with #1, augmented by optional constructs similar to your #2.
Please note that readability of checking code is IMHO very clear though voluminous and not very idiomatic.
OTOH, maintainability of the matrix is high - you have terse yet readable syntax from #1 where no conditions are needed and a clear though longer syntax for conditions which is flexible enough for many conditions per many settings like your #2.
my %allowed_status_changes = (
1 => [2,5],
2 => [1,5,{targets=>[2], conditions=>[$some_condition]}
,{targets=>[3,4], conditions=>[$other_condition, $more_cond]}]
3 => [4,2],
4 => [3,2],
5 => [],
);
sub is_allowed_transition {
my ($submitted_status, $original_status ) = #_;
foreach my $alowed_status (#$allowed_status_changes{$original_status}) {
return 1 if !ref $alowed_status && $alowed_status == $submitted_status;
if (ref $alowed_status) {
foreach my $target (#$alowed_status{targets}) {
foreach my $condition (#$alowed_status{conditions}) {
return 1 if check_condition($submitted_status
, $original_status, $condition);
}
}
}
}
return 0;
}
if ($prerequestsites
&& !$is_allowed_transition($submitted_status, $original_status )) {
return;
}
Although I agree with DVK for the most part, I have to say, once you start delving into arrays of arrays of hashes, you're reaching a code complexity level that is hard to maintain without much spinning of heads and bugs.
At this point, I'd probably reach for an object and a class, for a bit of syntactic sugar.
my $transitions = TransitionGraph->new();
$transition->add( 1, { targets => [ 2, 5 ] });
$transition->add( 2, { targets => [ 1, 5 ] });
$transition->add( 2, { targets => [ 2 ], conditions => [ $some_condition ] });
$transition->add( 2, { targets => [ 3, 4 ], conditions => [ $other_condition, $more_cond ]});
$transition->add( 3, { targets => [4,2] } );
$transition->add( 4, { targets => [3,2] } );
$transition->add( 5, { targets => [] } );
if( $transition->allowed( 1 , 3 )){
}
Class implementation is up to the user, but I'd use Moose.
The primary benefits of this is you're encapsulating how the state graph works so you can Just Use it and worry about how the graph works seperate from where its used.
nb. in the above proposed API, add() creates a new record if one does not exist, and updates that record if it does exist. This turned out to be simpler than having "upgrade" methods or "get this item and then modify it" techniques.
Internally, it could do this, or something like it:
sub add {
my ( $self , $input_state, $rules ) = #_;
my $state;
if ( $self->has_state( $input_state ) ) {
$state = $self->get_state( $input_state );
} else {
$state = TransitionGraphState->new( source_id => $input_state );
$self->add_state( $input_state, $state );
}
my $targets = delete $rules{targets};
for my $target ( #$targets ) {
$state->add_target( $target, $rules );
}
return $self;
}
sub allowed {
my ( $self, $from, $to ) = #_;
if ( not $self->has_state( $from ) ){
croak "NO source state $from in transition graph";
}
my $state = $self->get_state( $from );
return $state->allowed_to( $to );
}
This also has the cool perk of not requiring one particular code set to work on the sub-nodes, you can create seperate instances with their own behaviour just in case you want one source state to be treated differently.
$transition->add_state( 2, $some_other_class_wich_works_like_transitiongraphstate );
Hope this is helpful =).
There is nothing wrong with the second form. You are not going to be able to get around the fact that you must encode the state machine somewhere. In fact, I think having the entire machine encoded in one place like that is far easier to understand that something with too many layers of abstraction where you need to look in n different places to understand the flow of the machine.