3 Replies Latest reply on Apr 13, 2007 10:36 AM by Adrian Brock

    Russian dolls and implicit deployment ordering

    Bill Burke Master

      I don't think creating a pluggable implicit deployment ordering policy is what we should be spending our time on. Russian dolls and other implicit deployent policies are just hiding some of the inherent problems that exist in our code. Specifically, that too many components are using JNDI to obtain references to external services. If we fixed this problem, I don't think we would need to write implicit ordering policies.

      So how do we fix it?

      1) We need a registration deployer as well a parsing and real deployer. Why? Take EJB. @EJB usually does not have any more information for its reference other than the interface type it wants to inject. This is why the EJB deployer is broken up into 2 separate deployers. The Registration Deployer extracts basic metadata like EJB name, exposed business interfaces and registers an unstarted EJB container with an EJB registry. This is needed so that other EJB containers that have an @EJB reference can locate the "real" EJB container bean they depend on and create a kernel dependency. @PersistenceUnit references have similar issues.

      2) Stop using JNDI to inject components. Any component that uses a datasource is a culprit. MDB/JMS connector and their destination/connector dependencies are also a culprit. We tried to solve the datasource problem in the EJB container by trying to create a kernel/JMX ObjectName from the datasource JNDI name provided so that we could create a hard dependency. This becomes a problem when JCA gets refactored as we have to write adapters for each JCA implementation to generate these dependencies. So, what I'm saying is that I think the approach of guessing the kernel name based on the JNDI name is too fragile and JCA needs to provide an SPI to give us this capability.

      3) Expand our JNDI implementation so that it could be hooked into the MC's controller. So, when things get bound into JNDI, the kernel is notified and could unblock a JNDI dependency. THis is just an idea.

      4) Create a JNDI reference bean that polls JNDI for a specific entry, and when it is available triggers a state change in the MC Controller for beans depending on that entry.

      I don't think solution #2 is going to solve every JNDI dependency problem. Sometimes, specifically in MDB land, we will be working with thirdparty components and not be able to create a hard kernel dependency because the thirdparty components. #3 is a good option, but may not solve corner cases where a component depends on an external JNDI implementation (i.e. LDAP). #4 maybe the best solution as it could probably even be backported to 4.x.

      Thoughts?

        • 1. Re: Russian dolls and implicit deployment ordering
          Adrian Brock Master

           

          "bill.burke@jboss.com" wrote:

          3) Expand our JNDI implementation so that it could be hooked into the MC's controller. So, when things get bound into JNDI, the kernel is notified and could unblock a JNDI dependency. THis is just an idea.


          You can do this now with a KernelRegistryPlugin

          <bean name="JNDIPlugin" class="org.jboss.naming.JNDIPlugin">
           <property name="environment"><!-- jndi config here --></property>
          </bean>
          
          public class JNDIPlugin implements KernelRegistryPlugin
          {
           private Properties environment;
          
           public void setEnvironment(Properties environment)
           {
           this.environment = environment;
           }
          
           public KernelRegistryEntry getEntry(Object name)
           {
           if (name instanceof String == false)
           return null;
          
           InitialContext context;
           if (environment != null)
           context = new InitialContext(environment);
           else
           context = new InitialContext();
          
           try
           {
           Object o = context.lookup(name);
           if (o == null)
           return null;
           else
           return new AbstractKernelRegistry(o);
           }
           finally
           {
           context.close();
           }
           }
          }
          


          This has some advantages:
          1) It works with any jndi implementation
          2) It works with remote jndi implementation
          3) It doesn't require any work from anybody else

          It has lots of disadvantages:
          1) Namespace conflicts, e.g. jndi name matches a bean name
          2) It is going to be slow for remote jndi
          3) There is nothing that initiates a recheck when jndi bindings appear or disappear
          (although implementing jndi events api might facilitate this?)
          4) You can only depend on the thing existing,
          i.e. there are two states NOT_INSTALLED and INSTALLED
          5) Probably some others? :-)

          I much prefer the idea of using AOP (decorators) to handle jndi binding.
          @JNDIBinding(...)
          public class MyClass
          
          or
          
          <bean ...>
           <annotation>@JNDIBinding(name="whatever")</annotation>
          </bean>
          


          Because:
          1) You can change what the jndi binding action means in different environments,
          e.g. JBoss or Tomcat, without changing the configuration
          2) It enables all sorts of other useful features, like not even binding into
          jndi at all (for client usage) until the barrier service says "open the gates"
          we're ready to go.

          • 2. Re: Russian dolls and implicit deployment ordering
            Adrian Brock Master

             

            "adrian@jboss.org" wrote:

            I much prefer the idea of using AOP (decorators) to handle jndi binding.
            @JNDIBinding(...)
            public class MyClass
            
            or
            
            <bean ...>
             <annotation>@JNDIBinding(name="whatever")</annotation>
            </bean>
            


            Because:
            1) You can change what the jndi binding action means in different environments,
            e.g. JBoss or Tomcat, without changing the configuration
            2) It enables all sorts of other useful features, like not even binding into
            jndi at all (for client usage) until the barrier service says "open the gates"
            we're ready to go.


            This should also fit in with your requirement to know the jndi mapping to kernel
            dependency. The JNDI Binding aspect (since it is a "decorator") can do:

            Pseudo code:
            public void install(ControllerContext context)
            {
             JNDIBinding jndi = context.getMetaData().getAnnotation(JNDIBinding.class);
             if (jndi != null)
             map.put(jndi.name(), context.getName());
            }
            


            • 3. Re: Russian dolls and implicit deployment ordering
              Adrian Brock Master

              Also since we are currently developing support for aliases,
              this is another mechanism that could be used.

              e.g. When JCA creates its BeanMetaData or ServiceMetaData it could
              add an alias that is the jndi name,
              OR the JNDIBinding decorator could register it as a dynamic alias:
              http://jira.jboss.com/jira/browse/JBMICROCONT-170