| Summary: | Modify raises NPE when using "from" | ||
|---|---|---|---|
| Product: | [JBoss] JBoss Enterprise BRMS Platform 5 | Reporter: | nwallace <nwallace> |
| Component: | unspecified | Assignee: | Edson Tirelli <ed.tirelli> |
| Status: | CLOSED NEXTRELEASE | QA Contact: | |
| Severity: | unspecified | Docs Contact: | |
| Priority: | high | ||
| Version: | unspecified | ||
| Target Milestone: | --- | ||
| Target Release: | 5.0.1 | ||
| Hardware: | Unspecified | ||
| OS: | Unspecified | ||
| URL: | http://jira.jboss.org/jira/browse/BRMS-180 | ||
| Whiteboard: | |||
| Fixed In Version: | Doc Type: | Bug Fix | |
| Doc Text: | Story Points: | --- | |
| Clone Of: | Environment: | ||
| Last Closed: | 2009-09-01 12:28:52 UTC | Type: | Bug |
| Regression: | --- | Mount Type: | --- |
| Documentation: | --- | CRM: | |
| Verified Versions: | Category: | --- | |
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |
| Cloudforms Team: | --- | Target Upstream Version: | |
Link: Added: This issue is related to JBRULES-2085 Fix in place. For documenting this in the Release Notes, can you please confirm the following and fill in the missing information. Dot point explanations are fine: The CAUSE (what was actually broken) * CONSEQUENCES of the bug (how it impacts users.) * A null pointer exception occured when the keyword "from" was used in conjunction with the Modify command, The FIX (what was changed to eliminate this bug) and * RESULTS of the fix (what now happens for users.) * We are still awaiting the outstanding information for the Release Notes on this one. Please provide it as soon as possible. Thanks. The CAUSE (what was actually broken) * The use of "from" on a pattern causes the engine to create a temporary fact handle to assign the result of the from expression. Modify was using the temporary fact handle to modify the fact in the working memory. CONSEQUENCES of the bug (how it impacts users.) * Being temporary, that fact handle is not stored in the working memory and trying to modify a fact using the temporary fact handle was causing a null pointer exception. The FIX (what was changed to eliminate this bug) and * Modify construct was improved to properly deal with temporary fact handles, resolving the actual fact reference to the permanent fact handle. RESULTS of the fix (what now happens for users.) * No more Null Pointer Exceptions when using modify on a fact returned by "from". added to 5.0.CP01 Release Notes as resolved JBRULES-2085 Calling modify() on the fact returned when using from on a pattern would cause a null pointer exception. This was due to the fact handle in this situation not being stored in working memory because it was a temporary fact handle. The code was been updated to properly deal with temporary fact handles. |
Date of First Response: 2009-09-10 01:34:39 securitylevel_name: Public The attached file should generate everyting into a subdirectory ./movie and compile and execute. You'll have to modify the classpath, though. Regards -W # Shell this file to create subdir movie with *.java, Movie.drl, database.xml # # you'll have to modify the classpath setting - see below # mkdir movie || true cat <<'TheEnd' >movie/Main.java package movie; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.Collection; import javax.xml.bind.JAXBContext; import org.drools.KnowledgeBase; import org.drools.KnowledgeBaseFactory; import org.drools.builder.KnowledgeBuilder; import org.drools.builder.KnowledgeBuilderError; import org.drools.builder.KnowledgeBuilderFactory; import org.drools.builder.ResourceType; import org.drools.definition.KnowledgePackage; import org.drools.io.ResourceFactory; import org.drools.runtime.StatefulKnowledgeSession; import javax.xml.bind.Unmarshaller; public class Main { private StatefulKnowledgeSession session; public Main(){ } public void init() throws Exception { KnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase(); KnowledgeBuilder kBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); kBuilder.add( ResourceFactory.newFileResource( "movie/Movie.drl" ), ResourceType.DRL ); if( kBuilder.hasErrors() ){ for( KnowledgeBuilderError err: kBuilder.getErrors() ){ System.out.println( err.toString() ); } throw new IllegalStateException( "DRL errors" ); } kBase.addKnowledgePackages( kBuilder.getKnowledgePackages() ); File xml = new File( "database.xml" ); JAXBContext jc = JAXBContext.newInstance( Database.class ); Unmarshaller u = jc.createUnmarshaller(); InputStream inputStream = new FileInputStream( xml ); Database db = (Database)u.unmarshal( inputStream ); inputStream.close(); session = kBase.newStatefulKnowledgeSession(); for( Movie m: db.getMovie() ){ session.insert( m ); } for( Actor a: db.getActor() ){ session.insert( a ); } for( Role r: db.getRole() ){ session.insert( r ); } session.fireAllRules(); } public static void main( String[] args ) throws Exception { Main rf = new Main(); rf.init(); } } TheEnd cat <<'TheEnd' >movie/Role.java package movie; import javax.xml.bind.annotation.XmlAttribute; public class Role implements Item { private String actor; private String movie; public Role(){ } @XmlAttribute public String getActor() { return actor; } public void setActor(String actor) { this.actor = actor; } @XmlAttribute public String getMovie() { return movie; } public void setMovie(String movie) { this.movie = movie; } @Override public String toString(){ return actor + " plays in " + movie; } } TheEnd cat <<'TheEnd' >movie/Movie.java package movie; import java.util.HashSet; import java.util.Set; import javax.xml.bind.annotation.XmlAttribute; public class Movie implements Item { private String title; private Set<Actor> cast; public Movie(){ } @XmlAttribute public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Set<Actor> getCast(){ if( cast == null ) cast = new HashSet<Actor>(); return cast; } @Override public int hashCode(){ return title.hashCode(); } @Override public boolean equals( Object o ){ if( ! (o instanceof Movie ) ) return false; return this.title.equals( ((Movie)o).getTitle() ); } @Override public String toString(){ StringBuilder sb = new StringBuilder(); sb.append( title ).append( "\n" ); for( Actor a: getCast() ){ sb.append( " " ).append( a.getName() ).append( "\n" ); } return sb.toString(); } } TheEnd cat <<'TheEnd' >movie/Item.java package movie; /** * Marker interface for WMEs * @author Wolfgang Laun */ public interface Item { } TheEnd cat <<'TheEnd' >movie/Database.java package movie; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @XmlRootElement @XmlType(propOrder={"movie", "actor" , "role" }) public class Database { private List<Movie> movie; private List<Actor> actor; private List<Role> role; public Database(){ } @XmlElement public List<Movie> getMovie() { if( movie == null ) movie = new ArrayList<Movie>(); return movie; } @XmlElement public List<Actor> getActor() { if( actor == null ) actor = new ArrayList<Actor>(); return actor; } @XmlElement public List<Role> getRole() { if( role == null ) role = new ArrayList<Role>(); return role; } } TheEnd cat <<'TheEnd' >movie/Actor.java package movie; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlAttribute; public class Actor implements Item { private String name; private List<Movie> movies; public Actor(){ } @XmlAttribute public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Movie> getMovies(){ if( movies == null ) movies = new ArrayList<Movie>(); return movies; } @Override public String toString(){ StringBuilder sb = new StringBuilder(); sb.append( name ).append( "\n" ); for( Movie m: getMovies() ){ sb.append( " " ).append( m.getTitle() ).append( "\n" ); } return sb.toString(); } @Override public int hashCode(){ return name.hashCode(); } @Override public boolean equals( Object o ){ if( ! (o instanceof Actor ) ) return false; return this.name.equals( ((Actor)o).getName() ); } } TheEnd cat <<'TheEnd' >movie/Movie.drl package movie; /*** - List<?> as fact field type - Set<?> as fact field type - Match WMEs with elements from field with List<?> type: from - inline eval() for determining membership in Collection() - Write rules for a set of WME types using a "marker" interface. */ # # Fill the Movies' cast lists with data from Role. # rule fillCast salience 100 when $r : Role( $actor : actor, $movie : movie ) $a : Actor( name == $actor ) $m : Movie( title == $movie ) then modify( $m ){ getCast().add( $a ); } retract( $r ); end # # Fill the Actors' list of movies with data from a Movie's cast list # rule fillMovies salience 90 when $m : Movie( $cast : cast ) $a : Actor() from $cast then System.out.println( "movie " + $m.getTitle() + " actor " + $a.getName() ); modify( $a ){ getMovies().add( $m ); } end # # Find a movie where HB and LB are in together # rule findHBLB when $hb : Actor( name == "Humphrey Bogart" ) $lb : Actor( name == "Lauren Bacall" ) $m : Movie( $title : title, $cast : cast, eval( $cast.contains( $hb ) && $cast.contains( $lb ) ) ) then System.out.println( "HB & LB together in " + $title ); end # # Display any WME # rule showItem salience -100 when $i : Item() then System.out.println( $i.toString() ); end TheEnd cat <<'TheEnd' >database.xml <?xml version="1.0" encoding="UTF-8"?> <database> <movie title="Casablanca"/> <movie title="Key Largo"/> <movie title="To Have and Have Not"/> <movie title="The African Queen"/> <actor name="Humphrey Bogart"/> <actor name="Katherine Hepburn"/> <actor name="Ingrid Bergman"/> <actor name="Lauren Bacall"/> <role actor="Humphrey Bogart" movie="Casablanca"/> <role actor="Ingrid Bergman" movie="Casablanca"/> <role actor="Humphrey Bogart" movie="The African Queen"/> <role actor="Humphrey Bogart" movie="Key Largo"/> <role actor="Humphrey Bogart" movie="To Have and Have Not"/> <role actor="Lauren Bacall" movie="To Have and Have Not"/> <role actor="Lauren Bacall" movie="Key Largo"/> <role actor="Katherine Hepburn" movie="The African Queen"/> </database> TheEnd export CLASSPATH=.:/extra/Drools-5.0.1.SNAPSHOT/drools-core.jar:/extra/Drools-5.0.1.SNAPSHOT/drools-api.jar:/extra/Drools-5.0.1.SNAPSHOT/drools-compiler.jar:/extra/Drools-5.0.1.SNAPSHOT/drools-ant.jar:/extra/Drools-5.0.1.SNAPSHOT/antlr-runtime.jar:/usr/local/eclipse/plugins/org.eclipse.jdt.core_3.4.4.v_894_R34x.jar:/extra/Drools-5.0.0.CR1/bin/lib/mvel2-2.0.8pre1.jar javac movie/*.java java movie/Main cat <<'TheEnd' # # This is what I get: # movie Casablanca actor Ingrid Bergman Exception in thread "main" org.drools.runtime.rule.ConsequenceException: java.lang.NullPointerException at org.drools.runtime.rule.impl.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:23) at org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:943) at org.drools.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:885) at org.drools.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1086) at org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:682) at org.drools.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:649) at org.drools.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:183) at movie.Main.init(Main.java:65) at movie.Main.main(Main.java:70) Caused by: java.lang.NullPointerException at org.drools.base.DefaultKnowledgeHelper.modifyRetract(DefaultKnowledgeHelper.java:190) at movie.Rule_fillMovies_0.consequence(Rule_fillMovies_0.java:8) at movie.Rule_fillMovies_0ConsequenceInvoker.evaluate(Rule_fillMovies_0ConsequenceInvoker.java:28) at org.drools.common.DefaultAgenda.fireActivation(DefaultAgenda.java:934) ... 7 more TheEnd