0N/A/*
2362N/A * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.beans;
0N/A
0N/Aimport java.lang.ref.Reference;
0N/Aimport java.lang.reflect.Method;
2523N/Aimport java.lang.reflect.Modifier;
0N/A
0N/A/**
0N/A * An EventSetDescriptor describes a group of events that a given Java
0N/A * bean fires.
0N/A * <P>
0N/A * The given group of events are all delivered as method calls on a single
0N/A * event listener interface, and an event listener object can be registered
0N/A * via a call on a registration method supplied by the event source.
0N/A */
0N/Apublic class EventSetDescriptor extends FeatureDescriptor {
0N/A
0N/A private MethodDescriptor[] listenerMethodDescriptors;
0N/A private MethodDescriptor addMethodDescriptor;
0N/A private MethodDescriptor removeMethodDescriptor;
0N/A private MethodDescriptor getMethodDescriptor;
0N/A
0N/A private Reference<Method[]> listenerMethodsRef;
0N/A private Reference<Class> listenerTypeRef;
0N/A
0N/A private boolean unicast;
0N/A private boolean inDefaultEventSet = true;
0N/A
0N/A /**
0N/A * Creates an <TT>EventSetDescriptor</TT> assuming that you are
0N/A * following the most simple standard design pattern where a named
0N/A * event &quot;fred&quot; is (1) delivered as a call on the single method of
0N/A * interface FredListener, (2) has a single argument of type FredEvent,
0N/A * and (3) where the FredListener may be registered with a call on an
0N/A * addFredListener method of the source component and removed with a
0N/A * call on a removeFredListener method.
0N/A *
0N/A * @param sourceClass The class firing the event.
0N/A * @param eventSetName The programmatic name of the event. E.g. &quot;fred&quot;.
0N/A * Note that this should normally start with a lower-case character.
0N/A * @param listenerType The target interface that events
0N/A * will get delivered to.
0N/A * @param listenerMethodName The method that will get called when the event gets
0N/A * delivered to its target listener interface.
0N/A * @exception IntrospectionException if an exception occurs during
0N/A * introspection.
0N/A */
0N/A public EventSetDescriptor(Class<?> sourceClass, String eventSetName,
0N/A Class<?> listenerType, String listenerMethodName)
0N/A throws IntrospectionException {
0N/A this(sourceClass, eventSetName, listenerType,
0N/A new String[] { listenerMethodName },
0N/A Introspector.ADD_PREFIX + getListenerClassName(listenerType),
0N/A Introspector.REMOVE_PREFIX + getListenerClassName(listenerType),
0N/A Introspector.GET_PREFIX + getListenerClassName(listenerType) + "s");
0N/A
0N/A String eventName = NameGenerator.capitalize(eventSetName) + "Event";
0N/A Method[] listenerMethods = getListenerMethods();
0N/A if (listenerMethods.length > 0) {
0N/A Class[] args = getParameterTypes(getClass0(), listenerMethods[0]);
0N/A // Check for EventSet compliance. Special case for vetoableChange. See 4529996
0N/A if (!"vetoableChange".equals(eventSetName) && !args[0].getName().endsWith(eventName)) {
0N/A throw new IntrospectionException("Method \"" + listenerMethodName +
0N/A "\" should have argument \"" +
0N/A eventName + "\"");
0N/A }
0N/A }
0N/A }
0N/A
0N/A private static String getListenerClassName(Class cls) {
0N/A String className = cls.getName();
0N/A return className.substring(className.lastIndexOf('.') + 1);
0N/A }
0N/A
0N/A /**
0N/A * Creates an <TT>EventSetDescriptor</TT> from scratch using
0N/A * string names.
0N/A *
0N/A * @param sourceClass The class firing the event.
0N/A * @param eventSetName The programmatic name of the event set.
0N/A * Note that this should normally start with a lower-case character.
0N/A * @param listenerType The Class of the target interface that events
0N/A * will get delivered to.
0N/A * @param listenerMethodNames The names of the methods that will get called
0N/A * when the event gets delivered to its target listener interface.
0N/A * @param addListenerMethodName The name of the method on the event source
0N/A * that can be used to register an event listener object.
0N/A * @param removeListenerMethodName The name of the method on the event source
0N/A * that can be used to de-register an event listener object.
0N/A * @exception IntrospectionException if an exception occurs during
0N/A * introspection.
0N/A */
0N/A public EventSetDescriptor(Class<?> sourceClass,
0N/A String eventSetName,
0N/A Class<?> listenerType,
0N/A String listenerMethodNames[],
0N/A String addListenerMethodName,
0N/A String removeListenerMethodName)
0N/A throws IntrospectionException {
0N/A this(sourceClass, eventSetName, listenerType,
0N/A listenerMethodNames, addListenerMethodName,
0N/A removeListenerMethodName, null);
0N/A }
0N/A
0N/A /**
0N/A * This constructor creates an EventSetDescriptor from scratch using
0N/A * string names.
0N/A *
0N/A * @param sourceClass The class firing the event.
0N/A * @param eventSetName The programmatic name of the event set.
0N/A * Note that this should normally start with a lower-case character.
0N/A * @param listenerType The Class of the target interface that events
0N/A * will get delivered to.
0N/A * @param listenerMethodNames The names of the methods that will get called
0N/A * when the event gets delivered to its target listener interface.
0N/A * @param addListenerMethodName The name of the method on the event source
0N/A * that can be used to register an event listener object.
0N/A * @param removeListenerMethodName The name of the method on the event source
0N/A * that can be used to de-register an event listener object.
0N/A * @param getListenerMethodName The method on the event source that
0N/A * can be used to access the array of event listener objects.
0N/A * @exception IntrospectionException if an exception occurs during
0N/A * introspection.
0N/A * @since 1.4
0N/A */
0N/A public EventSetDescriptor(Class<?> sourceClass,
0N/A String eventSetName,
0N/A Class<?> listenerType,
0N/A String listenerMethodNames[],
0N/A String addListenerMethodName,
0N/A String removeListenerMethodName,
0N/A String getListenerMethodName)
0N/A throws IntrospectionException {
0N/A if (sourceClass == null || eventSetName == null || listenerType == null) {
0N/A throw new NullPointerException();
0N/A }
0N/A setName(eventSetName);
0N/A setClass0(sourceClass);
0N/A setListenerType(listenerType);
0N/A
0N/A Method[] listenerMethods = new Method[listenerMethodNames.length];
0N/A for (int i = 0; i < listenerMethodNames.length; i++) {
0N/A // Check for null names
0N/A if (listenerMethodNames[i] == null) {
0N/A throw new NullPointerException();
0N/A }
0N/A listenerMethods[i] = getMethod(listenerType, listenerMethodNames[i], 1);
0N/A }
0N/A setListenerMethods(listenerMethods);
0N/A
0N/A setAddListenerMethod(getMethod(sourceClass, addListenerMethodName, 1));
0N/A setRemoveListenerMethod(getMethod(sourceClass, removeListenerMethodName, 1));
0N/A
0N/A // Be more forgiving of not finding the getListener method.
2788N/A Method method = Introspector.findMethod(sourceClass, getListenerMethodName, 0);
2788N/A if (method != null) {
2788N/A setGetListenerMethod(method);
0N/A }
0N/A }
0N/A
0N/A private static Method getMethod(Class cls, String name, int args)
0N/A throws IntrospectionException {
0N/A if (name == null) {
0N/A return null;
0N/A }
0N/A Method method = Introspector.findMethod(cls, name, args);
2523N/A if ((method == null) || Modifier.isStatic(method.getModifiers())) {
0N/A throw new IntrospectionException("Method not found: " + name +
0N/A " on class " + cls.getName());
0N/A }
0N/A return method;
0N/A }
0N/A
0N/A /**
0N/A * Creates an <TT>EventSetDescriptor</TT> from scratch using
0N/A * <TT>java.lang.reflect.Method</TT> and <TT>java.lang.Class</TT> objects.
0N/A *
0N/A * @param eventSetName The programmatic name of the event set.
0N/A * @param listenerType The Class for the listener interface.
0N/A * @param listenerMethods An array of Method objects describing each
0N/A * of the event handling methods in the target listener.
0N/A * @param addListenerMethod The method on the event source
0N/A * that can be used to register an event listener object.
0N/A * @param removeListenerMethod The method on the event source
0N/A * that can be used to de-register an event listener object.
0N/A * @exception IntrospectionException if an exception occurs during
0N/A * introspection.
0N/A */
0N/A public EventSetDescriptor(String eventSetName,
0N/A Class<?> listenerType,
0N/A Method listenerMethods[],
0N/A Method addListenerMethod,
0N/A Method removeListenerMethod)
0N/A throws IntrospectionException {
0N/A this(eventSetName, listenerType, listenerMethods,
0N/A addListenerMethod, removeListenerMethod, null);
0N/A }
0N/A
0N/A /**
0N/A * This constructor creates an EventSetDescriptor from scratch using
0N/A * java.lang.reflect.Method and java.lang.Class objects.
0N/A *
0N/A * @param eventSetName The programmatic name of the event set.
0N/A * @param listenerType The Class for the listener interface.
0N/A * @param listenerMethods An array of Method objects describing each
0N/A * of the event handling methods in the target listener.
0N/A * @param addListenerMethod The method on the event source
0N/A * that can be used to register an event listener object.
0N/A * @param removeListenerMethod The method on the event source
0N/A * that can be used to de-register an event listener object.
0N/A * @param getListenerMethod The method on the event source
0N/A * that can be used to access the array of event listener objects.
0N/A * @exception IntrospectionException if an exception occurs during
0N/A * introspection.
0N/A * @since 1.4
0N/A */
0N/A public EventSetDescriptor(String eventSetName,
0N/A Class<?> listenerType,
0N/A Method listenerMethods[],
0N/A Method addListenerMethod,
0N/A Method removeListenerMethod,
0N/A Method getListenerMethod)
0N/A throws IntrospectionException {
0N/A setName(eventSetName);
0N/A setListenerMethods(listenerMethods);
0N/A setAddListenerMethod(addListenerMethod);
0N/A setRemoveListenerMethod( removeListenerMethod);
0N/A setGetListenerMethod(getListenerMethod);
0N/A setListenerType(listenerType);
0N/A }
0N/A
0N/A /**
0N/A * Creates an <TT>EventSetDescriptor</TT> from scratch using
0N/A * <TT>java.lang.reflect.MethodDescriptor</TT> and <TT>java.lang.Class</TT>
0N/A * objects.
0N/A *
0N/A * @param eventSetName The programmatic name of the event set.
0N/A * @param listenerType The Class for the listener interface.
0N/A * @param listenerMethodDescriptors An array of MethodDescriptor objects
0N/A * describing each of the event handling methods in the
0N/A * target listener.
0N/A * @param addListenerMethod The method on the event source
0N/A * that can be used to register an event listener object.
0N/A * @param removeListenerMethod The method on the event source
0N/A * that can be used to de-register an event listener object.
0N/A * @exception IntrospectionException if an exception occurs during
0N/A * introspection.
0N/A */
0N/A public EventSetDescriptor(String eventSetName,
0N/A Class<?> listenerType,
0N/A MethodDescriptor listenerMethodDescriptors[],
0N/A Method addListenerMethod,
0N/A Method removeListenerMethod)
0N/A throws IntrospectionException {
0N/A setName(eventSetName);
0N/A this.listenerMethodDescriptors = listenerMethodDescriptors;
0N/A setAddListenerMethod(addListenerMethod);
0N/A setRemoveListenerMethod(removeListenerMethod);
0N/A setListenerType(listenerType);
0N/A }
0N/A
0N/A /**
0N/A * Gets the <TT>Class</TT> object for the target interface.
0N/A *
0N/A * @return The Class object for the target interface that will
0N/A * get invoked when the event is fired.
0N/A */
0N/A public Class<?> getListenerType() {
0N/A return (this.listenerTypeRef != null)
0N/A ? this.listenerTypeRef.get()
0N/A : null;
0N/A }
0N/A
0N/A private void setListenerType(Class cls) {
0N/A this.listenerTypeRef = getWeakReference(cls);
0N/A }
0N/A
0N/A /**
0N/A * Gets the methods of the target listener interface.
0N/A *
0N/A * @return An array of <TT>Method</TT> objects for the target methods
0N/A * within the target listener interface that will get called when
0N/A * events are fired.
0N/A */
0N/A public synchronized Method[] getListenerMethods() {
0N/A Method[] methods = getListenerMethods0();
0N/A if (methods == null) {
0N/A if (listenerMethodDescriptors != null) {
0N/A methods = new Method[listenerMethodDescriptors.length];
0N/A for (int i = 0; i < methods.length; i++) {
0N/A methods[i] = listenerMethodDescriptors[i].getMethod();
0N/A }
0N/A }
0N/A setListenerMethods(methods);
0N/A }
0N/A return methods;
0N/A }
0N/A
0N/A private void setListenerMethods(Method[] methods) {
0N/A if (methods == null) {
0N/A return;
0N/A }
0N/A if (listenerMethodDescriptors == null) {
0N/A listenerMethodDescriptors = new MethodDescriptor[methods.length];
0N/A for (int i = 0; i < methods.length; i++) {
0N/A listenerMethodDescriptors[i] = new MethodDescriptor(methods[i]);
0N/A }
0N/A }
0N/A this.listenerMethodsRef = getSoftReference(methods);
0N/A }
0N/A
0N/A private Method[] getListenerMethods0() {
0N/A return (this.listenerMethodsRef != null)
0N/A ? this.listenerMethodsRef.get()
0N/A : null;
0N/A }
0N/A
0N/A /**
0N/A * Gets the <code>MethodDescriptor</code>s of the target listener interface.
0N/A *
0N/A * @return An array of <code>MethodDescriptor</code> objects for the target methods
0N/A * within the target listener interface that will get called when
0N/A * events are fired.
0N/A */
0N/A public synchronized MethodDescriptor[] getListenerMethodDescriptors() {
0N/A return listenerMethodDescriptors;
0N/A }
0N/A
0N/A /**
0N/A * Gets the method used to add event listeners.
0N/A *
0N/A * @return The method used to register a listener at the event source.
0N/A */
0N/A public synchronized Method getAddListenerMethod() {
2172N/A return getMethod(this.addMethodDescriptor);
0N/A }
0N/A
0N/A private synchronized void setAddListenerMethod(Method method) {
0N/A if (method == null) {
0N/A return;
0N/A }
0N/A if (getClass0() == null) {
0N/A setClass0(method.getDeclaringClass());
0N/A }
0N/A addMethodDescriptor = new MethodDescriptor(method);
243N/A setTransient(method.getAnnotation(Transient.class));
0N/A }
0N/A
0N/A /**
0N/A * Gets the method used to remove event listeners.
0N/A *
0N/A * @return The method used to remove a listener at the event source.
0N/A */
0N/A public synchronized Method getRemoveListenerMethod() {
2172N/A return getMethod(this.removeMethodDescriptor);
0N/A }
0N/A
0N/A private synchronized void setRemoveListenerMethod(Method method) {
0N/A if (method == null) {
0N/A return;
0N/A }
0N/A if (getClass0() == null) {
0N/A setClass0(method.getDeclaringClass());
0N/A }
0N/A removeMethodDescriptor = new MethodDescriptor(method);
243N/A setTransient(method.getAnnotation(Transient.class));
0N/A }
0N/A
0N/A /**
0N/A * Gets the method used to access the registered event listeners.
0N/A *
0N/A * @return The method used to access the array of listeners at the event
0N/A * source or null if it doesn't exist.
0N/A * @since 1.4
0N/A */
0N/A public synchronized Method getGetListenerMethod() {
2172N/A return getMethod(this.getMethodDescriptor);
0N/A }
0N/A
0N/A private synchronized void setGetListenerMethod(Method method) {
0N/A if (method == null) {
0N/A return;
0N/A }
0N/A if (getClass0() == null) {
0N/A setClass0(method.getDeclaringClass());
0N/A }
0N/A getMethodDescriptor = new MethodDescriptor(method);
243N/A setTransient(method.getAnnotation(Transient.class));
0N/A }
0N/A
0N/A /**
0N/A * Mark an event set as unicast (or not).
0N/A *
0N/A * @param unicast True if the event set is unicast.
0N/A */
0N/A public void setUnicast(boolean unicast) {
0N/A this.unicast = unicast;
0N/A }
0N/A
0N/A /**
0N/A * Normally event sources are multicast. However there are some
0N/A * exceptions that are strictly unicast.
0N/A *
0N/A * @return <TT>true</TT> if the event set is unicast.
0N/A * Defaults to <TT>false</TT>.
0N/A */
0N/A public boolean isUnicast() {
0N/A return unicast;
0N/A }
0N/A
0N/A /**
0N/A * Marks an event set as being in the &quot;default&quot; set (or not).
0N/A * By default this is <TT>true</TT>.
0N/A *
0N/A * @param inDefaultEventSet <code>true</code> if the event set is in
0N/A * the &quot;default&quot; set,
0N/A * <code>false</code> if not
0N/A */
0N/A public void setInDefaultEventSet(boolean inDefaultEventSet) {
0N/A this.inDefaultEventSet = inDefaultEventSet;
0N/A }
0N/A
0N/A /**
0N/A * Reports if an event set is in the &quot;default&quot; set.
0N/A *
0N/A * @return <TT>true</TT> if the event set is in
0N/A * the &quot;default&quot; set. Defaults to <TT>true</TT>.
0N/A */
0N/A public boolean isInDefaultEventSet() {
0N/A return inDefaultEventSet;
0N/A }
0N/A
0N/A /*
0N/A * Package-private constructor
0N/A * Merge two event set descriptors. Where they conflict, give the
0N/A * second argument (y) priority over the first argument (x).
0N/A *
0N/A * @param x The first (lower priority) EventSetDescriptor
0N/A * @param y The second (higher priority) EventSetDescriptor
0N/A */
0N/A EventSetDescriptor(EventSetDescriptor x, EventSetDescriptor y) {
0N/A super(x,y);
0N/A listenerMethodDescriptors = x.listenerMethodDescriptors;
0N/A if (y.listenerMethodDescriptors != null) {
0N/A listenerMethodDescriptors = y.listenerMethodDescriptors;
0N/A }
0N/A
0N/A listenerTypeRef = x.listenerTypeRef;
0N/A if (y.listenerTypeRef != null) {
0N/A listenerTypeRef = y.listenerTypeRef;
0N/A }
0N/A
0N/A addMethodDescriptor = x.addMethodDescriptor;
0N/A if (y.addMethodDescriptor != null) {
0N/A addMethodDescriptor = y.addMethodDescriptor;
0N/A }
0N/A
0N/A removeMethodDescriptor = x.removeMethodDescriptor;
0N/A if (y.removeMethodDescriptor != null) {
0N/A removeMethodDescriptor = y.removeMethodDescriptor;
0N/A }
0N/A
0N/A getMethodDescriptor = x.getMethodDescriptor;
0N/A if (y.getMethodDescriptor != null) {
0N/A getMethodDescriptor = y.getMethodDescriptor;
0N/A }
0N/A
0N/A unicast = y.unicast;
0N/A if (!x.inDefaultEventSet || !y.inDefaultEventSet) {
0N/A inDefaultEventSet = false;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Package-private dup constructor
0N/A * This must isolate the new object from any changes to the old object.
0N/A */
0N/A EventSetDescriptor(EventSetDescriptor old) {
0N/A super(old);
0N/A if (old.listenerMethodDescriptors != null) {
0N/A int len = old.listenerMethodDescriptors.length;
0N/A listenerMethodDescriptors = new MethodDescriptor[len];
0N/A for (int i = 0; i < len; i++) {
0N/A listenerMethodDescriptors[i] = new MethodDescriptor(
0N/A old.listenerMethodDescriptors[i]);
0N/A }
0N/A }
0N/A listenerTypeRef = old.listenerTypeRef;
0N/A
0N/A addMethodDescriptor = old.addMethodDescriptor;
0N/A removeMethodDescriptor = old.removeMethodDescriptor;
0N/A getMethodDescriptor = old.getMethodDescriptor;
0N/A
0N/A unicast = old.unicast;
0N/A inDefaultEventSet = old.inDefaultEventSet;
0N/A }
2172N/A
2172N/A void appendTo(StringBuilder sb) {
2172N/A appendTo(sb, "unicast", this.unicast);
2172N/A appendTo(sb, "inDefaultEventSet", this.inDefaultEventSet);
2172N/A appendTo(sb, "listenerType", this.listenerTypeRef);
2172N/A appendTo(sb, "getListenerMethod", getMethod(this.getMethodDescriptor));
2172N/A appendTo(sb, "addListenerMethod", getMethod(this.addMethodDescriptor));
2172N/A appendTo(sb, "removeListenerMethod", getMethod(this.removeMethodDescriptor));
2172N/A }
2172N/A
2172N/A private static Method getMethod(MethodDescriptor descriptor) {
2172N/A return (descriptor != null)
2172N/A ? descriptor.getMethod()
2172N/A : null;
2172N/A }
0N/A}