5 Replies Latest reply on Jan 22, 2010 2:12 AM by Nikolay Elenkov

    How to get FacesContext in a @Asynchronous method call

    Rodrigo Uchoa Novice

      Hey guys,


      We're using quartz to schedule some late at night tasks in the project that I work. We're basically calling an @Async method from a component thats annotated with @Startup and @Create, like the example below:






      @Startup
      class StartingUp {
      
          @Create
          public void startQuartz() {
              //call the async method
              //starting now and repeate every 60 seconds
              quartzJob.start(new Date(), 60000));
         }
      }




      And now the component that's actually doing all the work:




      @Name("quartzJob")
      class MyQuartzJob {
          
          @Asynchronous
          public void start(@Expiration date, @IntervalDuration Long interval) {
              //do some work here - FacesContext needed
          }
      }




      The schedulling is working just fine. The catch is that, as I have just found out, async method calls does not have access to a FacesContext object. If I call FacesContext.getCurrentInstance(), I get null.


      Explaining why I need the FacesContext on this matter would be cumbersome. But believe me, I need it. So does anyone have a clue how can I do it? A mock FacesContext would be just fine. I really need a FacesContext object associated with every thread inside that async call.


      All clues are appreciated.
      By the way, I'm using seam 2.1.



        • 1. Re: How to get FacesContext in a @Asynchronous method call
          yachaa Newbie
          You can try using seam FacesContext to get the JSF Context.

          org.jboss.seam.faces.FacesContext fc = Contexts.getApplicationContext().get("org.jboss.seam.faces.facesContex");
          fc.getContext(); //this will return you the JSF Context.

          If Seam FacesContext does not exist, you need to check whether the ApplicationContext has been populated.

          • 2. Re: How to get FacesContext in a @Asynchronous method call
            Nikolay Elenkov Master

            Basically, Quartz jobs are not associated with a web or JSF request, so no FacesContext. You cannot get it. So the main question is: why do you need it?

            • 3. Re: How to get FacesContext in a @Asynchronous method call
              Rodrigo Uchoa Novice

              Nikolay Elenkov wrote on Jan 21, 2010 13:40:


              Basically, Quartz jobs are not associated with a web or JSF request, so no FacesContext. You cannot get it. So the main question is: why do you need it?




              I knew someone would ask :) Anyway, here's the thing:
              Our bussiness tier is tightly coupled to JSF and Seam. In a way that, everytime I call a business façade, we have an interceptor that intercept the calls and look for a FacesContext in the current thread (he calls FacesContext.getCurrentInstance().getExternalContext()).


              Thats when the problem arises. That async method needs to do some business processing, so it's logic that he gets a reference to a business facade where all the business logic is already implemented. But since there's no FacesContext, I'm unable to make calls to any business methods because they keep throwing NullPointerException inside that interceptor I just told you about.


              I know that our architecture probably needs to be reviewed, but that's gonna take some time. I was looking for a quick workaround.



              If I could make a mock FacesContext and just associate it with the current thread, solves my problem.

              • 4. Re: How to get FacesContext in a @Asynchronous method call
                Rodrigo Uchoa Novice

                Ivan Sukianto wrote on Jan 21, 2010 13:34:


                You can try using seam FacesContext to get the JSF Context.

                org.jboss.seam.faces.FacesContext fc

                • Contexts.getApplicationContext().get(org.jboss.seam.faces.facesContex) fc.getContext(); //this will return you the JSF Context.



                If Seam FacesContext does not exist, you need to check whether the ApplicationContext has been populated.




                Like you said, Contexts.getApplicationContext().get(org.jboss.seam.faces.facesContex) is returning null. Even If this really worked, I would also need that the javax.faces.context.FacesContext returned by the call fc.getContext() be associated with the current thread. To avoid any calls to FacesContext.getCurrentInstance() from returning null.


                Can this work? How can I setup an ApplicationContext?

                • 5. Re: How to get FacesContext in a @Asynchronous method call
                  Nikolay Elenkov Master

                  Rodrigo Uchoa wrote on Jan 21, 2010 13:55:


                  I know that our architecture probably needs to be reviewed, but that's gonna take some time. I was looking for a quick workaround.

                  If I could make a mock FacesContext and just associate it with the current thread, solves my problem.


                  Well, there is a MockFacesContext in the org.jboss.seam.mock package. It is used in SeamTest along with a few other mocks. You could probably use that, but since they are calling a static method, I don't see how you can inject it. Find the source of FacesContext, maybe you could use some reflection magic, but that might have unwanted side effects. Better have them rethink the whole architecture. At least make the FacesContext a parameter or something. If all else fails, you could just copy the code in one of your classes...


                  HTH