/*
* Copyright 2015 Amazon Technologies, 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://aws.amazon.com/apache2.0
*
* This file 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 com.amazonaws.eclipse.elasticbeanstalk.util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.swt.widgets.Display;
/**
* Proxy Factory to create a dynamic proxy that will intercept all method calls and run them on the
* UI thread of the default {@link Display}
*/
public final class OnUiThreadProxyFactory {
/**
* Get dynamic proxy that will run all method calls on the UI thread
*
* @param interfaceClass
* Interface to proxy
* @param interfaceImpl
* Implementation to delegate calls to after wrapping them in a runnable to invoke on
* the UI thread
* @return Proxy class
*/
public static <T> T getProxy(Class<T> interfaceClass, T interfaceImpl) {
Object proxy = Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] { interfaceClass },
new OnUiThreadProxyFactory.OnUiThreadProxyHandler<T>(interfaceImpl));
return interfaceClass.cast(proxy);
}
/**
* Smiple handler to wrap calls in a runnable and submit them to be run on the UI thread of the
* default display
*
* @param <T>
* Type of interface being proxied
*/
private static final class OnUiThreadProxyHandler<T> implements InvocationHandler {
private final T interfaceImpl;
public OnUiThreadProxyHandler(T impl) {
this.interfaceImpl = impl;
}
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
final AtomicReference<Object> toReturnRef = new AtomicReference<Object>();
final AtomicReference<Throwable> throwRef = new AtomicReference<Throwable>();
Display.getDefault().syncExec(new Runnable() {
public void run() {
try {
toReturnRef.set(method.invoke(interfaceImpl, args));
} catch (InvocationTargetException e) {
throwRef.set(e.getTargetException());
} catch (UndeclaredThrowableException e) {
throwRef.set(e.getUndeclaredThrowable());
} catch (Exception e) {
throwRef.set(e);
}
}
});
// Throw the exception if any
if (throwRef.get() != null) {
throw throwRef.get();
}
return toReturnRef.get();
}
}
}