12 Replies Latest reply on Jun 20, 2008 12:51 PM by alrubinger

    Unit Tests for Unbinding References from JNDI in EJB3 Proxy

    alrubinger

      Jaikiran:

      Got another one I might be able to goad off to you. ;)

      Today I committed enhancements to /projects/ejb3/trunk/proxy/src/main/java/org/jboss/ejb3/proxy/jndiregistrar/JndiSessionRegistrarBase.java, specifically the addition of an "unbindEjb" method. The responsibility of this function is to remove all JNDI bindings for the specified EJB, and is likely called upon undeployment.

      Left the unit tests for you, figured it'd be a good entry into getting deeper into the EJB3 Proxy component codebase to see how things work. What we'll need is a test to:

      * Deploy an EJB (there are already a couple sample ones available in src/test/java)
      * Test that all expected bindings are there (very similar to what is done "proxy session" tests)
      * Undeploy the EJB
      * Test that all the previous bindings are no longer available (ie. NameNotFoundException on lookup)

      The tests themselves won't be tricky, but the setup, deployment, and creation of the test environment should prove educational. Questions either to here or IRC @ Freenode, #jboss-ejb3.

      http://jira.jboss.com/jira/browse/EJBTHREE-1420

      I'll see if I can't cook up another project after this that'll get you writing code in src/main/java, and off these tests. :)

      S,
      ALR

      PS - I still can't assign you tasks in JIRA; will see what I can do about this.

        • 1. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
          alrubinger

           

          "ALRubinger" wrote:
          PS - I still can't assign you tasks in JIRA; will see what I can do about this.


          The powers that be, did. You're all set. Just check that the email in your JIRA profile is up-to-date so you can receive alerts.

          S,
          ALR

          • 2. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
            jaikiran

            Andrew,

            I have started work on this. A few questions:

            1) I don't see a API which returns me a JndiSessionRegistrarBase, which i can use for calling the unbindEjb. I do see a setJndiRegistrar(JndiSessionRegistrarBase jndiRegistrar) on the SessionContainer. From what i have seen so far, the Ejb3Registrar (which i get from Ejb3RegistrarLocator.locateRegistrar) has an unbind method which will invoke the JndiSessionRegistrarBase.unbindEjb? So the test case should use the Ejb3Registrar for testing the JndiSessionRegistrarBase's unbindEjb?

            2) While trying out simple SLSB for this test case, i observed that the @RemoteBinding and the @LocalBinding values are not used for binding the EJBs. The EJBs always get bound to the default jndi names (ex: beanname/remote and beanname/local). Here's the bean definition:

            @Stateless
            @Local(MyStatelessLocal.class)
            @Remote(MyStatelessRemote.class)
            @RemoteBinding (jndiBinding="MyStatelessBeanRemote")
            @LocalBinding (jndiBinding="MyStatelessBeanLocal")
            public class MySLSBean implements MyStatelessLocal, MyStatelessRemote


            And here's the logs that i see:

            19:47:25,284 DEBUG [Ejb3McRegistrar] Created Ejb3McRegistrar with backing Kernel: org.jboss.kernel.Kernel@d251a3
            19:47:25,284 DEBUG [Ejb3RegistrarLocator] Bound Ejb3Registrar: org.jboss.ejb3.common.registrar.plugin.mc.Ejb3McRegistrar@1f5d386
            19:47:25,284 DEBUG [EmbeddedTestMcBootstrap] Deploying file:/D:/JBoss/EJB3/proxy/target/tests-classes/org/jboss/ejb3/test/proxy/jndiregistrar/unit/JndiSessionRegistrarBaseTestCase-beans.xml...
            19:47:26,284 WARN [BeanAnnotationAdapterFactory] Exception while creating bean annotation adapter instance: java.lang.IllegalAccessException: Class org.jboss.reflect.plugins.introspection.ReflectionUtils can not access a member of class org.jboss.kernel.plugins.annotations.BasicBeanAnnotationAdapter with modifiers "protected"
            19:47:26,440 DEBUG [JndiSessionRegistrarBase] Using Session EJB JNDI ObjectFactory: org.jboss.ejb3.proxy.objectfactory.session.stateless.StatelessSessionProxyObjectFactory
            19:47:26,628 INFO [EmbeddedTestMcBootstrap] Deployed: file:/D:/JBoss/EJB3/proxy/target/tests-classes/org/jboss/ejb3/test/proxy/jndiregistrar/unit/JndiSessionRegistrarBaseTestCase-beans.xml
            19:47:26,878 INFO [MetaDataHelper] Business Remote JNDI Name: MySLSBean/remote
             19:47:26,878 INFO [MetaDataHelper] Business Remote JNDI Name for org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessRemote: MySLSBean/remote-org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessRemote
            19:47:26,878 INFO [MetaDataHelper] Local JNDI Name: MySLSBean/local
            19:47:26,878 INFO [MetaDataHelper] Business Local JNDI Name for org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessLocal: MySLSBean/local-org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessLocal
            19:47:27,253 INFO [SessionContainer] Starting org.jboss.ejb3.test.proxy.common.container.StatelessContainer@1ba94d
            19:47:27,253 DEBUG [Ejb3McRegistrar] Returning from name "org.jboss.ejb3.JndiRegistrar.Session.SLSBJndiRegistrar": org.jboss.ejb3.proxy.jndiregistrar.JndiStatelessSessionRegistrar@7cd37a
            19:47:27,253 DEBUG [JndiSessionRegistrarBase] Found Session Bean: MySLSBean
            19:47:27,269 DEBUG [JndiStatelessSessionRegistrar] Registering with Remoting Dispatcher under name "MySLSBean/remote/ProxyFactory": org.jboss.ejb3.proxy.factory.session.stateless.StatelessSessionRemoteProxyFactory@16dc861
            19:47:27,269 DEBUG [JndiSessionRegistrarBase] Registering org.jboss.ejb3.proxy.factory.session.stateless.StatelessSessionRemoteProxyFactory@16dc861 under key "MySLSBean/remote/ProxyFactory"...
            19:47:27,284 DEBUG [ProxyFactoryBase] Started: org.jboss.ejb3.proxy.factory.session.stateless.StatelessSessionRemoteProxyFactory@16dc861
            19:47:27,284 DEBUG [SessionProxyFactoryBase] Created Session Bean Business Interface-Specific Proxy Constructor implementing "org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessRemote"
            19:47:27,284 DEBUG [SessionProxyFactoryBase] Created Session Bean Default EJB3 Business Proxy Constructor implementing [interface org.jboss.ejb3.proxy.intf.EjbProxy, interface org.jboss.ejb3.proxy.intf.SessionProxy, interface org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessRemote]
            19:47:27,284 DEBUG [Ejb3McRegistrar] Installed in AbstractKernelController@bf053f{} at "MySLSBean/remote/ProxyFactory": org.jboss.ejb3.proxy.factory.session.stateless.StatelessSessionRemoteProxyFactory@16dc861
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Adding RefAddr to Default Remote Reference: Type "Remote Business Interface", Content "org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessRemote"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Adding RefAddr to Default Remote Reference: Type "Remoting Host URL", Content "socket://localhost:3874"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Default Remote Business View for EJB MySLSBean to be bound into JNDI at "MySLSBean/remote"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Adding RefAddr to Reference: Type "ProxyFactoryKey", Content "MySLSBean/remote/ProxyFactory"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Adding RefAddr to Reference: Type "EJB Container Name", Content "org.jboss.ejb3.EJBContainer.StatelessSession.MySLSBean/f75a7411-0375-4ab4-aba0-48ea9e818a81"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Bound javax.naming.Reference into JNDI at "MySLSBean/remote"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Remote Business View for org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessRemote of EJB MySLSBean to be bound into JNDI at "MySLSBean/remote-org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessRemote"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Adding RefAddr to Reference: Type "ProxyFactoryKey", Content "MySLSBean/remote/ProxyFactory"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Adding RefAddr to Reference: Type "EJB Container Name", Content "org.jboss.ejb3.EJBContainer.StatelessSession.MySLSBean/f75a7411-0375-4ab4-aba0-48ea9e818a81"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Bound javax.naming.Reference into JNDI at "MySLSBean/remote-org.jboss.ejb3.test.proxy.jndiregistrar.MyStatelessRemote"
            19:47:27,300 DEBUG [JndiSessionRegistrarBase] Registering org.jboss.ejb3.proxy.factory.session.stateless.StatelessSessionLocalProxyFactory@cf829d under key "MySLSBean/local/ProxyFactory"...
            19:47:27,315 DEBUG [ProxyFactoryBase] Started: org.jboss.ejb3.proxy.factory.session.stateless.StatelessSessionLocalProxyFactory@cf829d
            


            Is this intentional to neglect the @RemoteBinding and @LocalBinding?




            • 3. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
              jaikiran

               

              "jaikiran" wrote:

              Is this intentional to neglect the @RemoteBinding and @LocalBinding?




              Just happened to see this http://www.jboss.com/index.html?module=bb&op=viewtopic&t=137339. I guess that's the reason why the annotations are not being picked up.


              • 4. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                alrubinger

                 

                "jaikiran" wrote:
                1) I don't see a API which returns me a JndiSessionRegistrarBase, which i can use for calling the unbindEjb.


                We've got mock Containers in EJB3 Proxy under src/test/java, so if you're installing your EJB into them, this logic is done for ya. :) Check out how the other session tests use these containers.

                "jaikiran" wrote:
                Just happened to see this http://www.jboss.com/index.html?module=bb&op=viewtopic&t=137339. I guess that's the reason why the annotations are not being picked up.


                Yep. If you want to mock it up, the place to add this logic is in EJB3 Test, MetaDataHelper. Though probably isn't worth the effort; I see that Alexey's tests for JBoss50Creator (the piece responsible for handling JBoss-specific annotations) are now passing, so I'll probably try to change over to use this soon.

                S,
                ALR

                • 5. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                  alrubinger

                   

                  "ALRubinger" wrote:
                  Though probably isn't worth the effort; I see that Alexey's tests for JBoss50Creator (the piece responsible for handling JBoss-specific annotations) are now passing, so I'll probably try to change over to use this soon.


                  Done.

                  http://jira.jboss.com/jira/browse/EJBTHREE-1422

                  So of course now we have:

                  http://jira.jboss.com/jira/browse/EJBTHREE-1423

                  S,
                  ALR

                  • 6. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                    jaikiran

                     

                    "ALRubinger" wrote:
                    Though probably isn't worth the effort; I see that Alexey's tests for JBoss50Creator (the piece responsible for handling JBoss-specific annotations) are now passing, so I'll probably try to change over to use this soon.

                    Done.

                    http://jira.jboss.com/jira/browse/EJBTHREE-1422

                    So of course now we have:

                    http://jira.jboss.com/jira/browse/EJBTHREE-1423

                    S,
                    ALR


                    I have a test case for EJBTHREE-1423 which fails even after we changed the MetaDataHelper to use JBoss50Creator.

                    @Stateless
                    @Remote (MyStatelessRemote.class)
                    @Local (MyStatelessLocal.class)
                    @RemoteBinding (jndiBinding = "MySLSBeanRemote")
                    @LocalBinding (jndiBinding = "MySLSBeanLocal")
                    public class MySLSBean implements MyStatelessLocal, MyStatelessRemote
                    {
                    


                    MetaDataHelper:

                    JBossMetaData metadata = new JBoss50Creator(finder).create(classes);
                    
                     // Get delegate
                     JBossSessionBeanMetaData beanMetaDataDelegate = (JBossSessionBeanMetaData) metadata
                     .getEnterpriseBean(beanImplClass.getSimpleName());
                    
                    // Mock up a @RemoteBinding if none specified but are required
                     if ((beanMetaDataDelegate.getBusinessRemotes() != null || beanMetaDataDelegate.getHome() != null)
                     && (beanMetaDataDelegate.getRemoteBindings() == null || beanMetaDataDelegate.getRemoteBindings().size() == 0))

                    The beanMetaDataDelegate.getRemoteBindings() returns null in the MetaDataHelper.

                    I came up with a test case for the JBossMetadata project to test this on the JBossMetadata trunk and even that fails. The @RemoteBinding (and @LocalBinding) are not yet being picked up. I'll probably wait for http://jira.jboss.com/jira/browse/JBMETA-45 to be done before moving ahead with the EJBTHREE-1423 test case.

                    • 7. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                      alrubinger

                       

                      "jaikiran" wrote:
                      I'll probably wait for http://jira.jboss.com/jira/browse/JBMETA-45 to be done before moving ahead with the EJBTHREE-1423 test case.


                      Yep. You can add a dependency on the JIRA task.

                      S,
                      ALR

                      • 8. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                        alrubinger

                        Some notes regarding Jaikiran's patch now attached to EJBTHREE-1420:

                        * Overall, the test looks good and follows the proper setup. :)
                        * Needs LGPL Headers and Copyright info (these should be in the Eclipse templates I'd send along)
                        * Tests must check not only the default local and remote bind values, but also those of the interface-specific bindings
                        * Already provided are SLSB and SFSB EJBs in the "common" test package; we can use these and do away with the ones specific to the "jndiregistrar" test package.
                        * The tests are checking for hardcoded JNDI bind values. Instead, should be checking against the same values used by Proxy; these are obtained from metadata:

                        JBossSessionBeanMetaData md = statelessSessionContainer.getMetaData();
                        md.getLocalHomeJndiName(); // Local Home Binding
                        md.getHomeJndiName(); // Remote Home Binding
                        md.determineJndiName(); // Default Business Remote Binding
                        md.determineLocalJndiName(); // Default Business Local Binding
                        BusinessRemotesMetaData businessRemotes = md.getBusinessRemotes();
                        for(String businessRemoteInterfaceName : businessRemotes)
                        {
                         md.determineResolvedJndiName(businessRemoteInterfaceName); // Interface-specific business remote JNDI Binding
                        }
                        BusinessLocalsMetaData businessLocals = md.getBusinessLocals();
                        for(String businessLocalInterfaceName: businessLocals)
                        {
                         md.determineResolvedJndiName(businessLocalInterfaceName); // Interface-specific business local JNDI Binding
                        }


                        The important thing is that the test setup looks great. :)

                        S,
                        ALR

                        • 9. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                          jaikiran

                          Andrew, thanks very much for reviewing the test case. I have started incorporating the comments.

                          "ALRubinger" wrote:

                          * Tests must check not only the default local and remote bind values, but also those of the interface-specific bindings


                          I do see the test cases and the logs which show that each bean binds to the default business JNDI name and also a interface-specific JNDI name. But what exactly is the difference between the default and the interface specific bindings? Let me know if i need to look up some document where this is explained.
                          For example, in this bean what gets bound to the interface specific jndi name and the what gets bound to the default jndi name?

                          @Stateless
                          @Local(MyStatelessLocal.class)
                          @Remote(MyStatelessRemote.class)
                          public class MyStateless30OnlyBean implements MyStatelessLocal, MyStatelessRemote
                          



                          "ALRubinger" wrote:

                          * Already provided are SLSB and SFSB EJBs in the "common" test package; we can use these and do away with the ones specific to the "jndiregistrar" test package.


                          I'll start using the "common" EJBs. I introduced the beans in the "jndiregistrar" to keep these test cases in the jndiregistrar, self-contained. But looking at the EJBs in the "common" package, looks like they were meant to be used across test cases.

                          "ALRubinger" wrote:

                          * The tests are checking for hardcoded JNDI bind values. Instead, should be checking against the same values used by Proxy; these are obtained from metadata:

                          JBossSessionBeanMetaData md = statelessSessionContainer.getMetaData();
                          md.getLocalHomeJndiName(); // Local Home Binding
                          md.getHomeJndiName(); // Remote Home Binding
                          md.determineJndiName(); // Default Business Remote Binding
                          md.determineLocalJndiName(); // Default Business Local Binding
                          BusinessRemotesMetaData businessRemotes = md.getBusinessRemotes();
                          for(String businessRemoteInterfaceName : businessRemotes)
                          {
                           md.determineResolvedJndiName(businessRemoteInterfaceName); // Interface-specific business remote JNDI Binding
                          }
                          BusinessLocalsMetaData businessLocals = md.getBusinessLocals();
                          for(String businessLocalInterfaceName: businessLocals)
                          {
                           md.determineResolvedJndiName(businessLocalInterfaceName); // Interface-specific business local JNDI Binding
                          }



                          Thanks! I wasn't aware of those APIs :)


                          One more question - Once the bean is unbound from the JNDI registry using:

                          Ejb3RegistrarLocator.locateRegistrar().unbind(statelessSessionContainer.getName());


                          Is the JBossMetaData present in the statelessSessionContainer (which got unbound) expected to still maintain the jndi names? Ex: Is the metadata.determineJndiName() expected to return the jndi name after the bean was unbound? Or is it expected to return null?




                          • 10. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                            alrubinger

                             

                            "jaikiran" wrote:
                            I do see the test cases and the logs which show that each bean binds to the default business JNDI name and also a interface-specific JNDI name. But what exactly is the difference between the default and the interface specific bindings?


                            This was put in place to support SessionContext.getInvokedBusinessInterface();.

                            The default business (remote|local) binding supports all business (remote|local) interfaces declared by the bean. This is the legacy behaviour, and from this "getInvokedBusinessInterface" is non-deterministic; the Proxy can be cast to any of the Business interfaces at compile-time, but the runtime has no way of knowing which business interface was invoked.

                            So we introduced the notion of a an "interface-specific" binding, which has the necessary information within the Proxy itself to allow the Container to know which business interface was invoked.

                            Check out the (lengthy) method in JndiSessionRegistrarBase.bindEjb for details in the comments.

                            "jaikiran" wrote:
                            One more question - Once the bean is unbound from the JNDI registry using:

                            Ejb3RegistrarLocator.locateRegistrar().unbind(statelessSessionContainer.getName());


                            Is the JBossMetaData present in the statelessSessionContainer (which got unbound) expected to still maintain the jndi names? Ex: Is the metadata.determineJndiName() expected to return the jndi name after the bean was unbound? Or is it expected to return null?


                            Yep, it's just metadata and should remain intact.

                            S,
                            ALR

                            • 11. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                              jaikiran

                              Thanks Andrew. Based on these inputs and the review comments, i have now updated the test case. The updated test case has been attached to the JIRA issue EJBTHREE-1420.

                              • 12. Re: Unit Tests for Unbinding References from JNDI in EJB3 Pr
                                alrubinger

                                Jaikiran:

                                This patch looks good, and is passing for me locally (added bonus). Just make sure your commit message has the associated JIRA reference in there. :)

                                S,
                                ALR