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.
lite.beans.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 lite.beans;
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 lite.beans.util.BeansUtils;
import lite.beans.util.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());
}
}