1 2 Previous Next 18 Replies Latest reply on Mar 14, 2008 10:07 AM by starksm64

    Generalizing dependency injection

    starksm64

      What I'm currently working on is how we are redoing the ejb3 injection layer to be a generalized mc based version. The pieces are:

      - The MappedReferenceMetaDataResolverDeployer creates a map of endpoint names to resolved names in the top DeploymentUnit under the attachment name MappedReferenceMetaDataResolverDeployer.endpointMap. The endpoint names are of the forms:
      + "ejb/" + vfsPath + ejbName : for ejbs in the deployment
      + "ejb/" + vfsPath + local-interface name : for BusinessLocals
      + "ejb/" + vfsPath + remote-interface name : for BusinessRemotes
      + "message-destination/" + vfsPath + destName : for MessageDestinations
      - Each ee container creates KernelDeployment/BeanMetaData attachments for its components using a bean factory that ties into the container pooling. I'm fuzzy on the bean factory details in terms of whether the pooling is something that can live in the mc code.
      - DependencyInjectionDeployer wires the beans together using the MappedReferenceMetaDataResolverDeployer referencer to referencee mappings to add the dependencies to the component BeanMetaData.

      I'm currently looking at this in the context of the ejb2 deployer to see what issues show up for mixing mbean/mcbean components together. Once that is working the ejb3, client and war deployers can be updated in a similar fashion.

        • 1. Re: Generalizing dependency injection
          alesj

           

          "scott.stark@jboss.org" wrote:
          I'm fuzzy on the bean factory details in terms of whether the pooling is something that can live in the mc code.

          To repeat my 'proposal' more publicly.
          I don't know how much this would help, but we can make our MC beanfactory more flexible by doing something like this:
          e.g. able to change the underlying impl class from GenericBeanFactory to anything that implments BeanFactory
          And I would also change the BeanFactory.createBean() method signature to createBean(Object... args).
          Being able to pass in additional information when creating/pooling bean.
          And we wouldn't be breaking any previous beanfactory usage.


          • 2. Re: Generalizing dependency injection
            wolfc

            Business interfaces can be implemented by multiple beans, so there must be a clarifier in between.
            + "ejb/" + vfsPath + local-interface name + "/" + ejbName
            should work.
            If we then get a non-deterministic injection we can throw an exception.
            Why not reverse it a bit:
            + "ejb/" + local-interface name + vfsPath + "/" + ejbName
            then traversal is a bit easier in case multiple jars within one ear contain the same interface.

            • 3. Re: Generalizing dependency injection
              starksm64

               

              "wolfc" wrote:
              Business interfaces can be implemented by multiple beans, so there must be a clarifier in between.
              + "ejb/" + vfsPath + local-interface name + "/" + ejbName should work.

              If we then get a non-deterministic injection we can throw an exception.
              Why not reverse it a bit:
              + "ejb/" + local-interface name + vfsPath + "/" + ejbName
              then traversal is a bit easier in case multiple jars within one ear contain the same interface.

              Working through the resolution implementation more, we want a simple lookup to resolve a reference, so the ejbName of the providing cannot be part of at least one form of the key. That is an unknown element from the point of view of the referencer. We need multiple keys for each provider, some of which may be non-unique.

              @EJB(beanInterface=X.class)
              

              translates to a lookup of the provider "ejb/X". If we have multiple providers of the X interface, only the first to be processed would be the provider? If we want to fail an attempt at injection of a non-unique provider, we would have to track the duplicate providers to thrown an exception with the duplicates.

              @EJB(beanInterface=X.class, name="XBean")
              

              translates to a lookup of "ejb/X/XBean". The ejb-name is only unique within an ejb-jar, so here again we can have duplicates sources matching this key.

              @EJB(beanInterface=X.class, name="some.jar#XBean")
              

              translates to a lookup of "ejb/X/some.jar/XBean". This is the only guaranteed unique key within a deployment.


              • 4. Re: Generalizing dependency injection
                wolfc

                 

                "alesj" wrote:
                "scott.stark@jboss.org" wrote:
                I'm fuzzy on the bean factory details in terms of whether the pooling is something that can live in the mc code.

                To repeat my 'proposal' more publicly.
                I don't know how much this would help, but we can make our MC beanfactory more flexible by doing something like this:
                e.g. able to change the underlying impl class from GenericBeanFactory to anything that implments BeanFactory
                And I would also change the BeanFactory.createBean() method signature to createBean(Object... args).
                Being able to pass in additional information when creating/pooling bean.
                And we wouldn't be breaking any previous beanfactory usage.

                What would the args be?

                • 5. Re: Generalizing dependency injection
                  wolfc

                   

                  "scott.stark@jboss.org" wrote:
                  Working through the resolution implementation more, we want a simple lookup to resolve a reference, so the ejbName of the providing cannot be part of at least one form of the key. That is an unknown element from the point of view of the referencer. We need multiple keys for each provider, some of which may be non-unique.
                  @EJB(beanInterface=X.class)

                  translates to a lookup of the provider "ejb/X". If we have multiple providers of the X interface, only the first to be processed would be the provider? If we want to fail an attempt at injection of a non-unique provider, we would have to track the duplicate providers to thrown an exception with the duplicates.

                  Exception if there are multiple providers are found in the same ear.
                  "scott.stark@jboss.org" wrote:

                  @EJB(beanInterface=X.class, name="XBean")

                  translates to a lookup of "ejb/X/XBean". The ejb-name is only unique within an ejb-jar, so here again we can have duplicates sources matching this key.

                  We are talking MC lookups here, right?
                  "scott.stark@jboss.org" wrote:

                  @EJB(beanInterface=X.class, name="some.jar#XBean")

                  translates to a lookup of "ejb/X/some.jar/XBean". This is the only guaranteed unique key within a deployment.

                  And I say reverse the bind. So the bind becomes:
                  "ejb/X/some.jar/XBean"

                  some.jar:
                  class TestBean { @EJB X a; }

                  Hooks java:comp/env/TestBean/a to MC "ejb/X/some.jar" (which is a map). If the during injection the map contains more than 1 item, exception.
                  @EJB(beanName="XBean") X b;

                  Hooks java:comp/env/TestBean/b to MC "ejb/X/some.jar/XBean".
                  @EJB(beanName="other.jar#XBean") X c;

                  Hooks java:comp/env/TestBean/c to MC "ejb/X/other.jar/XBean".

                  Note: 'name' is something else:
                  @EJB(name="x", beanName="XBean") X d;

                  Hooks java:comp/env/x to MC "ejb/X/some.jar/XBean".

                  • 6. Re: Generalizing dependency injection
                    alesj

                     

                    "wolfc" wrote:
                    What would the args be?

                    Anything you like. :-)

                    Making it a bit more portable.
                    But then again, if you were able to change the underlying beanfactory impl, you could always introduce your own interface.

                    • 7. Re: Generalizing dependency injection
                      wolfc

                      I think we need to separate injection and component construction (/destruction).

                      It seems we're forgetting again that a component class = 1 bean class + interceptor classes. So interceptor lifecycle is tied to the bean. While injection follows the same rules.

                      At the end of the day I want to have something like:

                      package org.jboss.ejb3.pool;
                      
                      /**
                       * Creates and destroys stateless objects.
                       *
                       * The object returned by create has dependencies injected. The PostConstruct
                       * callback, if defined, has been called.
                       *
                       * @author <a href="mailto:carlo.dewolf@jboss.com">Carlo de Wolf</a>
                       * @version $Revision: $
                       */
                      public interface StatelessObjectFactory<T>
                      {
                       /**
                       * Creates a new stateless object by calling it's empty constructor,
                       * do injection and calling post-construct.
                       *
                       * @return
                       */
                       T create();
                      
                       /**
                       * Perform any cleanup actions on the object, such as
                       * calling the pre-destroy callback.
                       *
                       * @param obj the object
                       */
                       void destroy(T obj);
                      }

                      http://viewvc.jboss.org/cgi-bin/viewvc.cgi/jbossas/projects/ejb3/trunk/pool/src/main/java/org/jboss/ejb3/pool/StatelessObjectFactory.java?view=markup

                      Behind the scenes it delegates to 'bean factory' for construction which delegates to injection for each object which is part of the component.

                      • 8. Re: Generalizing dependency injection
                        starksm64

                        An extension of org.jboss.beans.metadata.spi.factory.BeanFactory is needed:

                        public interface BeanFactory
                        {
                         /**
                         * Create bean.
                         *
                         * @return bean
                         * @throws Throwable for any error
                         */
                         Object createBean() throws Throwable;
                        }
                        public interface PooledBeanFactory extends BeanFactory
                        {
                         destroy(Object instance) throws Throwable;
                        }
                        




                        • 9. Re: Generalizing dependency injection

                          I thought EJB3 used its own thread local pooling to avoid contention?
                          Personally I think object pooling is an anti-pattern unless the constructed object
                          has some intensive construction steps.

                          • 10. Re: Generalizing dependency injection
                            wolfc

                            Pooling is not part of the mix right here. It's the next level.
                            What I showed is the interface with which EJB 3 pooling delegates for component creation. The factory needs to be injected into a pool.

                            There are both patterns and anti-patterns to pooling. What I showed at JBW was a resource-starvation scenario which makes EJB 3 (/ pooling) behave better than MC (/ instance). The question is whether to incorporate something like that in MC, but that's not what this thread is about. :-)

                            So pooling (which is outside of scope) will delegate to a component factory which will delegate to injection. So the pool is a higher level assembly.

                            • 11. Re: Generalizing dependency injection

                               

                              "wolfc" wrote:

                              There are both patterns and anti-patterns to pooling. What I showed at JBW was a resource-starvation scenario which makes EJB 3 (/ pooling) behave better than MC (/ instance). The question is whether to incorporate something like that in MC, but that's not what this thread is about. :-)


                              OK then OFF-TOPIC

                              Pooling has nothing to do with what you are talking about. Using a factory
                              to create a new instance of stateless object without pooling
                              rather than using a singleton also has the nice behaviour of not causing contention
                              and not having to worry about thread safety etc.

                              ON-TOPIC

                              I agree, the factory should just be used to create objects for any pooling
                              implementation ejb3 or the user cares to implement (including none :-).

                              • 12. Re: Generalizing dependency injection
                                wolfc

                                OFF-TOPIC :-)

                                Suppose I have a data source pool of 100 and I have two session beans which make use of that data source. One performs the search function for end users, the other is the admin interface.
                                Now I don't want to starve the data source by having 100 searchers active (and more in queue) while the admin is waiting to get anything done. So search bean will be pool limited to 75 and admin will receive similar treatment.
                                I say EJB 3 is all about resource management. :-)

                                • 13. Re: Generalizing dependency injection

                                   

                                  "wolfc" wrote:
                                  OFF-TOPIC :-)

                                  Suppose I have a data source pool of 100 and I have two session beans which make use of that data source. One performs the search function for end users, the other is the admin interface.
                                  Now I don't want to starve the data source by having 100 searchers active (and more in queue) while the admin is waiting to get anything done. So search bean will be pool limited to 75 and admin will receive similar treatment.
                                  I say EJB 3 is all about resource management. :-)


                                  What you are describing is called "flow control". You can do it outside an EJB
                                  with an aspect, e.g. a semaphore controlling access to a singleton.

                                  If the semaphore/pool uses priority queuing the admin request
                                  can "jump the queue" based on a higher privilege.


                                  • 14. Re: Generalizing dependency injection
                                    wolfc

                                     

                                    "adrian@jboss.org" wrote:
                                    What you are describing is called "flow control". You can do it outside an EJB
                                    with an aspect, e.g. a semaphore controlling access to a singleton.

                                    If the semaphore/pool uses priority queuing the admin request
                                    can "jump the queue" based on a higher privilege.

                                    A pool beats a semaphored singleton anytime.

                                    1 2 Previous Next