Coverage Report - org.apache.commons.lang3.event.EventUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
EventUtils
85%
12/14
N/A
3,2
EventUtils$EventBindingInvocationHandler
100%
11/11
100%
8/8
3,2
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.commons.lang3.event;
 19  
 
 20  
 import java.lang.reflect.InvocationHandler;
 21  
 import java.lang.reflect.InvocationTargetException;
 22  
 import java.lang.reflect.Method;
 23  
 import java.lang.reflect.Proxy;
 24  
 import java.util.Arrays;
 25  
 import java.util.HashSet;
 26  
 import java.util.Set;
 27  
 
 28  
 import org.apache.commons.lang3.reflect.MethodUtils;
 29  
 
 30  
 /**
 31  
  * Provides some useful event-based utility methods.
 32  
  *
 33  
  * @since 3.0
 34  
  */
 35  1
 public class EventUtils {
 36  
 
 37  
     /**
 38  
      * Adds an event listener to the specified source.  This looks for an "add" method corresponding to the event
 39  
      * type (addActionListener, for example).
 40  
      * @param eventSource   the event source
 41  
      * @param listenerType  the event listener type
 42  
      * @param listener      the listener
 43  
      * @param <L>           the event listener type
 44  
      *
 45  
      * @throws IllegalArgumentException if the object doesn't support the listener type
 46  
      */
 47  
     public static <L> void addEventListener(final Object eventSource, final Class<L> listenerType, final L listener) {
 48  
         try {
 49  7
             MethodUtils.invokeMethod(eventSource, "add" + listenerType.getSimpleName(), listener);
 50  2
         } catch (final NoSuchMethodException e) {
 51  2
             throw new IllegalArgumentException("Class " + eventSource.getClass().getName()
 52  
                     + " does not have a public add" + listenerType.getSimpleName()
 53  
                     + " method which takes a parameter of type " + listenerType.getName() + ".");
 54  0
         } catch (final IllegalAccessException e) {
 55  0
             throw new IllegalArgumentException("Class " + eventSource.getClass().getName()
 56  
                     + " does not have an accessible add" + listenerType.getSimpleName ()
 57  
                     + " method which takes a parameter of type " + listenerType.getName() + ".");
 58  1
         } catch (final InvocationTargetException e) {
 59  1
             throw new RuntimeException("Unable to add listener.", e.getCause());
 60  4
         }
 61  4
     }
 62  
 
 63  
     /**
 64  
      * Binds an event listener to a specific method on a specific object.
 65  
      *
 66  
      * @param <L>          the event listener type
 67  
      * @param target       the target object
 68  
      * @param methodName   the name of the method to be called
 69  
      * @param eventSource  the object which is generating events (JButton, JList, etc.)
 70  
      * @param listenerType the listener interface (ActionListener.class, SelectionListener.class, etc.)
 71  
      * @param eventTypes   the event types (method names) from the listener interface (if none specified, all will be
 72  
      *                     supported)
 73  
      */
 74  
     public static <L> void bindEventsToMethod(final Object target, final String methodName, final Object eventSource,
 75  
             final Class<L> listenerType, final String... eventTypes) {
 76  3
         final L listener = listenerType.cast(Proxy.newProxyInstance(target.getClass().getClassLoader(),
 77  
                 new Class[] { listenerType }, new EventBindingInvocationHandler(target, methodName, eventTypes)));
 78  3
         addEventListener(eventSource, listenerType, listener);
 79  3
     }
 80  
 
 81  1
     private static class EventBindingInvocationHandler implements InvocationHandler {
 82  
         private final Object target;
 83  
         private final String methodName;
 84  
         private final Set<String> eventTypes;
 85  
 
 86  
         /**
 87  
          * Creates a new instance of {@code EventBindingInvocationHandler}.
 88  
          *
 89  
          * @param target the target object for method invocations
 90  
          * @param methodName the name of the method to be invoked
 91  
          * @param eventTypes the names of the supported event types
 92  
          */
 93  3
         EventBindingInvocationHandler(final Object target, final String methodName, final String[] eventTypes) {
 94  3
             this.target = target;
 95  3
             this.methodName = methodName;
 96  3
             this.eventTypes = new HashSet<String>(Arrays.asList(eventTypes));
 97  3
         }
 98  
 
 99  
         /**
 100  
          * Handles a method invocation on the proxy object.
 101  
          *
 102  
          * @param proxy the proxy instance
 103  
          * @param method the method to be invoked
 104  
          * @param parameters the parameters for the method invocation
 105  
          * @return the result of the method call
 106  
          * @throws Throwable if an error occurs
 107  
          */
 108  
         @Override
 109  
         public Object invoke(final Object proxy, final Method method, final Object[] parameters) throws Throwable {
 110  4
             if (eventTypes.isEmpty() || eventTypes.contains(method.getName())) {
 111  3
                 if (hasMatchingParametersMethod(method)) {
 112  1
                     return MethodUtils.invokeMethod(target, methodName, parameters);
 113  
                 }
 114  2
                 return MethodUtils.invokeMethod(target, methodName);
 115  
             }
 116  1
             return null;
 117  
         }
 118  
 
 119  
         /**
 120  
          * Checks whether a method for the passed in parameters can be found.
 121  
          *
 122  
          * @param method the listener method invoked
 123  
          * @return a flag whether the parameters could be matched
 124  
          */
 125  
         private boolean hasMatchingParametersMethod(final Method method) {
 126  3
             return MethodUtils.getAccessibleMethod(target.getClass(), methodName, method.getParameterTypes()) != null;
 127  
         }
 128  
     }
 129  
 }