1

Since I'm working with Scala immutable objects within Drools, in order to update a fact I would need to create a new object to replace it. I've written a Scala method for the rule to call which returns just such an object.

My query is, what's the syntax for defining a new Scala case class object in the "then" section of a Drools rule? I've tried syntax similar to the following which I saw somewhere but it doesn't seem to be doing the trick either...(even for standard types like Strings)

then
    MyObject t = returnNewMyObject($a, $b)

Support and documentation for Drools + Scala seems to be rather limited at the moment. Any ideas?

(FYI I've read the following question and it's not the same query...my object is not a global: Drools Expert output object in Scala)

DRL File below:

package resources

import function drools.RuleFunctions.*
import order.Cart
import order.CartLine
import generic.Amount

import scala.*
import scala.Option
import org.kie.api.runtime.KieRuntime
import java.math.BigDecimal


    dialect  "mvel"


    rule "Eval Cart Line"  
        agenda-group "init"
        auto-focus true
        dialect  "mvel"
        lock-on-active true
        salience 1000
        when
             $cart: Cart($line: lines(), amount == null) //If Cart found with lines, but with no cart amount set
             $o : CartLine($id : ref, $qty: quantity) from $line
        then
            Cart $newB = updateLineAmount($cart, $id, $qty, kcontext.getKieRuntime())
            update(kcontext.getKieRuntime().getFactHandle($cart),$newB) 
    end

    rule "Product 20% Discount"
        agenda-group "LineDiscount"
        auto-focus true
        dialect  "mvel"
        lock-on-active true
        salience 900
        when
            $cart: Cart($line : lines, amount == null)
            $o : CartLine(ref == "1234", amount != null ) from $line
        then
            Cart $newB = addLineDiscount($cart, $o, 20.0, kcontext.KieRuntime())
            update(kcontext.getKieRuntime().getFactHandle($cart), $newB)
        end

Update

object RuleFunctions {

  def updateLineAmount(cart: Cart, id: String, qty: Int, krt: KieRuntime): Cart= {...}

  def addLineDiscount(cart: Cart, bLine : CartLine, discPerc: Double, krt: KieRuntime): Cart= {...}
}
Community
  • 1
  • 1
GroomedGorilla
  • 920
  • 2
  • 10
  • 30
  • If MyObject is defined as a case class, and your returnNewMyObject returns an instance of it, then I don't see the issue. Please clarify... –  Feb 04 '15 at 14:46
  • That's my thoughts exactly...but my IDE (IntelliJ) gives me the following error when I try anything of the sort: "JAVA_STATEMENT, '[', insert, insertLogical, modify, retract or update expected, got 'MyObject'". Could be an IDE issue? The Drools plugin for IntelliJ doesn't have the best support...other than reading the .drl files, my experience with it hasn't been very positive so far. – GroomedGorilla Feb 04 '15 at 14:59
  • Can you write some Java code that calls `MyObject t = returnNewMyObject($a, $b)`? Try with a simple Java wrapper class that has a single static Java method returning MyObject; import that and call that on the RHS. – laune Feb 04 '15 at 15:26
  • where is the code where you are attempting to create the new case class object? –  Feb 04 '15 at 15:36
  • Try not storing the Cart object, simply pass it in the call: `update(kcontext.getKieRuntime().getFactHandle($cart), addLineDiscount($cart, $o, 20.0, kcontext.KieRuntime()) )` – laune Feb 04 '15 at 15:40
  • Also, can you ignore IDE errors and call the DRL compiler no matter what? – laune Feb 04 '15 at 15:41
  • @I.K. The updateLineAmount and addLineDiscount each create a new case class object and return it. @laune That's actually how I first started trying to pass the call but had no luck there. I am actually ignoring IDE errors and running the project directly through SBT console. The errors I'm getting are mostly of this sort: `Unable to Analyse Expression Cart $newB = addLineDiscount($cart, $o, 20.0, kcontext.KieRuntime()); drools.update(kcontext.getKieRuntime().getFactHandle($basket), $newB);: [Error unable to resolve method using strict-mode: org.drools.core.spi.KnowledgeHelper.KieRuntime()]` – GroomedGorilla Feb 04 '15 at 15:48
  • 1
    Yes, it's clear in the error message. The compiler does not know anything about addLineDiscount. You have to give it a handle/reference to an object which has that method. Have you tried that? –  Feb 04 '15 at 15:59
  • 1
    You should turn off strict mode. – laune Feb 04 '15 at 16:05
  • @I.K. I'm passing in a reference in the imports part: `import function drools.RuleFunctions.*` Do I need to pass in a global variable as an instance of this object to actually use it? @laune ...any idea how to set this in the 6.1 build? I got as far as .setProperty for a KieBaseConfiguration but can't find what the property name is... – GroomedGorilla Feb 04 '15 at 16:45
  • `KieBaseOptionsConfiguration kbConf =...; kbConf.setProperty("drools.dialect.mvel.strict", "false");` – laune Feb 04 '15 at 17:03
  • Yep, got that ;) I just don't know what the property name (i.e. the first string) should be. Any ideas? Can't find any documentation on this property for the 6.1 build – GroomedGorilla Feb 04 '15 at 17:04
  • what if you use a Scala class instead of a Scala object? I'm thinking that drools can't handle Scala object types. –  Feb 04 '15 at 17:32
  • 1
    Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/70248/discussion-on-question-by-groomedgorilla-creating-new-scala-object-in-drools-rig). – Taryn Feb 04 '15 at 17:39
  • 1
    I'm not sure Drools can play with Scala. The thing is that the methods in Scala Object types are implicitly static; that's the whole point of putting them there. In Java you have to explicitly declare that the method is static. I'm thinking that when the Scala Object types are compiled down to byte codes, it is not the same as an equivalent Java class with static methods. More specifically, I am thinking that Drools can't pick up the fact there are static methods to import from a Scala Object type. –  Feb 04 '15 at 19:24

1 Answers1

1

Importing methods from Scala Object types can be problematic in Drools. The simple reason is that static methods do not exist in Scala in contrast with Java. This is because Scala takes a more stricter interpretation of what it means to be a pure object orientated language.

What this means is that whenever you try to use the Drools import function syntax, it cannot find any static methods to import. As a result, the Drools compiler complains about any references to methods contained in Scala singleton object types.

A work around for this is to write any classes which are going to be used in your DRLs in Java where you can explicitly define static methods. The Scala compiler will happily compile these along with your Scala classes.

  • 1
    @placplacboom I.K. and GroomedGorilla, I have it from Mark Proctor himself that the Drools team hasn't verified Scala in combination with Drools. There's a plan to do that after the next minor release (6.1). There was no statement that it should work as a matter of course, and there hasn't been any other reaction on that Drools list. You know, or can check, what has been discussed here on SO. – laune Feb 05 '15 at 04:26