All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.management.internal.MXBeanProxyInvocationHandler Maven / Gradle / Ivy

/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You
 * may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.management.internal;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.ObjectName;

/**
 * This proxy handler handles all the method call invoked on an MXBean It
 * follows same route as MBeanProxyInvocationHandler Only difference is after
 * obtaining the result it transforms the open type to the actual java type
 *
 * @author rishim
 *
 */
public class MXBeanProxyInvocationHandler {

  private ObjectName objectName;

  private MBeanProxyInvocationHandler proxyHandler;

  private final Map methodHandlerMap = OpenTypeUtil
      .newMap();

  // private LogWriterI18n logger;

  public MXBeanProxyInvocationHandler(ObjectName objectName,
      Class mxbeanInterface, MBeanProxyInvocationHandler proxyHandler)
      throws Exception {

    if (mxbeanInterface == null)
      throw new IllegalArgumentException("Null parameter");

    this.objectName = objectName;

    this.proxyHandler = proxyHandler;

    // this.logger = InternalDistributedSystem.getLoggerI18n();
    this.initHandlers(mxbeanInterface);
  }

  // Introspect the mbeanInterface and initialize this object's maps.
  //
  private void initHandlers(Class mbeanInterface) throws Exception {
    final Method[] methodArray = mbeanInterface.getMethods();

    final List methods = eliminateCovariantMethods(methodArray);

    for (Method m : methods) {
      String name = m.getName();

      String attrName = "";
      if (name.startsWith("get")) {
        attrName = name.substring(3);
      } else if (name.startsWith("is") && m.getReturnType() == boolean.class) {
        attrName = name.substring(2);
      }

      if (attrName.length() != 0 && m.getParameterTypes().length == 0
          && m.getReturnType() != void.class) { // For Getters

        methodHandlerMap
            .put(m, new GetterHandler(attrName, new OpenMethod(m)));
      } else if (name.startsWith("set") && name.length() > 3
          && m.getParameterTypes().length == 1
          && m.getReturnType() == void.class) { // For Setteres
        methodHandlerMap
            .put(m, new SetterHandler(attrName, new OpenMethod(m)));
      } else {
        methodHandlerMap.put(m, new OpHandler(attrName, new OpenMethod(m)));
      }
    }
  }

  /**
   * Eliminate methods that are overridden with a covariant return type.
   * Reflection will return both the original and the overriding method but we
   * need only the overriding one is of interest
   *
   * @param methodArray methods for elimination of covariant return types
   * @return the method after eliminating covariant menthods
   */
  static List eliminateCovariantMethods(Method[] methodArray) {

    final int len = methodArray.length;
    final Method[] sorted = methodArray.clone();
    Arrays.sort(sorted, MethodOrder.instance);
    final Set overridden = OpenTypeUtil.newSet();
    for (int i = 1; i < len; i++) {
      final Method m0 = sorted[i - 1];
      final Method m1 = sorted[i];

      if (!m0.getName().equals(m1.getName()))
        continue;

      if (Arrays.equals(m0.getParameterTypes(), m1.getParameterTypes())) {
        overridden.add(m0);
      }
    }

    final List methods = OpenTypeUtil.newList(Arrays
        .asList(methodArray));
    methods.removeAll(overridden);
    return methods;
  }

  /**
   * A comparator that defines a total order so that methods have the same name
   * and identical signatures appear next to each others. The methods are sorted
   * in such a way that methods which override each other will sit next to each
   * other, with the overridden method first - e.g. Object getFoo() is placed
   * before Integer getFoo(). This makes it possible to determine whether a
   * method overrides another one simply by looking at the method(s) that
   * precedes it in the list. (see eliminateCovariantMethods).
   **/
  private static class MethodOrder implements Comparator {
    public int compare(Method a, Method b) {
      final int cmp = a.getName().compareTo(b.getName());
      if (cmp != 0)
        return cmp;
      final Class[] aparams = a.getParameterTypes();
      final Class[] bparams = b.getParameterTypes();
      if (aparams.length != bparams.length)
        return aparams.length - bparams.length;
      if (!Arrays.equals(aparams, bparams)) {
        return Arrays.toString(aparams).compareTo(Arrays.toString(bparams));
      }
      final Class aret = a.getReturnType();
      final Class bret = b.getReturnType();
      if (aret == bret)
        return 0;

      if (aret.isAssignableFrom(bret))
        return -1;
      return +1;
    }

    public final static MethodOrder instance = new MethodOrder();
  }

  /**
   * Hanlder for MXBean Proxy
   *
   * @author rishim
   *
   */
  private abstract class MethodHandler {
    MethodHandler(String name, OpenMethod cm) {
      this.name = name;
      this.convertingMethod = cm;
    }

    String getName() {
      return name;
    }

    OpenMethod getConvertingMethod() {
      return convertingMethod;
    }

    abstract Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

    private final String name;
    private final OpenMethod convertingMethod;
  }

  private class GetterHandler extends MethodHandler {
    GetterHandler(String attributeName, OpenMethod cm) {
      super(attributeName, cm);
    }

    @Override
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      assert (args == null || args.length == 0);
      final String methodName = method.getName();
      String attrName = "";
      if (methodName.startsWith("get")) {
        attrName = methodName.substring(3);
      } else if (methodName.startsWith("is")
          && method.getReturnType() == boolean.class) {
        attrName = methodName.substring(2);

      }
      return proxyHandler.delegateToObjectState(attrName);
    }
  }

  private class SetterHandler extends MethodHandler {
    SetterHandler(String attributeName, OpenMethod cm) {
      super(attributeName, cm);
    }

    @Override
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      final String methodName = method.getName();
      final Class[] paramTypes = method.getParameterTypes();
      final String[] signature = new String[paramTypes.length];
      for (int i = 0; i < paramTypes.length; i++)
        signature[i] = paramTypes[i].getName();
      return proxyHandler.delegateToFunctionService(objectName, methodName,
          args, signature);

    }
  }

  private class OpHandler extends MethodHandler {

    OpHandler(String operationName, OpenMethod cm) {
      super(operationName, cm);

    }

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      final String methodName = method.getName();
      final Class[] paramTypes = method.getParameterTypes();
      final String[] signature = new String[paramTypes.length];
      for (int i = 0; i < paramTypes.length; i++)
        signature[i] = paramTypes[i].getName();
      return proxyHandler.delegateToFunctionService(objectName, methodName,
          args, signature);
    }

  }

  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {

    MethodHandler handler = methodHandlerMap.get(method);
    OpenMethod cm = handler.getConvertingMethod();

    Object[] openArgs = cm.convertParamsToOpenTypes(args);
    Object result = handler.invoke(proxy, method, openArgs);
    return cm.convertOpenTypeToReturnValue(result);
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy