/**************************************************************************** * Copyright 2008-2011 ThoughtWorks, Inc. * * Licensed 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. * * Initial Contributors: * Håkan Råberg * Manish Chakravarty * Pavan K S ***************************************************************************/ package com.thoughtworks.krypton.driver.web.browser; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.eclipse.swt.widgets.Display; public class Decorators { public static final class SWTThreadingDecorator<T> implements InvocationHandler { private static final List<String> STACK_TRACE_FILTER = Arrays.asList("java.lang.Thread", "java.util.concurrent.ThreadPoolExecutor", "com.thoughtworks.selenium.SeleneseTestCase", "$Proxy", "org.eclipse.swt.widgets", "org.eclipse.swt.SWT", "com.thoughtworks.twist.driver.web.browser.Decorators"); private T anInstance; private SWTThreadingDecorator(T anInstance) { this.anInstance = anInstance; } public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable { if (Display.getCurrent() == Display.getDefault()) { try { return method.invoke(anInstance, args); } catch (InvocationTargetException e) { throw unwind(e); } finally { Display.getDefault().update(); } } try { final Object[] result = new Object[1]; Display.getDefault().syncExec(new Runnable() { public void run() { try { result[0] = method.invoke(anInstance, args); } catch (Exception e) { throw new RuntimeException(e); } finally { Display.getDefault().update(); } } }); return result[0]; } catch (RuntimeException e) { throw unwind(e); } } private Throwable unwind(Throwable t) { Throwable original = t; List<StackTraceElement> stack = new ArrayList<StackTraceElement>(); do { if (!(t instanceof InvocationTargetException)) { stack.addAll(0, Arrays.asList(t.getStackTrace())); } original = t; t = t.getCause(); } while (t != null); for (Iterator<StackTraceElement> iterator = stack.iterator(); iterator.hasNext();) { StackTraceElement element = (StackTraceElement) iterator.next(); for (String prefix : STACK_TRACE_FILTER) { if (element.getClassName().startsWith(prefix)) { iterator.remove(); } } } original.setStackTrace(stack.toArray(new StackTraceElement[0])); return original; } public T getInstance() { return anInstance; } } private static final class LoggingDecorator<T> implements InvocationHandler { private T anInstance; private Logger log; private LoggingDecorator(T anInstance) { this.anInstance = anInstance; this.log = LoggerFactory.getLogger(anInstance.getClass()); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { log.debug("{}: {}", method.getName(), args); return method.invoke(anInstance, args); } catch (InvocationTargetException e) { throw e.getCause(); } } } @SuppressWarnings("unchecked") public static <T> T wrapWithLogging(Class<T> anInterface, T anInstance) { return (T) Proxy.newProxyInstance(Decorators.class.getClassLoader(), new Class[] { anInterface }, new LoggingDecorator<T>( anInstance)); } @SuppressWarnings("unchecked") public static <T> T wrapWithSWTThreading(Class<T> anInterface, T anInstance) { return (T) Proxy.newProxyInstance(Decorators.class.getClassLoader(), new Class[] { anInterface }, new SWTThreadingDecorator<T>( anInstance)); } }