001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.event;
006:
007: import com.tc.asm.Type;
008: import com.tc.logging.TCLogger;
009: import com.tc.logging.TCLogging;
010: import com.tc.object.ClientObjectManager;
011: import com.tc.object.ObjectID;
012: import com.tc.object.dmi.DmiClassSpec;
013: import com.tc.object.dmi.DmiDescriptor;
014: import com.tc.object.loaders.ClassProvider;
015: import com.tc.object.lockmanager.api.LockLevel;
016: import com.tc.object.logging.RuntimeLogger;
017: import com.tc.util.Assert;
018: import com.tcclient.object.DistributedMethodCall;
019:
020: import java.lang.reflect.InvocationTargetException;
021: import java.lang.reflect.Method;
022: import java.util.HashSet;
023: import java.util.Set;
024:
025: public class DmiManagerImpl implements DmiManager {
026: private static final TCLogger logger = TCLogging
027: .getLogger(DmiManager.class);
028: private static final String lockName = "@DistributedMethodCall";
029: private static final Object TRUE = new Object();
030:
031: private final ClassProvider classProvider;
032: private final ClientObjectManager objMgr;
033: private final RuntimeLogger runtimeLogger;
034: private final ThreadLocal feedBack;
035: private final ThreadLocal nesting;
036:
037: public DmiManagerImpl(ClassProvider cp, ClientObjectManager om,
038: RuntimeLogger rl) {
039: Assert.pre(cp != null);
040: Assert.pre(om != null);
041: Assert.pre(rl != null);
042: this .classProvider = cp;
043: this .objMgr = om;
044: this .runtimeLogger = rl;
045: this .feedBack = new ThreadLocal();
046: this .nesting = new ThreadLocal();
047: }
048:
049: public boolean distributedInvoke(Object receiver, String method,
050: Object[] params, boolean runOnAllNodes) {
051: if (feedBack.get() != null) {
052: return false;
053: }
054: if (nesting.get() != null) {
055: return false;
056: }
057: nesting.set(TRUE);
058:
059: Assert.pre(receiver != null);
060: Assert.pre(method != null);
061: Assert.pre(params != null);
062:
063: final String methodName = method.substring(0, method
064: .indexOf('('));
065: final String paramDesc = method.substring(method.indexOf('('));
066: final DistributedMethodCall dmc = new DistributedMethodCall(
067: receiver, params, methodName, paramDesc);
068: if (runtimeLogger.distributedMethodDebug())
069: runtimeLogger.distributedMethodCall(receiver.getClass()
070: .getName(), dmc.getMethodName(), dmc
071: .getParameterDesc());
072: objMgr.getTransactionManager().begin(lockName,
073: LockLevel.CONCURRENT);
074: try {
075: final ObjectID receiverId = objMgr.lookupOrCreate(receiver)
076: .getObjectID();
077: final ObjectID dmiCallId = objMgr.lookupOrCreate(dmc)
078: .getObjectID();
079: final DmiClassSpec[] classSpecs = getClassSpecs(
080: classProvider, receiver, params);
081: final DmiDescriptor dd = new DmiDescriptor(receiverId,
082: dmiCallId, classSpecs, runOnAllNodes);
083: objMgr.getTransactionManager().addDmiDescriptor(dd);
084: return true;
085: } finally {
086: objMgr.getTransactionManager().commit(lockName);
087: }
088: }
089:
090: public void distributedInvokeCommit() {
091: if (feedBack.get() != null) {
092: return;
093: }
094: Assert.pre(nesting.get() != null);
095: nesting.set(null);
096: }
097:
098: public void invoke(DistributedMethodCall dmc) {
099: try {
100: if (runtimeLogger.distributedMethodDebug())
101: runtimeLogger.distributedMethodCall(dmc.getReceiver()
102: .getClass().getName(), dmc.getMethodName(), dmc
103: .getParameterDesc());
104: feedBack.set(TRUE);
105: invoke0(dmc);
106: } catch (Throwable e) {
107: // FIXME: debug code
108: e.printStackTrace();
109: // FIXME: end debug code
110: runtimeLogger.distributedMethodCallError(dmc.getReceiver()
111: .getClass().getName(), dmc.getMethodName(), dmc
112: .getParameterDesc(), e);
113: if (logger.isDebugEnabled())
114: logger.debug("Ignoring distributed method call", e);
115: } finally {
116: feedBack.set(null);
117: }
118: }
119:
120: private static void invoke0(DistributedMethodCall dmc)
121: throws IllegalArgumentException, IllegalAccessException,
122: InvocationTargetException {
123: final ClassLoader origContextLoader = Thread.currentThread()
124: .getContextClassLoader();
125: Method m = getMethod(dmc);
126: m.setAccessible(true);
127:
128: ClassLoader tcl = dmc.getReceiver().getClass().getClassLoader();
129: if (tcl == null)
130: tcl = ClassLoader.getSystemClassLoader();
131: Thread.currentThread().setContextClassLoader(tcl);
132:
133: try {
134: m.invoke(dmc.getReceiver(), dmc.getParameters());
135: } finally {
136: Thread.currentThread().setContextClassLoader(
137: origContextLoader);
138: }
139: }
140:
141: private static Method getMethod(DistributedMethodCall dmc) {
142: String methodName = dmc.getMethodName();
143: String paramDesc = dmc.getParameterDesc();
144:
145: Class c = dmc.getReceiver().getClass();
146:
147: while (c != null) {
148: Method[] methods = c.getDeclaredMethods();
149: for (int i = 0; i < methods.length; i++) {
150: Method m = methods[i];
151: if (!m.getName().equals(methodName)) {
152: continue;
153: }
154: Class[] argTypes = m.getParameterTypes();
155: StringBuffer signature = new StringBuffer("(");
156: for (int j = 0; j < argTypes.length; j++) {
157: signature.append(Type.getDescriptor(argTypes[j]));
158: }
159: signature.append(")");
160: signature.append(Type.getDescriptor(m.getReturnType()));
161: if (signature.toString().equals(paramDesc)) {
162: return m;
163: }
164: }
165:
166: c = c.getSuperclass();
167: }
168: throw new RuntimeException("Method " + methodName + paramDesc
169: + " does not exist on this object: "
170: + dmc.getReceiver());
171: }
172:
173: private static void checkClassAvailability(
174: ClassProvider classProvider, DmiClassSpec[] classSpecs)
175: throws ClassNotFoundException {
176: Assert.pre(classSpecs != null);
177: for (int i = 0; i < classSpecs.length; i++) {
178: DmiClassSpec s = classSpecs[i];
179: classProvider.getClassFor(s.getClassName(), s
180: .getClassLoaderDesc());
181: }
182: }
183:
184: private static DmiClassSpec[] getClassSpecs(
185: ClassProvider classProvider, Object receiver,
186: Object[] params) {
187: Assert.pre(classProvider != null);
188: Assert.pre(receiver != null);
189: Assert.pre(params != null);
190:
191: Set set = new HashSet();
192: set.add(getClassSpec(classProvider, receiver));
193: for (int i = 0; i < params.length; i++) {
194: final Object p = params[i];
195: if (p != null)
196: set.add(getClassSpec(classProvider, p));
197: }
198: DmiClassSpec[] rv = new DmiClassSpec[set.size()];
199: set.toArray(rv);
200: return rv;
201: }
202:
203: private static Object getClassSpec(ClassProvider classProvider,
204: Object obj) {
205: Assert.pre(classProvider != null);
206: Assert.pre(obj != null);
207: final String classLoader = classProvider
208: .getLoaderDescriptionFor(obj.getClass());
209: final String className = obj.getClass().getName();
210: return new DmiClassSpec(classLoader, className);
211: }
212:
213: public DistributedMethodCall extract(DmiDescriptor dd) {
214: Assert.pre(dd != null);
215:
216: try {
217: checkClassAvailability(classProvider, dd.getClassSpecs());
218: } catch (ClassNotFoundException e) {
219: if (logger.isDebugEnabled())
220: logger.debug("Ignoring distributed method call", e);
221: return null;
222: }
223:
224: try {
225: DistributedMethodCall dmc = (DistributedMethodCall) objMgr
226: .lookupObject(dd.getDmiCallId());
227: // FIXME: debug code below ----------
228: dmc.getClass();
229: dmc.getReceiver().getClass().getName();
230: dmc.getMethodName();
231: dmc.getParameterDesc();
232: // FIXME: debug code above ----------
233:
234: return dmc;
235: } catch (Throwable e) {
236: // FIXME: debug code
237: e.printStackTrace();
238: // FIXME: end debug code
239:
240: if (logger.isDebugEnabled())
241: logger.debug("Ignoring distributed method call", e);
242: return null;
243: }
244:
245: // unreachable
246: }
247:
248: }
|