8 Replies Latest reply on Dec 6, 2010 10:43 PM by Hui Onn Tan

    Seam Observer annotation not working under multiple Wars

    K Reynolds Newbie

      Our project has an application scoped job manager which is created @Startup.  When we added a second war to the project, the org.jboss.seam.annotations.Observer annotation no longer responds when raising a call using Events.instance().raiseEvent(...) from this job manager.


      Does anyone understand why @Observer stopped working? Any information for a work around... maybe a configuration change?



      Version Seam 2.2.1




      Thanks,

        • 1. Re: Seam Observer annotation not working under multiple Wars
          Nikolay Elenkov Master

          Keep in mind that that application = WAR. When you add a second WAR, Seam is initialized one more time, so that might have something to do with it. What's in the second WAR? Where are the @Observer methods: in WAR1, WAR2 or both?



          I should add this as a signature line:


          --
          This forum's formatting is ridiculous.

          • 2. Re: Seam Observer annotation not working under multiple Wars
            K Reynolds Newbie

            Both the Observer and Raise Event are in War1.  War2 does not contain either.


            • 3. Re: Seam Observer annotation not working under multiple Wars
              Nikolay Elenkov Master

              K Reynolds wrote on Dec 02, 2010 00:13:


              Both the Observer and Raise Event are in War1.  War2 does not contain either.




              OK, provide more details and code.

              • 4. Re: Seam Observer annotation not working under multiple Wars
                K Reynolds Newbie

                All of this code is contained in the first War.


                EJB Call...




                ((JobManager)Component.getInstance("jobManager")).schedule(job);





                Summary of the JobManager, @Observer(event.JobCompleted) never hears the event from Events.instance().raiseEvent(event.JobCompleted, job):


                
                import org.jboss.seam.Component;
                import org.jboss.seam.ScopeType;
                import org.jboss.seam.annotations.Create;
                import org.jboss.seam.annotations.Destroy;
                import org.jboss.seam.annotations.In;
                import org.jboss.seam.annotations.Logger;
                import org.jboss.seam.annotations.Name;
                import org.jboss.seam.annotations.Observer;
                import org.jboss.seam.annotations.Scope;
                import org.jboss.seam.annotations.Startup;
                import org.jboss.seam.annotations.TransactionPropagationType;
                import org.jboss.seam.annotations.Transactional;
                import org.jboss.seam.core.Events;
                import org.jboss.seam.log.Log;
                
                
                @Name("jobManager")
                @Startup
                @Scope(ScopeType.APPLICATION)
                public class JobManager {
                
                    public enum Status {
                        COMPLETED;
                    }
                
                    Queue<Job> jobs;
                
                    @Transactional(TransactionPropagationType.REQUIRED)
                    public void addJob(Job job) {
                        jobs.add(job);
                        executeNextJob(job);
                    }
                
                    private boolean executeNextJob(Job job) {
                        Status status =  job.execute();
                       if (status == Status.COMPLETED) {
                           //NOTE - The observer never hears the event if there are two Wars...
                            Events.instance().raiseEvent("event.JobCompleted", job);
                        }
                    }
                
                    @Observer("event.JobCompleted")
                    public void onJobCompleted(Job job) {
                        //NOTE - This never gets called!
                        jobs.remove(job);
                        executeNextJob(jobs get next job... );
                    }
                }
                




                • 5. Re: Seam Observer annotation not working under multiple Wars
                  Nikolay Elenkov Master

                  Strange indeed. All raiseEvent does is get the methods listening for this particular event and call them in sequence (in the same thread).
                  So either your observer is not registered for some reason, or it gets cleared/overwritten when second WAR is initialized. Put a breakpoint in raiseEvent and check what happens or dump the contents of the list to log to see what's there:


                  List<Init.ObserverMethodExpression> list = Init.instance().getObserverMethodExpressions("event.JobCompleted");
                  for(Init.ObserverMethodExpression> o :list) {
                     log.debug(o.toString());
                  }
                  



                  HTH


                  • 6. Re: Seam Observer annotation not working under multiple Wars
                    Hui Onn Tan Newbie

                    I has been struggling with an issue about multiple WARs in single EAR last few days. But I am not sure whether the cause of your problem is the same.


                    For more info, you can refer to https://jira.jboss.org/browse/JBSEAM-3119
                    In the thread, it did mention that static Lifecycle.application will cause error for multiple WARs.


                    The condition where I encounter my problem:
                    jboss-seam.jar is deployed in top EAR folder - so Lifecycle class is loaded by a EAR classloader (which is accessed by multiple WARs).
                    In this case, Lifecycle.application is always replaced by last loaded web appliation.


                    However, this will not cause any issue if the requests to Application-scoped components are web request (where ServletContext is used instead of Lifecycle.application).


                    For my case, the error happens where the request is originated from RMI call.
                    (I use Lifecycle.beginCall() to create the contexts for RMI call. In your case, it seems that the event is published by scheduled job and Lifecycle.beginCall() is invoked in @Asynchronous implicitly which is in another thread - so I assume it meets the condition too).


                    Then seam will get the Application-scoped component in second WAR and the error happens...



                    As I really need to deploy multiple WARs in single EAR, I choose to patch/hack Lifecycle class
                    I understand it is a very ugly and risky solution, and have to check the side-effect myself : (

                    • 7. Re: Seam Observer annotation not working under multiple Wars
                      K Reynolds Newbie

                      Tan Hui Onn,


                      Thanks, this is exactly what is happening.  How did you patch the Lifecycle class?  I think in my situation I will patch the Events.raiseEvent method.  I would like to walk through all the ApplicationContexts to find the observer.  How did you get a list of ApplicationContexts?

                      • 8. Re: Seam Observer annotation not working under multiple Wars
                        Hui Onn Tan Newbie

                        I create a class ApplicationMap to map application name to application contexts.

                        I replace Lifecycle.application with ApplicationMap applicationMap
                        Then I add beginCall(String applicationName), beginApplication(Map app, String applicationName) and modify ServletLifeCycle accordingly.


                        Since this forum does not support attachment, I emailed you my modified file for your reference.


                        (Footer note: getting the application name in my case is a bit tricky as my component is in a jar shared by all WARs. So I inject the application name into the component with component.xml)