During OptaPlanner solving phrase, I wish to update a global variable. The changes of global variable will modify my next rules validation.
Result.java
package com.domain;
public static boolean status;
...
...
Sample.drl
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder;
import com.domain.Result;
global HardSoftScoreHolder scoreHolder;
rule "Sample Rule"
when
$PlanningEntity:PlanningEntity()
then
somelogic($PlanningEntity);
if(Result.status){
scoreHolder.addHardConstraintMatch(kcontext, -500);
}
end
function void somelogic(PlanningEntity planningEntity){
if(condition 1...){
Result.status = true;
}else if(condition 2...){
Result.status = false;
}else{
//Do Nothing
}
}
My Question:
How can I declare the static global variable per solving session. (To avoid multiple users doing the OptaPlanner solver at the same timing.)
Currently you can't reliably use a global variable because OptaPlanner might spawn multiple drools sessions (needed for future features such as multi-threaded solving, population based heuristics, ...).
The workaround is simple: simply add a singleton problem fact and use that. See the *Parametrization classes in the examples.
Related
I am using Drools version 6.5.0.Final and I have a simple rule like:
rule "Test Rule"
when
$obj : MyObject(testValue == null || testValue != "NEW")
then
$obj.testValue = "NEW";
update($obj);
end
So I also implemented a RuleRuntimeEventListener class and it gets invoked when this rule is executed. The problem is the passed in ObjectUpdatedEvent instance's getObject() and getOldObject() calls return the same exact object - which is the object after the update. So for this the getOldObject() call returns an object that has a value of "NEW" for the testValue property. I am expecting getOldObject to return me the value of testValue that isn't "NEW" which is after it was changed by the rule.
This seems like a bug to me and was wondering if anybody had any similar issues with this or if there is any workaround? I want to be notified when any property of an object is changed by a rule and what the old and new values were.
I see that there is support for using the java bean's PropertyChangeListener, but that looks like I have to create the fact objects with a addPropertyChangeListener and removePropertyChangeListener methods and also in all my fact's setter methods I have to use PropertyChangeSupport and fire a property change event via firePropertyChange method. I really don't want to have to do that.
Thanks
This seems to be a bug in Drools, the issue is also present in 7.16.0.FINAL. By doing the following
System.out.println(getOldObject() == getObject());
You will get an output of "true" indicating that both objects are of the same reference.
I just raised it as a bug on the Drools site
https://issues.jboss.org/browse/DROOLS-4305
public class Differ implements AgendaEventListener {
private List<Object> oldFacts;
public void beforeMatchFired(BeforeMatchFiredEvent event){
List<Object> facts = event.getMatch().getObjects();
// copy (!) facts into oldFacts
}
public void afterMatchFired(AfterMatchFiredEvent event){
List<Object> facts = event.getMatch().getObjects();
// compare facts with oldFacts
}
//...
}
You may want to be more selective in copying and comparing. Also, a generic way of comparing using the stringified object contents might be considered.
BeforeMatchFiredEvent
I have two Facts named OptionalCover and OptionalPremiumComponent and OptionalCover has a reference of OptionalPremiumComponent in it. So this is what I'm inserting into working memory.
private static OptionalCover getOptionalCover(Double sumAssured, Double premiumRate) {
OptionalPremiumComponent premiumComponent = new OptionalPremiumComponent();
premiumComponent.setSumAssured(sumAssured);
premiumComponent.setPremiumRate(premiumRate);
OptionalCover optionalCover = new OptionalCover();
optionalCover.setPremiumComponent(premiumComponent);
return optionalCover;
}
kieSession.insert(getOptionalCover(1000000.0, 0.02));
I have created the following rule in drools
import java.lang.Number;
rule "OptionalCoverCalculation"
dialect "java"
when
opc : OptionalPremiumComponent( sumAssured > 1I && sumAssured != null && premiumRate != null && premiumRate > 0.0 )
then
opc.setPremium( opc.getSumAssured() * 0.001 * opc.getPremiumRate() );
System.out.println("Here");
end
The problem is, the above rule is not being fired when I insert the parent object. Do I have to do anything else to enable this behaviour? Is it supported?
Thank you.
The Drools engine has no way of telling that your Cover contains a Component. (Well, it has, as it might use reflection - but where should it stop?)
So, you'll have to insert the OptionalPremiumComponent as well.
To reduce the amount of clutter in your code you might write a sorts of clever methods so that you can insert Cover and Component with a single call.
For instance, if you have many similar "contains" relationships and if you want to reason freely, you might implement s.th. like
interface FactContainer {
List<Object> factChildren(); -- return all contained fact objects
-- OR --
void insertAll( KieSession ks );
}
where factChildren would return a List with the premiumComponent or an empty List, or, alternatively, one method insertAll that handles everything internally.
I am completely new to Drools and just exploring. So far I had been using a single rule and withing which we use if conditions just like java.
Now I had to use complex rules where I need to use multiple if and else chain but to end it when one in the series of conditions satisfies.
I call the drools from the Apache Camel. The rules should reply back to Camel.
Now How do I do to break the chain of rules and then send response back to the caller which is Camel code when one of if and else condition fails.
1.Can I use multiple end statements to respond back?
2.I can use functions and I know is to write functions in java and import them.
3.Is there any possibility to create functions in Drools and use just like in java?
I am not using the Drools in the way it should be used but so far the rules had not been so complex as the one we are using them now . Any help is is useful for me.
Here is an example which I would like to use please suggest if the below would work or some other alternative like the below.
rule "my rule"
when
#some condition
then
if(){
end
}else if(){
#do something
}
if(){
#do some other logic
}
end
Sample after My second comment
When
object:SomeObject(); // This helps for my camel code to trigger this rule and this rule only
then
if(){
}
else if()
{
return;
}else if() {
}
if(){
}else if(){
return;
}
if(){
}
end
I don't know what you mean by "breaking a chain of rules". Evaluating rules ends all by iteself, when there aren't any more rule activations to be executed,
Answers to 1. - 3.:
No. - There is no such thing I can associate with the term "respond back", but there aren't "multiple end statements [for one rule]".
Yes, you can use static Java function: import the class, call it, as in Java.
Yes. this is explained in the Drools manual, in a section with the title "Function". The example is from the manual:
function String hello(String name) {
return "Hello "+name+"!";
}
Comment on the rule added later to the question
You cannot use end between then and the actual end of the rule. If you want to terminate the consequence part of a rule, use Java's return statement (without an expression, of course).
Reconsider using complex conditional statements in the consequence. Logic decisions should be expressed in the condition parts of rules.
Much later Workaround due to possible Guvnor bug - does not accept return;
boolean skip = false;
if(){
} else
if() {
skip = true; // return;
} else
if() {
}
if( ! skip ){
if(){
} else
if(){
skip = true; // return;
}
}
if( ! skip ){
if (){
}
}
end
I need a special keyword in my code to be replaced by a consequence of symbols before the build.
For example, I want hello to be replaced by Debug.Log("Hello");
According to this, MonoDevelop didn't have this feature in 2006. Has anything changed?
If no, are there any plugins/external tools implementing it?
I don't think that switching to another IDE will be helpful unless it can use code completion for unity3d.
Please, don't answer that macro definitions are evil.
Update:
I understood that my example was too abstract. In fact, I want to replace read("name"); with
var name;
name=gameObject.Find("name");
if(!name)
return;
name=name.param;
1)Every script should have all needed variables declared + a variable called "self".
2)They should be public.
3)
public static function set_var(target,name:String,value)
{
var fi=typeof(target).GetField(name);
fi.SetValue(target,value);
}
public static function read(name:String,target):String
{
set_var(target,"self",target);
return "var rtmp=self.gameObject.GetComponent(\""+name+"\");"+"if(!rtmp)return;"+name+"=rtmp.param;";
}
4)eval(read("name",this));
5)As far as I know, it wouldn't work in unity C#
6)Probably, set_var can be replaced by assignment
Far better solution:
var component_names = ["hello","thing","foo"];
var component;
for(var name:String in component_names)
{
component = gameObject.GetComponent(name);
if(!component)
return;
set_var(this,name,component.param);
}
(Requires set_var() from the first one)
I got following situation
private volatile bool _inProgress = false;
public void DoSomethingStart()
{
if(_inProgress == false)
{
foo.BeginInvoke(null, null); // DoSomething
_inProgress = true;
}
}
[CatchAllExceptionsFromHere]
private void DoSomething()
{ }
The aspects works so far. All exceptions are handeled from CatchAllExceptionsFromHere. But i want to set "_inProgress = false" in the finally clause of the aspect - so if DoSomething has finished "_inProgress" should be set to false. Since Attributes cant take any object - is there a workaround?
Thanks michael
Aspects can take values on the declaration to set property values or just like a constructor. What you want is an OnMethodBoundaryAspect and in the OnExit method (which fires even if an error has occured, so it's just like a finally) you want to set the value of _inProgress.
However, the aspect needs to be an instance aspect and you'll need to either import the _inProgress member or just introduce it so that the aspect has access to it. It depends on if your class needs access to it. If it does the have the aspect import the member. Read up on how to do these things with these links
Aspect lifetime & scope part 1
Aspect lifetime & scope part 2
Introducing members part 1
Introducing members part 2