org.openmdx.dalvik.uses.java.beans.EventHandler Maven / Gradle / Ivy
/*
* Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openmdx.dalvik.uses.java.beans;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.openmdx.dalvik.uses.sun.reflect.misc.MethodUtil;
/**
* The EventHandler
class provides
* support for dynamically generating event listeners whose methods
* execute a simple statement involving an incoming event object
* and a target object.
*
* The EventHandler
class is intended to be used by interactive tools, such as
* application builders, that allow developers to make connections between
* beans. Typically connections are made from a user interface bean
* (the event source)
* to an application logic bean (the target). The most effective
* connections of this kind isolate the application logic from the user
* interface. For example, the EventHandler
for a
* connection from a JCheckBox
to a method
* that accepts a boolean value can deal with extracting the state
* of the check box and passing it directly to the method so that
* the method is isolated from the user interface layer.
*
* Inner classes are another, more general way to handle events from
* user interfaces. The EventHandler
class
* handles only a subset of what is possible using inner
* classes. However, EventHandler
works better
* with the long-term persistence scheme than inner classes.
* Also, using EventHandler
in large applications in
* which the same interface is implemented many times can
* reduce the disk and memory footprint of the application.
*
* The reason that listeners created with EventHandler
* have such a small
* footprint is that the Proxy
class, on which
* the EventHandler
relies, shares implementations
* of identical
* interfaces. For example, if you use
* the EventHandler
create
methods to make
* all the ActionListener
s in an application,
* all the action listeners will be instances of a single class
* (one created by the Proxy
class).
* In general, listeners based on
* the Proxy
class require one listener class
* to be created per listener type (interface),
* whereas the inner class
* approach requires one class to be created per listener
* (object that implements the interface).
*
*
* You don't generally deal directly with EventHandler
* instances.
* Instead, you use one of the EventHandler
* create
methods to create
* an object that implements a given listener interface.
* This listener object uses an EventHandler
object
* behind the scenes to encapsulate information about the
* event, the object to be sent a message when the event occurs,
* the message (method) to be sent, and any argument
* to the method.
* The following section gives examples of how to create listener
* objects using the create
methods.
*
*
*
* As EventHandler
ultimately relies on reflection to invoke
* a method we recommend against targeting an overloaded method. For example,
* if the target is an instance of the class MyTarget
which is
* defined as:
*
* public class MyTarget { * public void doIt(String); * public void doIt(Object); * } ** Then the method
doIt
is overloaded. EventHandler will invoke
* the method that is appropriate based on the source. If the source is
* null, then either method is appropriate and the one that is invoked is
* undefined. For that reason we recommend against targeting overloaded
* methods.
*
* @see java.lang.reflect.Proxy
* @see java.util.EventObject
*
*
* openMDX/Dalvik Notice (January 2013):
* THIS CODE HAS BEEN MODIFIED AND ITS NAMESPACE HAS BEEN PREFIXED WITH
* org.openmdx.dalvik.uses.
*
EventHandler
object;
* you generally use one of the create
methods
* instead of invoking this constructor directly. Refer to
* {@link org.openmdx.dalvik.uses.java.beans.EventHandler#create(Class, Object, String, String)
* the general version of create} for a complete description of
* the eventPropertyName
and listenerMethodName
* parameter.
*
* @param target the object that will perform the action
* @param action the name of a (possibly qualified) property or method on
* the target
* @param eventPropertyName the (possibly qualified) name of a readable property of the incoming event
* @param listenerMethodName the name of the method in the listener interface that should trigger the action
*
* @throws NullPointerException if target
is null
* @throws NullPointerException if action
is null
*
* @see EventHandler
* @see #create(Class, Object, String, String, String)
* @see #getTarget
* @see #getAction
* @see #getEventPropertyName
* @see #getListenerMethodName
*/
public EventHandler(Object target, String action, String eventPropertyName, String listenerMethodName) {
this.target = target;
this.action = action;
if (target == null) {
throw new NullPointerException("target must be non-null");
}
if (action == null) {
throw new NullPointerException("action must be non-null");
}
this.eventPropertyName = eventPropertyName;
this.listenerMethodName = listenerMethodName;
}
/**
* Returns the object to which this event handler will send a message.
*
* @return the target of this event handler
* @see #EventHandler(Object, String, String, String)
*/
public Object getTarget() {
return target;
}
/**
* Returns the name of the target's writable property
* that this event handler will set,
* or the name of the method that this event handler
* will invoke on the target.
*
* @return the action of this event handler
* @see #EventHandler(Object, String, String, String)
*/
public String getAction() {
return action;
}
/**
* Returns the property of the event that should be
* used in the action applied to the target.
*
* @return the property of the event
*
* @see #EventHandler(Object, String, String, String)
*/
public String getEventPropertyName() {
return eventPropertyName;
}
/**
* Returns the name of the method that will trigger the action.
* A return value of null
signifies that all methods in the
* listener interface trigger the action.
*
* @return the name of the method that will trigger the action
*
* @see #EventHandler(Object, String, String, String)
*/
public String getListenerMethodName() {
return listenerMethodName;
}
private Object applyGetters(Object target, String getters) {
if (getters == null || getters.equals("")) {
return target;
}
int firstDot = getters.indexOf('.');
if (firstDot == -1) {
firstDot = getters.length();
}
String first = getters.substring(0, firstDot);
String rest = getters.substring(Math.min(firstDot + 1, getters.length()));
try {
Method getter = null;
if (target != null) {
getter = ReflectionUtils.getMethod(target.getClass(),
"get" + NameGenerator.capitalize(first),
new Class[]{});
if (getter == null) {
getter = ReflectionUtils.getMethod(target.getClass(),
"is" + NameGenerator.capitalize(first),
new Class[]{});
}
if (getter == null) {
getter = ReflectionUtils.getMethod(target.getClass(), first, new Class[]{});
}
}
if (getter == null) {
throw new RuntimeException("No method called: " + first +
" defined on " + target);
}
Object newTarget = MethodUtil.invoke(getter, target, new Object[]{});
return applyGetters(newTarget, rest);
}
catch (Throwable e) {
throw new RuntimeException("Failed to call method: " + first +
" on " + target, e);
}
}
/**
* Extract the appropriate property value from the event and
* pass it to the action associated with
* this EventHandler
.
*
* @param proxy the proxy object
* @param method the method in the listener interface
* @return the result of applying the action to the target
*
* @see EventHandler
*/
public Object invoke(final Object proxy, final Method method, final Object[] arguments) {
AccessControlContext acc = this.acc;
if ((acc == null) && (System.getSecurityManager() != null)) {
throw new SecurityException("AccessControlContext is not set");
}
return AccessController.doPrivileged(new PrivilegedAction