13 Replies Latest reply on Jan 30, 2005 3:34 PM by starksm64

    Dynamically Attaching Interceptors to any (X)MBean

    dimitris

      I scratched my head quite a few times trying to figure out:
      http://www.jboss.org/index.html?module=bb&op=viewtopic&t=56668

      The main issue here was that we want to attach an intereptor-like chain to existing deployers (e.g. EJBDeployer) so that related deployers (e.g. WebService) can not only react to notifications but be able also to fail the whole thing if something is wrong on their side.

      XMBeans can have interceptors but the problem is those are defined statically at deployment time. If we could dynamically add/remove interceptors that would solve a big part of the problem.

      So I created the internal hooks to allow any (X)MBean to become "Interceptable". To expose the Interceptable interface you just have to specify in the xmbean descriptor the DynamicInterceptor, and expose some predefined operations:

       <mbean>
       ...
       <descriptors>
       <interceptors>
       <interceptor code="org.jboss.mx.interceptor.DynamicInterceptor"/>
       </interceptors>
       </descriptors>
       ...
      
       &interceptable;
      

      Using the addOperationInterceptor()/removeOperationInterceptor() methods, you can attach/detach at runtime new interceptors to the running MBean.

      I've included a helper base class that extends ServiceMBeanSupport, called InterceptorServiceMBeanSupport that lets you quickly write Services that upon start-up attach themselves as interceptors to an Interceptable target (X)MBean, and detach themselves upon stop.

      You simply override an invoke(Invocation) method to do whatever you want, and configure a dependency on the Interceptable MBean, e.g.:
       <mbean code="org.jboss.test.jmx.interceptors.AdderInterceptorService"
       name="jboss.test:service=adderinterceptor">
      
       <depends optional-attribute-name="Interceptable" proxy-type="attribute">
       jboss.test:service=interceptable
       </depends>
       </mbean>
      

      This example MBean dynamically attaches itself to another XMBean, then monitors calls to method add(int a, int b) and just increments the result by one, so 1+1 gives 3.

      As it is now, it let's you intercept operations (I could do it for attribute get/sets, too, but I don't know who would use that), and also puts every new dynamic interceptors first in the chain, so it's really in your invoke() code to decide whether to do your stuff then forward the call, or the other way round.

      I can imagine this can have many other usages apart from deployer chaining.

      The next step would be to re-write either the Portal or WebService deployers based on this, and see how it goes.

        • 1. Re: Dynamically Attaching Interceptors to any (X)MBean
          dimitris

          Correct, except that there is no restriction on what deployers may need this interceptor. Any deployment can have a component that uses the security service and if the deployment bundles the security domain configuration it would need this interceptor.

          Another equivalent example would be a logging interceptor that configured an application scoped logger repositories if a log4j.xml was found in the deployment.

          In general there needs to be a deployment metadata specification which declares the dependencies the deployment has on injections provided by deployment interceptors.

          • 2. Re: Dynamically Attaching Interceptors to any (X)MBean
            starksm64

            So the still missing piece is a generalization of the deployment that eliminates all of the duplicate file and url processing that exists today for manipulating resources in the deployment, including unpacking of the deployment into the tmp/deploy directory.

            A simple initial test usecase is to transform the existing org.jboss.security.auth.login.DynamicLoginConfig service into a deployer that associates with all deployers to look for a defined resource (META-INF/login-config.xml for example) to install the custom security config on startup and remove it on shutdown.

            • 3. Re: Dynamically Attaching Interceptors to any (X)MBean
              dimitris

              If I understand, DynamicLoginConfig is associated with a new deployment in order to add optional security domain configuration information.

              (BTW, since this new security domain information is registered to the XMLLoginConfig reporitory, it can be used by any module, so there is no scoping for that, right?)

              I've looked through the code in HEAD, but I can't find whom currently uses DynamicLoginConfig, or is this something that should be added?

              • 5. Re: Dynamically Attaching Interceptors to any (X)MBean
                starksm64

                There is no explicit user of the DynamicLoginConfig in the server codebase as this is handled statically via the login-config.xml. This service is used by deployments that want to be able to augment the login-config as part of their deployment process. The testsuite security unit tests make use of DynamicLoginConfig to install the test security domain settings.

                • 6. Re: Dynamically Attaching Interceptors to any (X)MBean
                  starksm64

                  Correct, except that there is no restriction on what deployers may need this interceptor. Any deployment can have a component that uses the security service and if the deployment bundles the security domain configuration it would need this interceptor.

                  Another equivalent example would be a logging interceptor that configured an application scoped logger repositories if a log4j.xml was found in the deployment.

                  In general there needs to be a deployment metadata specification which declares the dependencies the deployment has on injections provided by deployment interceptors.

                  • 7. Re: Dynamically Attaching Interceptors to any (X)MBean
                    dimitris

                    I came across an interesting problem: Deployers register to the MainDeployer using their direct reference (this), so calls don't go through the MBeanServer and thus cannot be intercepted.

                    I can "trick" this by registering a dynamic proxy instead, but there seem to be some problems with deployers that downcast this to the subdeployer interface, or even the implementation class (e.g. RARDeployer).

                    So I think I'm going to handle this per case, for those subdeployer that want the interception capability (they'll have to be deployed as xmbean, too).

                    • 8. Re: Dynamically Attaching Interceptors to any (X)MBean

                      The only reason for that downcast is to get at "global" resources
                      for the bootstrap context. It is not downcasting to use the object as a deployer.

                      This is just lazy/bad design on my part.

                      It should really be using injection, i.e. the deployer does the following during deployment
                      deployment.setXXX(...)
                      rather than the deployment lazily doing
                      deployer.getXXX()

                      This would need a hook in SimpleSubDeployerSupport.registerDeployment
                      so each subclass can do the injection after the instantiation of the deployment object.

                      There is already a task to improve this area of the RARDeployer:
                      http://jira.jboss.com/jira/browse/JBJCA-10

                      • 9. Re: Dynamically Attaching Interceptors to any (X)MBean
                        dimitris

                        Thanks, I'm slowly seeing other issues as well:

                        Do you know how proxies generated by either MBeanServerInvocationHandler or MBeanProxyExt handle hashCode() and equals() ?

                        • 10. Re: Dynamically Attaching Interceptors to any (X)MBean

                          Not without looking at the code, which you can do just as well as I can.

                          • 11. Re: Dynamically Attaching Interceptors to any (X)MBean
                            dimitris

                            Ok, I was looking in the code anyway, the question was really if there are any known/obvious issues with dynamic proxies and equality, e.g proxies added/removed from LinkedList.

                            • 12. Re: Dynamically Attaching Interceptors to any (X)MBean
                              dimitris

                              I have a working prototype of the EJBDeployer that can be enhanced with a LoginConfigInterceptor either statically or dynamically. It detects the presense of META-INF/login-config.xml and creates/destroys the security domains upon deployment undeployment of an ejb jar.

                              I modified slightly EJBDeployer to register a dynamic proxy with the MainDeployer, because I didn't want to change the base class (SubDeployerSupport), at least, not yet.

                              I'm thinking of making this permanent, i.e. xmbean-ize the EJBDeployer descriptor (ejb-deployer.xml), with this interceptor enabled. If not wanted, it's simple to comment it out.

                              To which other Deployers we would be interested adding the LoginConfigInterceptor? WARDeployer, SARDeployer?

                              • 13. Re: Dynamically Attaching Interceptors to any (X)MBean
                                starksm64

                                There are two problems with this.

                                1. The LoginConfigInterceptor is not considering operation in an aggregate deployment like an ear that can have multiple login-config.xml descriptors. It would just work if very login-config.xml was distinct, but it will fail if there are overlapping application-policy definitions. One possible mode of operation in the aggregate case would be to merge all login-config.xml descriptors with any conflicts being resolved by taking the application-policy first defined in a breadth-first traversal of the deployment heirarchy.

                                2. There is no support for a global specification of inteceptor(s) which should be applied to all deployers. This is an aspect of the more general configuration issue raised here:

                                http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3864275#3864275