/******************************************************************************* * Copyright (c) 2006 Eclipse Foundation * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bjorn Freeman-Benson - initial implementation * Ward Cunningham - initial implementation *******************************************************************************/ package org.eclipse.eclipsemonkey; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.eclipse.core.runtime.IPath; /** * */ public class Subscription { private final String addMethodName; private Object listenerProxy; private Method removeMethod; private Object source; private String sourceString; /** * */ public String trouble = null; /** * * @param _sourceString * @param addMethodName */ public Subscription(String _sourceString, String addMethodName) { this.sourceString = _sourceString; this.addMethodName = addMethodName; } /** * * @param path */ public void subscribe(IPath path) { try { MenuRunMonkeyScript runner = new MenuRunMonkeyScript(path); source = runner.run(this.sourceString, new Object[0], false); subscribe(path, source, addMethodName); } catch (Throwable e) { trouble(e); } } /** * * @param e */ protected void trouble(Throwable e) { if (e instanceof RunMonkeyException) { RunMonkeyException x = (RunMonkeyException) e; trouble = x.errorMessage + x.optionalLineNumber(); } else { trouble = e.getMessage(); } EclipseMonkeyPlugin.getDefault().notifyScriptsChanged(); } /** * * */ public void unsubscribe() { if (trouble != null || removeMethod == null) return; try { removeMethod.invoke(source, new Object[] { listenerProxy }); removeMethod = null; } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } private void subscribe(IPath path, Object foo, String methodName) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { InvocationHandler listener = new ScriptSubscriptionListener(path, this); Method addMethod = findAddMethod(foo, methodName); Class listenerType = addMethod.getParameterTypes()[0]; listenerProxy = Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[] { listenerType }, listener); addMethod.invoke(foo, new Object[] { listenerProxy }); } private Method findAddMethod(Object source, String methodName) throws NoSuchMethodException { Method methods[] = source.getClass().getMethods(); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; if (!(m.getName().equals(methodName))) continue; if (m.getParameterTypes().length != 1) continue; if (findRemoveMethod(source, methodName, m.getParameterTypes()) == null) continue; return m; } throw new NoSuchMethodException(Messages.Subscription_ERR_MSG_Cant_find_add_method); } private Method findRemoveMethod(Object source, String methodName, Class[] parameterTypes) { String removeMethodName = "remove" + methodName.substring(3); //$NON-NLS-1$ try { removeMethod = source.getClass().getMethod(removeMethodName, parameterTypes); return removeMethod; } catch (Exception e) { return null; } } class ScriptSubscriptionListener implements InvocationHandler { IPath script; Subscription subscription; /** * @param script * @param subscription */ public ScriptSubscriptionListener(IPath script, Subscription subscription) { this.script = script; this.subscription = subscription; } /** * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /* * we do NOT want the ctrl-shift-M "re-run the last script" accelerator * bound to this script. */ try { MenuRunMonkeyScript runner = new MenuRunMonkeyScript(script); return runner.run(method.getName(), args, false); } catch (RunMonkeyException x) { subscription.unsubscribe(); subscription.trouble(x); return null; } } } /** * @see java.lang.Object#toString() */ public String toString() { return (trouble == null ? "" : trouble + ": ") + this.sourceString //$NON-NLS-1$ //$NON-NLS-2$ + "()." + this.addMethodName //$NON-NLS-1$ + (removeMethod == null ? " (not listening)" : ""); //$NON-NLS-1$ //$NON-NLS-2$ } }