1 2 Previous Next 29 Replies Latest reply on Jul 16, 2009 5:12 PM by thatproblemguy

    Accessing renderer from a MDB

    rlperry

      Should I be able to use a org.jboss.seam.faces.Renderer from a message driven bean?


      I wrote some test code to find out, but it is going very poorly. 


      I would very much like to use seam's email template from a MDB.  If it matters, I would eventually like for the email to include a PDF template, though may failing test code does not yet include this.


      Very similar code works wonderfully when call as a result of interaction with a web browser.  Being pretty new to JSF and Seam I do not really know if this general direction is even plausible.  Guidance would be greatly appreciated.


      The MDB looks like:



      @MessageDriven(activationConfig =
      {
         @ActivationConfigProperty(propertyName="cronTrigger", propertyValue="0 * * * * ?")
      })
      @ResourceAdapter("quartz-ra.rar")
      @Name("timeListener")
      public class TimeMDB implements Job
      {
         private static final Logger log = Logger.getLogger(TimeMDB.class);
      
         @EJB FleetMaintenance fml;
      
         @In(create=true)    
         private Renderer renderer;
      
         public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
         {
             log.info("************* The MDB got called!!!!");
             renderer.render("/EMailTest.xhtml");
             log.info("************** Email sent successfully!!!!");
         }
      }



      The logged exception follows:


      Caused by: java.lang.IllegalStateException: Application was not properly initialized at startup, could not find Factory: javax.faces.application.ApplicationFactory
           at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:256)
           at org.jboss.seam.mock.MockFacesContext.<init>(MockFacesContext.java:60)
           at org.jboss.seam.ui.facelet.FaceletsRenderer$RenderingContext.init(FaceletsRenderer.java:95)
           at org.jboss.seam.ui.facelet.FaceletsRenderer$RenderingContext.run(FaceletsRenderer.java:77)
           at org.jboss.seam.ui.facelet.FaceletsRenderer.render(FaceletsRenderer.java:169)
           at com.myrslink.webface.reports.TimeMDB.execute(TimeMDB.java:37)
           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
           at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
           at java.lang.reflect.Method.invoke(Method.java:585)
           at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
           at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
           at org.jboss.seam.intercept.EJBInvocationContext.proceed(EJBInvocationContext.java:44)
           at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
           at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:31)
           at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
           at org.jboss.seam.core.BijectionInterceptor.aroundInvoke(BijectionInterceptor.java:46)
           at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
           at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42)
           at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
           at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:118)
           at org.jboss.seam.intercept.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:50)
           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
           at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
           at java.lang.reflect.Method.invoke(Method.java:585)
           at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:118)
           at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
           at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
           at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
           at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
           at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47)
           at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
           at org.jboss.aspects.tx.TxPolicy.invokeInCallerTx(TxPolicy.java:126)
           ... 11 more




        • 1. Re: Accessing renderer from a MDB
          jazir1979

          Hi Robert,


          I have hacked my way through this and got it to work using some of the Mock objects from SeamTest, but it's not for the faint-hearted.  It also seems to break and require more changes every time I upgrade Seam.  Hopefully there's an easier way which somebody can suggest, but here's what I had to do to dummy up the correct JSF context in order to use the Renderer from my MDB:


                  try {
                      FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
                  } catch (final IllegalStateException e) {
                      LOG.info("Doing dummy JSF configuration for back-end e-mail processing!");
          
                      final Application application = new SeamApplication(new MockApplication());
                      final MockServletContext servletContext = new MockServletContext();
                      final HttpServletRequest request = new MockHttpServletRequest(
                              new MockHttpSession(servletContext));
                      final ExternalContext externalContext = new MockExternalContext(servletContext, request);
                      final MockFacesContext facesContext = new MockFacesContext(externalContext, application);
                      facesContext.setViewRoot(new UIViewRoot());
                      facesContext.setCurrent();
          
                      FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY,
                              "com.sun.faces.renderkit.RenderKitFactoryImpl");
                      ((RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY))
                          .addRenderKit("HTML_BASIC", new RenderKitImpl());
                      FactoryFinder.setFactory(FactoryFinder.APPLICATION_FACTORY,
                              "com.sun.faces.application.ApplicationFactoryImpl");
          
                      final Application realApp = new SeamApplication(
                              ((ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY))
                              .getApplication());
                      ((ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY))
                          .setApplication(realApp);
                      realApp.addELResolver(new SeamELResolver());
          
                      final MockFacesContext realFacesContext = new MockFacesContext(externalContext);
                      final UIViewRoot viewRoot = new UIViewRoot();
                      viewRoot.setRenderKitId("HTML_BASIC");
                      realFacesContext.setViewRoot(viewRoot);
                      realFacesContext.setResponseWriter(new HtmlResponseWriter(
                              new StringWriter(), "text/html", "UTF-8"));
                      realFacesContext.setCurrent();
          
                      LOG.info("FacesContext: #0", realFacesContext);
                      LOG.info("FacesContext Response Writer: #0", realFacesContext.getResponseWriter());
          
                      realApp.setViewHandler(new FaceletViewHandler(new ViewHandlerImpl()));
                      realApp.addComponent("org.jboss.seam.mail.ui.UIMessage", "org.jboss.seam.mail.ui.UIMessage");
                      realApp.addComponent("org.jboss.seam.mail.ui.UIFrom", "org.jboss.seam.mail.ui.UIFrom");
                      realApp.addComponent("org.jboss.seam.mail.ui.UITo", "org.jboss.seam.mail.ui.UITo");
                      realApp.addComponent("org.jboss.seam.mail.ui.UISubject", "org.jboss.seam.mail.ui.UISubject");
                      realApp.addComponent("org.jboss.seam.mail.ui.UIBody", "org.jboss.seam.mail.ui.UIBody");
                      realApp.addComponent("org.jboss.seam.mail.ui.UIAttachment",
                              "org.jboss.seam.mail.ui.UIAttachment");
                      realApp.addComponent("org.jboss.seam.mail.ui.UIHeader", "org.jboss.seam.mail.ui.UIHeader");
          



          As you can see, it's really quite horrific.  I even had to add all of the UI Components I use in my mail templates.  There has to be a better way, but this does the job for me :)


          hope it helps,
          Daniel.

          • 2. Re: Accessing renderer from a MDB

            Robert,


            Have you been able to get this operational?  I'm facing a similar issue (in my case, emailing from a click generated in one WAR using a template defined in another WAR, but eventually moving to MDB driven emails as you stated).


            I'm moderately leary about both performance issues and the potential - if done incorrectly - to wedge my application by putting mock or duplicate components into play.

            • 3. Re: Accessing renderer from a MDB
              rlperry

              No, I have not.  While I really appreciated Daniel's post, and should have said so sooner, it very much felt like the wrong way for me. In the end I decided that for my specific needs forgoing the niceties of Seam in regard to email and PDF was the proper route.  I actually have more needs for each outside of the webface, than within the webface.


              The email part never really bothered me, it was the PDF stuff that REALLY had my interest, but working with iText directly seems like it will work out fine. 


              That said, should one of the might of Seam development want to state there views on this, it might clear things up a bit for the rest of us.  (e.g. It was never intended for that purpose, and.... or You idiots, you just need to....)

              • 4. Re: Accessing renderer from a MDB
                pmuir

                For Seam mail (and I think PDF too) I want to make it so the Renderer will work outside of an initialized JSF lifecycle (Seam needs to boot it's own copy of JSF I think). If anyone wants to give this a go...

                • 5. Re: Accessing renderer from a MDB
                  dragospd.dragospd.yahoo.com

                  Thanks for your input Daniel. I tried your approach and it works.


                  Isn't it possible to initialize the JSF context once and have it available for each instance of MDB?. Is this context available only for the current thread? Is it ever GC'ed? Could someone explain the mechanics of how this is working?


                  Thanks

                  • 6. Re: Accessing renderer from a MDB
                    hispeedsurfer.hispeedsurfer.gmx.net

                    Hi Daniel and Robert,


                    I have exactly the same problem sending emails from inside a mdb.
                    Have tried the approach but get a



                    java.lang.NoClassDefFoundError: com/sun/facelets/FaceletViewHandler




                    at startup.


                    Can you give me a hint get this working.



                    Thanks

                    • 7. Re: Accessing renderer from a MDB
                      vladimir.kovalyuk

                      Pete,
                      I badly need this capability. I'm planning to have timer-based check ing of conditions and sending email notifications.


                      Can't find another topic where I stated that Seam Mail example doesn't work in async mode (the same cause) and you asked me to give the latest versions of AS and Seam go. I unpacked AS and Seam in fresh folders and ran Seam Mail example - it reports the same exception in log (see above in this topic) :(

                      • 8. Re: Accessing renderer from a MDB
                        hispeedsurfer.hispeedsurfer.gmx.net

                        Hi, I have tried the approach from Daniel Young, but with      without success.


                        I need this capability urgently.



                        My case: I have a big queue with many time-consuming queries. After each query I have to send a mail. But sending mails using seam renderer component I get the IllegalStateException like descriped above.


                        Environment: Seam 2.0.1.GA and jboss-4.2.2.GA



                        I hope someone can give me an advice or solution!

                        • 9. Re: Accessing renderer from a MDB
                          gsegura

                          Maybe a faster hack would be the MDB to fake http request to get inside the context where those components are available, like:


                          http://myself/emailthis.seam?idEmailInfo=XXX




                          Either pass all parameters in the request or just use it as trigger and pick up the parameters from other (db) place.



                          • 10. Re: Accessing renderer from a MDB
                            larshuber

                            Hi Pete


                            can you give an example how to initialize/create/inject the Renderer outside a JSF lifecycle.


                            Thanks, Lars

                            • 11. Re: Accessing renderer from a MDB
                              larshuber

                              Hi Pete


                              can you give an example how to initialize/create/inject the Renderer outside a JSF lifecycle.


                              Thanks, Lars

                              • 12. Re: Accessing renderer from a MDB
                                hispeedsurfer.hispeedsurfer.gmx.net

                                Hi Seam developers,


                                is there some news according to this topic, I mean to send mail from a MDB.



                                Thanks a lot

                                • 13. Re: Accessing renderer from a MDB
                                  accless

                                  It would be great to get an update on this topic soon!


                                  Async-Email creation in the backend is mandatory for professional applications...


                                  Does seam provide another solution for creating emails WITHOUT the renderer ?



                                  greetings

                                  • 14. Re: Accessing renderer from a MDB
                                    rlperry

                                    I suspect everyone knows, but just to make certain that fellow readers do not get lost, you can still send email from a MDB using Java Mail, etc...  What we are talking about here Seams extremely nice methodology for sending an email, specifically using xhtml and El.


                                    I do have a client who is screaming for this and though I have avoided the immediate need, I suspect I will come back around to having to have a solution. If that time comes before the Seam developers have a elegant solution then I suppose I will go with an Ugly hack of some sort. 


                                    That said I do think this will be a common request that will never go away, especially as Seam moves into the enterprise.  In the mean time an update would be really nice even if it is just something to the effect of This is not even on the horizon.

                                    1 2 Previous Next