Package com.subhajit.metering

Source Code of com.subhajit.metering.MeteringInvocationHandler

package com.subhajit.metering;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReentrantLock;

import com.subhajit.common.jmx.util.AggregateData;
import com.subhajit.common.jmx.util.Counter;
import com.subhajit.common.jmx.util.Timer;
import com.subhajit.common.util.IConstants;

/**
* Invocation handler that counts, times and measures CPU utilization for method
* calls.
*
* <p>
* Used by {@link MeteringProxy}.
* </p>
*
* @author sdasgupta
*
*/
public class MeteringInvocationHandler implements InvocationHandler {
  /**
   * The target object being proxied.
   */
  private final Object target;

  /**
   * {@link Map} in which each entry's {@link Entry#getKey()} returns a String
   * representing a {@link Method} of a proxied interface, and
   * {@link Entry#getValue()} returns a {@link CpuMeter} metering invocations
   * of that method.
   */
  private final Map<String, CpuMeter> cpuMeterMap;

  /**
   * {@link Map} in which each entry's {@link Entry#getKey()} returns a String
   * representing a {@link Method} of a proxied interface, and
   * {@link Entry#getValue()} returns a {@link Timer} metering invocation
   * times for that method.
   */
  private final Map<String, Timer> executionTimers;

  /**
   * {@link Map} in which each entry's {@link Entry#getKey()} returns a String
   * representing a {@link Method} of a proxied interface, and
   * {@link Entry#getValue()} returns a {@link Counter} measuring invocation
   * counts of that method.
   */
  private final Map<String, Counter> executionCounters;

  /**
   * The interfaces being proxied.
   *
   * @see {@link MeteringProxy}.
   */
  private final Class<?>[] interfaces;

  private final ReentrantLock lock;

  // private final Map<Method, MethodBean> methodBeans;

  /**
   * Package protected constructor for use by {@link MeteringProxy}.
   *
   * @param target
   *            The target object being metered.
   * @param interfaces
   *            Proxied interfaces implemented by the target object.
   */
  MeteringInvocationHandler(Object target, Class<?>... interfaces) {
    super();
    executionTimers = new HashMap<String, Timer>();
    executionCounters = new HashMap<String, Counter>();
    this.target = target;
    cpuMeterMap = new HashMap<String, CpuMeter>();
    this.interfaces = new Class<?>[interfaces.length];
    System.arraycopy(interfaces, 0, this.interfaces, 0, interfaces.length);
    // methodBeans = new HashMap<Method, MethodBean>();
    for (Class<?> klass : interfaces) {
      for (Method method : klass.getMethods()) {
        // MethodBean methodBean = new MethodBean(method);
        // methodBeans.put(method, methodBean);
        String methodStr = toString(method);
        cpuMeterMap.put(methodStr, new CpuMeter());
        executionTimers.put(methodStr, new Timer());
        executionCounters.put(methodStr, new Counter());
      }
    }
    lock = new ReentrantLock();
  }

  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    lock.lock();
    try {
      final String methodStr = toString(method);
      CpuMeter cpuMeter = cpuMeterMap.get(methodStr);
      AggregateData<Long> executionTimer = executionTimers.get(methodStr);
      Counter executionCounter = executionCounters.get(methodStr);
      executionCounter.add(1);
      long t0 = System.nanoTime();
      try {
        cpuMeter.beginRequest();
        try {
          return method.invoke(target, args);
        } finally {
          cpuMeter.endRequest();
        }
      } finally {
        t0 = System.nanoTime() - t0;
        executionTimer.addData(t0);
      }
    } finally {
      lock.unlock();
    }
  }

  /**
   * Gets a copy of {@link #cpuMeterMap}.
   *
   * @return
   */
  public Map<String, CpuMeter> getCpuMeters() {
    Map<String, CpuMeter> ret = new HashMap<String, CpuMeter>();
    ret.putAll(cpuMeterMap);
    return ret;
  }

  /**
   * Gets a copy of {@link #executionTimers}.
   *
   * @return
   */
  public Map<String, Timer> getExecutionTimes() {
    Map<String, Timer> ret = new HashMap<String, Timer>();
    ret.putAll(executionTimers);
    return ret;
  }

  /**
   * Gets a copy of {@link #executionCounters}.
   *
   * @return
   */
  public Map<String, Counter> getExecutionCounters() {
    Map<String, Counter> ret = new HashMap<String, Counter>();
    ret.putAll(executionCounters);
    return ret;
  }

  public void reset() {
    lock.lock();
    try {
      for (Map.Entry<String, CpuMeter> entry : cpuMeterMap.entrySet()) {
        entry.getValue().reset();
      }
      for (Map.Entry<String, Counter> entry : executionCounters
          .entrySet()) {
        entry.getValue().reset();
      }
      for (Map.Entry<String, Timer> entry : executionTimers.entrySet()) {
        entry.getValue().reset();
      }
    } finally {
      lock.unlock();
    }
  }

  private static final ThreadLocal<Map<Method, String>> methodsMap = new ThreadLocal<Map<Method, String>>();

  private static String toString(Method method) {
    Map<Method, String> methods = methodsMap.get();
    if (methods == null) {
      methods = new HashMap<Method, String>();
      methodsMap.set(methods);
    }
    if (methods.containsKey(method)) {
      return methods.get(method);
    } else {
      StringBuilder methodStr = new StringBuilder().append(
          method.getName()).append("(");
      boolean firstArg = true;
      for (Class<?> klass : method.getParameterTypes()) {
        if (!firstArg) {
          methodStr.append(IConstants.COMMA);
          firstArg = false;
        }
        methodStr.append(klass.getCanonicalName());
      }
      methodStr.append(")");
      String methodStrStr = methodStr.toString();
      methods.put(method, methodStrStr);
      return methodStrStr;
    }
  }
}
TOP

Related Classes of com.subhajit.metering.MeteringInvocationHandler

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.