1 2 Previous Next 15 Replies Latest reply on Jan 26, 2010 7:38 PM by swiegersf.francois.swiegers.gmail.com

    Using request scope with remote EJB

    swiegersf.francois.swiegers.gmail.com

      Good day,


      I have a remote SLSB that I'm invoking from a Java app. I'm trying to reference a request scoped injected dependency from the EJB like so:



      @Remote
      public interface InjectorService {
      
          public String doSomething();
      
          @Stateless
          public static class InjectorServiceBean implements InjectorService {
      
              @Inject
              InjectMe injectMe;
      
              @Override
              public String doSomething() {
                  return injectMe.toString();
              }
          }
      
          @RequestScoped
          public static class InjectMe {
          }
      }




      My client code:




      public class Main {
      
          @EJB
          private static InjectorService remoteEjb;
      
          public static void main(String[] args) {
             System.out.println(remoteEjb.doSomething());
             System.out.println(remoteEjb.doSomething());
          }
      }





      However, on invoking the above service from my client, I get




      Caused by: javax.enterprise.context.ContextNotActiveException: No active contexts for scope type javax.enterprise.context.RequestScoped
              at org.jboss.weld.BeanManagerImpl.getContext(BeanManagerImpl.java:928)
              at org.jboss.weld.bean.proxy.ClientProxyMethodHandler.getProxiedInstance(ClientProxyMethodHandler.java:140)
              at org.jboss.weld.bean.proxy.ClientProxyMethodHandler.invoke(ClientProxyMethodHandler.java:101)
              at domain.InjectorService$InjectMe_$$_javassist_258.toString(InjectorService$InjectMe_$$_javassist_258.java)
              at domain.InjectorService$InjectorServiceBean.doSomething(InjectorService.java:22)



      According to the Weld apidocs, the request scope context should be available for remote EJB's





      The request scope is active: ... during any remote method invocation of any EJB, ...

      Am I barking up the wrong tree here?


      If I remove the RequestScoped annotation from my class, then it runs, but then my EJB uses the same instance upon every invocation from my client.


      I'm running my app using the Glassfish V3 plugin that comes with Netbeans 6.8.


        • 1. Re: Using request scope with remote EJB
          nickarls

          Tried @Inject for the EJB?

          • 2. Re: Using request scope with remote EJB
            swiegersf.francois.swiegers.gmail.com

            Hi Nicklas


            Thanks for the swift response.


            Do you mean I must add the @Inject annotation on the client side? If I do that, I get the same error. Here is my code:




            public class Main {
            
                @Inject @EJB
                private static InjectorService remoteEjb;
            
                public static void main(String[] args) {
                   System.out.println(remoteEjb.doSomething());
                   System.out.println(remoteEjb.doSomething());
                }
            }



            If I remove the @EJB annotation and make it an instance variable, then it simply stays NULL, as if CDI is ignoring the @Inject annotation on my client.


            I am of course quite a newbie with CDI, so I may in fact completely miss what you've suggested ...

            • 3. Re: Using request scope with remote EJB
              swiegersf.francois.swiegers.gmail.com

              OK, after some further reading I conclude that my NullPointerException is due to the fact that my client is not running under a CDI context.

              • 4. Re: Using request scope with remote EJB
                swiegersf.francois.swiegers.gmail.com

                I can get the desired behaviour by implementing a custom scope using this tutorial.


                However, this is clumsy, as this scope really just behaves like a RequestScoped service would if it was invoked from a servlet container via the EJB's local interface.


                Surely the normal request scope context must be available when doing a standard remote EJB invocation?


                I don't think my problem is with the client either, because the client of the EJB should not be concerned with its CDI context.


                My central question really is just: Is it a bug that Glassfish/Weld is not activating the request scope for remote EJB invocations, or is that how CDI specifies it?

                • 5. Re: Using request scope with remote EJB
                  nickarls

                  Yes the request scope is available when doing a remote EJB invocation but the request scope is a HTTP request, which is not available in SE (if the Weld SE extension doesn't do any mock magic, haven't checked).

                  • 6. Re: Using request scope with remote EJB
                    swiegersf.francois.swiegers.gmail.com

                    Thanks Nicklas,


                    I'm not using the SE extension - I'm using EJB's in Glassfish. I think the problem is that my EJB is invoked via RMI/IIOP, not the servlet layer, which means that there is no HTTP context to propagate to CDI.


                    I was hoping that Weld would activate the standard scopes outside of the servlet context, since the EJB context should provide the same semantics as an HTTP context.

                    • 7. Re: Using request scope with remote EJB
                      swiegersf.francois.swiegers.gmail.com

                      I found the following interceptor in Weld:



                      org.jboss.weld.ejb.SessionBeanInterceptor

                      It seems to do exactly what I am looking for here. However, curiously, it does not seem to be active by default, and when I try to switch in on using beans.xml, Glassfish complains that the interceptor does not have the @Interceptor annotation.


                      I managed to get it working by copying the source code into my own interceptor. I also had to add weld-core.jar to my ejb classpath (for some reason Glassfish cannot load org.jboss.weld.context.beanstore.HashMapBeanStore, probably due to a dependency that is not present is the default distribution).


                      It does work and, regardless of the nasty interceptor binding I have to add to my EJB, is a far better way to deal with this than defining a custom scope.


                      However, I still feel that a CDI implementation should provide standard context activation outside of a servlet context, because the Java EE spec does not require access to EJB's to go through a servlet layer.


                      I suppose doing a similar interceptor-style solution for session and conversation scope could be more tricky as you would have to access the EJB context, which is probably not as standards-driven as the HTTP equivalents. I'll give it a bash over then next few days.


                      I appreciate the pointers, Nicklas (over a weekend, nothing less!).

                      • 8. Re: Using request scope with remote EJB
                        gavin.king

                        Your description of your problem is all a bit muddled, making it very difficult to understand what it really is that you're missing. But let me give it a shot:


                        (1) The combination @Inject @EJB is always wrong. I've no idea what you were trying to do with that, but it doesn't mean anything at all.


                        (2) CDI does not support the use of @Inject on static fields or methods.


                        (3) You can't use @Inject to inject a reference to a remote EJB, unless you define the resource using @Produces @EJB (see spec section 3.5).


                        (4) You can not, in general, use Java EE features like @Inject and @EJB in a main() method, unless you are in a Java EE application client jar, or have something special like the Weld Java SE extension. Even if you are using an application client jar, the CDI spec does not require that the container support CDI (spec 12.1), and I doubt that GlassFish does support this.


                        So you need to find a better way to get a reference to the remote EJB. Once you have this remote EJB reference, you can indeed inject @RequestScoped beans into it (see spec 6.7.1). Your problem does not have much to do with the lack of a context on the client, because CDI contexts are not propagated across remote calls (spec 6.7).


                        • 9. Re: Using request scope with remote EJB
                          gavin.king

                          What I'm trying to say is that just about the whole of this thread appears to be riddled with misunderstanding.

                          • 10. Re: Using request scope with remote EJB
                            swiegersf.francois.swiegers.gmail.com

                            What I'm trying to say is that just about the whole of this thread appears to be riddled with misunderstanding.

                            Yep, I'll take responsibility for that - I am obviously quite a newbie here, so some of these concepts are still taking shape in my mind, so my questions may not be clear. I'll try to fix that now.


                            First some background: I develop and support an enterprise application that makes extensive use of rich application clients (not RIA, but SWT on the desktop) that invoke EJB's using RMI/IIOP directly. This is not a web application, so we don't make use of any servlet/HTTP based technology - we call the RMI interface directly. My task at the moment is to determine the effort required to bring this app up to Java EE 6 standards, including adopting the excellent CDI approach over our current Guice implementation.


                            My question is not about the client side of the application at all - I simply included that snippet so that someone with better knowledge can replicate my situation if he/she so chooses. I should have added that it runs inside the Glassfish client container though.


                            What I want to do is use the standard scopes of CDI (request, session, conversation and application) on my server side EJB's, without going through a servlet engine, but using RMI/IIOP directly.


                            As you point out (6.7.1), it should work regardless of whether the activation goes through the servlet layer or via RMI. However, as my first example shows, this does not seem to work out of the box with the current Glassfish release, either because:





                            1. Its a bug in Weld/Glassfish

                            2. I'm doing something stupid

                            3. CDI is not required to support RMI activations unless you go through a servlet layer first




                            In case 1 or 2 I'm not really concerned (but please tell me if I'm doing something stupid!) :)


                            If it is case 3, then I want the community's opinion on whether RMI/IIOP is still a viable protocol if we want to adopt CDI on the server using the standard scope types.


                            Thanks for the time, I hope that clears things up a bit.

                            • 11. Re: Using request scope with remote EJB
                              swiegersf.francois.swiegers.gmail.com



                              As you point out (6.7.1), it should work

                              Just to correct, you said the request scope should work, not necessarily the session or conversation scopes.

                              • 12. Re: Using request scope with remote EJB
                                gavin.king

                                Well, 3 is certainly not true, according to the spec.

                                • 13. Re: Using request scope with remote EJB
                                  swiegersf.francois.swiegers.gmail.com

                                  Thanks


                                  If I want my RMI server to also support SessionScoped and ConversationScoped contexts (these, as far as I can see, is not required to be supported outside of the servlet context), what are my practical options for doing this?



                                  1. Implement a custom scope

                                  2. Use an interceptor to activate the scope



                                  Neither of these approaches are perfect (but I think 2 is better than 1), is there another way that I'm unaware of?


                                  • 14. Re: Using request scope with remote EJB
                                    pmuir

                                    This is a bug in GlassFish, they need to register org.jboss.weld.ejb.SessionBeanInterceptor as an EJB interceptor in any app which has CDI enabled (as documented in A.2 of the Weld ref guide). Please raise an issue in the GlassFish issue tracker.

                                    1 2 Previous Next