1 2 Previous Next 15 Replies Latest reply on Apr 9, 2010 3:53 PM by starksm64

    OSGi ServiceMix interfering with bean injection

    thomas.diesler

      https://jira.jboss.org/jira/browse/JBAS-7884

       

      Multiple beans match class type: javax.transaction.TransactionManager


      2010-04-08 16:49:09,091 WARN [org.jboss.dependency.plugins.tracker.AbstractContextRegistry] (RMI TCP Connection(4)-127.0.0.1) Multiple beans match class type [enable trace log for details]: interface javax.transaction.TransactionManager
      2010-04-08 16:49:09,091 TRACE [org.jboss.dependency.plugins.tracker.AbstractContextRegistry] (RMI TCP Connection(4)-127.0.0.1) Matching contexts: 
       [AbstractKernelControllerContext@11a6c8d{ metadata=AbstractBeanMetaData@2f1d7a{name=RealTransactionManager bean=null properties= constructor=AbstractConstructorMetaData@13835b4{parameters= factory=AbstractDependencyValueMetaData@14def4f{value=TransactionManager} factoryMethod=getTransactionManager} autowireCandidate=true}name=RealTransactionManager target=com.arjuna.ats.jbossatx.jta.TransactionManagerDelegate@943402 state=Installed depends=AbstractDependencyInfo@1e2a4f1{idependOn=[AbstractDependencyItem@1c955b7{name=RealTransactionManager dependsOn=TransactionManager whenRequired=Instantiated dependentState=Installed resolved=RESOLVED}]}}, 
       Service{id=8,classes=[javax.transaction.TransactionManager]}]
      
      

       

       

      This seems to be another case of the OSGi ServiceMix interfering with ordinary been contexts.

       

      The OSGi semanic is that a client requesting a service reference will get at most one according to well defined ordering rules. It is actually very common that there is more than one service available that implements a given interface.

       

      How is this suposed to work at the MC level?

       

       

        • 1. Re: OSGi ServiceMix interfering with bean injection
          thomas.diesler

          Looking at this, it seems that it is the responsiblility of the client to use a different API when there is a posibility multiple matching contexts. This does not seem right IMHO.

           

          /**
              * If zero or multiple instances match class clazz
              * a warning is issued, but no throwable is thrown
              *
              * @param clazz the class to match
              * @return context whose target is instance of this class clazz param or null if zero or multiple such instances
              */
             public ControllerContext getContextByClass(Class<?> clazz)
             {
                Set<ControllerContext> contexts = getInstantiatedContexts(clazz);
                int numberOfMatchingBeans = 0;
                if (contexts != null)
                {
                   numberOfMatchingBeans = contexts.size();
                }
          
                if (log.isTraceEnabled())
                {
                   log.trace("Checking for contextual injection, current matches: " + numberOfMatchingBeans + " - " + clazz);
                }
          
                if (numberOfMatchingBeans != 1)
                {
                   if (numberOfMatchingBeans > 1)
                   {
                      log.warn("Multiple beans match class type [enable trace log for details]: " + clazz);
                      if (log.isTraceEnabled())
                      {
                         log.trace("Matching contexts: " + contexts);
                      }
                   }
                   return null;
                }
                return contexts.iterator().next();
             }
          
          
          • 2. Re: OSGi ServiceMix interfering with bean injection
            starksm64

            What are the sources of the multiple beans that implement an interface like the TM? In general, there should only be one true implementation of an interface like the TM in a given server instance. If there is a legitimate reason for this, perhaps we need a mapping from interface to bean name for the resolving the ambiguity. We should have a plugin interface for this as well.

            • 3. Re: OSGi ServiceMix interfering with bean injection
              alesj
              How is this suposed to work at the MC level?

              All I can say atm is check my service-mix branch for more details,

              as that's where this is properly implemented:

              * http://anonsvn.jboss.org/repos/jbossas/projects/jboss-osgi/projects/runtime/framework/branches/alesj_service-mix/

              • 4. Re: OSGi ServiceMix interfering with bean injection
                alesj
                Looking at this, it seems that it is the responsiblility of the client to use a different API when there is a posibility multiple matching contexts. This does not seem right IMHO.

                This is OK, and this is how it should be -- dumb as possible on server/registry side.

                It's the clients that must know what to bind and what not.

                Again, see my branch for custom OSGiMetaData; <osgi > bean element.

                • 5. Re: OSGi ServiceMix interfering with bean injection
                  alesj
                  What are the sources of the multiple beans that implement an interface like the TM? In general, there should only be one true implementation of an interface like the TM in a given server instance. If there is a legitimate reason for this, perhaps we need a mapping from interface to bean name for the resolving the ambiguity. We should have a plugin interface for this as well.

                  Multiple matching refs come from duplicate MC ControllerContext registrations.

                  Once as MC bean, 2nd as OSGi service -- for same instance.

                   

                  Plugin interface?

                  • 6. Re: OSGi ServiceMix interfering with bean injection
                    alesj
                    The OSGi semanic is that a client requesting a service reference will get at most one according to well defined ordering rules. It is actually very common that there is more than one service available that implements a given interface.

                    Sure, why is this then a problem?

                    We mock the OSGi ordering rules in MDRUtils for non-OSGi services/contexts.

                    • 7. Re: OSGi ServiceMix interfering with bean injection
                      starksm64

                      A plugin interface that replaces the current more than 1 match loop to resolve the ambiguity from the context of the caller:

                       

                            if (numberOfMatchingBeans != 1)
                            {
                               if (numberOfMatchingBeans > 1)
                               {
                                  log.warn("Multiple beans match class type [enable trace log for details]: " + clazz);
                                  if (log.isTraceEnabled())
                                  {
                                     log.trace("Matching contexts: " + contexts);
                                  }
                               }
                               return null;
                            }
                      
                      

                       

                      It seems like we should have more control over how this lookup behaves as if one can register multiple context matching a class, it is not very useful to not be able to have a method that returns a match.

                       

                      There is no difference in type or behavior between the TM registered with the MC or OSGi service registry other than life cycle states or some such right?

                      • 8. Re: OSGi ServiceMix interfering with bean injection
                        alesj
                        A plugin interface that replaces the current more than 1 match loop to resolve the ambiguity from the context of the caller:

                         

                              if (numberOfMatchingBeans != 1)
                              {
                                 if (numberOfMatchingBeans > 1)
                                 {
                                    log.warn("Multiple beans match class type [enable trace log for details]: " + clazz);
                                    if (log.isTraceEnabled())
                                    {
                                       log.trace("Matching contexts: " + contexts);
                                    }
                                 }
                                 return null;
                              }
                         
                         
                        

                         

                        It seems like we should have more control over how this lookup behaves as if one can register multiple context matching a class, it is not very useful to not be able to have a method that returns a match.

                        I don't see a reason for a plugin.

                        Or how are you gonna apply every caller's context?

                         

                        This is a straight fwd method, if you want more control - which is what you want -- you have this 2 methods:

                         

                        /**
                            * Get all instantiated contexts of a given type
                            *
                            * @param clazz the type
                            * @return the contexts
                            */
                           Set<ControllerContext> getInstantiatedContexts(Class<?> clazz);
                        
                           /**
                            * Get all contexts of a type which are in the given state or above.
                            * Note: state must not be null
                            *
                            * @param clazz the type
                            * @param state the required state
                            * @return the contexts
                            * @throws IllegalArgumentException for null state
                            */
                           Set<ControllerContext> getContexts(Class<?> clazz, ControllerState state);
                        

                         

                        Then you can freely apply caller's context.

                         

                        There is no difference in type or behavior between the TM registered with the MC or OSGi service registry other than life cycle states or some such right?

                        This, plus type hiding -- OSGi doesn't expose much else than registered interfaces, where POJO reveals it all. :-)

                        OSGi also has a notion of filtering (LDAP query), which can be mocked in our MC beans as well (see tests in alesj_service-mix branch).

                        ...

                        • 9. Re: OSGi ServiceMix interfering with bean injection
                          thomas.diesler
                          What are the sources of the multiple beans that implement an interface like the TM? In general, there should only be one true implementation of an interface like the TM in a given server instance.


                          The OSGi integration makes the TM available as OSGi service in the OSGi service registry. The ServiceMix implementation treats every OSGi service as ControllerContext. Hence a client asking the AbstractContextRegistry for the implementation of a given interface will see all MC beans that are registered under this interface plus the OSGi services that are registered under the interface.


                          It seems that it is generally unsafe to call getContextByClass(Class<?> clazz)because the caller would not know whether there is only one context for that class. I claim that getContextByClass(Class<?> clazz) should have some "top of the list" or selection semantic. If a client is interested in all contexts that implement a given clazz it should call something like getAllContextsByClass(Class<?> clazz). The selection semantic should follow what OSGi suggests (i.e. ranking first, service id second a.s.o.) like in ContextComparator

                           

                          I need to look at Ales' service mix branch to see if this really addresses this issue.

                          • 10. Re: OSGi ServiceMix interfering with bean injection
                            starksm64

                            The reason for a plugin would be to address what seems to be an asymmetry and very limited applicability of the getContextByClass(Class<?> clazz) method. If I'm doing a type based lookup, I would think I would set my context filter policy plugin and then call getContextByClass(Class<?> clazz). As it is now, the javadoc for getContextByClass(Class<?> clazz) needs to say its useless if more than one context for a given type exists.

                            • 11. Re: OSGi ServiceMix interfering with bean injection
                              alesj

                              As it is now, the javadoc for getContextByClass(Class<?> clazz) needs to say its useless if more than one context for a given type exists.

                              I view this as a shortcut for autowiring by type.

                              Like I said, if you need more control, use different method.

                               

                              Current registry is nothing more than a fancy Map.

                              Or what would you need / expect?

                               

                              I guess we can re-write it to use sort of MapMaker::makeComputingMap?

                              * http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/collect/MapMaker.java

                              Making it easier to apply your context / filtering.

                              • 12. Re: OSGi ServiceMix interfering with bean injection
                                starksm64

                                The concern is that if it is common to have multiple contexts implementing the same interface, we should have an efficient mechanism for resovling the correct context. Having to reimplement querying all installed contexts and apply filtering rules is prone to error and inefficiency and we need to fight that tendency as performance of contextual injection is important.

                                 

                                If we can have more information available such that one can have a getContextByClass(Class<?> clazz, 

                                ControllerContext caller) and have this work in O(1).
                                • 13. Re: OSGi ServiceMix interfering with bean injection
                                  alesj

                                  I don't think there are many cases where you need typed injection, at least not in current AS/MC.

                                  And even if you had multiple cases, you usually don't have a lot of matching beans; mostly a handful.

                                   

                                  I don't see how your API would be any useful, as you have too dynamic system to somehow index that.

                                  e.g. in OSGi case, any LDAP filter at the lookup, where matching properties can change on the fly on existing services

                                  Or do you really want to cache any possible scenario and do updates/re-indexing on runtime changes?

                                   

                                  Although for CDI kind of injection, afair, we currently don't index things,

                                  but this idea - indexing - was part of discussion and actual lookup implementation; plugable - prepared but not yet implemented.

                                  (this is easier, since it's statically typed - cannot change at runtime)

                                  • 14. Re: OSGi ServiceMix interfering with bean injection
                                    thomas.diesler

                                    I guess we can re-write it to use sort of MapMaker::makeComputingMap?

                                    * http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/collect/MapMaker.java

                                    Making it easier to apply your context / filtering.

                                     

                                    Please take note of the quality of javadoc these guys provide. One of the underlying problems we have with the MC code is that it is unsufficiently documented to a degree where semantic intentions are not clear at all.

                                     

                                    /**
                                     * Abstract context registry
                                     *
                                     * @author <a href="ales.justin@jboss.com">Ales Justin</a>
                                     */
                                    public class AbstractContextRegistry extends AbstractLockHolder implements ContextQueries, ContextRegistry
                                    
                                    

                                     

                                    Instead the javadoc should give the user sufficient information on how this class should be used. From this allone it should become apparent of whether the lookup semantic based on a single class is useful or not. In OSGi this is well defined, here it is not.

                                     

                                    If I read your posts correctly, you are saying that the caller should use getContexts(Class<?> clazz) and do the filtering himself if he is not sure whether there are multiple contexts available. This can only be the case if he created the context himself with a key that is private to him. All other clients must use a variety of undefined filtering mechanisms.

                                     

                                    If the javadoc would spell this out explicitly, we could take it as the basis for further discussion. Perhaps it's a good idea to start with the javadoc. We can then review and potentially modify the intended semantics. Having well defined/documented public interfaces is not just a matter of style it actually saves real costs.

                                    1 2 Previous Next