2 Replies Latest reply on Jul 26, 2007 4:04 PM by Elias Ross

    How to emulate ServiceMBeanSupport using AOP

    Elias Ross Master

      I got this to work, it's pretty slick actually... Thanks Ales.

      Service.java :

      /**
       * Interface defines the basic operations for a service.
       */
      public interface Service {
      
       /**
       * Possible states for a service.
       */
       enum State {
       /**
       * Initial state; no lifecycle methods called.
       */
       INITIAL,
       /**
       * Created state; dependencies not ready.
       */
       CREATED,
       /**
       * Started state; dependencies in started state.
       */
       STARTED,
       /**
       * Stopped state; dependencies also stopped.
       */
       STOPPED,
       /**
       * Destroyed state.
       */
       DESTROYED
       }
      
       /**
       * Starts the service
       * @throws Exception if this lifecycle method failed
       */
       public void start() throws Exception;
      
       /**
       * Starts the service
       * @throws Exception if this lifecycle method failed
       */
       public void stop() throws Exception;
      
       /**
       * Creates the service
       * @throws Exception if this lifecycle method failed
       */
       public void create() throws Exception;
      
       /**
       * Destroys the service
       * @throws Exception if this lifecycle method failed
       */
       public void destroy() throws Exception;
      
       /**
       * Returns the service state; or null if not known.
       */
       public State getState();
      
       /**
       * Returns the service name; or null if not known.
       */
       public String getName();
      }
      


      LifecycleInterceptor.java:
      public class LifecycleInterceptor {
      
       private Log log = LogFactory.getLog(getClass());
      
       private Kernel kernel;
      
       /**
       * Maps the service method names to controller states.
       */
       private enum Methods {
      
       start(ControllerState.INSTALLED),
       stop(ControllerState.CREATE),
       create(ControllerState.CREATE),
       destroy(ControllerState.INSTANTIATED);
      
       private ControllerState cs;
      
       Methods(ControllerState cs) {
       this.cs = cs;
       }
      
       public ControllerState getState() {
       return cs;
       }
       };
      
       private boolean calledByKernel() {
       // The following detects if the kernel is calling us
       StackTraceElement[] sta = Thread.currentThread().getStackTrace();
       for (StackTraceElement se : sta) {
       String c = se.getClassName();
       if (c.startsWith("org.jboss.kernel"))
       return true;
       }
       return false;
       }
      
       /**
       * Determines the controller context, by method name chooses
       * and sets new controller state in the kernel.
       *
       * If called by the kernel, returns.
       *
       * @param inv method invocation
       */
       public Object handle(Invocation inv) throws Throwable {
       Service target = (Service) inv.getTargetObject();
      
       if (calledByKernel())
       return inv.invokeNext();
      
       KernelController controller = kernel.getController();
       ControllerContext context;
       MethodInvocation minv = (MethodInvocation)inv;
       String mname = minv.getMethod().getName();
       context = kernel.getController().getContext(target.getName(), null);
       if (context == null) {
       log.debug("service not installed " + target.getName());
       return inv.invokeNext();
       }
      
       // We assume the method call is a lifecycle method (by configuration)
       ControllerState state = Methods.valueOf(mname).getState();
       log.debug("controller change " + target.getName() + " to " + state.getStateString() + " for " + mname + "()");
       controller.change(context, state);
       return null;
       }
      
       /**
       * Returns kernel.
       */
       public Kernel getKernel() {
       return kernel;
       }
      
       /**
       * Sets kernel.
       */
       public void setKernel(Kernel kernel) {
       this.kernel = kernel;
       }
      
      }
      


      -beans.xml declaration:

       <aop:aspect xmlns:aop="urn:jboss:aop-beans:1.0"
       name="LifecycleAdvice"
       class="LifecycleInterceptor"
       method="handle"
       pointcut="execution(public void com.autodesk.lbs.service.Service->*())">
       <property name="kernel">
       <inject bean="jboss.kernel:service=Kernel" />
       </property>
       <depends>LifecycleCallback</depends>
       </aop:aspect>
      


      One weakness is that the Name has to be stored in the target, there's no way, given a Service to find its name in the Microcontainer. (That I know of.)

        • 1. Re: How to emulate ServiceMBeanSupport using AOP
          Ales Justin Master

           

          "genman" wrote:

          One weakness is that the Name has to be stored in the target, there's no way, given a Service to find its name in the Microcontainer. (That I know of.)

          What can help is new stuff that I've added previous week:
          <inject fromContext="name"/>
          

          This will 'inject' you underlying bean name.

          • 2. Re: How to emulate ServiceMBeanSupport using AOP
            Elias Ross Master

            Thanks ... Look forward to that in the annotated format.

            Actually, I find that a Lifecycle-Configure is probably the way to go, rather than doing an .

            One addendum, if somebody happens to try my code out, the aspect declaration works better as:

             <aop:aspect xmlns:aop="urn:jboss:aop-beans:1.0"
             name="LifecycleAdvice"
             class="com.autodesk.lbs.service.mc.LifecycleInterceptor"
             method="handle"
             pointcut="
             execution(public void $instanceof{com.autodesk.lbs.service.Service}->create())
             OR
             execution(public void $instanceof{com.autodesk.lbs.service.Service}->start())
             OR
             execution(public void $instanceof{com.autodesk.lbs.service.Service}->stop())
             OR
             execution(public void $instanceof{com.autodesk.lbs.service.Service}->destroy())
             ">
             <property name="kernel">
             <inject bean="jboss.kernel:service=Kernel" />
             </property>
             <depends>LifecycleCallback</depends>
             </aop:aspect>
            [/cpde]