| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| EventUtils |
|
| 3.2;3.2 | ||||
| EventUtils$EventBindingInvocationHandler |
|
| 3.2;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 | * @version $Id: EventUtils.java 1436770 2013-01-22 07:09:45Z ggregory $ | |
| 35 | */ | |
| 36 | 1 | public class EventUtils { |
| 37 | ||
| 38 | /** | |
| 39 | * Adds an event listener to the specified source. This looks for an "add" method corresponding to the event | |
| 40 | * type (addActionListener, for example). | |
| 41 | * @param eventSource the event source | |
| 42 | * @param listenerType the event listener type | |
| 43 | * @param listener the listener | |
| 44 | * @param <L> the event listener type | |
| 45 | * | |
| 46 | * @throws IllegalArgumentException if the object doesn't support the listener type | |
| 47 | */ | |
| 48 | public static <L> void addEventListener(final Object eventSource, final Class<L> listenerType, final L listener) { | |
| 49 | try { | |
| 50 | 7 | MethodUtils.invokeMethod(eventSource, "add" + listenerType.getSimpleName(), listener); |
| 51 | 2 | } catch (final NoSuchMethodException e) { |
| 52 | 2 | throw new IllegalArgumentException("Class " + eventSource.getClass().getName() |
| 53 | + " does not have a public add" + listenerType.getSimpleName() | |
| 54 | + " method which takes a parameter of type " + listenerType.getName() + "."); | |
| 55 | 0 | } catch (final IllegalAccessException e) { |
| 56 | 0 | throw new IllegalArgumentException("Class " + eventSource.getClass().getName() |
| 57 | + " does not have an accessible add" + listenerType.getSimpleName () | |
| 58 | + " method which takes a parameter of type " + listenerType.getName() + "."); | |
| 59 | 1 | } catch (final InvocationTargetException e) { |
| 60 | 1 | throw new RuntimeException("Unable to add listener.", e.getCause()); |
| 61 | 4 | } |
| 62 | 4 | } |
| 63 | ||
| 64 | /** | |
| 65 | * Binds an event listener to a specific method on a specific object. | |
| 66 | * | |
| 67 | * @param <L> the event listener type | |
| 68 | * @param target the target object | |
| 69 | * @param methodName the name of the method to be called | |
| 70 | * @param eventSource the object which is generating events (JButton, JList, etc.) | |
| 71 | * @param listenerType the listener interface (ActionListener.class, SelectionListener.class, etc.) | |
| 72 | * @param eventTypes the event types (method names) from the listener interface (if none specified, all will be | |
| 73 | * supported) | |
| 74 | */ | |
| 75 | public static <L> void bindEventsToMethod(final Object target, final String methodName, final Object eventSource, | |
| 76 | final Class<L> listenerType, final String... eventTypes) { | |
| 77 | 3 | final L listener = listenerType.cast(Proxy.newProxyInstance(target.getClass().getClassLoader(), |
| 78 | new Class[] { listenerType }, new EventBindingInvocationHandler(target, methodName, eventTypes))); | |
| 79 | 3 | addEventListener(eventSource, listenerType, listener); |
| 80 | 3 | } |
| 81 | ||
| 82 | 1 | private static class EventBindingInvocationHandler implements InvocationHandler { |
| 83 | private final Object target; | |
| 84 | private final String methodName; | |
| 85 | private final Set<String> eventTypes; | |
| 86 | ||
| 87 | /** | |
| 88 | * Creates a new instance of {@code EventBindingInvocationHandler}. | |
| 89 | * | |
| 90 | * @param target the target object for method invocations | |
| 91 | * @param methodName the name of the method to be invoked | |
| 92 | * @param eventTypes the names of the supported event types | |
| 93 | */ | |
| 94 | 3 | EventBindingInvocationHandler(final Object target, final String methodName, final String[] eventTypes) { |
| 95 | 3 | this.target = target; |
| 96 | 3 | this.methodName = methodName; |
| 97 | 3 | this.eventTypes = new HashSet<String>(Arrays.asList(eventTypes)); |
| 98 | 3 | } |
| 99 | ||
| 100 | /** | |
| 101 | * Handles a method invocation on the proxy object. | |
| 102 | * | |
| 103 | * @param proxy the proxy instance | |
| 104 | * @param method the method to be invoked | |
| 105 | * @param parameters the parameters for the method invocation | |
| 106 | * @return the result of the method call | |
| 107 | * @throws Throwable if an error occurs | |
| 108 | */ | |
| 109 | @Override | |
| 110 | public Object invoke(final Object proxy, final Method method, final Object[] parameters) throws Throwable { | |
| 111 | 4 | if (eventTypes.isEmpty() || eventTypes.contains(method.getName())) { |
| 112 | 3 | if (hasMatchingParametersMethod(method)) { |
| 113 | 1 | return MethodUtils.invokeMethod(target, methodName, parameters); |
| 114 | } else { | |
| 115 | 2 | return MethodUtils.invokeMethod(target, methodName); |
| 116 | } | |
| 117 | } | |
| 118 | 1 | return null; |
| 119 | } | |
| 120 | ||
| 121 | /** | |
| 122 | * Checks whether a method for the passed in parameters can be found. | |
| 123 | * | |
| 124 | * @param method the listener method invoked | |
| 125 | * @return a flag whether the parameters could be matched | |
| 126 | */ | |
| 127 | private boolean hasMatchingParametersMethod(final Method method) { | |
| 128 | 3 | return MethodUtils.getAccessibleMethod(target.getClass(), methodName, method.getParameterTypes()) != null; |
| 129 | } | |
| 130 | } | |
| 131 | } |