001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.object.bytecode;
005:
006: import com.tc.asm.MethodVisitor;
007: import com.tc.asm.Opcodes;
008: import com.tc.asm.Type;
009:
010: import java.lang.reflect.Method;
011: import java.util.Collections;
012: import java.util.HashMap;
013: import java.util.Map;
014:
015: /**
016: * A helper class to assist in adding Manager method calls into instrumented classes <br>
017: * <br>
018: * Actually, this class could probably be generalized as some form of interface caller for instrumented classes
019: */
020: public class ManagerHelperFactory {
021: private final Class managerUtilClass;
022: private final Map methods;
023:
024: public ManagerHelperFactory() {
025: this .managerUtilClass = ManagerUtil.class;
026: this .methods = findMethods();
027: }
028:
029: private Map findMethods() {
030: Map map = new HashMap();
031:
032: Method[] mgrUtilMethods = this .managerUtilClass
033: .getDeclaredMethods();
034:
035: for (int i = 0; i < mgrUtilMethods.length; i++) {
036: Method m = mgrUtilMethods[i];
037: String name = m.getName();
038: MethodDetail md = new MethodDetail(m);
039:
040: if (map.containsKey(name)) {
041: throw new RuntimeException("Duplicated method name ["
042: + name + "] on interface "
043: + managerUtilClass.getName());
044: } else {
045: map.put(name, md);
046: }
047: }
048:
049: return Collections.unmodifiableMap(map);
050: }
051:
052: public ManagerHelper createHelper() {
053: return new ManagerHelperImpl();
054: }
055:
056: private static class MethodDetail implements Opcodes {
057: final String name;
058: final String desc;
059: final boolean takesManagerAsAnArg;
060:
061: MethodDetail(Method m) {
062: desc = Type.getMethodDescriptor(m);
063: name = m.getName();
064: takesManagerAsAnArg = hasManagerClass(m.getParameterTypes());
065: }
066:
067: private boolean hasManagerClass(Class[] parameterTypes) {
068: if (parameterTypes == null)
069: return false;
070: for (int i = 0; i < parameterTypes.length; i++) {
071: if (parameterTypes[i].getName().equals(
072: Manager.class.getName())) {
073: return true;
074: }
075: }
076: return false;
077: }
078:
079: }
080:
081: private class ManagerHelperImpl implements ManagerHelper, Opcodes {
082: public ManagerHelperImpl() {
083: //
084: }
085:
086: public void callManagerMethod(String name, MethodVisitor mv) {
087: MethodDetail md = findMethodDetail(name);
088: callMethod(md, mv);
089: }
090:
091: private MethodDetail findMethodDetail(String name) {
092: MethodDetail md = (MethodDetail) methods.get(name);
093: if (md == null) {
094: // make formatter work
095: throw new RuntimeException("No such method [" + name
096: + "] on manager class: "
097: + managerUtilClass.getName());
098: }
099: return md;
100: }
101:
102: private void callMethod(MethodDetail md, MethodVisitor mv) {
103: // TODO: We can easily optimize for manager methods that take 0/1/2? arguments. Provided that a few swap
104: // instructions are faster than an invokestatic
105: mv.visitMethodInsn(INVOKESTATIC, ManagerUtil.CLASS,
106: md.name, md.desc);
107: }
108:
109: }
110:
111: }
|