Save This Page
Home » openjdk-7 » java » beans » [javadoc | source]
    1   /*
    2    * Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   package java.beans;
   26   
   27   import java.lang.reflect.InvocationHandler;
   28   import java.lang.reflect.InvocationTargetException;
   29   import java.lang.reflect.Proxy;
   30   import java.lang.reflect.Method;
   31   import java.security.AccessControlContext;
   32   import java.security.AccessController;
   33   import java.security.PrivilegedAction;
   34   
   35   import java.util.EventObject;
   36   import sun.reflect.misc.MethodUtil;
   37   
   38   /**
   39    * The <code>EventHandler</code> class provides
   40    * support for dynamically generating event listeners whose methods
   41    * execute a simple statement involving an incoming event object
   42    * and a target object.
   43    * <p>
   44    * The <code>EventHandler</code> class is intended to be used by interactive tools, such as
   45    * application builders, that allow developers to make connections between
   46    * beans. Typically connections are made from a user interface bean
   47    * (the event <em>source</em>)
   48    * to an application logic bean (the <em>target</em>). The most effective
   49    * connections of this kind isolate the application logic from the user
   50    * interface.  For example, the <code>EventHandler</code> for a
   51    * connection from a <code>JCheckBox</code> to a method
   52    * that accepts a boolean value can deal with extracting the state
   53    * of the check box and passing it directly to the method so that
   54    * the method is isolated from the user interface layer.
   55    * <p>
   56    * Inner classes are another, more general way to handle events from
   57    * user interfaces.  The <code>EventHandler</code> class
   58    * handles only a subset of what is possible using inner
   59    * classes. However, <code>EventHandler</code> works better
   60    * with the long-term persistence scheme than inner classes.
   61    * Also, using <code>EventHandler</code> in large applications in
   62    * which the same interface is implemented many times can
   63    * reduce the disk and memory footprint of the application.
   64    * <p>
   65    * The reason that listeners created with <code>EventHandler</code>
   66    * have such a small
   67    * footprint is that the <code>Proxy</code> class, on which
   68    * the <code>EventHandler</code> relies, shares implementations
   69    * of identical
   70    * interfaces. For example, if you use
   71    * the <code>EventHandler</code> <code>create</code> methods to make
   72    * all the <code>ActionListener</code>s in an application,
   73    * all the action listeners will be instances of a single class
   74    * (one created by the <code>Proxy</code> class).
   75    * In general, listeners based on
   76    * the <code>Proxy</code> class require one listener class
   77    * to be created per <em>listener type</em> (interface),
   78    * whereas the inner class
   79    * approach requires one class to be created per <em>listener</em>
   80    * (object that implements the interface).
   81    *
   82    * <p>
   83    * You don't generally deal directly with <code>EventHandler</code>
   84    * instances.
   85    * Instead, you use one of the <code>EventHandler</code>
   86    * <code>create</code> methods to create
   87    * an object that implements a given listener interface.
   88    * This listener object uses an <code>EventHandler</code> object
   89    * behind the scenes to encapsulate information about the
   90    * event, the object to be sent a message when the event occurs,
   91    * the message (method) to be sent, and any argument
   92    * to the method.
   93    * The following section gives examples of how to create listener
   94    * objects using the <code>create</code> methods.
   95    *
   96    * <h2>Examples of Using EventHandler</h2>
   97    *
   98    * The simplest use of <code>EventHandler</code> is to install
   99    * a listener that calls a method on the target object with no arguments.
  100    * In the following example we create an <code>ActionListener</code>
  101    * that invokes the <code>toFront</code> method on an instance
  102    * of <code>javax.swing.JFrame</code>.
  103    *
  104    * <blockquote>
  105    *<pre>
  106    *myButton.addActionListener(
  107    *    (ActionListener)EventHandler.create(ActionListener.class, frame, "toFront"));
  108    *</pre>
  109    * </blockquote>
  110    *
  111    * When <code>myButton</code> is pressed, the statement
  112    * <code>frame.toFront()</code> will be executed.  One could get
  113    * the same effect, with some additional compile-time type safety,
  114    * by defining a new implementation of the <code>ActionListener</code>
  115    * interface and adding an instance of it to the button:
  116    *
  117    * <blockquote>
  118    *<pre>
  119   //Equivalent code using an inner class instead of EventHandler.
  120    *myButton.addActionListener(new ActionListener() {
  121    *    public void actionPerformed(ActionEvent e) {
  122    *        frame.toFront();
  123    *    }
  124    *});
  125    *</pre>
  126    * </blockquote>
  127    *
  128    * The next simplest use of <code>EventHandler</code> is
  129    * to extract a property value from the first argument
  130    * of the method in the listener interface (typically an event object)
  131    * and use it to set the value of a property in the target object.
  132    * In the following example we create an <code>ActionListener</code> that
  133    * sets the <code>nextFocusableComponent</code> property of the target
  134    * (myButton) object to the value of the "source" property of the event.
  135    *
  136    * <blockquote>
  137    *<pre>
  138    *EventHandler.create(ActionListener.class, myButton, "nextFocusableComponent", "source")
  139    *</pre>
  140    * </blockquote>
  141    *
  142    * This would correspond to the following inner class implementation:
  143    *
  144    * <blockquote>
  145    *<pre>
  146   //Equivalent code using an inner class instead of EventHandler.
  147    *new ActionListener() {
  148    *    public void actionPerformed(ActionEvent e) {
  149    *        myButton.setNextFocusableComponent((Component)e.getSource());
  150    *    }
  151    *}
  152    *</pre>
  153    * </blockquote>
  154    *
  155    * It's also possible to create an <code>EventHandler</code> that
  156    * just passes the incoming event object to the target's action.
  157    * If the fourth <code>EventHandler.create</code> argument is
  158    * an empty string, then the event is just passed along:
  159    *
  160    * <blockquote>
  161    *<pre>
  162    *EventHandler.create(ActionListener.class, target, "doActionEvent", "")
  163    *</pre>
  164    * </blockquote>
  165    *
  166    * This would correspond to the following inner class implementation:
  167    *
  168    * <blockquote>
  169    *<pre>
  170   //Equivalent code using an inner class instead of EventHandler.
  171    *new ActionListener() {
  172    *    public void actionPerformed(ActionEvent e) {
  173    *        target.doActionEvent(e);
  174    *    }
  175    *}
  176    *</pre>
  177    * </blockquote>
  178    *
  179    * Probably the most common use of <code>EventHandler</code>
  180    * is to extract a property value from the
  181    * <em>source</em> of the event object and set this value as
  182    * the value of a property of the target object.
  183    * In the following example we create an <code>ActionListener</code> that
  184    * sets the "label" property of the target
  185    * object to the value of the "text" property of the
  186    * source (the value of the "source" property) of the event.
  187    *
  188    * <blockquote>
  189    *<pre>
  190    *EventHandler.create(ActionListener.class, myButton, "label", "source.text")
  191    *</pre>
  192    * </blockquote>
  193    *
  194    * This would correspond to the following inner class implementation:
  195    *
  196    * <blockquote>
  197    *<pre>
  198   //Equivalent code using an inner class instead of EventHandler.
  199    *new ActionListener {
  200    *    public void actionPerformed(ActionEvent e) {
  201    *        myButton.setLabel(((JTextField)e.getSource()).getText());
  202    *    }
  203    *}
  204    *</pre>
  205    * </blockquote>
  206    *
  207    * The event property may be "qualified" with an arbitrary number
  208    * of property prefixes delimited with the "." character. The "qualifying"
  209    * names that appear before the "." characters are taken as the names of
  210    * properties that should be applied, left-most first, to
  211    * the event object.
  212    * <p>
  213    * For example, the following action listener
  214    *
  215    * <blockquote>
  216    *<pre>
  217    *EventHandler.create(ActionListener.class, target, "a", "b.c.d")
  218    *</pre>
  219    * </blockquote>
  220    *
  221    * might be written as the following inner class
  222    * (assuming all the properties had canonical getter methods and
  223    * returned the appropriate types):
  224    *
  225    * <blockquote>
  226    *<pre>
  227   //Equivalent code using an inner class instead of EventHandler.
  228    *new ActionListener {
  229    *    public void actionPerformed(ActionEvent e) {
  230    *        target.setA(e.getB().getC().isD());
  231    *    }
  232    *}
  233    *</pre>
  234    * </blockquote>
  235    * The target property may also be "qualified" with an arbitrary number
  236    * of property prefixs delimited with the "." character.  For example, the
  237    * following action listener:
  238    * <pre>
  239    *   EventHandler.create(ActionListener.class, target, "a.b", "c.d")
  240    * </pre>
  241    * might be written as the following inner class
  242    * (assuming all the properties had canonical getter methods and
  243    * returned the appropriate types):
  244    * <pre>
  245    *   //Equivalent code using an inner class instead of EventHandler.
  246    *   new ActionListener {
  247    *     public void actionPerformed(ActionEvent e) {
  248    *         target.getA().setB(e.getC().isD());
  249    *    }
  250    *}
  251    *</pre>
  252    * <p>
  253    * As <code>EventHandler</code> ultimately relies on reflection to invoke
  254    * a method we recommend against targeting an overloaded method.  For example,
  255    * if the target is an instance of the class <code>MyTarget</code> which is
  256    * defined as:
  257    * <pre>
  258    *   public class MyTarget {
  259    *     public void doIt(String);
  260    *     public void doIt(Object);
  261    *   }
  262    * </pre>
  263    * Then the method <code>doIt</code> is overloaded.  EventHandler will invoke
  264    * the method that is appropriate based on the source.  If the source is
  265    * null, then either method is appropriate and the one that is invoked is
  266    * undefined.  For that reason we recommend against targeting overloaded
  267    * methods.
  268    *
  269    * @see java.lang.reflect.Proxy
  270    * @see java.util.EventObject
  271    *
  272    * @since 1.4
  273    *
  274    * @author Mark Davidson
  275    * @author Philip Milne
  276    * @author Hans Muller
  277    *
  278    */
  279   public class EventHandler implements InvocationHandler {
  280       private Object target;
  281       private String action;
  282       private String eventPropertyName;
  283       private String listenerMethodName;
  284       private AccessControlContext acc;
  285   
  286       /**
  287        * Creates a new <code>EventHandler</code> object;
  288        * you generally use one of the <code>create</code> methods
  289        * instead of invoking this constructor directly.  Refer to
  290        * {@link java.beans.EventHandler#create(Class, Object, String, String)
  291        * the general version of create} for a complete description of
  292        * the <code>eventPropertyName</code> and <code>listenerMethodName</code>
  293        * parameter.
  294        *
  295        * @param target the object that will perform the action
  296        * @param action the name of a (possibly qualified) property or method on
  297        *        the target
  298        * @param eventPropertyName the (possibly qualified) name of a readable property of the incoming event
  299        * @param listenerMethodName the name of the method in the listener interface that should trigger the action
  300        *
  301        * @throws NullPointerException if <code>target</code> is null
  302        * @throws NullPointerException if <code>action</code> is null
  303        *
  304        * @see EventHandler
  305        * @see #create(Class, Object, String, String, String)
  306        * @see #getTarget
  307        * @see #getAction
  308        * @see #getEventPropertyName
  309        * @see #getListenerMethodName
  310        */
  311       @ConstructorProperties({"target", "action", "eventPropertyName", "listenerMethodName"})
  312       public EventHandler(Object target, String action, String eventPropertyName, String listenerMethodName) {
  313           this.acc = AccessController.getContext();
  314           this.target = target;
  315           this.action = action;
  316           if (target == null) {
  317               throw new NullPointerException("target must be non-null");
  318           }
  319           if (action == null) {
  320               throw new NullPointerException("action must be non-null");
  321           }
  322           this.eventPropertyName = eventPropertyName;
  323           this.listenerMethodName = listenerMethodName;
  324       }
  325   
  326       /**
  327        * Returns the object to which this event handler will send a message.
  328        *
  329        * @return the target of this event handler
  330        * @see #EventHandler(Object, String, String, String)
  331        */
  332       public Object getTarget()  {
  333           return target;
  334       }
  335   
  336       /**
  337        * Returns the name of the target's writable property
  338        * that this event handler will set,
  339        * or the name of the method that this event handler
  340        * will invoke on the target.
  341        *
  342        * @return the action of this event handler
  343        * @see #EventHandler(Object, String, String, String)
  344        */
  345       public String getAction()  {
  346           return action;
  347       }
  348   
  349       /**
  350        * Returns the property of the event that should be
  351        * used in the action applied to the target.
  352        *
  353        * @return the property of the event
  354        *
  355        * @see #EventHandler(Object, String, String, String)
  356        */
  357       public String getEventPropertyName()  {
  358           return eventPropertyName;
  359       }
  360   
  361       /**
  362        * Returns the name of the method that will trigger the action.
  363        * A return value of <code>null</code> signifies that all methods in the
  364        * listener interface trigger the action.
  365        *
  366        * @return the name of the method that will trigger the action
  367        *
  368        * @see #EventHandler(Object, String, String, String)
  369        */
  370       public String getListenerMethodName()  {
  371           return listenerMethodName;
  372       }
  373   
  374       private Object applyGetters(Object target, String getters) {
  375           if (getters == null || getters.equals("")) {
  376               return target;
  377           }
  378           int firstDot = getters.indexOf('.');
  379           if (firstDot == -1) {
  380               firstDot = getters.length();
  381           }
  382           String first = getters.substring(0, firstDot);
  383           String rest = getters.substring(Math.min(firstDot + 1, getters.length()));
  384   
  385           try {
  386               Method getter = null;
  387               if (target != null) {
  388                   getter = ReflectionUtils.getMethod(target.getClass(),
  389                                         "get" + NameGenerator.capitalize(first),
  390                                         new Class[]{});
  391                   if (getter == null) {
  392                       getter = ReflectionUtils.getMethod(target.getClass(),
  393                                      "is" + NameGenerator.capitalize(first),
  394                                      new Class[]{});
  395                   }
  396                   if (getter == null) {
  397                       getter = ReflectionUtils.getMethod(target.getClass(), first, new Class[]{});
  398                   }
  399               }
  400               if (getter == null) {
  401                   throw new RuntimeException("No method called: " + first +
  402                                              " defined on " + target);
  403               }
  404               Object newTarget = MethodUtil.invoke(getter, target, new Object[]{});
  405               return applyGetters(newTarget, rest);
  406           }
  407           catch (Throwable e) {
  408               throw new RuntimeException("Failed to call method: " + first +
  409                                          " on " + target, e);
  410           }
  411       }
  412   
  413       /**
  414        * Extract the appropriate property value from the event and
  415        * pass it to the action associated with
  416        * this <code>EventHandler</code>.
  417        *
  418        * @param proxy the proxy object
  419        * @param method the method in the listener interface
  420        * @return the result of applying the action to the target
  421        *
  422        * @see EventHandler
  423        */
  424       public Object invoke(final Object proxy, final Method method, final Object[] arguments) {
  425           return AccessController.doPrivileged(new PrivilegedAction() {
  426               public Object run() {
  427                   return invokeInternal(proxy, method, arguments);
  428               }
  429           }, acc);
  430       }
  431   
  432       private Object invokeInternal(Object proxy, Method method, Object[] arguments) {
  433           String methodName = method.getName();
  434           if (method.getDeclaringClass() == Object.class)  {
  435               // Handle the Object public methods.
  436               if (methodName.equals("hashCode"))  {
  437                   return new Integer(System.identityHashCode(proxy));
  438               } else if (methodName.equals("equals")) {
  439                   return (proxy == arguments[0] ? Boolean.TRUE : Boolean.FALSE);
  440               } else if (methodName.equals("toString")) {
  441                   return proxy.getClass().getName() + '@' + Integer.toHexString(proxy.hashCode());
  442               }
  443           }
  444   
  445           if (listenerMethodName == null || listenerMethodName.equals(methodName)) {
  446               Class[] argTypes = null;
  447               Object[] newArgs = null;
  448   
  449               if (eventPropertyName == null) {     // Nullary method.
  450                   newArgs = new Object[]{};
  451                   argTypes = new Class[]{};
  452               }
  453               else {
  454                   Object input = applyGetters(arguments[0], getEventPropertyName());
  455                   newArgs = new Object[]{input};
  456                   argTypes = new Class[]{input == null ? null :
  457                                          input.getClass()};
  458               }
  459               try {
  460                   int lastDot = action.lastIndexOf('.');
  461                   if (lastDot != -1) {
  462                       target = applyGetters(target, action.substring(0, lastDot));
  463                       action = action.substring(lastDot + 1);
  464                   }
  465                   Method targetMethod = ReflectionUtils.getMethod(
  466                                target.getClass(), action, argTypes);
  467                   if (targetMethod == null) {
  468                       targetMethod = ReflectionUtils.getMethod(target.getClass(),
  469                                "set" + NameGenerator.capitalize(action), argTypes);
  470                   }
  471                   if (targetMethod == null) {
  472                       String argTypeString = (argTypes.length == 0)
  473                           ? " with no arguments"
  474                           : " with argument " + argTypes[0];
  475                       throw new RuntimeException(
  476                           "No method called " + action + " on " +
  477                           target.getClass() + argTypeString);
  478                   }
  479                   return MethodUtil.invoke(targetMethod, target, newArgs);
  480               }
  481               catch (IllegalAccessException ex) {
  482                   throw new RuntimeException(ex);
  483               }
  484               catch (InvocationTargetException ex) {
  485                   throw new RuntimeException(ex.getTargetException());
  486               }
  487           }
  488           return null;
  489       }
  490   
  491       /**
  492        * Creates an implementation of <code>listenerInterface</code> in which
  493        * <em>all</em> of the methods in the listener interface apply
  494        * the handler's <code>action</code> to the <code>target</code>. This
  495        * method is implemented by calling the other, more general,
  496        * implementation of the <code>create</code> method with both
  497        * the <code>eventPropertyName</code> and the <code>listenerMethodName</code>
  498        * taking the value <code>null</code>. Refer to
  499        * {@link java.beans.EventHandler#create(Class, Object, String, String)
  500        * the general version of create} for a complete description of
  501        * the <code>action</code> parameter.
  502        * <p>
  503        * To create an <code>ActionListener</code> that shows a
  504        * <code>JDialog</code> with <code>dialog.show()</code>,
  505        * one can write:
  506        *
  507        *<blockquote>
  508        *<pre>
  509        *EventHandler.create(ActionListener.class, dialog, "show")
  510        *</pre>
  511        *</blockquote>
  512        *
  513        * @param listenerInterface the listener interface to create a proxy for
  514        * @param target the object that will perform the action
  515        * @param action the name of a (possibly qualified) property or method on
  516        *        the target
  517        * @return an object that implements <code>listenerInterface</code>
  518        *
  519        * @throws NullPointerException if <code>listenerInterface</code> is null
  520        * @throws NullPointerException if <code>target</code> is null
  521        * @throws NullPointerException if <code>action</code> is null
  522        *
  523        * @see #create(Class, Object, String, String)
  524        */
  525       public static <T> T create(Class<T> listenerInterface,
  526                                  Object target, String action)
  527       {
  528           return create(listenerInterface, target, action, null, null);
  529       }
  530   
  531       /**
  532       /**
  533        * Creates an implementation of <code>listenerInterface</code> in which
  534        * <em>all</em> of the methods pass the value of the event
  535        * expression, <code>eventPropertyName</code>, to the final method in the
  536        * statement, <code>action</code>, which is applied to the <code>target</code>.
  537        * This method is implemented by calling the
  538        * more general, implementation of the <code>create</code> method with
  539        * the <code>listenerMethodName</code> taking the value <code>null</code>.
  540        * Refer to
  541        * {@link java.beans.EventHandler#create(Class, Object, String, String)
  542        * the general version of create} for a complete description of
  543        * the <code>action</code> and <code>eventPropertyName</code> parameters.
  544        * <p>
  545        * To create an <code>ActionListener</code> that sets the
  546        * the text of a <code>JLabel</code> to the text value of
  547        * the <code>JTextField</code> source of the incoming event,
  548        * you can use the following code:
  549        *
  550        *<blockquote>
  551        *<pre>
  552        *EventHandler.create(ActionListener.class, label, "text", "source.text");
  553        *</pre>
  554        *</blockquote>
  555        *
  556        * This is equivalent to the following code:
  557        *<blockquote>
  558        *<pre>
  559   //Equivalent code using an inner class instead of EventHandler.
  560        *new ActionListener() {
  561        *    public void actionPerformed(ActionEvent event) {
  562        *        label.setText(((JTextField)(event.getSource())).getText());
  563        *     }
  564        *};
  565        *</pre>
  566        *</blockquote>
  567        *
  568        * @param listenerInterface the listener interface to create a proxy for
  569        * @param target the object that will perform the action
  570        * @param action the name of a (possibly qualified) property or method on
  571        *        the target
  572        * @param eventPropertyName the (possibly qualified) name of a readable property of the incoming event
  573        *
  574        * @return an object that implements <code>listenerInterface</code>
  575        *
  576        * @throws NullPointerException if <code>listenerInterface</code> is null
  577        * @throws NullPointerException if <code>target</code> is null
  578        * @throws NullPointerException if <code>action</code> is null
  579        *
  580        * @see #create(Class, Object, String, String, String)
  581        */
  582       public static <T> T create(Class<T> listenerInterface,
  583                                  Object target, String action,
  584                                  String eventPropertyName)
  585       {
  586           return create(listenerInterface, target, action, eventPropertyName, null);
  587       }
  588   
  589       /**
  590        * Creates an implementation of <code>listenerInterface</code> in which
  591        * the method named <code>listenerMethodName</code>
  592        * passes the value of the event expression, <code>eventPropertyName</code>,
  593        * to the final method in the statement, <code>action</code>, which
  594        * is applied to the <code>target</code>. All of the other listener
  595        * methods do nothing.
  596        * <p>
  597        * The <code>eventPropertyName</code> string is used to extract a value
  598        * from the incoming event object that is passed to the target
  599        * method.  The common case is the target method takes no arguments, in
  600        * which case a value of null should be used for the
  601        * <code>eventPropertyName</code>.  Alternatively if you want
  602        * the incoming event object passed directly to the target method use
  603        * the empty string.
  604        * The format of the <code>eventPropertyName</code> string is a sequence of
  605        * methods or properties where each method or
  606        * property is applied to the value returned by the preceeding method
  607        * starting from the incoming event object.
  608        * The syntax is: <code>propertyName{.propertyName}*</code>
  609        * where <code>propertyName</code> matches a method or
  610        * property.  For example, to extract the <code>point</code>
  611        * property from a <code>MouseEvent</code>, you could use either
  612        * <code>"point"</code> or <code>"getPoint"</code> as the
  613        * <code>eventPropertyName</code>.  To extract the "text" property from
  614        * a <code>MouseEvent</code> with a <code>JLabel</code> source use any
  615        * of the following as <code>eventPropertyName</code>:
  616        * <code>"source.text"</code>,
  617        * <code>"getSource.text"</code> <code>"getSource.getText"</code> or
  618        * <code>"source.getText"</code>.  If a method can not be found, or an
  619        * exception is generated as part of invoking a method a
  620        * <code>RuntimeException</code> will be thrown at dispatch time.  For
  621        * example, if the incoming event object is null, and
  622        * <code>eventPropertyName</code> is non-null and not empty, a
  623        * <code>RuntimeException</code> will be thrown.
  624        * <p>
  625        * The <code>action</code> argument is of the same format as the
  626        * <code>eventPropertyName</code> argument where the last property name
  627        * identifies either a method name or writable property.
  628        * <p>
  629        * If the <code>listenerMethodName</code> is <code>null</code>
  630        * <em>all</em> methods in the interface trigger the <code>action</code> to be
  631        * executed on the <code>target</code>.
  632        * <p>
  633        * For example, to create a <code>MouseListener</code> that sets the target
  634        * object's <code>origin</code> property to the incoming <code>MouseEvent</code>'s
  635        * location (that's the value of <code>mouseEvent.getPoint()</code>) each
  636        * time a mouse button is pressed, one would write:
  637        *<blockquote>
  638        *<pre>
  639        *EventHandler.create(MouseListener.class, "mousePressed", target, "origin", "point");
  640        *</pre>
  641        *</blockquote>
  642        *
  643        * This is comparable to writing a <code>MouseListener</code> in which all
  644        * of the methods except <code>mousePressed</code> are no-ops:
  645        *
  646        *<blockquote>
  647        *<pre>
  648   //Equivalent code using an inner class instead of EventHandler.
  649        *new MouseAdapter() {
  650        *    public void mousePressed(MouseEvent e) {
  651        *        target.setOrigin(e.getPoint());
  652        *    }
  653        *};
  654        * </pre>
  655        *</blockquote>
  656        *
  657        * @param listenerInterface the listener interface to create a proxy for
  658        * @param target the object that will perform the action
  659        * @param action the name of a (possibly qualified) property or method on
  660        *        the target
  661        * @param eventPropertyName the (possibly qualified) name of a readable property of the incoming event
  662        * @param listenerMethodName the name of the method in the listener interface that should trigger the action
  663        *
  664        * @return an object that implements <code>listenerInterface</code>
  665        *
  666        * @throws NullPointerException if <code>listenerInterface</code> is null
  667        * @throws NullPointerException if <code>target</code> is null
  668        * @throws NullPointerException if <code>action</code> is null
  669        *
  670        * @see EventHandler
  671        */
  672       public static <T> T create(Class<T> listenerInterface,
  673                                  Object target, String action,
  674                                  String eventPropertyName,
  675                                  String listenerMethodName)
  676       {
  677           // Create this first to verify target/action are non-null
  678           EventHandler eventHandler = new EventHandler(target, action,
  679                                                        eventPropertyName,
  680                                                        listenerMethodName);
  681           if (listenerInterface == null) {
  682               throw new NullPointerException(
  683                             "listenerInterface must be non-null");
  684           }
  685           return (T)Proxy.newProxyInstance(target.getClass().getClassLoader(),
  686                                            new Class[] {listenerInterface},
  687                                            eventHandler);
  688       }
  689   }

Save This Page
Home » openjdk-7 » java » beans » [javadoc | source]