1 2 Previous Next 16 Replies Latest reply on Aug 3, 2009 1:27 AM by phantasmo

    Seam with EJB3 Remote in separate projects

    rene.felder

      We generated a Seam project using seam gen and added an EJB3 component and separated the .war project from the .ear project so that we have two separate projects. The EJB3 component comes up fine as we can see in the logfile, but we were not able to connection seam to the EJB 3 Remote Interface:


      Logfile EJB3 Startup:


      2009-07-30 15:20:52,174 INFO  [org.jboss.ejb3.JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.stateful.StatefulContainer
      2009-07-30 15:20:52,174 INFO  [org.jboss.ejb3.JmxKernelAbstraction] installing MBean: jboss.j2ee:ear=info-ear.ear,jar=info-service.jar,name=NachrichtenList,service=EJB3 with dependencies:
      2009-07-30 15:20:52,174 INFO  [org.jboss.ejb3.JmxKernelAbstraction]      persistence.units:ear=info-ear.ear,jar=info-service.jar,unitName=info_seamgen
      2009-07-30 15:20:52,206 INFO  [org.jboss.ejb3.EJBContainer] STARTED EJB: at.sozvers.itsv.seucc.info.service.impl.NachrichtenList ejbName: NachrichtenList



      EJB 3 Code:


      @Name("nachrichtenList")
      @Scope(ScopeType.SESSION)
      @Stateful
      public class NachrichtenList extends EntityQuery<Nachrichten> implements INachrichtenList {
      ...
      }



      @Remote
      public interface INachrichtenList extends Serializable {
           public abstract Nachrichten getNachrichten();
      }



      Within the JNDI View the EJB 3 is listed correct:


       +- info-ear (class: org.jnp.interfaces.NamingContext)
        |   +- NachrichtenList (class: org.jnp.interfaces.NamingContext)
        |   |   +- remote (class: java.lang.Object)
        |   |   +- remoteStatefulProxyFactory (proxy: $Proxy372 implements interface org.jboss.ejb3.ProxyFactory)
      



      So it 'seam's that the EJB3 came up correct! So now we connected Seam to the EJB 3 component, so we set up the components.xml file with following jndi-pattern:


      <core:init debug="true" jndi-pattern="info-ear/#{ejbName}/remote"/>



      Now in the logfile we can see that the components.xml file is read correct:


      2009-07-30 14:52:56,487 INFO  [org.jboss.seam.init.Initialization] reading /WEB-INF/components.xml



      Now we wanted to use the component in our xhtml file:


      <h:inputText id="inhalt" value="#{nachrichtenList.nachrichten.inhalt}"
                                         onblur="resetBGColor(this)" onfocus="setBGColor(this)"
                                         class="form_input_6spalten" maxlength="20" tabindex="1"
                                         title="Inhalt" />



      But we get the result that the component resolved to null:


      Caused by: javax.el.PropertyNotFoundException: /NachrichtenList.xhtml @35,25 value="#{nachrichtenList.nachrichten.inhalt}": Target Unreachable, identifier 'nachrichtenList' resolved to null
           at com.sun.facelets.el.TagValueExpression.getType(TagValueExpression.java:62)




      So now we read the documentation and all tutorials to find out what went wrong. We also tried to use the ejb-ref approach. So we definied the ejb-ref in the web.xml:


           <ejb-ref>
                <ejb-ref-name>info-ear/NachrichtenList/remote</ejb-ref-name>
                <ejb-ref-type>Session</ejb-ref-type>
                <remote>at.sozvers.itsv.seucc.info.service.impl.INachrichtenList</remote>
                <home>at.sozvers.itsv.seucc.info.service.impl.INachrichtenList</home>
           </ejb-ref>
      



      We also integrated the seam interceptor within the ejb-jar.xml:


      <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>



      Nothing changed! It 'seams's that Seam is not able to connect to a remote EJB 3 that is not located in the same ear file. Is this possible? Or are we doing something wrong?
      Rene

        • 1. Re: Seam with EJB3 Remote in separate projects
          asookazian

          1) what app server and version?


          2) does the JNDI lookup work or not?


          3) this may not be a Seam issue, it may be related to app server config and/or EJB3 issue (although it may involve configs in Seam, not sure)


          4) what is the architecture here in terms of servers and deployments?

          • 2. Re: Seam with EJB3 Remote in separate projects
            rene.felder

            1) JBoss 4.2.3
            2) how can I find out? Seam does not log anything about the lookup. Currently I use the debug Log Level but can't see any lookups
            3) Seam does the lookup and my EJB3 comes up correct. So why should it be an app server problem?
            4) Two separate deployments on one server. The war Deployment goes into a war file, the EJB3 goes into an ear file. Both have different classloaders so we need a remote Interface for the EJB. EAR Deployer is set to callByValue!


            Seam does not give any information when looking up EJB's! So how can anyone find out! There's no information if an EJB cannot be found!

            • 3. Re: Seam with EJB3 Remote in separate projects
              rene.felder

              1. JBoss 4.2.3

              2. how can I find out? Seam does not log anything about the lookup. Currently I use the debug Log Level but can't see any lookups

              3. Seam does the lookup and my EJB3 comes up correct. So why should it be an app server problem?

              4. Two separate deployments on one server. The war Deployment goes into a war file, the EJB3 goes into an ear file. Both have different classloaders so we need a remote Interface for the EJB. EAR Deployer is set to callByValue!



              Seam does not give any information when looking up EJB's! So how can anyone find out! There's no information if an EJB cannot be found!

              • 4. Re: Seam with EJB3 Remote in separate projects
                asookazian

                SiA book:



                When the Seam container determines that an instance of the component needs to
                be created, Seam asks the EJB container for a reference to the session bean instance
                using a JNDI lookup. Once Seam has a reference to the session bean instance, Seam
                adds additional services to it and then binds it to a context variable, just as Seam
                would do with a JavaBean component instance. The two containers are working
                together to create and initialize an instance of a session bean component.

                When you deploy your app, Seam installs all classes marked with @Name (Seam components).


                Here's an example of server.log output for seam-booking project:


                13:16:39,547 INFO  [Component] Component: hotelSearch, scope: SESSION, type: STATEFUL_SESSION_BEAN, class: org.jboss.seam.example.booking.HotelSearchingAction, JNDI: jboss-seam-booking/HotelSearchingAction/local



                So if I were you I would check this JNDI value on deployment of your app and then also consider using @Local rather than @Remote interface since you are deploying two apps in the same app server (same JVM/process should not require remote interfaces which is a performance penalty compared to local interfaces).


                I tried to verify the JNDI binding name via JBoss JMX console but was not able to find it...


                I also was unable to find any reference to the JNDI name when Seam/EJB container does JNDI lookup in the booking app when I looked in the server.log...  Perhaps it's not being logged?




                • 5. Re: Seam with EJB3 Remote in separate projects
                  asookazian

                  I verified that there is no logging in the method that instantiates the session bean (Seam 2.1.2):


                  org.jboss.seam.Component.java:


                  protected Object instantiateSessionBean() 
                         throws Exception, 
                                NamingException
                     {
                        Component old = SeamInterceptor.COMPONENT.get();
                        SeamInterceptor.COMPONENT.set(this);
                        try {
                           Object bean = Naming.getInitialContext().lookup(jndiName);
                           return wrap(bean, new ClientSideInterceptor(bean, this));
                        } finally {
                           SeamInterceptor.COMPONENT.set(old);
                        }
                     }



                  From SiA:


                  <ejb-local-ref>
                  <ejb-ref-name>open18ee/RegisterActionBean/local</ejb-ref-name>
                  <ejb-ref-type>Session</ejb-ref-type>
                  <local>org.open18.action.RegisterAction</local>
                  </ejb-local-ref>




                  This step is not required on JBoss AS 4 since the component is automatically registered
                  with JNDI using the pattern: application name/component name/client view type.

                  You should write a servlet or session bean that does a JNDI lookup to get an instance of the remote EJB.  So I mean test it out by actually writing the JNDI API lookup code like we used to do in EJB2.x.  Then you can isolate your problem to see if it's Seam or not that's having the issue.  One step at a time when doing RCA (root cause analysis).


                  Here's an example from JSR220-core:


                  @Resource(name=”jdbc/EmployeeAppDB”, type=javax.sql.DataSource)
                  @Stateless public class EmployeeServiceBean
                  implements EmployeeService {
                  EJBContext ejbContext;
                  public void changePhoneNumber(...) {
                  ...
                  // obtain the initial JNDI context
                  Context initCtx = new InitialContext();
                  // perform JNDI lookup to obtain resource manager
                  // connection factory
                  javax.sql.DataSource ds = (javax.sql.DataSource)
                  initCtx.lookup("java:comp/env/jdbc/EmployeeAppDB");
                  // Invoke factory to obtain a connection. The security
                  // principal is not given, and therefore
                  // it will be configured by the Deployer.
                  java.sql.Connection con = ds.getConnection();
                  ...
                  }
                  }



                  The other option is to add debug breakpoints in the Seam core method I posted above to see what that method is returning, etc.  Thank goodness for open-source, I highly doubt you can even think about adding brkpts in .NET core code!

                  • 6. Re: Seam with EJB3 Remote in separate projects
                    barakka

                    Hi,


                    I'm just speculating here as I'm struggling with this myself. If I understand correctly you have a war which would like to access ejb from a separate ear. You have configured the jndi-pattern of the war to point to the ear. You ear is also using seam as you are providing the @Name to your ear.


                    If my understanding is correct, you are out of luck trying to access the ear ejb from the jsf using the seam component name via EL resolution. The ejb seam component exists only in the ear project, the war does not know any component named as your ejb, hence it can't be available to the EL for resolution.


                    If my understanding is correct, you shouldn't be able to inject the ear in any war bean as well, as from a quick look to the seam code it looks to me that seam is only able to inject seam components, which are known to the local seam framework instance. And in your war the ejb will not be known as a seam component (unless you include the ejb bean class in the war - being it a war the bean would be recognized by seam but not deployed as an ejb-, which I guess is not desirable). But I might be wrong and I'd be happy if someone could clarify this point.


                    My suggestion, if you want the ejb to be accessible from jsf in the war (or to any other war bean), is to define a factory (or a manager using @Unwrap) in the war itself, inject the ear in that factory using the standard @EJB and ejb3 resolution mechanisms, and return your result.


                    Hope this might help, and please tell me if my guess is right.


                    Best,
                    Riccardo.


                    PS: Notice that the interceptor in the ejb-jar of the ear is mandatory, if you want seam to work with your ejbs (within the ear, that is).

                    • 7. Re: Seam with EJB3 Remote in separate projects
                      swd847

                      Riccardo is correct, you cannot use remote EJB's as seam components (I don't think that there is any particular reason why this couldn't be added in, with some limitations).


                      If all you want to do is inject remote ejb's into seam components then that should not be to hard, you have to create a generic manager component that looks up the remote ejb and puts it into the context using @Unwrap. You need to use a manager rather than @Factory so you can destroy the remote bean in the managers @Destory method.


                      Of course this would be easier if you just put the war in the ear.

                      • 8. Re: Seam with EJB3 Remote in separate projects
                        rene.felder

                        Thanks a lot for your really helpful information! I digged into the code myselve and found out that Seam only creates components within the same classloader (Initialization.create()). So therefore the method Component.instantiateSessionBean() is never called as Seam did not found any Name Annotations within the same classloader.


                        I mean thats really weird! Seam shouldn't care about packaging of the components. It shouldn't matter if the war is packaged separate. And worse there's no documentation about that. I agree with Riccardo it should be possible to integrate that feature. The limitation will be that the EJB3 can only be looked up at access time as it is not declared anyhwhere at startup time. That breaks the Seam logic as all the components are created at deployment time. Another solution would be to specify EJB's within the component.xml file.


                        So I have to fallback to my old solution where I created the EJB's using the Springframework that is really good integrated into Seam. The problem with this solution is that I loose the advantage of lazy loading JPA Entity references that is normally managed by the Seamframework using the open session in view pattern.


                        So here is my workaround:


                        Within the spring.xml


                        <jee:remote-slsb id="nachrichtenList" lookup-home-on-startup="false" refresh-home-on-connect-failure="true" business-interface="INachrichtenList" jndi-name="${nachrichtenList.jndiname}">
                           <jee:environment>
                              java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
                              java.naming.factory.url.pkgs=org.jboss.naming.client
                              java.naming.provider.url=${nachrichtenList.provider.url}
                           </jee:environment>
                        </jee:remote-slsb>



                        Within the components.xml:


                        <spring:context-loader config-locations="classpath*:/spring.xml"/>



                        The advantage of this solution is that the EJB3 can be located anywhere even on another machine.

                        • 9. Re: Seam with EJB3 Remote in separate projects
                          rene.felder

                          ... just one idea:
                          If an Interface is annotated with an @Name Component and derives from a Remote Interface it can checked against an EJB3 component.


                          I'm not realy sure why Interfaces with a @Name Annotation are not considered as components. The ComponentDeploymentHandler looks for all Classes/Interfaces that are Annotated with the Name.class:


                          private static Set<Class<? extends Annotation>> ANNOTATION_TYPES = new HashSet<Class<? extends Annotation>>(Arrays.asList(Name.class));


                          • 10. Re: Seam with EJB3 Remote in separate projects
                            swd847

                            There are good reasons for the way seam handles this:


                            - It is not really possible to scan a remote AS for component definitions, it is not even possible to scan a j2ee app in the same AS in a portable manner. This is more of a java issue than a seam one.


                            - Interfaces can't be components. What if there are two classes that implement it, or none? The concept does not make sense.


                            - Remote ejbs can never be first class seam components. e.g. you can't propagate the persistence unit, anything to be injected you have to be serialisable etc. Basically it would behave totally differently to every other seam component.


                            - It is relatively easy to define a factory in xml that allows you to inject a remote EJB, which is really all you need.


                            Stuart

                            • 11. Re: Seam with EJB3 Remote in separate projects
                              asookazian

                              Stuart Douglas wrote on Jul 31, 2009 00:22:


                              Riccardo is correct, you cannot use remote EJB's as seam components (I don't think that there is any particular reason why this couldn't be added in, with some limitations).



                              I did not know  that.  So that seams like a major possible limitation.  Say you have two JBoss clusters with two different Seam apps deployed in the same WAN.  So you're basically saying you can't inject an instance of component A from cluster A's app into component B from cluster B's app?


                              Is there any documentation covering this?  I know that since EJB 2.0, most JEE architectures push for using local interfaces rather than remote interfaces for performance considerations but in this case it sounds like the app must be deployed into more than one cluster so that we can use local interface rather than remote interface...

                              • 12. Re: Seam with EJB3 Remote in separate projects
                                asookazian

                                Well this works when business method is invoked from JSF page in the same JVM:


                                remote interface:


                                @Remote
                                public interface TestStartupInsertApplicationSiteRemote {
                                     public void startup();
                                     public void end();
                                     public void destroy();
                                }



                                implementation class:


                                @Stateful
                                @Name("insertAppSite")
                                @Scope(ScopeType.CONVERSATION)
                                @JndiName("BETS/TestStartupInsertApplicationSite/remote")
                                public class TestStartupInsertApplicationSite implements TestStartupInsertApplicationSiteRemote {...}



                                So is the limitation that you can't invoke a method or inject this SFSB from a Seam component deployed in a different app in a different JVM?

                                • 13. Re: Seam with EJB3 Remote in separate projects
                                  swd847

                                  Just because you can inject it does not mean that it is working the way you expect.


                                  The seam interceptors for the remote app will be running in a different app context than the one that you are running in, so you will be using the scopes on the remote server for injection, and every other service provided by seam. So all you have access to is the event and application scopes (possibly buisiness process). This is probably just the tip of the iceberg.


                                  It is however perfectly possible to inject remote ejbs as seam components, you just create a manager component that uses @Unwrap to stick them in the appropriate scope.

                                  • 14. Re: Seam with EJB3 Remote in separate projects
                                    phantasmo

                                    Hmmm... This is a very curious topic. I have some problems wrapping my mind around this, so it would be really cool if someone could clarify if the remote EJB acquired through JNDI will ever be able to use locally provided Seam services like bijection? Will it have access to local contexts?

                                    1 2 Previous Next