10 Replies Latest reply on Apr 20, 2007 7:41 AM by adrian.brock

    Install Items

      While discussing how the OSGi service layer works,
      we came up with a better way of doing something that is already supported
      in the Microcontainer.

      An example would be the new deployers configuration
      where you "manually" install deployers into the main deployer, e.g.

      <!--
       Security Deployer
      -->
      <deployment xmlns="urn:jboss:bean-deployer:2.0">
       <bean name="SecurityDeployer" class="org.jboss.deployment.security.SecurityDeployer">
       <install bean="MainDeployer" method="addDeployer">
       <parameter>
       <this/>
       </parameter>
       </install>
       <uninstall bean="MainDeployer" method="removeDeployer">
       <parameter>
       <this/>
       </parameter>
       </uninstall>
       <property name="type">security</property>
       <property name="ignoreSuffixes">
       <set elementClass="java.lang.String">
       <value>xml</value>
       <value>beans</value>
       <value>deployer</value>
       </set>
       </property>
       </bean>
      </deployment>
      


      The idea is to remove the install and uninstall from the individual deployer xmls
      and instead configure the MainDeployer to want all implementations
      of a specific class, in this case org.jboss.deployers.spi.deployer.Deployer
      and have the Microcontainer do the add/remove invocations.

       /**
       * Add a deployer
       *
       * @param deployer the deployer
       */
       @Install
       public synchronized void addDeployer(Deployer deployer) { ... }
      
       /**
       * Remove a deployer
       *
       * @param deployer the deployer
       */
       @Uninstall
       public synchronized void removeDeployer(Deployer deployer) { ... }
      


      This feature is being tracked here:
      http://jira.jboss.com/jira/browse/JBMICROCONT-165

        • 1. Re: Install Items
          alesj

          Why should InstallItem be referenced by DependencyInfo?

          I need to register a 'callback / install' item directly into the controller - holding the information of requested class, cardinality, target context, target method/property.

          Since with Controller.resolveContexts() I never iterate over already installed context's.
          And even if I did, I should only iterate over those who actually hold any install item.

          • 2. Re: Install Items

            I don't understand any of your comment. e.g.

            "alesj" wrote:
            Why should InstallItem be referenced by DependencyInfo?


            Because that is where cross context dependency info is stored
            and where the real implementation of the dependency resolution is done.


            I need to register a 'callback / install' item directly into the controller - holding the information of requested class, cardinality, target context, target method/property.


            The only thing registered directly in the controller are the contexts.
            These have DependencyInfo, i.e. what is required before the context can
            change state.


            Since with Controller.resolveContexts() I never iterate over already installed context's.
            And even if I did, I should only iterate over those who actually hold any install item.


            What does that have to do with it? There are two points of integration.

            1) I add something that wants to pickup all previously deployed implementations
            of an interface.

            2) I install something that implements the interface wanted by something (1)
            type (1)

            Neither is directly related to resolveContexts().

            The only part of the resolution process is the cardinality. And that is
            only indirectly in that there should be a "DependencyItem implementation"
            that says the context is not resolved for this state unless there N other
            objects implementing the interface.
            The "N" could be zero meaning it is always resolved.

            • 3. Re: Install Items
              alesj

               

              "adrian@jboss.org" wrote:
              I don't understand any of your comment. e.g.

              Yes, I expected this. :-)

              Let me try to put it better.
              I don't see any other place to hold the information about callback - e.g. (2) in JBMICROCONT-165 - than the KernelController. I need something like Class --> CallbackItems.
              Since when a new bean is instantiated - its classes, interfaces are resolved - I don't want to go over all already installed beans and 'ask' them if they need this new bean.

              I have already hacked something in this direction, I can put it in after I have tests done.
              Or how/where do you see the point of integration of this Class --> CallbackItems mapping?

              • 4. Re: Install Items

                No. The whole point of making the InstallItem seperate on the DependencyInfo
                is that it will hold just that callback information.

                Internally, the controller will pull out that information and index it by interface
                (in a similar way to the @Inject was done).
                It will pull out that information at the "required state" specified on the InstallItem
                (default INSTALLED).

                It is then just a case of iterating over all the callbacks
                by looking up that index as new contexts reach the relevant state.

                NOTE: There are two states in the above.
                1) At what state we inject into the context
                2) At what state the injectee must be before we add it

                • 5. Re: Install Items
                  alesj

                  Where to put such code:

                   /**
                   * Add callback context.
                   *
                   * @param name the depend on name
                   * @param context context interested in name
                   */
                   void addCallbackContext(Object name, ControllerContext context);
                  
                   /**
                   * Remove callback context.
                   *
                   * @param name the depend on name
                   * @param context context interested in name
                   */
                   void removeCallbackContext(Object name, ControllerContext context);
                  
                   /**
                   * Get interested contexts.
                   *
                   * @param name dependent name
                   * @return set of contexts interested in name or null if none such exists
                   */
                   Set<ControllerContext> getCallbackContexts(Object name);
                  
                  


                  Best place would be Controller, but this is too specific for state machine.
                  Should I create a middle interface, between Controller and KernelController?

                  • 6. Re: Install Items

                    You still don't understand.

                    The callback is a generic thing.

                    It's also an implementation detail handled internally by the controller,
                    so you don't need anything on the controller itself.

                    e.g. something like

                    public interface InstallItem<T>
                    {
                     ControllerState whenRequired();
                     ControllerState requiredState();
                     int getCardinality();
                     Class<T> getItemType();
                    }
                    
                    public interface SingleInstallItem<T> extends InstallItem<T>
                    {
                     add(T item);
                     remove(T item);
                    }
                    
                    
                    public interface CollectionInstallItem<T> extends InstallItem<T>
                    {
                     set(Collection<? extends T> items);
                    }
                    


                    And then in the controller (pseudo code):

                    protected void install(ControllerContext context, ControllerState toState)
                    {
                     // do it (what it does now)
                    
                     Collection<InstallItem> installs = context.getDependencyInfo().getInstallItems();
                     if (installs != null && installs.isEmpty() == false)
                     {
                     for (InstallItem install : installs)
                     {
                     if (install.getWhenRequired().equals(toState)
                     {
                     addToIndex(install.getItemItype(), install);
                     // also install what already exists
                     }
                     }
                     }
                    
                     Collection<Class<?> implements = getClassesImplemented(context.getTarget());
                     if (implements != null && implements.isEmpty() == false)
                     {
                     for (Class implement : implements)
                     {
                     Set<InstallItem> installs = getFromIndex(implement);
                     // Do the installs if we are at the required state
                     {
                     // eventually leading to something like
                     InstallItem install = // from installs
                     if (toState.equals(install.getRequiredState))
                     install.add(context.getTarget());
                     }
                     }
                     }
                    }
                    


                    • 7. Re: Install Items

                      Well actually you've got to hook up the intallation target as well in there somewhere
                      so you've either got to have

                      public interface InstallItem
                      {
                       // ...
                       setTarget(Object object)
                      }
                      
                      or
                      
                      public interface SingleInstallItem
                      {
                       add(Object target, Object item);
                      }
                      


                      I think I prefer the second method since it is more stateless for the user
                      (less error prone and less likely to leak)
                      But that means the internal index of install items must also remember which context
                      owns the install item so it can retrieve the target from the context.

                      • 8. Re: Install Items
                        alesj

                        Would this work:

                         MethodInfo mi = Configurator.findMethodInfo(getClassInfo(context), methodName, new String[]{signature});
                         TypeInfo info = mi.getParameterTypes()[0];
                         Class parameterType = info.getType();
                         if (Collection.class.isAssignableFrom(parameterType))
                         {
                         if (info instanceof ParameterizedClassInfo)
                         {
                         ParameterizedClassInfo pci = (ParameterizedClassInfo)info;
                         Class clazz = pci.getActualTypeArguments()[0].getType();
                         callback = CollectionCallbackItemFactory.createCollectionCallbackItem(parameterType, clazz, whenRequired, dependentState, context, methodName);
                         }
                         else
                         throw new IllegalArgumentException("Unable to determine collection element class type: " + this);
                         }
                        
                        


                        Or how to get element class type?

                        Is this (the only) way?
                        - http://www.jboss.org/index.html?module=bb&op=viewtopic&t=88613&postdays=0&postorder=asc&start=30

                        • 9. Re: Install Items
                          alesj

                          Changed previous post from ParameterizedArrayInfo to ParameterizedClassInfo. ;-)

                          • 10. Re: Install Items

                            Without seeing the context its hard to say. :-)

                            This is the way I have it working in some uncommitted code for the
                            managed object stuff.

                             if (typeInfo.isCollection())
                             return generateCollection((ClassInfo) typeInfo);
                            
                             /**
                             * Generate a collection metatype
                             *
                             * @param typeInfo the type info
                             * @return the metatype
                             */
                             public ArrayMetaType generateCollection(ClassInfo typeInfo)
                             {
                             TypeInfo elementType = objectTypeInfo;
                            
                             TypeInfo[] types = typeInfo.getActualTypeArguments();
                             if (types != null)
                             elementType = types[0];
                            
                             MetaType elementMetaType = resolve(elementType);
                             return new ArrayMetaType(1, elementMetaType);
                             }
                            


                            Of course in that code, I fallback to java.lang.Object when it is not Generic. :-)