[rules-users] NullPointerException when using Drools rule template

Wolfgang Laun wolfgang.laun at gmail.com
Thu Nov 11 03:56:14 EST 2010


[Note: I see that template parsing is rather wobbly. The JIRA has to
be fixed in
org.drools.template.parser.DefaultTemplateContainer, and I think there are other
"holes" in the parseTemplate method.]

Roger,

while my previous suggestion avoids the NPE, it may not be the
adequate solution for your situation. I see that you have several
rules which classify ContractRule w.r.t. season and hourType. These do
not rely on template parameters, and they would be better off in a
separate simple .drl file.

Now let's look at your reduced original template

template contract_rate
  rule "Summer on peak primary rate"
  when
    $r : ContractRule( season == "summer" && hourType == "onPeak" &&
type == "primary")
  then
    $r.setRate(@{summerOnPeakPrimaryRate});
  end
end template

>From the other parameter names I can imagine that you have similar
hand-written rules for all
other combinations of these three field values; templating is just
used to insert the rate values
programmatically rather than hand-coded. (I suppose good old
properties would solve this task
quite well!)

But templating may be used to save you the trouble of writing and
maintaining all the set-rate
rules themselves. (Just imagine of the Contractor comes up with the
notion of adding a rebate
for groups: You'll have to double your rules manually!)

Here's the template to achieve everything with a single rule:

template header
theSeason
theHour
theType
theRate

package resource
import resource.ContractRule
template contract_rate
rule "@{theSeason} @{theHour} @{theType} rate"    ### DO NOT INDENT
THIS LINE. ARRGH!
  when
    $r : ContractRule( season == "@{theSeason}" && hourType ==
"@{theHour}" && type == "@{theType}")
  then
    $r.setRate(@{theRate});
  end
end template

Now you'll have to use more than one parameter map - one for each such
combination. [[Aside: Adding
the "group" rebate can be done by
* adding the template parameter,
* adding the restriction to the template rule
* extending the rule name
* extend addParamMap
* write the additional addParamMap() calls ]]

Collection<Map<String,Object>> paramMaps = new ArrayList<Map<String,Object>>();

  private void addParamMap( String season, String hour, String type, int rate ){
     Map<String,Object> params = new HashMap<String,Object>();
     params.put( "theSeason", season );
     params.put( "theHour",   hour );
     params.put( "theType",   type );
     params.put( "theRate",   rate );
     paramMaps.add( params );
  }

    addParamMap( "summer", "onPeak",   "primary",   299 );
    addParamMap( "summer", "onPeak",   "secondary", 524 );
    addParamMap( "summer", "semiPeak", "primary",   176 );
    addParamMap( "summer", "semiPeak", "secondary", 305 );
    addParamMap( "summer", "offPeak",  "primary",   139 );
    addParamMap( "summer", "offPeak",  "secondary", 243 );
    addParamMap( "winter", "onPeak",   "primary",   249 );
    addParamMap( "winter", "onPeak",   "secondary", 438 );
    addParamMap( "winter", "semiPeak", "primary",   176 );
    addParamMap( "winter", "semiPeak", "secondary", 305 );
    addParamMap( "winter", "offPeak",  "primary",   139 );
    addParamMap( "winter", "offPeak",  "secondary", 243 );

    String drl = converter.compile(paramMaps, dis);

And here we go: This is the generated DRL text:

package resource
import resource.ContractRule

rule "winter offPeak secondary rate"
  when
    $r : ContractRule( season == "winter" && hourType == "offPeak" &&
type == "secondary")
  then
    $r.setRate(243);
  end

rule "winter offPeak primary rate"
  when
    $r : ContractRule( season == "winter" && hourType == "offPeak" &&
type == "primary")
  then
    $r.setRate(139);
  end

rule "winter semiPeak secondary rate"
  when
    $r : ContractRule( season == "winter" && hourType == "semiPeak" &&
type == "secondary")
  then
    $r.setRate(305);
  end

rule "winter semiPeak primary rate"
  when
    $r : ContractRule( season == "winter" && hourType == "semiPeak" &&
type == "primary")
  then
    $r.setRate(176);
  end

rule "winter onPeak secondary rate"
  when
    $r : ContractRule( season == "winter" && hourType == "onPeak" &&
type == "secondary")
  then
    $r.setRate(438);
  end

rule "winter onPeak primary rate"
  when
    $r : ContractRule( season == "winter" && hourType == "onPeak" &&
type == "primary")
  then
    $r.setRate(249);
  end

rule "summer offPeak secondary rate"
  when
    $r : ContractRule( season == "summer" && hourType == "offPeak" &&
type == "secondary")
  then
    $r.setRate(243);
  end

rule "summer offPeak primary rate"
  when
    $r : ContractRule( season == "summer" && hourType == "offPeak" &&
type == "primary")
  then
    $r.setRate(139);
  end

rule "summer semiPeak secondary rate"
  when
    $r : ContractRule( season == "summer" && hourType == "semiPeak" &&
type == "secondary")
  then
    $r.setRate(305);
  end

rule "summer semiPeak primary rate"
  when
    $r : ContractRule( season == "summer" && hourType == "semiPeak" &&
type == "primary")
  then
    $r.setRate(176);
  end

rule "summer onPeak secondary rate"
  when
    $r : ContractRule( season == "summer" && hourType == "onPeak" &&
type == "secondary")
  then
    $r.setRate(524);
  end

rule "summer onPeak primary rate"
  when
    $r : ContractRule( season == "summer" && hourType == "onPeak" &&
type == "primary")
  then
    $r.setRate(299);
  end

-W

2010/11/10 Roger Smith <rogersmith1711 at gmail.com>:
> Wolfgang -
> Thank you!!
>
> On Wed, Nov 10, 2010 at 11:07 AM, Wolfgang Laun <wolfgang.laun at gmail.com>
> wrote:
>>
>> If you move the
>>  template contract_rate
>> up in front of the first rule "holiday july 4th" the NPE is gone. I
>> haven't been able to validate the (presumably) generated rule set, but
>> you should be able to do that now.
>>
>> Nevertheless, this warrants a JIRA, which I'll create forthwith. Also,
>> the docs should indicate what is permitted up front, preceding the
>> "template" statement.
>>
>> -W
>>
>>
>> 2010/11/10 Roger Smith <rogersmith1711 at gmail.com>:
>> > Wolfgang,
>> >
>> > I have enclosed the template. For debugging purpose, I have removed all
>> > but
>> > one rule.
>> >
>> > Thanks,
>> >
>> > Roger
>> >
>> > - O -
>> >
>> > template header
>> > summerOnPeakPrimaryRate
>> > summerOnPeakSecondaryRate
>> > summerSemiPeakPrimaryRate
>> > summerSemiPeakSecondaryRate
>> > summerOffPeakPrimaryRate
>> > summerOffPeakSecondaryRate
>> > winterOnPeakPrimaryRate
>> > winterOnPeakSecondaryRate
>> > winterSemiPeakPrimaryRate
>> > winterSemiPeakSecondaryRate
>> > winterOffPeakPrimaryRate
>> > winterOffPeakSecondaryRate
>> >
>> > package tradex.contract.sde
>> >
>> > import tradex.process.ruler.server.ContractRule
>> >
>> > rule "holiday july 4th"
>> > when
>> >   $r : ContractRule( year == 2010 && month == 7 && day == 4 && holiday
>> > ==
>> > false)
>> > then
>> >   modify($r){
>> >     setHoliday(true)
>> >   }
>> > end
>> >
>> > rule "holiday xmas"
>> > when
>> >   $r : ContractRule( year == 2010 && month == 12 && day == 25 && holiday
>> > ==
>> > false)
>> > then
>> >   modify($r){
>> >     setHoliday(true)
>> >   }
>> > end
>> >
>> > rule "Season summer"
>> > when
>> >   $r : ContractRule( dayOfYear >= 121 && dayOfYear <= 273 && season ==
>> > "undefined")
>> > then
>> >   modify($r){
>> >     setSeason("summer")
>> >   }
>> > end
>> >
>> > rule "Season winter"
>> > when
>> >   $r : ContractRule( (dayOfYear >= 274 || dayOfYear <= 120) && season ==
>> > "undefined")
>> > then
>> >   modify($r){
>> >     setSeason("winter")
>> >   }
>> > end
>> >
>> >
>> > rule "On peak hour"
>> > when
>> >   $r : ContractRule( holiday == false && dayOfWeek >= 1 && dayOfWeek <=
>> > 6
>> > && hourOfDay >= 1400 && hourOfDay <= 2000 &&
>> >   hourType == "undefined")
>> > then
>> >   modify($r){
>> >     setHourType("onPeak")
>> >   }
>> >
>> > end
>> >
>> > rule "Semi peak hour"
>> > when
>> >   $r : ContractRule( holiday == false && dayOfWeek >= 1 && dayOfWeek <=
>> > 6
>> > && (hourOfDay >= 600 && hourOfDay < 1400 ||
>> >   hourOfDay > 2000 && hourOfDay <= 2200) && hourType == "undefined")
>> > then
>> >   modify($r){
>> >     setHourType("semiPeak")
>> >   }
>> > end
>> >
>> > rule "Off peak hour"
>> > when
>> >   $r : ContractRule( (holiday == true ||  dayOfWeek == 7  || hourOfDay <
>> > 600
>> > || hourOfDay > 2200) && hourType == "undefined" )
>> > then
>> >   modify($r){
>> >     setHourType("offPeak")
>> >   }
>> > end
>> >
>> > template contract_rate
>> >   rule "Summer on peak primary rate"
>> >   when
>> >     $r : ContractRule( season == "summer" && hourType == "onPeak" &&
>> > type ==
>> > "primary")
>> >   then
>> >     $r.setRate(@{summerOnPeakPrimaryRate});
>> >   end
>> > end template
>> >
>> >
>> >
>> >
>> > 2010/11/9 Wolfgang Laun <wolfgang.laun at gmail.com>
>> >>
>> >> Seeing the template .drl would help to resolve this. Are all
>> >> @{parameter}s
>> >> declared in the template header?
>> >> -W
>> >>
>> >> 2010/11/9 Roger Smith <rogersmith1711 at gmail.com>
>> >>>
>> >>>
>> >>> All -
>> >>>
>> >>> I tried out Drools rule template with a with a proptotype app. Drools
>> >>> is
>> >>> throwing NullPointerException as below. I would much appreciate if
>> >>> someone
>> >>> on this list can help.
>> >>> java.lang.NullPointerException
>> >>>     at
>> >>>
>> >>> org.drools.template.parser.DefaultTemplateColumn.createCellCondition(DefaultTemplateColumn.java:68)
>> >>>     at
>> >>>
>> >>> org.drools.template.parser.DefaultTemplateColumn.addCondition(DefaultTemplateColumn.java:91)
>> >>>     at
>> >>>
>> >>> org.drools.template.parser.DefaultTemplateRuleBase.createColumnConditions(DefaultTemplateRuleBase.java:105)
>> >>>     at
>> >>>
>> >>> org.drools.template.parser.DefaultTemplateRuleBase.createTemplateRule(DefaultTemplateRuleBase.java:98)
>> >>>     at
>> >>>
>> >>> org.drools.template.parser.DefaultTemplateRuleBase.getDTRules(DefaultTemplateRuleBase.java:85)
>> >>>     at
>> >>>
>> >>> org.drools.template.parser.DefaultTemplateRuleBase.<init>(DefaultTemplateRuleBase.java:64)
>> >>>     at
>> >>>
>> >>> org.drools.template.parser.TemplateDataListener.<init>(TemplateDataListener.java:76)
>> >>>     at
>> >>>
>> >>> org.drools.template.parser.TemplateDataListener.<init>(TemplateDataListener.java:52)
>> >>>     at
>> >>>
>> >>> org.drools.template.ObjectDataCompiler.compile(ObjectDataCompiler.java:44)
>> >>>
>> >>>
>> >>> Here is my code
>> >>>
>> >>>         KnowledgeBuilder kBuilder =
>> >>> KnowledgeBuilderFactory.newKnowledgeBuilder();
>> >>>         ObjectDataCompiler converter = new ObjectDataCompiler();
>> >>>         InputStream dis = new FileInputStream( new File(
>> >>> "/home/pranab/Projects/gridx/ct11_1.drl" ) );
>> >>>         if (null == dis){
>> >>>           System.out.println("null rule template stream");
>> >>>           return;
>> >>>         }
>> >>>
>> >>>         Collection<Map<String,Object>> paramMaps = new
>> >>> ArrayList<Map<String,Object>>();
>> >>>
>> >>>         Map<String,Object> params = new HashMap<String,Object>();
>> >>>
>> >>>         params.put("summerOnPeakPrimaryRate", new Integer(299));
>> >>>         params.put("summerOnPeakSecondaryRate", new Integer(524));
>> >>>         params.put("summerSemiPeakPrimaryRate", new Integer(176));
>> >>>         params.put("summerSemiPeakSecondaryRate", new Integer(305));
>> >>>         params.put("summerOffPeakPrimaryRate", new Integer(139));
>> >>>         params.put("summerOffPeakSecondaryRate", new Integer(243));
>> >>>         params.put("winterOnPeakPrimaryRate", new Integer(249));
>> >>>         params.put("winterOnPeakSecondaryRate", new Integer(438));
>> >>>         params.put("winterSemiPeakPrimaryRate", new Integer(176));
>> >>>         params.put("winterSemiPeakSecondaryRate", new Integer(305));
>> >>>         params.put("winterOffPeakPrimaryRate", new Integer(139));
>> >>>         params.put("winterOffPeakSecondaryRate", new Integer(243));
>> >>>         paramMaps.add(params);
>> >>>
>> >>>         String drl = converter.compile(paramMaps, dis);
>> >>>         Reader rdr = new StringReader( drl );
>> >>>         kBuilder.add( ResourceFactory.newReaderResource(rdr),
>> >>> ResourceType.DRL);
>> >>>
>> >>>
>> >>> The line in blue is throwing the exception. This code is very similar
>> >>> to
>> >>> the example code in Drools Expert guide.
>> >>>
>> >>> Best,
>> >>>
>> >>> Roger
>> >>>
>> >>> _______________________________________________
>> >>> rules-users mailing list
>> >>> rules-users at lists.jboss.org
>> >>> https://lists.jboss.org/mailman/listinfo/rules-users
>> >>>
>> >>
>> >>
>> >> _______________________________________________
>> >> rules-users mailing list
>> >> rules-users at lists.jboss.org
>> >> https://lists.jboss.org/mailman/listinfo/rules-users
>> >>
>> >
>> >
>> > _______________________________________________
>> > rules-users mailing list
>> > rules-users at lists.jboss.org
>> > https://lists.jboss.org/mailman/listinfo/rules-users
>> >
>> >
>>
>> _______________________________________________
>> rules-users mailing list
>> rules-users at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/rules-users
>
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>




More information about the rules-users mailing list