/**
   * Routes a method invocation (not a property get/set) to the corresponding operation on the
   * managed resource.
   *
   * @param method the method corresponding to operation on the managed resource.
   * @param args the invocation arguments
   * @return the value returned by the method invocation.
   */
  private Object invokeOperation(Method method, Object[] args) throws JMException, IOException {
    MethodCacheKey key = new MethodCacheKey(method.getName(), method.getParameterTypes());
    MBeanOperationInfo info = (MBeanOperationInfo) this.allowedOperations.get(key);
    if (info == null) {
      throw new InvalidInvocationException(
          "Operation '" + method.getName() + "' is not exposed on the management interface");
    }

    String[] signature = null;
    synchronized (this.signatureCache) {
      signature = (String[]) this.signatureCache.get(method);
      if (signature == null) {
        signature = JmxUtils.getMethodSignature(method);
        this.signatureCache.put(method, signature);
      }
    }
    return this.server.invoke(this.objectName, method.getName(), args, signature);
  }