Uploaded image for project: 'JBRULES'
  1. JBRULES
  2. JBRULES-3659

matches operator on variable cause intermittent thread fork and throws exception

    XMLWordPrintable

    Details

    • Steps to Reproduce:
      Hide

      The java code that does this multiple insertion and firing is like this:

      Main.java
      package drools;
      
      import org.drools.KnowledgeBase;
      import org.drools.KnowledgeBaseFactory;
      import org.drools.builder.KnowledgeBuilder;
      import org.drools.builder.KnowledgeBuilderFactory;
      import org.drools.builder.ResourceType;
      import org.drools.definition.KnowledgePackage;
      import org.drools.event.rule.DebugWorkingMemoryEventListener;
      import org.drools.io.ResourceFactory;
      import org.drools.runtime.StatefulKnowledgeSession;
      
      import java.util.Collection;
      
      public class Main {
      
          static StatefulKnowledgeSession ksession;
      
          public static void main(String[] argv) throws Exception {
              initRules();
      
              // fire once to run the no condition LHS
              ksession.fireAllRules();
      
              for (int i=0;i < 100; i++) {
              Person person = new Person();
              person.setName("Test");
              ksession.insert(person);
              ksession.fireAllRules();
              }
      
          }
      
          private static void initRules() {
              KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
      
      		// this will parse and compile in one step
      		kbuilder.add(ResourceFactory.newClassPathResource("main.drl", Main.class), ResourceType.DRL);
      
      		// Check the builder for errors
      		if (kbuilder.hasErrors()) {
      			System.out.println(kbuilder.getErrors().toString());
      			throw new RuntimeException("Unable to compile \"main.drl\".");
      		}
      
      		// get the compiled packages (which are serializable)
      		Collection<KnowledgePackage> pkgs = kbuilder
      				.getKnowledgePackages();
      
      		// add the packages to a knowledgebase (deploy the knowledge packages).
      	    KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
      		kbase.addKnowledgePackages(pkgs);
      
      		ksession = kbase.newStatefulKnowledgeSession();
      
      		ksession.addEventListener(new DebugWorkingMemoryEventListener());
          }
      
      }
      
      

      The Person is a simple POJO

      Person.java
      public class Person {
      
          private String name;
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      }
      

      The rule file that does the matching is like this:

      main.drl
      package drools;
      
      dialect "mvel"
      
      declare Stuff
      	regexp : String
      end
      
      rule "Test Regex"
      	salience 100
          when
          then
          	Stuff s = new Stuff("Test")
              System.out.println("Insert reg ex variable");
              insert (s);
      end
      
      rule "Test Equality"
      	salience 10
          when
          	Stuff( $regexp : regexp )
              Person( name matches $regexp )
              //Person( name matches "Test" )
          then
              System.out.println("Found name");
      end
      
      rule "Dump person"
          when
              $p : Person( )
          then
              retract ( $p )
      end
      
      Show
      The java code that does this multiple insertion and firing is like this: Main.java package drools; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseFactory; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderFactory; import org.drools.builder.ResourceType; import org.drools.definition.KnowledgePackage; import org.drools.event.rule.DebugWorkingMemoryEventListener; import org.drools.io.ResourceFactory; import org.drools.runtime.StatefulKnowledgeSession; import java.util.Collection; public class Main { static StatefulKnowledgeSession ksession; public static void main( String [] argv) throws Exception { initRules(); // fire once to run the no condition LHS ksession.fireAllRules(); for ( int i=0;i < 100; i++) { Person person = new Person(); person.setName( "Test" ); ksession.insert(person); ksession.fireAllRules(); } } private static void initRules() { KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); // this will parse and compile in one step kbuilder.add(ResourceFactory.newClassPathResource( "main.drl" , Main.class), ResourceType.DRL); // Check the builder for errors if (kbuilder.hasErrors()) { System .out.println(kbuilder.getErrors().toString()); throw new RuntimeException( "Unable to compile \" main.drl\ "." ); } // get the compiled packages (which are serializable) Collection<KnowledgePackage> pkgs = kbuilder .getKnowledgePackages(); // add the packages to a knowledgebase (deploy the knowledge packages). KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(pkgs); ksession = kbase.newStatefulKnowledgeSession(); ksession.addEventListener( new DebugWorkingMemoryEventListener()); } } The Person is a simple POJO Person.java public class Person { private String name; public String getName() { return name; } public void setName( String name) { this .name = name; } } The rule file that does the matching is like this: main.drl package drools; dialect "mvel" declare Stuff regexp : String end rule "Test Regex" salience 100 when then Stuff s = new Stuff( "Test" ) System .out.println( "Insert reg ex variable" ); insert (s); end rule "Test Equality" salience 10 when Stuff( $regexp : regexp ) Person( name matches $regexp ) //Person( name matches "Test" ) then System .out.println( "Found name" ); end rule "Dump person" when $p : Person( ) then retract ( $p ) end

      Description

      When an event is inserted and fired multiple times where the matches operator is used using a variable (instead of a constant string), a separate thread can be spawn and cause a null pointer exception.

      Exception in thread "Thread-0" java.lang.NullPointerException
      	at org.drools.rule.constraint.ConditionAnalyzer.analyzeSingleCondition(ConditionAnalyzer.java:113)
      	at org.drools.rule.constraint.ConditionAnalyzer.analyzeCondition(ConditionAnalyzer.java:99)
      	at org.drools.rule.constraint.ConditionAnalyzer.analyzeCondition(ConditionAnalyzer.java:70)
      	at org.drools.rule.constraint.MvelConditionEvaluator.getAnalyzedCondition(MvelConditionEvaluator.java:83)
      	at org.drools.rule.constraint.MvelConstraint.executeJitting(MvelConstraint.java:269)
      	at org.drools.rule.constraint.MvelConstraint.access$200(MvelConstraint.java:50)
      	at org.drools.rule.constraint.MvelConstraint$ConditionJitter.run(MvelConstraint.java:249)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
      	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
      	at java.lang.Thread.run(Unknown Source)
      

      This problem disappear when the regexp is a constant string instead of a variable. No new thread is spawned when using the constant string.

      The thread spawning was observed using a separate profiler tool.

      The exception usually happens in the middle of the console output. A search on null pointer exception will get you there.

        Attachments

          Activity

            People

            Assignee:
            mfusco Mario Fusco
            Reporter:
            azerith Andreas Ali (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: