6 Replies Latest reply on Aug 1, 2008 3:33 PM by Stefano Travelli

    How do I make an EntityHome subclass stateful?

    keith bannister Newbie

      Hi,


      I'm trying  to make an EntityHome stateful so it doesn't keep having to go back to the database for stuff.


      It looks like the seam-gen generated EntityHome isn't an EJB3 Bean (doesn't implement an interface, not marked as stateful/stateless etc).


      How do I make it stateful?


      I tried just adding the @Stateful and implementing an interface marked with @Local but I get


      org.jboss.seam.InstantiationException: Could not instantiate Seam component: radioSourceHome
      ...


      Caused by: javax.naming.NameNotFoundException: RadioSourceHome not bound


      Everything's packaged in an EAR using eclipse. - I have an EJB Jar project and a seam project. I have EJB3 beans in the EJB jar file that do different things and they work fine.


      There's something fundamental I'm not understanding about this....


      Grrr.

        • 1. Re: How do I make an EntityHome subclass stateful?
          Eric H Novice

          Don't.


          Create a long-running conversation and make sure that your EntityHome thing is part of it.  Seam keeps a conversation-scoped cache, so that's what you want.


          ------------


          JBoss consulting services

          • 2. Re: How do I make an EntityHome subclass stateful?
            keith bannister Newbie

            OK that's fine, but according the tutorial http://docs.jboss.com/seam/2.0.1.GA/reference/en/html/tutorial.html#d0e1568 (hotel booking example) I have to make my bean Stateful, when I do that I get



            org.jboss.seam.InstantiationException: Could not instantiate Seam component: radioSourceHome
                 at org.jboss.seam.Component.newInstance(Component.java:1962)
                 at org.jboss.seam.Component.getInstance(Component.java:1865)
                 at org.jboss.seam.Component.getInstance(Component.java:1832)
                 at org.jboss.seam.Namespace.getComponentInstance(Namespace.java:55)
                 at org.jboss.seam.Namespace.getComponentInstance(Namespace.java:50)
                 at org.jboss.seam.el.SeamELResolver.resolveBase(SeamELResolver.java:166)
                 at org.jboss.seam.el.SeamELResolver.getValue(SeamELResolver.java:53)
                 at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:53)
                 at com.sun.faces.el.FacesCompositeELResolver.getValue(FacesCompositeELResolver.java:64)
                 at org.jboss.seam.core.Validators$ValidatingResolver.getValue(Validators.java:182)
                 at org.jboss.el.parser.AstIdentifier.getValue(AstIdentifier.java:44)
                 at org.jboss.el.parser.AstValue.getTarget(AstValue.java:34)
                 at org.jboss.el.parser.AstValue.setValue(AstValue.java:83)
                 at org.jboss.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:249)
                 at org.jboss.seam.core.Validators.validate(Validators.java:140)
                 at org.jboss.seam.navigation.Param.validateConvertedValue(Param.java:237)
                 at org.jboss.seam.navigation.Pages.convertAndValidateStringValuesInPageContext(Pages.java:743)
                 at org.jboss.seam.navigation.Pages.postRestore(Pages.java:393)
                 at org.jboss.seam.jsf.SeamPhaseListener.postRestorePage(SeamPhaseListener.java:528)
                 at org.jboss.seam.jsf.SeamPhaseListener.afterRestoreView(SeamPhaseListener.java:374)
                 at org.jboss.seam.jsf.SeamPhaseListener.afterServletPhase(SeamPhaseListener.java:211)
                 at org.jboss.seam.jsf.SeamPhaseListener.afterPhase(SeamPhaseListener.java:184)
                 at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:280)
                 at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117)
                 at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244)
                 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                 at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
                 at org.jboss.seam.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:68)
                 at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                 at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
                 at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                 at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
                 at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                 at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:44)
                 at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                 at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:141)
                 at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:281)
                 at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)
                 at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                 at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58)
                 at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                 at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
                 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                 at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
                 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
                 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
                 at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
                 at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:432)
                 at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
                 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
                 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
                 at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
                 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
                 at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
                 at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
                 at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
                 at java.lang.Thread.run(Thread.java:595)
            Caused by: javax.naming.NameNotFoundException: RadioSourceHome not bound
                 at org.jnp.server.NamingServer.getBinding(NamingServer.java:529)
                 at org.jnp.server.NamingServer.getBinding(NamingServer.java:537)
                 at org.jnp.server.NamingServer.getObject(NamingServer.java:543)
                 at org.jnp.server.NamingServer.lookup(NamingServer.java:267)
                 at sun.reflect.GeneratedMethodAccessor99.invoke(Unknown Source)
                 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                 at java.lang.reflect.Method.invoke(Method.java:585)
                 at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294)
                 at sun.rmi.transport.Transport$1.run(Transport.java:153)
                 at java.security.AccessController.doPrivileged(Native Method)
                 at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
                 at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)
                 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)
                 at java.lang.Thread.run(Thread.java:595)
                 at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:247)
                 at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
                 at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:126)
                 at org.jnp.server.NamingServer_Stub.lookup(Unknown Source)
                 at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:667)
                 at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:627)
                 at javax.naming.InitialContext.lookup(InitialContext.java:351)
                 at org.jboss.seam.Component.instantiateSessionBean(Component.java:1279)
                 at org.jboss.seam.Component.instantiate(Component.java:1265)
                 at org.jboss.seam.Component.newInstance(Component.java:1958)
                 ... 61 more
            
            


            • 3. Re: How do I make an EntityHome subclass stateful?
              keith bannister Newbie

              Perhaps I should describe my problem better.


              I have a page I can navigate to using a url like this:


              http://localhost:8080/most/RadioSource.seam?radioSourceId=2403


              This page has a number of graphs on it, each of which references the same (large) list of data that I only want to retrieve from the database once.


              To plot a graph, I use the following XHTML:



              <s:graphicImage value="#{radioSourceHome.decChart}" />



              and I have a corresponding function in RadioSourceHome:


              @Factory(value="decChart")
                  public byte[] getDecChart() {      
              
                      List<Measurements> meas = getMeasurements();
                      return createDecChart(meas);
                  }
              



              So my problem is, in the original version, getMeasurements() would go to the database each time.


              But I want to cache the results of getMeasurements() so I don't have go to the database each time.




              Here's what I have


              @Name("radioSourceHome")
              // @Stateful - uncommenting this breaks - see above post
              public class RadioSourceHome extends EntityHome<RadioSource> {
                   
              @In @Out
              List<Measurements> measurements;
              ...
              
              @Factory
              public List<Measurements> getMeasurements() {
              
              if (measurements == null) {
                  measurements = em.createQuery().....
              }
              
              return measurements;
              
              }
              
              @Factory(value="decChart")
                  public byte[] getDecChart() {      
              
                      List<Measurements> meas = getMeasurements();
                      return createDecChart(meas);
                  }
              



              My question is: Is this the right way to do it? if not, how?


              EntityHome manages to get a magical copy of the parent object I'm interested in by parsing the URL, so I'd like to leverage that if possible (I don't know how it's getting this magical copy, I just know I can get it by calling getInstance()).


              Help appreciated.

              • 4. Re: How do I make an EntityHome subclass stateful?
                Alexander Torstling Newbie

                I can only guess that you get some sort of naming problem using generics in your interface. Check your jndiView (JndiView.list method) in Jboss jmx console when your app is running, there you will have all your beans with jndi names listed. Perhaps you get some sort of deployment error?

                • 5. Re: How do I make an EntityHome subclass stateful?
                  Stefano Travelli Newbie

                  What you really want is to put 'measurement' in a PAGE or CONVERSATION scope.


                  In order to achieve this you don't need to extends EntityHome. Either annotate the component with @Scope(ScopeType.CONVERSATION) or specify that scope type in @Out or (better) @Factory annotations.


                  That is:



                  @Factory(value="decChart", scope = ScopeType.CONVERSATION)
                      public byte[] getDecChart() {      
                  
                          List<Measurements> meas = getMeasurements();
                          return createDecChart(meas);
                      }
                  
                  



                  Btw. Components that extends EntityHome are indeed statefull, even if they are not statefull session bean. Go ahead in the Seam documentation: chapter 3 will clarify you about the contextual component model.


                  Hope this helps.
                  stefano


                  • 6. Re: How do I make an EntityHome subclass stateful?
                    Stefano Travelli Newbie

                    Maybe my previous response is a little cryptic.


                    Here is the long story:


                    Create a Home componente for the entity:



                    @Name("radioSourceHome')
                    public RadioSourceHome extends EntityHome<RadioSource> {
                    
                      public void setRadioSourceId(Long id)
                      {
                         setId(id);
                      }
                    
                      public Long getRadioSourceId()
                      {
                         return (Long) getId();
                      }
                    
                    ....
                    
                    }
                    




                    Create a component with a factory for the data:


                    @Name("chartController")
                    public ChartController extends PersistenceController {
                    
                      @In(create = true)
                      RadioSourceHome radioSourceHome;
                    
                      @Factory(value = "chartData", scope = ScopeType.CONVERSATION)
                      public byte[] getChartData()
                      {
                         RadioSource radioSource = radioSourceHome.getInstance();
                    
                         return createDecChart(getEntityManager().createQuery()....);
                      }
                    
                       ...
                    
                    }
                    



                    In the chart.xhtml template you'll have:


                    <s:graphicImage value="#{charData}" />
                    
                    



                    And this is the chart.page.xml:


                    <begin-conversation join="true" />
                    
                    <param name="radioSourceId" value="#{radioSourceHome.radioSourceId}" />
                    
                    ...
                    



                    The first line says: when entering this page begin a conversation context or join an existing one.


                    The second says: take radioSourceId parameter and put it in the property evaluated by this expression. The expression asks for a radioSourceHome component, so, if it's not already there, a RadioSourceHome will be created and stored in the conversation context. Then the parameter value is set so that the magic in EntityHome will retrieve your entity.


                    In the xhtml template, the graphicImage tag value attribute looks for chartData. The first time the page is displayed Seam won't find this variabile, but during startup it was registered that chartData has a factory method in the chartController component.
                    So the ChartController component is instantiated, RadioSourceHome get injected and the getChartData method invoked.


                    The result will be placed in the conversation context (you can opt for a PAGE context here, depending on your needs), so that in subsequent calls inside the same conversation the cached value will be used instead of calling the method.


                    Regards


                    stefano