Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.googlecode.openbeans.EventHandler Maven / Gradle / Ivy
/*
* 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 com.googlecode.openbeans;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.StringTokenizer;
import org.apache.harmony.beans.BeansUtils;
import org.apache.harmony.beans.internal.nls.Messages;
public class EventHandler implements InvocationHandler
{
private Object target;
private String action;
private String eventPropertyName;
private String listenerMethodName;
final private AccessControlContext context;
public EventHandler(Object target, String action, String eventPropertyName, String listenerMethodName)
{
if (target == null || action == null)
{
throw new NullPointerException();
}
this.target = target;
this.action = action;
this.eventPropertyName = eventPropertyName;
this.listenerMethodName = listenerMethodName;
this.context = AccessController.getContext();
}
public Object invoke(final Object proxy, final Method method, final Object[] arguments)
{
return AccessController.doPrivileged(new PrivilegedAction() {
public Object run()
{
return invokeImpl(proxy, method, arguments);
}
}, context);
}
private Object invokeImpl(Object proxy, Method method, Object[] arguments)
{
Class> proxyClass = proxy.getClass();
Object[] theArguments = arguments == null ? new Object[0] : arguments;
Object result = null;
// if a proxy
if (Proxy.isProxyClass(proxyClass))
{
InvocationHandler handler = Proxy.getInvocationHandler(proxy);
// if a valid object
if (handler instanceof EventHandler)
{
// if the method from the Object class is called
String methodName = method.getName();
if (method.getDeclaringClass() == Object.class)
{
if (theArguments.length == 0)
{
if ("hashCode".equals(methodName)) { //$NON-NLS-1$
result = Integer.valueOf(hashCode());
}
else if ("toString".equals(methodName)) { //$NON-NLS-1$
result = proxy.getClass().getSimpleName() + toString().substring(getClass().getName().length());
}
}
else if (theArguments.length == 1 && theArguments[0] != null && "equals".equals(methodName)) { //$NON-NLS-1$
result = Boolean.valueOf(proxy == theArguments[0]);
}
}
else if (isValidInvocation(method, theArguments))
{
// if listener method
try
{
// extract value from event property name
Object[] args = getArgs(theArguments);
// extract method to be invoked on target
Method m = getMethod(proxy, method, theArguments, args);
// we have a valid listener method at this point
result = m.invoke(target, args);
}
catch (RuntimeException e)
{
throw e;
}
catch (Throwable t)
{
throw new RuntimeException(t);
}
}
else
{
// in order to be compatible with RI
if (listenerMethodName.equals(methodName))
{
throw new IllegalArgumentException(Messages.getString("beans.4D")); //$NON-NLS-1$
}
}
}
}
else
{
// HARMONY-2495
if (null == method)
{
throw new NullPointerException(Messages.getString("beans.55")); //$NON-NLS-1$
}
}
return result;
}
public String getListenerMethodName()
{
return listenerMethodName;
}
public String getEventPropertyName()
{
return eventPropertyName;
}
public String getAction()
{
return action;
}
public Object getTarget()
{
return target;
}
@SuppressWarnings("unchecked")
public static T create(Class listenerInterface, Object target, String action, String eventPropertyName, String listenerMethodName)
{
if (action == null || target == null || listenerInterface == null)
{
throw new NullPointerException();
}
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[] { listenerInterface }, new EventHandler(target, action,
eventPropertyName, listenerMethodName));
}
public static T create(Class listenerInterface, Object target, String action, String eventPropertyName)
{
return create(listenerInterface, target, action, eventPropertyName, null);
}
public static T create(Class listenerInterface, Object target, String action)
{
return create(listenerInterface, target, action, null, null);
}
private boolean isValidInvocation(Method method, Object[] arguments)
{
// all listener methods are valid
if (listenerMethodName == null)
{
return true;
}
// method's name matches
if (listenerMethodName.equals(method.getName()))
{
// no arguments in call are valid
if (eventPropertyName == null && (arguments == null || arguments.length == 0))
{
return true;
}
// one-argument call is also valid
if (arguments != null && arguments.length == 1)
{
return true;
}
}
return false;
}
private Object[] getArgs(Object[] arguments) throws Exception
{
if (eventPropertyName == null)
{
return new Object[0];
}
else if ((arguments == null) || (arguments.length == 0))
{
return arguments;
}
else
{
Object arg = arguments[0];
StringTokenizer st = new StringTokenizer(eventPropertyName, "."); //$NON-NLS-1$
while (st.hasMoreTokens())
{
String propertyName = st.nextToken();
PropertyDescriptor pd = findPropertyDescriptor(arg.getClass(), propertyName);
Method getMethod = null;
if (pd != null)
{
getMethod = pd.getReadMethod();
if (getMethod != null)
{
arg = getMethod.invoke(arg, new Object[] {});
}
else
{
throw new IntrospectionException(Messages.getString("beans.11", propertyName)); //$NON-NLS-1$
}
}
else
{
getMethod = findStaticGetter(arg.getClass(), propertyName);
if (getMethod != null)
{
arg = getMethod.invoke(null, new Object[] {});
}
else
{
// cannot access property getter
// RI throws NPE here so we should do the same
throw new NullPointerException(Messages.getString("beans.12", propertyName)); //$NON-NLS-1$
}
}
}
return new Object[] { arg };
}
}
private Method getMethod(Object proxy, Method method, Object[] arguments, Object[] args) throws Exception
{
// filtering - examine if the 'method' could be applied to proxy
boolean found = false;
if (listenerMethodName == null)
{
// can be invoke with any listener method
Class>[] proxyInterfaces = proxy.getClass().getInterfaces();
for (Class> proxyInstance : proxyInterfaces)
{
Method[] interfaceMethods = proxyInstance.getMethods();
for (Method listenerMethod : interfaceMethods)
{
if (equalNames(listenerMethod, method) && canInvokeWithArguments(listenerMethod, arguments))
{
found = true;
break;
}
}
if (found)
{
break;
}
}
}
else if (listenerMethodName.equals(method.getName()))
{
// can be invoked with a specified listener method
found = true;
}
if (found == false)
{
return null;
}
// 'Method' can be applied to proxy - filtering succeeded
try
{
Method result = findMethod(target.getClass(), args);
if (result == null)
{
PropertyDescriptor pd = findPropertyDescriptor(target.getClass(), action);
if (pd != null)
{
result = pd.getWriteMethod();
if (result == null)
{
throw new NoSuchMethodException(Messages.getString("beans.13", action)); //$NON-NLS-1$
}
}
else
{
throw new IndexOutOfBoundsException(Messages.getString("beans.14")); //$NON-NLS-1$
}
}
return result;
}
catch (IntrospectionException ie)
{
throw new IndexOutOfBoundsException(Messages.getString("beans.14")); //$NON-NLS-1$
}
}
private PropertyDescriptor findPropertyDescriptor(Class> theClass, String propertyName) throws IntrospectionException
{
BeanInfo beanInfo = Introspector.getBeanInfo(theClass);
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds)
{
if (pd.getName().equals(propertyName))
{
return pd;
}
}
return null;
}
private Method findStaticGetter(Class> theClass, String propertyName)
{
Method[] methods = theClass.getMethods();
for (Method method : methods)
{
int modifiers = method.getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))
{
String methodName = method.getName();
String postfix = null;
if (methodName.startsWith("get")) { //$NON-NLS-1$
postfix = methodName.substring(3);
}
else if (methodName.startsWith("is")) { //$NON-NLS-1$
postfix = methodName.substring(2);
}
else
{
continue;
}
if ((method.getParameterTypes().length != 0) || (method.getReturnType() == void.class))
{
continue;
}
postfix = Introspector.decapitalize(postfix);
if (postfix.equals(propertyName))
{
return method;
}
}
}
return null;
}
private Method findMethod(Class> type, Object[] args)
{
Method[] methods = type.getMethods();
for (Method method : methods)
{
if (action.equals(method.getName()) && canInvokeWithArguments(method, args))
{
return method;
}
}
return null;
}
private static boolean canInvokeWithArguments(Method method, Object[] arguments)
{
Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != arguments.length)
{
return false;
}
for (int index = 0; index < arguments.length; index++)
{
Class> argumentType = (arguments[index] == null) ? null : arguments[index].getClass();
if (argumentType == null || BeansUtils.isPrimitiveWrapper(argumentType, parameterTypes[index]))
{
continue;
}
if (!argumentType.isAssignableFrom(parameterTypes[index]))
{
return false;
}
}
return true;
}
private static boolean equalNames(Method m1, Method m2)
{
return m1.getName().equals(m2.getName());
}
}