10 Replies Latest reply on Aug 15, 2007 4:21 PM by gavin.king

    how to use PropertyChangeListener on entity beans for drools

    ellenzhao

      I want to use:

      StatefulSession ss = myRuleBase.newStatefulSession();
      ss.setGlobal("conversationBean", this);
      ...
      ss.insert(entity, true);
      ...
      


      The true flag means the obj I inserted into the ss rule session is a dynamic object, the stateful rule session is aware of the changes of the properties of the entity. But according to Drools manual section 1.6.4.5, I must write code like this in my entity beans:

      private final PropertyChangeSupport changes = new PropertyChangeSupport( this );
      ...
      public void addPropertyChangeListener(final PropertyChangeListener l) {
       this.changes.addPropertyChangeListener( l );
      }
      
      public void removePropertyChangeListener(final PropertyChangeListener l) {
       this.changes.removePropertyChangeListener( l );
      }
      ...
      
      public void setState(final String newState) {
       String oldState = this.state;
       this.state = newState;
       this.changes.firePropertyChange( "state",
       oldState,
       newState );
      }
      


      I have a feeling that frameworks like hibernate or seam or the ejb 3 container have already some property change listeners employed for entity beans....the property change listeners do already exist, how can I make Drools share the property change listeners? Thanks!


      Regards,
      Ellen

        • 1. Re: how to use PropertyChangeListener on entity beans for dr
          gavin.king

          I wish that were true, but unfortunately it's not the case.

          • 2. Re: how to use PropertyChangeListener on entity beans for dr
            ellenzhao

            sorry, I meant "...if the property change listeners do already exist, how can I ...." in my last post

            • 3. Re: how to use PropertyChangeListener on entity beans for dr
              ellenzhao

              just now I tried to modify the entity beans like the examples in drools manual, so far it works well and does not break anything in my application, fingers crossed, hope this really will not break the parts I have not tested yet ....

              • 4. Re: how to use PropertyChangeListener on entity beans for dr
                ellenzhao

                just had a thought, how about there is a global property change notifier for entity beans in container, at least in a conversation....EntityManager (this is database agenda) wants to monitor the property changes, rule base agenda wants to monitor the property changes, and for some other people, their BPM agenda wants to monitors property changes....a global property change notifier would be handy, each kind of service agendas only needs to register themselves....How's that feasible with Seam? Thanks!


                • 5. Re: how to use PropertyChangeListener on entity beans for dr
                  gavin.king

                  I've thought about it before, but I don't really see how it would work. Not without significant rearchitecture of both Hibernate and Drools.

                  • 6. annotation for Drools
                    ellenzhao

                    A few annotations for Drools might be handy. Currently there is a good candidates in my mind: @DynamicSlot

                    Once Seam detects there is any property setter in an entity class annotated with @DynamicSlot, it could automatically generate the boilerplate code like shown in the Drools manual. Or if not generate code, at least manipulate the bytecode....

                    • 7. Re: annotation for Drools
                      mark.proctor

                       

                      "ellenzhao" wrote:
                      A few annotations for Drools might be handy. Currently there is a good candidates in my mind: @DynamicSlot

                      Once Seam detects there is any property setter in an entity class annotated with @DynamicSlot, it could automatically generate the boilerplate code like shown in the Drools manual. Or if not generate code, at least manipulate the bytecode....



                      I looked at a weaving type framework for drools, some of the code is even still be in the codebase (although not used or finished).
                      http://anonsvn.labs.jboss.com/labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/JavaFact.java
                      http://anonsvn.labs.jboss.com/labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/JavaFactRegistryEntry.java
                      http://anonsvn.labs.jboss.com/labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/DelegateJavaFactHandler.java

                      The idea was that the microcontainer would have a configuration of multiple named rulebases and working memories and a settings file would specify which working memories would monitor (auto insert on creation and update on modifications) which facts. AOP would then weave into the object generating the correct notification code; using the jboss pojo cache approach to have tx.begin() and tx.end() any facts that are modified in that block are removed from any monitoring working memories using session.modifyRetract(); and then at the end when tx.end() is called we call session.modifyInsert(); on each modified object. In future releases if we know the changed fields, we can make engine re-evaluation more efficient, so we might be able to use that information too.

                      • 8. Re: how to use PropertyChangeListener on entity beans for dr
                        ellenzhao

                        okay, the dynamic drools property thing turns out not so wonderful. Say if an entity has 10 fields whose setter are plugged a property change listener, the propertyChangeListener will cause 10 evaluations in the Rete network, while if batch update -- to be concrete:

                        ...
                        StatefulSession ss = myRuleBase.newStatefulSession();
                        
                        ss.setGlobal("myManager", myManager),
                        ...
                        FactHandle fh1 = ss.insert(myEntity1);
                        FactHandle fh2 = ss.insert(myEntity2);
                        ..
                        
                        // here you modify your entities wildly,
                        // for example modify all 10+ or 20+ fields
                        
                        entityManager.flush();
                        ss.update(fh1, myEntity1);
                        ss.update(fh2, myEntity2);
                        ...
                        
                        ss.fireAllRules();
                        


                        only cause one evaluation to each entity in the Rete network. So this approach is much more recommended. StatefulSession's (rule session, please do not confuse with hibernate session) update(fh, obj) is much like entityManager's flush().

                        Maybe it is a good idea to tie entityManager's flush together with stateful rule session's update together.....

                        I was using the propertychangelistener approach because I happened to have 2 entities who both have only one field needing to be monitored in the stateful rule session. Sorry for the confusion/mislead. And big thanks to Mark Proctor for clarifying this issue to me.


                        Regards,
                        Ellen

                        • 9. Re: how to use PropertyChangeListener on entity beans for dr
                          ellenzhao

                          just read this:

                          http://markproctor.blogspot.com/2007/06/declarative-relational-programming.html

                          For some domain this can be very effective approach.

                          • 10. Re: how to use PropertyChangeListener on entity beans for dr
                            gavin.king

                            Email from Mark:


                            I chatted to the guy, on irc, he just didn't realise you can call
                            session.update( myObjHandle ) - and that the update( myObj ) call can
                            even be done via a hibernate save listener, so think he's all happy now.
                            No need to notify the engine each time a single property changes.

                            session.update( myObjectHandle ) actually works by using something
                            called "shadow facts". We proxy inserted objects and create a shallow
                            cache of each field value. When you call update it actually retracts
                            using the old cached field values.

                            You can turn shadow facts off, but then you cannot use session.update(
                            myObjectHandle) instead you have to call session.modifyRetract(
                            myObjectHandle) before the first setter is called, and
                            session.modifyInsert( myObjectHandle, myObject ) after the last setter
                            is applied. Turning shadow facts off improves performance about 10%,
                            depending on how many fields you have, and uses slightly more memory.

                            After we do 4.0, maybe we can look on how we can solve problems like
                            this, for better integration. PropertyChangeListeners are not very
                            efficient, we don't really want to notify the engine each time a field
                            changed. In MVEL we have the following syntax:
                            modify ( person ) { age+= 1, location = "london" }

                            I call this a block setter. The engine is notified before the first
                            setter and after the last setter - i.e. it basically auto calls
                            modifyRetract and modifyInsert for you.

                            Anyway I'd be interested to hear ideas you have on this. Two I can think
                            of are hooking into the hibernate save() method and some how hooking
                            into a transaction block. So that at the start of the transaction block
                            all used facts are retracted from the network, and re-insert at the end
                            of the network; or just simply calling update( objectHandle ) at the end
                            of the transaction block.

                            In later issues we will track the actual fields changed, in a
                            consequence using MVEL, this allows for more efficient network
                            re-evaluation. maybe using AOP (like jgroups) we can achieve something
                            similar with seam and hibernate - although have to be sure that the cost
                            of the AOP stuff, isn't higher than the full network evaluation.