10 Replies Latest reply on Mar 27, 2008 6:05 AM by alesj

    beanfactory extensions

    starksm64

      I need to be able to do something like this to delegate ee container injection to the mc:

      <deployment xmlns="urn:jboss:bean-deployer:2.0">
       <beanfactory name="PooledFactoryType1"
       factoryClass="org.jboss.test.kernel.deployment.support.container.TestPooledBeanFactory"
       class="org.jboss.test.kernel.deployment.support.container.BeanType1">
       <property name="prop1">prop1DefaultValue</property>
       </beanfactory>
       <bean name="BeanContainerType1" class="org.jboss.test.kernel.deployment.support.container.BeanContainer">
       <property name="factory"><inject bean="PooledFactoryType1"/></property>
       </bean>
      
       <beanfactory name="PooledFactoryType2"
       factoryClass="org.jboss.test.kernel.deployment.support.container.TestPooledBeanFactory"
       class="org.jboss.test.kernel.deployment.support.container.BeanType2">
       <property name="bean1"><inject bean="BeanContainerType1" property="bean"/></property>
       </beanfactory>
       <bean name="BeanContainerType2" class="org.jboss.test.kernel.deployment.support.container.BeanContainer">
       <property name="factory"><inject bean="PooledFactoryType2"/></property>
       </bean>
      
       <bean name="BeanUser#1" class="org.jboss.test.kernel.deployment.support.container.BeanUser">
       <property name="bean1"><inject bean="BeanContainerType1" property="bean"/></property>
       <property name="bean2"><inject bean="BeanContainerType2" property="bean"/></property>
       </bean>
       <bean name="BeanUser#2" class="org.jboss.test.kernel.deployment.support.container.BeanUser">
       <property name="bean1"><inject bean="BeanContainerType1" property="bean"/></property>
       <property name="bean2"><inject bean="BeanContainerType2" property="bean"/></property>
       </bean>
      </deployment>
      


      The only missing piece right now is not being able to set a factoryClass on a beanfactory.

      The BeanContainer is only acting as a wrapper around the PooledFactoryType to expose the createBean method as a property. Arguably this can be dropped in factory of a factory injection notion that would call createBean() to obtain the injected value?

       <bean name="BeanUser#2" class="org.jboss.test.kernel.deployment.support.container.BeanUser">
       <property name="bean1"><inject factory="PooledFactoryType1" /></property>
       <property name="bean2"><inject factory="PooledFactoryType2"/></property>
       </bean>
      



        • 1. Re: beanfactory extensions
          alesj

           

          "scott.stark@jboss.org" wrote:

          The only missing piece right now is not being able to set a factoryClass on a beanfactory.

          I can hack this pretty fast.
          As long as it's approved. :-)

          "scott.stark@jboss.org" wrote:

          The BeanContainer is only acting as a wrapper around the PooledFactoryType to expose the createBean method as a property. Arguably this can be dropped in factory of a factory injection notion that would call createBean() to obtain the injected value?

          You already have this. ;-)
           <bean name="BeanUser#2" class="org.jboss.test.kernel.deployment.support.container.BeanUser">
           <property name="bean1"><value-factory bean="PooledFactoryType1" method="createBean" /></property>
           <property name="bean2"><value-factory bean="PooledFactoryType2" method="createBean"/></property>
           </bean>
          



          • 2. Re: beanfactory extensions
            starksm64

             

            "alesj" wrote:

            You already have this. ;-)

            Ok, that will work. Still seems like the BeanFactory is not as integrated as it could be, for example, showing up at the BeanMetaData level in place of a ctor.

            • 3. Re: beanfactory extensions

               

              "scott.stark@jboss.org" wrote:
              "alesj" wrote:

              You already have this. ;-)

              Ok, that will work. Still seems like the BeanFactory is not as integrated as it could be, for example, showing up at the BeanMetaData level in place of a ctor.


              It's deliberately "not as integrated as it could be".
              Because I want you to be able to write your own BeanMetaDataFactory
              to do whatever you like, e.g. see the VFSClassLoaderFactory in the new classloaders.

              If you can't write your own then theres something wrong with the rest of the api. ;-)

              The beanfactory/GenericBeanMetaDataFactory is just an example that happens
              to live in the MC codebase and xml namespace. :-)

              • 4. Re: beanfactory extensions

                 

                "alesj" wrote:
                "scott.stark@jboss.org" wrote:

                The only missing piece right now is not being able to set a factoryClass on a beanfactory.

                I can hack this pretty fast.
                As long as it's approved. :-)


                It should just be a case of adding an attribute to beanfactory to override the hardwired
                GenericBeanFactory implementation class?

                • 5. Re: beanfactory extensions
                  alesj

                   

                  "adrian@jboss.org" wrote:

                  It should just be a case of adding an attribute to beanfactory to override the hardwired GenericBeanFactory implementation class?

                  Yup.
                  That's why I said it will be pretty fast. ;-)


                  • 6. Re: beanfactory extensions
                    alesj

                     

                    "adrian@jboss.org" wrote:

                    It should just be a case of adding an attribute to beanfactory to override the hardwired GenericBeanFactory implementation class?

                    Do we leave it completely to the user if the new factory class doesn't have the right 'shape' to get all those things injected:
                     /** The configurator */
                     protected KernelConfigurator configurator;
                    
                     /** The bean class name */
                     protected String bean;
                    
                     /** The access mode */
                     protected BeanAccessMode accessMode;
                    
                     /** The classloader */
                     protected ClassLoaderMetaData classLoader;
                    
                     /** The constructor metadata */
                     protected ConstructorMetaData constructor;
                    
                     /** The properties Map<propertyName, ValueMetaData> */
                     protected Map<String, ValueMetaData> properties;
                    
                     /** The create lifecycle method */
                     protected LifecycleMetaData create;
                    
                     /** The start lifecycle method */
                     protected LifecycleMetaData start;
                    


                    I don't see what much we could do.
                    Perhaps GenericBeanFactoryMetaData::getBeans could return some extended AbstractBeanMetaData where we would override describeVisit method to check if the bean has appropriate hooks to do instantiation with KernelConfigurator parameter, configuration with all those properties, ...

                    • 7. Re: beanfactory extensions

                      Just document that the factory class should extend GenericBeanFactory
                      (or at least have the same "callbacks").

                      Raise a JIRA issue to turn this into a proper spi, but don't do it now,
                      I don't want any more moving targets over the next couple of days. :-)

                      • 8. Re: beanfactory extensions
                        alesj

                         

                        "adrian@jboss.org" wrote:

                        Raise a JIRA issue to turn this into a proper spi.

                        http://jira.jboss.com/jira/browse/JBMICROCONT-271

                        • 9. Re: beanfactory extensions
                          starksm64

                           

                          "adrian@jboss.org" wrote:

                          It's deliberately "not as integrated as it could be".
                          Because I want you to be able to write your own BeanMetaDataFactory
                          to do whatever you like, e.g. see the VFSClassLoaderFactory in the new classloaders.

                          If you can't write your own then theres something wrong with the rest of the api. ;-)

                          The beanfactory/GenericBeanMetaDataFactory is just an example that happens
                          to live in the MC codebase and xml namespace. :-)

                          Yes, but we are talking about different apis. The BeanFactory which creates instances and BeanMetaDataFactory which provides collections of BeanMetaData. Maybe BeanFactory is no longer preferred and the beanfactoryType description in bean-deployer_2_0.xsd referring to GenericBeanFactory is out of date. I see the GenericBeanMetaDataFactory is annotated as the beanfactoryType as well.

                          It seems both notions are needed, a BeanMetaDataFactory describes a collection of interrelated beans, the BeanFactory controls how instances are obtained. A javaee container has a BeanMetaDataFactory for its container/aspects, and a BeanFactory for obtaining instances.

                          Back to my other question about the benefit of a beanfactory (as in BeanFactory) vs a ctor factory, its a semantic difference only from the point of view of who is actually creating bean instances. The mc deployer InstantiateAction has a one instance to one BeanMetaData view.

                          I need a container notion where the state machine dependencies represented by the BeanMetaData collections end up injecting an instance that is a function of the "key" type for the bean and pooling policy. I guess this can be encapsulated in the injection value metadata, but its a bit abstract still.


                          • 10. Re: beanfactory extensions
                            alesj

                             

                            "adrian@jboss.org" wrote:

                            Raise a JIRA issue to turn this into a proper spi, but don't do it now,
                            I don't want any more moving targets over the next couple of days. :-)

                            What should we consider a proper spi here?

                            I've added this abstract class, which holds all the "callbacks" that are required from GenericBeanFactoryMetaData.

                            package org.jboss.beans.metadata.spi.factory;
                            
                            import java.util.Map;
                            import java.util.List;
                            
                            import org.jboss.beans.info.spi.BeanAccessMode;
                            import org.jboss.beans.info.spi.BeanInfo;
                            import org.jboss.beans.metadata.spi.ClassLoaderMetaData;
                            import org.jboss.beans.metadata.spi.ConstructorMetaData;
                            import org.jboss.beans.metadata.spi.LifecycleMetaData;
                            import org.jboss.beans.metadata.spi.ValueMetaData;
                            import org.jboss.beans.metadata.spi.ParameterMetaData;
                            import org.jboss.kernel.spi.config.KernelConfigurator;
                            import org.jboss.joinpoint.spi.MethodJoinpoint;
                            import org.jboss.joinpoint.spi.JoinpointException;
                            
                            /**
                             * SPI contract of bean factory we can create from GenericBeanFactoryMetaData.
                             *
                             * @author <a href="mailto:ales.justin@jboss.com">Ales Justin</a>
                             */
                            public abstract class AbstractBeanFactory implements BeanFactory
                            {
                             /** The configurator */
                             protected KernelConfigurator configurator;
                            
                             /** The bean class name */
                             protected String bean;
                            
                             /** The access mode */
                             protected BeanAccessMode accessMode;
                            
                             /** The classloader */
                             protected ClassLoaderMetaData classLoader;
                            
                             /** The constructor metadata */
                             protected ConstructorMetaData constructor;
                            
                             /** The properties Map<propertyName, ValueMetaData> */
                             protected Map<String, ValueMetaData> properties;
                            
                             /** The create lifecycle method */
                             protected LifecycleMetaData create;
                            
                             /** The start lifecycle method */
                             protected LifecycleMetaData start;
                            
                             protected AbstractBeanFactory(KernelConfigurator configurator)
                             {
                             if (configurator == null)
                             throw new IllegalArgumentException("Null configurator");
                             this.configurator = configurator;
                             }
                            
                             /**
                             * Get the configurator.
                             *
                             * @return the configurator
                             */
                             protected KernelConfigurator getConfigurator()
                             {
                             return configurator;
                             }
                            
                             /**
                             * Get the bean name
                             *
                             * @return the bean
                             */
                             public String getBean()
                             {
                             return bean;
                             }
                            
                             /**
                             * Set the bean name
                             *
                             * @param bean the bean name
                             */
                             public void setBean(String bean)
                             {
                             this.bean = bean;
                             }
                            
                             /**
                             * Get the access mode.
                             *
                             * @return the access mode
                             */
                             public BeanAccessMode getAccessMode()
                             {
                             return accessMode;
                             }
                            
                             /**
                             * Set the access mode.
                             *
                             * @param accessMode the access mode.
                             */
                             public void setAccessMode(BeanAccessMode accessMode)
                             {
                             this.accessMode = accessMode;
                             }
                            
                             /**
                             * Get the classLoader.
                             *
                             * @return the classLoader.
                             */
                             public ClassLoaderMetaData getClassLoader()
                             {
                             return classLoader;
                             }
                            
                             /**
                             * Set the classLoader.
                             *
                             * @param classLoader the classLoader.
                             */
                             public void setClassLoader(ClassLoaderMetaData classLoader)
                             {
                             this.classLoader = classLoader;
                             }
                            
                             /**
                             * Get the constructor metadata
                             *
                             * @return the contructor metadata
                             */
                             public ConstructorMetaData getConstructor()
                             {
                             return constructor;
                             }
                            
                             /**
                             * Set the constructor metadata
                             *
                             * @param constructor the constructor metadata
                             */
                             public void setConstructor(ConstructorMetaData constructor)
                             {
                             this.constructor = constructor;
                             }
                            
                             /**
                             * Get the properties
                             *
                             * @return the properties Map<propertyName, ValueMetaData>
                             */
                             public Map<String, ValueMetaData> getProperties()
                             {
                             return properties;
                             }
                            
                             /**
                             * Set the properties
                             *
                             * @param properties the properties Map<propertyName, ValueMetaData>
                             */
                             public void setProperties(Map<String, ValueMetaData> properties)
                             {
                             this.properties = properties;
                             }
                            
                             /**
                             * Get the create.
                             *
                             * @return the create.
                             */
                             public LifecycleMetaData getCreate()
                             {
                             return create;
                             }
                            
                             /**
                             * Set the create.
                             *
                             * @param create the create.
                             */
                             public void setCreate(LifecycleMetaData create)
                             {
                             this.create = create;
                             }
                            
                             /**
                             * Get the start.
                             *
                             * @return the start.
                             */
                             public LifecycleMetaData getStart()
                             {
                             return start;
                             }
                            
                             /**
                             * Set the start.
                             *
                             * @param start the start.
                             */
                             public void setStart(LifecycleMetaData start)
                             {
                             this.start = start;
                             }
                            
                             /**
                             * Invoke a lifecycle method
                             *
                             * @param methodName the default method name
                             * @param lifecycle the lifecycle
                             * @param info the bean info
                             * @param cl the classloader
                             * @param target the target
                             * @throws Throwable for any error
                             */
                             protected void invokeLifecycle(String methodName, LifecycleMetaData lifecycle, BeanInfo info, ClassLoader cl, Object target) throws Throwable
                             {
                             if (lifecycle == null || lifecycle.isIgnored() == false)
                             {
                             String method = methodName;
                             if (lifecycle != null && lifecycle.getMethodName() != null)
                             method = lifecycle.getMethodName();
                             List<ParameterMetaData> parameters = null;
                             if (lifecycle != null)
                             parameters = lifecycle.getParameters();
                             MethodJoinpoint joinpoint;
                             try
                             {
                             joinpoint = configurator.getMethodJoinPoint(info, cl, method, parameters, false, true);
                             }
                             catch (JoinpointException ignored)
                             {
                             return;
                             }
                             joinpoint.setTarget(target);
                             joinpoint.dispatch();
                             }
                             }
                            }