/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG and others.
* 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.ui.ridgets.annotation.handler;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import org.eclipse.riena.core.annotationprocessor.AnnotatedOverriddenMethodsGuard;
import org.eclipse.riena.core.annotationprocessor.AnnotationProcessor;
import org.eclipse.riena.core.annotationprocessor.DisposerList;
import org.eclipse.riena.core.annotationprocessor.IAnnotatedMethodHandler;
import org.eclipse.riena.ui.ridgets.IRidget;
import org.eclipse.riena.ui.ridgets.IRidgetContainer;
/**
* "Helper" for concrete annotation handlers.
*
* @since 3.0
*/
public abstract class AbstractRidgetContainerAnnotationHandler implements IAnnotatedMethodHandler {
/**
* ThreadLocal disposer list
*
* @since 6.1
*/
protected ThreadLocal<DisposerList> disposers = new ThreadLocal<DisposerList>();
/**
* ThreadLocal optional arguments list
*
* @since 6.1
*/
protected ThreadLocal<Map<?, ?>> optionalArgs = new ThreadLocal<Map<?, ?>>();
protected IRidget getRidget(final Annotation annotation, final Method method,
final IRidgetContainer ridgetContainer, final String ridgetId) {
final IRidget ridget = ridgetContainer.getRidget(ridgetId);
if (ridget != null) {
return ridget;
}
throw new IllegalStateException(annotation + " defined unknown ridget id on method '" + method + "'."); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* @since 6.1
*/
public void handleAnnotation(final Annotation annotation, final Object object, final Method method, final Map<?, ?> optionalArgs,
final AnnotatedOverriddenMethodsGuard guard, final DisposerList disposers) {
if (!optionalArgs.containsKey(AnnotationProcessor.PROCESS_TARGET)
|| !(optionalArgs.get(AnnotationProcessor.PROCESS_TARGET) instanceof IRidgetContainer)) {
throw new IllegalArgumentException("Argument '" + AnnotationProcessor.PROCESS_TARGET + "' must be set."); //$NON-NLS-1$ //$NON-NLS-2$
}
final IRidgetContainer ridgetContainer = (IRidgetContainer) optionalArgs.get(AnnotationProcessor.PROCESS_TARGET);
this.disposers.set(disposers);
this.optionalArgs.set(optionalArgs);
handleAnnotation(annotation, ridgetContainer, object, method, guard);
this.disposers.remove();
this.optionalArgs.remove();
}
/**
* @since 6.1
*/
public abstract void handleAnnotation(final Annotation annotation, final IRidgetContainer ridgetContainer, final Object target, final Method targetMethod,
final AnnotatedOverriddenMethodsGuard guard);
protected void errorUnsupportedRidgetType(final Annotation annotation, final IRidget ridget) {
throw new IllegalStateException(annotation + " defined for incompatible ridget type '" //$NON-NLS-1$
+ ridget.getClass().getName() + "' with id '" + ridget.getID() + "'."); //$NON-NLS-1$ //$NON-NLS-2$
}
protected <L> L createListener(final Class<L> listenerClazz, final String listenerMethodName, final Object target,
final Method targetMethod) {
return (L) Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[] { listenerClazz },
new ListenerHandler(target, listenerClazz, listenerMethodName, targetMethod));
}
private static class ListenerHandler implements InvocationHandler {
private final Object target;
private final Class<?> listenerClazz;
private final String listenerMethodName;
private final Method targetMethod;
public ListenerHandler(final Object target, final Class<?> listenerClazz, final String listenerMethodName,
final Method targetMethod) {
this.target = target;
this.listenerClazz = listenerClazz;
this.listenerMethodName = listenerMethodName;
this.targetMethod = targetMethod;
if (!targetMethod.isAccessible()) {
targetMethod.setAccessible(true);
}
}
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
final String methodName = method.getName();
if (method.getDeclaringClass() == Object.class) {
if (methodName.equals("hashCode")) { //$NON-NLS-1$
return System.identityHashCode(proxy);
} else if (methodName.equals("equals")) { //$NON-NLS-1$
return proxy == args[0];
} else if (methodName.equals("toString")) { //$NON-NLS-1$
return "Proxy for " + listenerClazz.getName() + " " + proxy.getClass().getName() + '@' //$NON-NLS-1$ //$NON-NLS-2$
+ Integer.toHexString(proxy.hashCode());
}
}
if (methodName.equals(listenerMethodName)) {
try {
if (targetMethod.getParameterTypes().length == 0) {
return targetMethod.invoke(target);
} else {
return targetMethod.invoke(target, args);
}
} catch (final InvocationTargetException e) {
throw e.getTargetException();
}
}
return null;
}
}
/**
* Getter for the disposer list.
*
* @return the disposers
* @since 6.1
*/
public DisposerList getDisposers() {
return disposers.get();
}
/**
* Getter for the optional arguments.
*
* @return the optionalArgs
* @since 6.1
*/
public Map<?, ?> getOptionalArgs() {
return optionalArgs.get();
}
}