8 Replies Latest reply on Nov 29, 2013 10:12 AM by jblinick

    Listen to @Observes only when started in a mvp presenter

    marius.gerwinn

      Hi,

       

      a while ago errai CDI events where updated so that they can be used on client side only (adding removing some bugs & adding @LocalEvent for @Portable annotated classes)

      Since then we make a lot of use of them and basicly replace the standard EventBus provided by gwt.

       

      The only thing that is left is the possibility to unsubscribe from an observe event. This is especially needed when using in the context of MVP in a presenter.

      -->We only want to receive @Observe events if the presenter is currently started. This is our current implementation:

       

      package com.google.gwt.activity.shared.Activity;
      
      public interface MyActivity extends Activity{
      
           public boolean isStarted();
      }
      
      public class MyPresenter extends MyActivity{
      
            //will be called when MessageEvent happens
           void onMessageReceiveEvent(@Observes MessageEvent event){
                if(isStarted())
                     //DO something
           }
      }
      

       

       

      It would be nice if we can get rid of that "isStarted" check and only receive events if the presenter is started.

      I assume we can do something like this with errai by adding a qualifier:

      public class MyPresenter extends MyActivity{
      
      
            //will be called MessageEvent is fired & presenter is
      
           void onMessageReceiveEvent(@Observes @IsStarted MessageEvent event){
            
                     //DO something
           }
      }
      

       

      Can you give me a hint were I can get started implementing this?

       

      This post is probably related to: Is it possible to unsubscribe an @Observes annotated methode?

        • 1. Re: Listen to @Observes only when started in a mvp presenter
          csa

          Hi Marius,

           

          The only way you can currently unsubscribe from @Observes is by destroying the bean instance (as Mike described in the post you linked to). I am wondering though, couldn't that be the solution to your problem? Basically, you'd look up (create) a new instance of the presenter when it's "started" (instead of setting the boolean flag) and you destroy it when you no longer need it.

           

          CDI event qualifiers don't seem to be the right solution there because they are not designed to make event routing decisions based on observer state at run time. Their purpose is to be able to differentiate between different events of the same type.

           

          Cheers,

          Christian

          1 of 1 people found this helpful
          • 2. Re: Listen to @Observes only when started in a mvp presenter
            mbarkley

            Hi Marius,

             

            For the sake of brainstorming, here's an idea I have about how what I will call "Conditional Event Observation" that you are describing could work.

             

            We could have a new annotation which marks a method returning a boolean in the sending or receiving class like so. I'll illustrate my idea with a receiving example.

             

            First we could create a new annotation Condition, that takes a qualifier. This annotation would be placed on a method returning a boolean in a class with an Observes method like so:

             

            public interface Receiver extends {
             @Condition(MyConditionQualifier.class)
             public boolean conditionLogic() { return true; }
            
              public void businessLogic(@Observes @MyConditionQualifier SomeEventType) {
               //...
              }
            }
            

             

            Now suppose another class fires a @Default Event<SomeEventType>. This is what would happen:

            1. The CDI container finds each Receiver instance.
            2. For each Receiver instance, the container invokes conditionLogic.
            3. For each instance, if conditionLogic returned true, the container will pass a copy of the fired event with the @MyConditionQualifier (and probably without @Default).

             

            A few things that could follow from this approach:

            • A similar concept could be applied to sending an event (i.e. a qualifier is added based on a condition in the sending bean).
            • You could have multiple conditions per @Observes method just by using several qualfiers.

             

            I'd love to get feedback on this. Does this seem like it would fit your usage, Marius?

            1 of 1 people found this helpful
            • 3. Re: Listen to @Observes only when started in a mvp presenter
              mbarkley

              To follow up, there are some drawbacks to this approach I didn't think of earlier:

              • It significantly changes the semantics of qualifiers.
              • It would introduce different code between the client and server.
              • It adds an extra complexity to the routing logic of events, which is perhaps not ideal.

               

              Marius, would it not be possible to make your presenter @Dependent scoped and simply destroy it while a presentation isn't being used? If there's a reason why that doesn't work for you I would be interested in hearing about it.

              • 4. Re: Listen to @Observes only when started in a mvp presenter
                jblinick

                FWIW I agree with Christian.  I don't think straying too far from the CDI spec is a good idea.  For this particular requirement, it seems pretty easy to achieve the desired functionality without adding anything to the framework.  You could just create a CdiObserver for the presenter, and create and destroy it as needed.

                • 5. Re: Listen to @Observes only when started in a mvp presenter
                  jblinick

                  Marius,

                   

                  Just as a word of caution, when we first discoved Errai CDI, we were also tempted to go a little CDI crazy.  I would strongly consider looking at your use of CDI events, and perhaps reconsider bringin in Errai RPC to handle more traditional communication.  CDI events are great, but trying to bend the functionality to do everything is probably not the best idea.  Just my two cents...

                  • 6. Re: Listen to @Observes only when started in a mvp presenter
                    marius.gerwinn

                    First of all thank you very much for all that helpful input. I really appreciate that!

                     

                    As I do understand so far the requested extension to cdi would be somehow possible but somehow mess up general idea of cdi and can make things complicated.

                    I agree with that.

                     

                    Regarding the proposed solution from mike, christian and max:

                    Marius, would it not be possible to make your presenter @Dependent scoped and simply destroy it while a presentation isn't being used? If there's a reason why that doesn't work for you I would be interested in hearing about it.

                    Unfortunately this is not so easy in our case with MVP. Let me explain:

                    We have a big application with a lot of presenters in there. To speed up navigation (user experience) we do some prefetching and precreating of instances wherever we can.

                    This works pretty well since we create a presenter (the linked view and some more subpresenters) when the browser is idle. When the actually navigates to a view we call our start method and only have to do

                    the really necessary current context specific stuff.

                    We furthermore reuse a lot of views/presenters and do not fully recreate them.

                    For that reasons we are currently dependent on our presenter logic with start & stop.

                     

                    But i think with your hints came of with a good solution for that specific problem:

                    I externalised all @Observes annotated methods to some inner static class. So this class is a CDIObserver class.

                    When i start my presenter i do create an instance of that cdi observer using the bean manager.

                    On stop i call destroy on that CDIObserver instance.

                     

                    public class MyConcretePresenter extends MyPresenter{
                    
                        @Inject
                        AsyncBeanManager bm;
                       
                        MyCDIObserver myCDIObserver;
                       
                       
                        @Dependent
                        public static class MyCDIObserver extends CDIObserver<MyConcretePresenter> {
                           
                            void onSomeUpdate(@Observes SomeUpdateEvent event){
                                //DO something
                                presenter.someVariable++;
                                presenter.doFoo();
                            }
                        }
                       
                        void onStart(){
                            bm.lookupBeans(MyCDIObserver.class).getInstance(new CreationalCallback<MyCDIObserver>(){
                               
                                @Override
                                public void callback(MyCDIObserver beanInstance) {
                                    myCDIObserver= beanInstance;
                                    myCDIObserver.setPresenter(MyConcretePresenter.this);
                                   
                                    //now listening to cdi events
                                }
                            });
                           
                        }
                       
                        void onStop(){
                            if(myCDIObserver!=null)
                                bm.destroyBean(myCDIObserver);
                            //not listening to cdi events anymore
                        }
                    
                        int someVariable;
                       
                        void doFoo(){
                           
                        }
                    }
                    
                    
                    


                    I also wrote some helper classes and put common functionality in our custom abstract base presenter, so the concrete presenters are much cleaner than in the example.

                    • 7. Re: Listen to @Observes only when started in a mvp presenter
                      marius.gerwinn

                      Josh,

                      Thanks for your comments regarding the correct usage of CDI events. Actually we do not use CDI events for Client/Server communication at all. We basically just use them as a neat replacement for the gwt event bus. We do so since there is absolutely no boilerplate. You simple can "use any class and just fire them".

                      • 8. Re: Listen to @Observes only when started in a mvp presenter
                        jblinick

                        Marius,

                         

                        I misread your original post.  I thought you said you were replacing the errai messagebus, not the GWT Event Bus.  Adding GWT events is a real pain.  Depending on the design of the UI, I could see how this would be very useful.