blob: 408346bc2ddd9ca092d7d114c063329464d04834 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.netbeans.modules.debugger.jpda.visual.remote;
import java.awt.Component;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.EventListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class RemoteAWTServiceListener implements InvocationHandler {
private final Component c;
private final Class listenerClass;
public RemoteAWTServiceListener(Component c, Class listenerClass) {
this.c = c;
this.listenerClass = listenerClass;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if ("equals".equals(methodName) && args.length == 1) {
return (proxy == args[0]) ? Boolean.TRUE : Boolean.FALSE;
}
logEventData(methodName, args.length > 0 ? args[0] : null, listenerClass);
return null;
}
public EventListener createLoggingListener(Class c) {
return (EventListener) Proxy.newProxyInstance(c.getClassLoader(), new Class[] { c }, this);
}
public static Object add(Component c, Class listenerClass) {
String addName = "add"+listenerClass.getSimpleName();
Method addListenerMethod;
try {
addListenerMethod = c.getClass().getMethod(addName, new Class[] { listenerClass });
} catch (NoSuchMethodException ex) {
return null;
} catch (SecurityException ex) {
return null;
}
RemoteAWTServiceListener rl = new RemoteAWTServiceListener(c, listenerClass);
Object listener = rl.createLoggingListener(listenerClass);
try {
addListenerMethod.invoke(c, new Object[] { listener });
} catch (Exception ex) {
return null;
}
return listener;
}
public static boolean remove(Component c, Class listenerClass, Object listener) {
String removeName = "remove"+listenerClass.getSimpleName();
Method removeListenerMethod;
try {
removeListenerMethod = c.getClass().getMethod(removeName, new Class[] { listenerClass });
} catch (NoSuchMethodException ex) {
return false;
} catch (SecurityException ex) {
return false;
}
try {
Object removed = removeListenerMethod.invoke(c, new Object[] { listener });
if (removed instanceof Boolean) {
return ((Boolean) removed).booleanValue();
} else {
return true;
}
} catch (Exception ex) {
return false;
}
}
private void logEventData(String methodName, Object event, Class listenerClass) {
//System.err.println("RemoteServiceListener.logEventData("+methodName+", "+event+")");
String toString = String.valueOf(event);
Map properties = new HashMap();
if (event != null) {
Method[] methods = event.getClass().getMethods();
for (int mi = 0; mi < methods.length; mi++) {
Method m = methods[mi];
String mname = m.getName();
if ((mname.startsWith("get") || mname.startsWith("is") || mname.equals("paramString")) &&
m.getParameterTypes().length == 0) {
if (mname.startsWith("get") && mname.length() > 3) {
char c1 = mname.charAt(3);
if (mname.length() <= 4 || !Character.isUpperCase(mname.charAt(4))) {
c1 = Character.toLowerCase(c1);
}
mname = c1 + mname.substring(4);
}
if (mname.startsWith("is") && mname.length() > 2) {
mname = Character.toLowerCase(mname.charAt(2)) + mname.substring(3);
}
Object value;
try {
value = m.invoke(event, new Object[] {});
} catch (Exception ex) {
continue;
}
String valueStr = String.valueOf(value);
properties.put(mname, valueStr);
}
}
}
String[] data = new String[2 + 2*properties.size()];
int i = 0;
data[i++] = methodName;
data[i++] = toString;
for (Iterator it = properties.keySet().iterator(); it.hasNext(); ) {
String name = (String) it.next();
String value = (String) properties.get(name);
data[i++] = name;
data[i++] = value;
}
String[] stack = retrieveStack();
RemoteAWTService.pushEventData(c, listenerClass, data, stack);
}
private static final int STACK_OFFSET = 8;
private static String[] retrieveStack() {
//Thread.currentThread().getStackTrace(); JDK 5 call
Thread t = Thread.currentThread();
try {
Method getStackTrace;
try {
getStackTrace = Thread.class.getMethod("getStackTrace", new Class[] {});
} catch (Exception ex) {
// JDK 5 methods not available
// new Exception().getStackTrace(); JDK 1.4 call
getStackTrace = Exception.class.getMethod("getStackTrace", new Class[] {});
}
Object[] stackTraceElements = (Object[]) getStackTrace.invoke(t, new Object[] {});
int n = stackTraceElements.length;
int s = Math.min(STACK_OFFSET, n);
String[] elements = new String[n - s];
for (int i = s; i < n; i++) {
Method getClassName = stackTraceElements[i].getClass().getMethod("getClassName", new Class[] {});
String className = (String) getClassName.invoke(stackTraceElements[i], new Object[] {});
Method getMethodName = stackTraceElements[i].getClass().getMethod("getMethodName", new Class[] {});
String methodName = (String) getMethodName.invoke(stackTraceElements[i], new Object[] {});
Method getFileName = stackTraceElements[i].getClass().getMethod("getFileName", new Class[] {});
String fileName = (String) getFileName.invoke(stackTraceElements[i], new Object[] {});
Method getLineNumber = stackTraceElements[i].getClass().getMethod("getLineNumber", new Class[] {});
Integer lineNumber = (Integer) getLineNumber.invoke(stackTraceElements[i], new Object[] {});
elements[i - s] = className + "." + methodName + "(" + fileName + ":" + lineNumber + ")";
}
return elements;
} catch (Exception ex) {
}
// JDK 1.3 or older
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
new Exception().printStackTrace(pw);
pw.close();
StringBuffer sb = sw.getBuffer();
// TODO
return new String[] { sb.toString() };
}
}