aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/commons/lang3/event/EventUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/apache/commons/lang3/event/EventUtils.java')
-rw-r--r--src/main/java/org/apache/commons/lang3/event/EventUtils.java129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/lang3/event/EventUtils.java b/src/main/java/org/apache/commons/lang3/event/EventUtils.java
new file mode 100644
index 000000000..546c06818
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/event/EventUtils.java
@@ -0,0 +1,129 @@
+/*
+ * 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 org.apache.commons.lang3.event;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.commons.lang3.reflect.MethodUtils;
+
+/**
+ * Provides some useful event-based utility methods.
+ *
+ * @since 3.0
+ */
+public class EventUtils {
+
+ /**
+ * Adds an event listener to the specified source. This looks for an "add" method corresponding to the event
+ * type (addActionListener, for example).
+ * @param eventSource the event source
+ * @param listenerType the event listener type
+ * @param listener the listener
+ * @param <L> the event listener type
+ *
+ * @throws IllegalArgumentException if the object doesn't support the listener type
+ */
+ public static <L> void addEventListener(final Object eventSource, final Class<L> listenerType, final L listener) {
+ try {
+ MethodUtils.invokeMethod(eventSource, "add" + listenerType.getSimpleName(), listener);
+ } catch (final NoSuchMethodException e) {
+ throw new IllegalArgumentException("Class " + eventSource.getClass().getName()
+ + " does not have a public add" + listenerType.getSimpleName()
+ + " method which takes a parameter of type " + listenerType.getName() + ".");
+ } catch (final IllegalAccessException e) {
+ throw new IllegalArgumentException("Class " + eventSource.getClass().getName()
+ + " does not have an accessible add" + listenerType.getSimpleName ()
+ + " method which takes a parameter of type " + listenerType.getName() + ".");
+ } catch (final InvocationTargetException e) {
+ throw new IllegalArgumentException("Unable to add listener.", e.getCause());
+ }
+ }
+
+ /**
+ * Binds an event listener to a specific method on a specific object.
+ *
+ * @param <L> the event listener type
+ * @param target the target object
+ * @param methodName the name of the method to be called
+ * @param eventSource the object which is generating events (JButton, JList, etc.)
+ * @param listenerType the listener interface (ActionListener.class, SelectionListener.class, etc.)
+ * @param eventTypes the event types (method names) from the listener interface (if none specified, all will be
+ * supported)
+ */
+ public static <L> void bindEventsToMethod(final Object target, final String methodName, final Object eventSource,
+ final Class<L> listenerType, final String... eventTypes) {
+ final L listener = listenerType.cast(Proxy.newProxyInstance(target.getClass().getClassLoader(),
+ new Class[] { listenerType }, new EventBindingInvocationHandler(target, methodName, eventTypes)));
+ addEventListener(eventSource, listenerType, listener);
+ }
+
+ private static class EventBindingInvocationHandler implements InvocationHandler {
+ private final Object target;
+ private final String methodName;
+ private final Set<String> eventTypes;
+
+ /**
+ * Creates a new instance of {@link EventBindingInvocationHandler}.
+ *
+ * @param target the target object for method invocations
+ * @param methodName the name of the method to be invoked
+ * @param eventTypes the names of the supported event types
+ */
+ EventBindingInvocationHandler(final Object target, final String methodName, final String[] eventTypes) {
+ this.target = target;
+ this.methodName = methodName;
+ this.eventTypes = new HashSet<>(Arrays.asList(eventTypes));
+ }
+
+ /**
+ * Handles a method invocation on the proxy object.
+ *
+ * @param proxy the proxy instance
+ * @param method the method to be invoked
+ * @param parameters the parameters for the method invocation
+ * @return the result of the method call
+ * @throws Throwable if an error occurs
+ */
+ @Override
+ public Object invoke(final Object proxy, final Method method, final Object[] parameters) throws Throwable {
+ if (eventTypes.isEmpty() || eventTypes.contains(method.getName())) {
+ if (hasMatchingParametersMethod(method)) {
+ return MethodUtils.invokeMethod(target, methodName, parameters);
+ }
+ return MethodUtils.invokeMethod(target, methodName);
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether a method for the passed in parameters can be found.
+ *
+ * @param method the listener method invoked
+ * @return a flag whether the parameters could be matched
+ */
+ private boolean hasMatchingParametersMethod(final Method method) {
+ return MethodUtils.getAccessibleMethod(target.getClass(), methodName, method.getParameterTypes()) != null;
+ }
+ }
+}