Package org.jboss.mx.server

Source Code of org.jboss.mx.server.AbstractMBeanInvoker$OperationKey

/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.mx.server;

import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

import java.lang.reflect.Method;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.JMException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.RuntimeErrorException;
import javax.management.RuntimeMBeanException;
import javax.management.RuntimeOperationsException;

import org.jboss.mx.server.Invocation;
import org.jboss.mx.server.InvocationException;

import org.jboss.mx.logging.Logger;
import org.jboss.mx.logging.SystemLogger;


/**
*
* @author  <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
* @version $Revision: 1.3 $
*
*/
public abstract class AbstractMBeanInvoker
   implements MBeanInvoker
{
  
   // Attributes ----------------------------------------------------
     
   /**
    * The target object for this invoker.
    */
   private Object resource             = null;
  
   /**
    * The metadata describing this MBean.
    */
   protected MBeanInfo info                        = null;

   protected Map attributeContextMap               = new HashMap();
   protected Map operationContextMap               = new HashMap();
   protected Map constructorContextMap             = new HashMap();

   protected InvocationContext getMBeanInfoCtx     = null;
   protected InvocationContext preRegisterCtx      = null;
   protected InvocationContext postRegisterCtx     = null;
   protected InvocationContext preDeregisterCtx    = null;
   protected InvocationContext postDeregisterCtx   = null;
  
   // TODO: allow to config invoker specific logs
   //     : multitarget mbean for invoker + log?
  
   protected Logger log                            = SystemLogger.getLogger(AbstractMBeanInvoker.class);

   private boolean isDelayedRegistration           = false;
  
  
   // Constructors --------------------------------------------------

   /**
    * Constructs a new invoker.
    */
   public AbstractMBeanInvoker()
   {
   }
  
   /**
    * Constructs a new invoker with a given target resource.
    */
   public AbstractMBeanInvoker(Object resource)
   {
      this();
      this.resource = resource;
   }

  
   // DynamicMBean implementation -----------------------------------
  
   /**
    * Invokes the target resource. The default invocation used by this invoker
    * implement sends the invocation through a stack of interceptors before
    * reaching the target method.
    *
    * @param   operationName  name of the target method
    * @param   args           argumetns for the target method
    * @param   signature      signature of the target method
    *
    * @throws MBeanExcpetion if the target method raised a hecked exception
    * @throws ReflectionException if there was an error trying to resolve or
    *         invoke the target method
    * @throws RuntimeMBeanException if the target method raised an unchecked
    *         exception
    * @throws RuntimerErrorException if the target method raised an error
    */   
   public Object invoke(String operationName, Object[] args, String[] signature)
         throws MBeanException, ReflectionException
   {

      // TODO:  __JBOSSMX_INVOCATION
     
      // get the server side invocation context        
      OperationKey key = new OperationKey(operationName, signature);
      InvocationContext ctx = (InvocationContext)operationContextMap.get(key);

      // if the server does not contain this context, we do not have the operation
      if (ctx == null)
      {
         throw new ReflectionException(new IllegalArgumentException(
               "Unable to find operation " + operationName +
               getSignatureString(signature))
         );
      }
     
      // create the invocation object
      Invocation invocation = new Invocation();        
     
      // copy the server's invocation context to the invocation
      invocation.addContext(ctx);

      // set the invocation's entry point
      invocation.setType(InvocationContext.OP_INVOKE);
     
      // set the args
      invocation.setArgs(args);
     
      try
      {
         // the default invocation implementation will invoke each interceptor
         // declared in the invocation context before invoking the target method
         return invocation.invoke();        
      }
     
      // Both interceptors and the invocation object propagate only one exception
      // type, InvocationException, which wraps the underlying JMX exception
      // (which in turn may wrap application exception, as per the JMX spec).
      // Unwrap the outermost InvocationException layer here.
      catch (InvocationException e)
      {
         if (e.getTargetException() instanceof MBeanException)
            throw (MBeanException)e.getTargetException();
         else if (e.getTargetException() instanceof ReflectionException)
            throw (ReflectionException)e.getTargetException();
         else if (e.getTargetException() instanceof RuntimeMBeanException)
            throw (RuntimeMBeanException)e.getTargetException();
         else if (e.getTargetException() instanceof RuntimeErrorException)
            throw (RuntimeErrorException)e.getTargetException();        
         else
            throw new RuntimeException(e.getTargetException().toString());
      }
     
      // any other throwable object that gets propagated back to the invoker
      // indicates an error in the server or in the interceptor implementation.
      catch (Throwable t)
      {
         throw new RuntimeOperationsException(new RuntimeException(
               "Unhandled throwable propagated to the invoker by " +
               invocation + ":" +t.toString())
         );
        
         // TODO:  mark interceptors so we can track which interceptor fails
      }
     
      // TODO: should be fixed by adding invocation return value object
      finally
      {
         ctx.setDescriptor(invocation.getDescriptor());
      }
     
   }

   /**
    * Returns an attribte value. The request for the value is forced through
    * a set of interceptors before the value is returned.
    *
    * @param   attribute   attribute name
    *
    * @return  attribute value
    *
    * @throws AttributeNotFoundException if the requested attribute is not
    *         part of the MBean's management interface
    * @throws MBeanException if retrieving the attribute value causes an
    *         application exception
    * @throws ReflectionException if there was an error trying to retrieve
    *         the attribute value
    */
   public Object getAttribute(String attribute)
         throws AttributeNotFoundException, MBeanException, ReflectionException
   {
      // TODO:  __JBOSSMX_INVOCATION

      // lookup the server side invocation context
      InvocationContext ctx = (InvocationContext)attributeContextMap.get(attribute);

      // if we don't have a server side invocation context for the attribute,
      // it does not exist as far as we are concerned
      if (ctx == null)
         throw new AttributeNotFoundException("not found: " + attribute);
     
      // create the invocation object
      Invocation invocation = new Invocation();
     
      // copy the server's invocation context to the invocation
      invocation.addContext(ctx);

      // indicate the invocation access point was getAttribute() method
      invocation.setType(InvocationContext.OP_GETATTRIBUTE);
     
      try
      {
         return invocation.invoke();
      }

      // Both interceptors and the invocation object propagate only one exception
      // type, InvocationException, which wraps the underlying JMX exception
      // (which in turn may wrap application exception, as per the JMX spec).
      // Unwrap the outermost InvocationException layer here.
      catch (InvocationException e)
      {
         if (e.getTargetException() instanceof AttributeNotFoundException)
            throw (AttributeNotFoundException)e.getTargetException();
         if (e.getTargetException() instanceof MBeanException)
            throw (MBeanException)e.getTargetException();
         else if (e.getTargetException() instanceof ReflectionException)
            throw (ReflectionException)e.getTargetException();
         else if (e.getTargetException() instanceof RuntimeMBeanException)
            throw (RuntimeMBeanException)e.getTargetException();
         else if (e.getTargetException() instanceof RuntimeErrorException)
            throw (RuntimeErrorException)e.getTargetException();        
         else
            throw new RuntimeException(e.getTargetException().toString());
      }

      // any other throwable object that gets propagated back to the invoker
      // indicates an error in the server or in the interceptor implementation.
      catch (Throwable t)
      {
         throw new RuntimeOperationsException(new RuntimeException(
               "Unhandled throwable propagated to the invoker by " +
               invocation + ":" +t.toString())
         );
        
         // TODO:  mark interceptors so we can track which interceptor fails           
      }
     
      // TODO: should be fixed by adding invocation return value object
      finally
      {
         ctx.setDescriptor(invocation.getDescriptor());
      }
   }

   /**
    * Sets an attribute value. The operation is forced through a set of
    * interceptors before the new value for the attribute is set.
    *
    * @param   attribute   new attribute value
    *
    * @throws AttributeNotFoundException if the requested attribute is not part
    *         of the MBean's management interface
    * @throws InvalidAttributeValueException if the attribute contains a value
    *         not suitable for the attribute
    * @throws MBeanException if setting the attribute value causes an application
    *         exception
    * @throws ReflectionException if there was an error trying to set the
    *         attribute value.
    */
   public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
         InvalidAttributeValueException, MBeanException, ReflectionException
   {
      // TODO:  __JBOSSMX_INVOCATION
     
      if (attribute == null)
         throw new InvalidAttributeValueException("null attribute");
        
      // lookup the server side invocation context
      InvocationContext ctx = (InvocationContext)attributeContextMap.get(attribute.getName());
     
      // if we don't have a server side invocation context for the attribute,
      // it does not exist as far as we are concerned
      if (ctx == null)
         throw new AttributeNotFoundException("not found: " + attribute.getName());

      // create the invocation object     
      Invocation invocation = new Invocation();

      // copy the server context to the invocation     
      invocation.addContext(ctx);

      // indicate the access point as setAttribute()
      invocation.setType(InvocationContext.OP_SETATTRIBUTE);
     
      // set the attribute value as the argument
      invocation.setArgs(new Object[] { attribute.getValue() });
     
      try
      {
         // the default invocation implementation will invoke each interceptor
         // declared in the invocation context before invoking the target method        
         invocation.invoke();     
      }

      // Both interceptors and the invocation object propagate only one exception
      // type, InvocationException, which wraps the underlying JMX exception
      // (which in turn may wrap application exception, as per the JMX spec).
      // Unwrap the outermost InvocationException layer here.     
      catch (InvocationException e)
      {
         if (e.getTargetException() instanceof InvalidAttributeValueException)
            throw (InvalidAttributeValueException)e.getTargetException();
         if (e.getTargetException() instanceof AttributeNotFoundException)
            throw (AttributeNotFoundException)e.getTargetException();
         if (e.getTargetException() instanceof MBeanException)
            throw (MBeanException)e.getTargetException();
         else if (e.getTargetException() instanceof ReflectionException)
            throw (ReflectionException)e.getTargetException();
         else if (e.getTargetException() instanceof RuntimeMBeanException)
            throw (RuntimeMBeanException)e.getTargetException();
         else if (e.getTargetException() instanceof RuntimeErrorException)
            throw (RuntimeErrorException)e.getTargetException();        
         else
            throw new RuntimeException(e.getTargetException().toString());
      }
     
      // any other throwable object that gets propagated back to the invoker
      // indicates an error in the server or in the interceptor implementation.     
      catch (Throwable t)
      {
         throw new RuntimeOperationsException(new RuntimeException(
               "Unhandled throwable propagated to the invoker by " +
               invocation + ":" +t.toString())
         );
      }
     
      // TODO: should be fixed by adding invocation return value object
      finally
      {
         ctx.setDescriptor(invocation.getDescriptor());
      }     
   }

   public MBeanInfo getMBeanInfo()
   {
      // create the invocation object
      Invocation invocation = new Invocation(getMBeanInfoCtx);
  
      // set the invocation's access point as getMBeanInfo()
      invocation.setType(InvocationContext.OP_GETMBEANINFO);
     
      try
      {
         MBeanInfo info = (MBeanInfo)invocation.invoke();

         return info;
      }
      catch (InvocationException e)
      {
         throw new RuntimeOperationsException(new RuntimeException(
               "Unhandled throwable propagated to the invoker by " +
               invocation + ":" + e.toString())
         );
      }
   }        
        
   public AttributeList getAttributes(java.lang.String[] attributes)
   {
      if (attributes == null)
         throw new IllegalArgumentException("null array");

      AttributeList list = new AttributeList();

      for (int i = 0; i < attributes.length; ++i)
      {
         try
         {
            list.add(new Attribute(attributes[i], getAttribute(attributes[i])));
         }
         catch (JMException ignored)
         {
            // if the attribute could not be retrieved, skip it
         }
      }

      return list;
   }

   public AttributeList setAttributes(AttributeList attributes)
   {
      if (attributes == null
         throw new IllegalArgumentException("null list");

      AttributeList results = new AttributeList();
      Iterator it           = attributes.iterator();

      while (it.hasNext())
      {
         try
         {
            Attribute attr = (Attribute)it.next();
            setAttribute(attr);
            results.add(attr);
         }
         catch (JMException ignored)
         {
            // if unable to set the attribute, skip it
         }
      }

      return results;
   }
  
  
   // MBeanRegistration implementation ------------------------------
  
   /**
    * Initializes this invoker. At the registration time we can be sure that
    * all of the metadata is available and initialize the invoker and cache
    * the data accordingly.   <p>
    *
    * Subclasses that override the <tt>preRegister</tt> method must make sure
    * they call <tt>super.preRegister()</tt> in their implementation to
    * ensure proper initialization of the invoker.
    */
   public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception
   {
      initAttributeContexts(info.getAttributes());
     
      initOperationContexts(info.getOperations());
     
      initDispatchers();
     
      if (!isDelayedRegistration)
         return invokePreRegister(server, name);
      else
         return name;
   }
  
   /**
    */
   public void postRegister(Boolean registrationSuccessful)
   {
      if (!isDelayedRegistration)
         invokePostRegister(registrationSuccessful);
   }
  
   /**
    */
   public void preDeregister() throws Exception
   {
      if (!isDelayedRegistration)
         invokePreDeregister();
   }
  
   /**
    */
   public void postDeregister()
   {
      if (!isDelayedRegistration)
         invokePostDeregister();
   }

  
   // NotificationEmitter implementation ------------------------
  
   public void addNotificationListener(NotificationListener listener,
                                       NotificationFilter filter, Object handback)
   {
      addNotificationListenerToResource(listener, filter, handback);
   }
  
   protected void addNotificationListenerToResource(
         NotificationListener listener, NotificationFilter filter, Object handback
   )
   {
      if (resource instanceof NotificationBroadcaster)
      {
         ((NotificationBroadcaster)resource).addNotificationListener(
               listener, filter, handback
         );
      }
      else
      {
         throw new RuntimeMBeanException(new IllegalArgumentException(
               "Target XXX is not a notification broadcaster"
              
               // FIXME: add the XXX object name, store from registration
         ));
      }
   }
  
   public void removeNotificationListener(NotificationListener listener)
         throws ListenerNotFoundException
   {
      removeNotificationListenerFromResource(listener);
   }
  
   protected void removeNotificationListenerFromResource(NotificationListener listener)
         throws ListenerNotFoundException
   {
      if (resource instanceof NotificationBroadcaster)
      {
         ((NotificationBroadcaster)resource).removeNotificationListener(
               listener
         );
      }
      else
      {
         throw new RuntimeMBeanException(new IllegalArgumentException(
               "Target XXX is not a notification broadcaster"
              
               // FIXME: add the XXX object name, store from registration
         ));
      }
   }
  
   public void removeNotificationListener(NotificationListener listener,
                                          NotificationFilter filter,
                                          Object handback)
         throws ListenerNotFoundException
   {
      removeNotificationListenerFromResource(listener, filter, handback);
   }
  
   protected void removeNotificationListenerFromResource(NotificationListener listener,
                                          NotificationFilter filter,
                                          Object handback)
         throws ListenerNotFoundException
   {
      if (resource instanceof NotificationEmitter)
      {
         ((NotificationEmitter)resource).removeNotificationListener(
               listener, filter, handback
         );
      }
      else
      {
         throw new RuntimeMBeanException(new IllegalArgumentException(
               "Target XXX is not a notification emitter"
              
               // FIXME: add the XXX object name, store from registration
         ));
      }
   }
  
   public MBeanNotificationInfo[] getNotificationInfo()
   {
      return getNotificationInfoFromResource();
   }
  
   protected MBeanNotificationInfo[] getNotificationInfoFromResource()
   {
      if (resource instanceof NotificationBroadcaster)
      {
         return ((NotificationBroadcaster)resource).getNotificationInfo();
      }
      else
         return new MBeanNotificationInfo[] {};
   }
  
  
   // MBeanInvoker implementation -----------------------------------

   public Object getResource()
   {
      return resource;
   }

   public void setResource(Object resource)
   {
      this.resource = resource;
   }
  
   public MBeanInfo getMetaData()
   {
      return info;
   }
  
   public void suspend() {}
  
   public void suspend(long wait) throws TimeoutException {}
  
   public void suspend(boolean force) {}
  
   public boolean isSuspended() { return false; }
  
   public void setInvocationTimeout(long time) {}
  
   public long getInvocationTimeout() { return 0l; }
  
   public void resume() {}
  
  
   // Protected -----------------------------------------------------

   protected void setDelayedRegistration(boolean b)
   {
      this.isDelayedRegistration = b;
   }
  
   protected boolean isDelayedRegistration()
   {
      return isDelayedRegistration;
   }
  
   protected ObjectName invokePreRegister(MBeanServer server, ObjectName name)
         throws Exception
   {     
      if (resource instanceof MBeanRegistration)
         return ((MBeanRegistration)resource).preRegister(server, name);
        
      return name;
   }
  
   protected void invokePostRegister(Boolean b)
   {
      if (resource instanceof MBeanRegistration)
         ((MBeanRegistration)resource).postRegister(b);
   }
  
   protected void invokePreDeregister() throws Exception
   {
      if (resource instanceof MBeanRegistration)
         ((MBeanRegistration)resource).preDeregister();
   }
  
   protected void invokePostDeregister()
   {
      if (resource instanceof MBeanRegistration)
         ((MBeanRegistration)resource).postDeregister();
   }
  
   protected void initAttributeContexts(MBeanAttributeInfo[] attributes)
   {
      // create invocation contexts for attributes
      for (int i = 0; i < attributes.length; ++i)
      {
         InvocationContext ctx = new InvocationContext();
        
         // fill in some default values, the attribute name
         ctx.setName(attributes[i].getName());
        
         ctx.setAttributeType(attributes[i].getType());
        
         // set myself as the invoker
         ctx.setInvoker(this);
        
         //ctx.add(InvocationContext.ATTRIBUTE_ACCESS, getAccessCode(attributes[i]));

         // store
         attributeContextMap.put(attributes[i].getName(), ctx);
      }     
   }
  
   protected void initOperationContexts(MBeanOperationInfo[] operations)
   {
      // create invocation contexts for operations
      for (int i = 0; i < operations.length; ++i)
      {
         InvocationContext ctx = new InvocationContext();
        
         // extract operation name + signature
         String opName                  = operations[i].getName();
         MBeanParameterInfo[] signature = operations[i].getSignature();
        
         // name is unchanged, fill in the context
         ctx.setName(opName);

         // signature doesn't change..
         ctx.setSignature(signature);
        
         // set myself as the invoker
         ctx.setInvoker(this);
        
         // add impact as part of ctx map (rarely accessed information)
         //ctx.add(InvocationContext.OPERATION_IMPACT, operations[i].getImpact());

         // create an operation key consisting of the name + signature
         // (required for overloaded operations)
         OperationKey opKey = new OperationKey(opName, signature);         
        
         // store
         operationContextMap.put(opKey, ctx);
      }
   }
  
   protected void initDispatchers()
   {
      MBeanOperationInfo[] operations = info.getOperations();
      MethodMapper mmap = new MethodMapper(resource.getClass());
     
      for (int i = 0; i < operations.length; ++i)
      {

         OperationKey opKey = new OperationKey(operations[i].getName(), operations[i].getSignature());
         InvocationContext ctx = (InvocationContext)operationContextMap.get(opKey);
        
         Method m = mmap.lookupOperation(operations[i]);

         ctx.setDispatcher(new ReflectedDispatcher(resource, m));
        
         // TODO: should setResource be part of the dispatcher?
         ctx.setResource(resource);
     
     
      getMBeanInfoCtx = new InvocationContext();
      getMBeanInfoCtx.setInvoker(this);     
   }
  
   protected String getSignatureString(String[] signature)
   {
      if (signature == null)
         return "()";
      if (signature.length == 0)
         return "()";
        
      StringBuffer sbuf = new StringBuffer(512);
     
      sbuf.append("(");
      for (int i = 0; i < signature.length - 1; ++i)
      {
         sbuf.append(signature[i]);
         sbuf.append(",");
      }
      sbuf.append(signature[signature.length - 1]);
      sbuf.append(")");
     
      return sbuf.toString();
   }
  

   // Inner classes -------------------------------------------------
   protected final class OperationKey
   {
      String[] keys = null;
      int hash      = 0;
     
      public OperationKey(final String name, final String[] signature)
      {
         if (signature != null)
         {           
            keys = new String[signature.length + 1];
           
            keys[0] = name;
           
            System.arraycopy(signature, 0, keys, 1, signature.length);

            hash = name.hashCode();
         }
        
         else
         {
            keys = new String[] { name };
            hash = name.hashCode();
         }
      }
     
      public OperationKey(String name, MBeanParameterInfo[] signature)
      {
         if (signature == null)
            signature = new MBeanParameterInfo[0];
           
         keys = new String[signature.length + 1];
        
         keys[0] = name;

         for (int i = 0; i < signature.length; ++i)
         {
            keys[i + 1] = signature[i].getType();
         }
        
         hash = name.hashCode();
      }
     
      public OperationKey(MBeanOperationInfo info)
      {
         this(info.getName(), info.getSignature());
      }
     
      public int hashCode()
      {
         return hash;
      }
     
      public boolean equals(Object o)
      {
         OperationKey target = (OperationKey)o;
        
         if (target.keys.length != keys.length)
            return false;
           
         for (int i = 0; i < keys.length; ++i)
         {
            if (!(keys[i].equals(target.keys[i])))
               return false;
         }
        
         return true;
      }
     
   }

}


TOP

Related Classes of org.jboss.mx.server.AbstractMBeanInvoker$OperationKey

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.