Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/beans/EventSetDescriptor.java
38829 views
/*1* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.beans;2627import java.lang.ref.Reference;28import java.lang.reflect.Method;29import java.lang.reflect.Modifier;3031/**32* An EventSetDescriptor describes a group of events that a given Java33* bean fires.34* <P>35* The given group of events are all delivered as method calls on a single36* event listener interface, and an event listener object can be registered37* via a call on a registration method supplied by the event source.38*/39public class EventSetDescriptor extends FeatureDescriptor {4041private MethodDescriptor[] listenerMethodDescriptors;42private MethodDescriptor addMethodDescriptor;43private MethodDescriptor removeMethodDescriptor;44private MethodDescriptor getMethodDescriptor;4546private Reference<Method[]> listenerMethodsRef;47private Reference<? extends Class<?>> listenerTypeRef;4849private boolean unicast;50private boolean inDefaultEventSet = true;5152/**53* Creates an <TT>EventSetDescriptor</TT> assuming that you are54* following the most simple standard design pattern where a named55* event "fred" is (1) delivered as a call on the single method of56* interface FredListener, (2) has a single argument of type FredEvent,57* and (3) where the FredListener may be registered with a call on an58* addFredListener method of the source component and removed with a59* call on a removeFredListener method.60*61* @param sourceClass The class firing the event.62* @param eventSetName The programmatic name of the event. E.g. "fred".63* Note that this should normally start with a lower-case character.64* @param listenerType The target interface that events65* will get delivered to.66* @param listenerMethodName The method that will get called when the event gets67* delivered to its target listener interface.68* @exception IntrospectionException if an exception occurs during69* introspection.70*/71public EventSetDescriptor(Class<?> sourceClass, String eventSetName,72Class<?> listenerType, String listenerMethodName)73throws IntrospectionException {74this(sourceClass, eventSetName, listenerType,75new String[] { listenerMethodName },76Introspector.ADD_PREFIX + getListenerClassName(listenerType),77Introspector.REMOVE_PREFIX + getListenerClassName(listenerType),78Introspector.GET_PREFIX + getListenerClassName(listenerType) + "s");7980String eventName = NameGenerator.capitalize(eventSetName) + "Event";81Method[] listenerMethods = getListenerMethods();82if (listenerMethods.length > 0) {83Class[] args = getParameterTypes(getClass0(), listenerMethods[0]);84// Check for EventSet compliance. Special case for vetoableChange. See 452999685if (!"vetoableChange".equals(eventSetName) && !args[0].getName().endsWith(eventName)) {86throw new IntrospectionException("Method \"" + listenerMethodName +87"\" should have argument \"" +88eventName + "\"");89}90}91}9293private static String getListenerClassName(Class<?> cls) {94String className = cls.getName();95return className.substring(className.lastIndexOf('.') + 1);96}9798/**99* Creates an <TT>EventSetDescriptor</TT> from scratch using100* string names.101*102* @param sourceClass The class firing the event.103* @param eventSetName The programmatic name of the event set.104* Note that this should normally start with a lower-case character.105* @param listenerType The Class of the target interface that events106* will get delivered to.107* @param listenerMethodNames The names of the methods that will get called108* when the event gets delivered to its target listener interface.109* @param addListenerMethodName The name of the method on the event source110* that can be used to register an event listener object.111* @param removeListenerMethodName The name of the method on the event source112* that can be used to de-register an event listener object.113* @exception IntrospectionException if an exception occurs during114* introspection.115*/116public EventSetDescriptor(Class<?> sourceClass,117String eventSetName,118Class<?> listenerType,119String listenerMethodNames[],120String addListenerMethodName,121String removeListenerMethodName)122throws IntrospectionException {123this(sourceClass, eventSetName, listenerType,124listenerMethodNames, addListenerMethodName,125removeListenerMethodName, null);126}127128/**129* This constructor creates an EventSetDescriptor from scratch using130* string names.131*132* @param sourceClass The class firing the event.133* @param eventSetName The programmatic name of the event set.134* Note that this should normally start with a lower-case character.135* @param listenerType The Class of the target interface that events136* will get delivered to.137* @param listenerMethodNames The names of the methods that will get called138* when the event gets delivered to its target listener interface.139* @param addListenerMethodName The name of the method on the event source140* that can be used to register an event listener object.141* @param removeListenerMethodName The name of the method on the event source142* that can be used to de-register an event listener object.143* @param getListenerMethodName The method on the event source that144* can be used to access the array of event listener objects.145* @exception IntrospectionException if an exception occurs during146* introspection.147* @since 1.4148*/149public EventSetDescriptor(Class<?> sourceClass,150String eventSetName,151Class<?> listenerType,152String listenerMethodNames[],153String addListenerMethodName,154String removeListenerMethodName,155String getListenerMethodName)156throws IntrospectionException {157if (sourceClass == null || eventSetName == null || listenerType == null) {158throw new NullPointerException();159}160setName(eventSetName);161setClass0(sourceClass);162setListenerType(listenerType);163164Method[] listenerMethods = new Method[listenerMethodNames.length];165for (int i = 0; i < listenerMethodNames.length; i++) {166// Check for null names167if (listenerMethodNames[i] == null) {168throw new NullPointerException();169}170listenerMethods[i] = getMethod(listenerType, listenerMethodNames[i], 1);171}172setListenerMethods(listenerMethods);173174setAddListenerMethod(getMethod(sourceClass, addListenerMethodName, 1));175setRemoveListenerMethod(getMethod(sourceClass, removeListenerMethodName, 1));176177// Be more forgiving of not finding the getListener method.178Method method = Introspector.findMethod(sourceClass, getListenerMethodName, 0);179if (method != null) {180setGetListenerMethod(method);181}182}183184private static Method getMethod(Class<?> cls, String name, int args)185throws IntrospectionException {186if (name == null) {187return null;188}189Method method = Introspector.findMethod(cls, name, args);190if ((method == null) || Modifier.isStatic(method.getModifiers())) {191throw new IntrospectionException("Method not found: " + name +192" on class " + cls.getName());193}194return method;195}196197/**198* Creates an <TT>EventSetDescriptor</TT> from scratch using199* <TT>java.lang.reflect.Method</TT> and <TT>java.lang.Class</TT> objects.200*201* @param eventSetName The programmatic name of the event set.202* @param listenerType The Class for the listener interface.203* @param listenerMethods An array of Method objects describing each204* of the event handling methods in the target listener.205* @param addListenerMethod The method on the event source206* that can be used to register an event listener object.207* @param removeListenerMethod The method on the event source208* that can be used to de-register an event listener object.209* @exception IntrospectionException if an exception occurs during210* introspection.211*/212public EventSetDescriptor(String eventSetName,213Class<?> listenerType,214Method listenerMethods[],215Method addListenerMethod,216Method removeListenerMethod)217throws IntrospectionException {218this(eventSetName, listenerType, listenerMethods,219addListenerMethod, removeListenerMethod, null);220}221222/**223* This constructor creates an EventSetDescriptor from scratch using224* java.lang.reflect.Method and java.lang.Class objects.225*226* @param eventSetName The programmatic name of the event set.227* @param listenerType The Class for the listener interface.228* @param listenerMethods An array of Method objects describing each229* of the event handling methods in the target listener.230* @param addListenerMethod The method on the event source231* that can be used to register an event listener object.232* @param removeListenerMethod The method on the event source233* that can be used to de-register an event listener object.234* @param getListenerMethod The method on the event source235* that can be used to access the array of event listener objects.236* @exception IntrospectionException if an exception occurs during237* introspection.238* @since 1.4239*/240public EventSetDescriptor(String eventSetName,241Class<?> listenerType,242Method listenerMethods[],243Method addListenerMethod,244Method removeListenerMethod,245Method getListenerMethod)246throws IntrospectionException {247setName(eventSetName);248setListenerMethods(listenerMethods);249setAddListenerMethod(addListenerMethod);250setRemoveListenerMethod( removeListenerMethod);251setGetListenerMethod(getListenerMethod);252setListenerType(listenerType);253}254255/**256* Creates an <TT>EventSetDescriptor</TT> from scratch using257* <TT>java.lang.reflect.MethodDescriptor</TT> and <TT>java.lang.Class</TT>258* objects.259*260* @param eventSetName The programmatic name of the event set.261* @param listenerType The Class for the listener interface.262* @param listenerMethodDescriptors An array of MethodDescriptor objects263* describing each of the event handling methods in the264* target listener.265* @param addListenerMethod The method on the event source266* that can be used to register an event listener object.267* @param removeListenerMethod The method on the event source268* that can be used to de-register an event listener object.269* @exception IntrospectionException if an exception occurs during270* introspection.271*/272public EventSetDescriptor(String eventSetName,273Class<?> listenerType,274MethodDescriptor listenerMethodDescriptors[],275Method addListenerMethod,276Method removeListenerMethod)277throws IntrospectionException {278setName(eventSetName);279this.listenerMethodDescriptors = (listenerMethodDescriptors != null)280? listenerMethodDescriptors.clone()281: null;282setAddListenerMethod(addListenerMethod);283setRemoveListenerMethod(removeListenerMethod);284setListenerType(listenerType);285}286287/**288* Gets the <TT>Class</TT> object for the target interface.289*290* @return The Class object for the target interface that will291* get invoked when the event is fired.292*/293public Class<?> getListenerType() {294return (this.listenerTypeRef != null)295? this.listenerTypeRef.get()296: null;297}298299private void setListenerType(Class<?> cls) {300this.listenerTypeRef = getWeakReference(cls);301}302303/**304* Gets the methods of the target listener interface.305*306* @return An array of <TT>Method</TT> objects for the target methods307* within the target listener interface that will get called when308* events are fired.309*/310public synchronized Method[] getListenerMethods() {311Method[] methods = getListenerMethods0();312if (methods == null) {313if (listenerMethodDescriptors != null) {314methods = new Method[listenerMethodDescriptors.length];315for (int i = 0; i < methods.length; i++) {316methods[i] = listenerMethodDescriptors[i].getMethod();317}318}319setListenerMethods(methods);320}321return methods;322}323324private void setListenerMethods(Method[] methods) {325if (methods == null) {326return;327}328if (listenerMethodDescriptors == null) {329listenerMethodDescriptors = new MethodDescriptor[methods.length];330for (int i = 0; i < methods.length; i++) {331listenerMethodDescriptors[i] = new MethodDescriptor(methods[i]);332}333}334this.listenerMethodsRef = getSoftReference(methods);335}336337private Method[] getListenerMethods0() {338return (this.listenerMethodsRef != null)339? this.listenerMethodsRef.get()340: null;341}342343/**344* Gets the <code>MethodDescriptor</code>s of the target listener interface.345*346* @return An array of <code>MethodDescriptor</code> objects for the target methods347* within the target listener interface that will get called when348* events are fired.349*/350public synchronized MethodDescriptor[] getListenerMethodDescriptors() {351return (this.listenerMethodDescriptors != null)352? this.listenerMethodDescriptors.clone()353: null;354}355356/**357* Gets the method used to add event listeners.358*359* @return The method used to register a listener at the event source.360*/361public synchronized Method getAddListenerMethod() {362return getMethod(this.addMethodDescriptor);363}364365private synchronized void setAddListenerMethod(Method method) {366if (method == null) {367return;368}369if (getClass0() == null) {370setClass0(method.getDeclaringClass());371}372addMethodDescriptor = new MethodDescriptor(method);373setTransient(method.getAnnotation(Transient.class));374}375376/**377* Gets the method used to remove event listeners.378*379* @return The method used to remove a listener at the event source.380*/381public synchronized Method getRemoveListenerMethod() {382return getMethod(this.removeMethodDescriptor);383}384385private synchronized void setRemoveListenerMethod(Method method) {386if (method == null) {387return;388}389if (getClass0() == null) {390setClass0(method.getDeclaringClass());391}392removeMethodDescriptor = new MethodDescriptor(method);393setTransient(method.getAnnotation(Transient.class));394}395396/**397* Gets the method used to access the registered event listeners.398*399* @return The method used to access the array of listeners at the event400* source or null if it doesn't exist.401* @since 1.4402*/403public synchronized Method getGetListenerMethod() {404return getMethod(this.getMethodDescriptor);405}406407private synchronized void setGetListenerMethod(Method method) {408if (method == null) {409return;410}411if (getClass0() == null) {412setClass0(method.getDeclaringClass());413}414getMethodDescriptor = new MethodDescriptor(method);415setTransient(method.getAnnotation(Transient.class));416}417418/**419* Mark an event set as unicast (or not).420*421* @param unicast True if the event set is unicast.422*/423public void setUnicast(boolean unicast) {424this.unicast = unicast;425}426427/**428* Normally event sources are multicast. However there are some429* exceptions that are strictly unicast.430*431* @return <TT>true</TT> if the event set is unicast.432* Defaults to <TT>false</TT>.433*/434public boolean isUnicast() {435return unicast;436}437438/**439* Marks an event set as being in the "default" set (or not).440* By default this is <TT>true</TT>.441*442* @param inDefaultEventSet <code>true</code> if the event set is in443* the "default" set,444* <code>false</code> if not445*/446public void setInDefaultEventSet(boolean inDefaultEventSet) {447this.inDefaultEventSet = inDefaultEventSet;448}449450/**451* Reports if an event set is in the "default" set.452*453* @return <TT>true</TT> if the event set is in454* the "default" set. Defaults to <TT>true</TT>.455*/456public boolean isInDefaultEventSet() {457return inDefaultEventSet;458}459460/*461* Package-private constructor462* Merge two event set descriptors. Where they conflict, give the463* second argument (y) priority over the first argument (x).464*465* @param x The first (lower priority) EventSetDescriptor466* @param y The second (higher priority) EventSetDescriptor467*/468EventSetDescriptor(EventSetDescriptor x, EventSetDescriptor y) {469super(x,y);470listenerMethodDescriptors = x.listenerMethodDescriptors;471if (y.listenerMethodDescriptors != null) {472listenerMethodDescriptors = y.listenerMethodDescriptors;473}474475listenerTypeRef = x.listenerTypeRef;476if (y.listenerTypeRef != null) {477listenerTypeRef = y.listenerTypeRef;478}479480addMethodDescriptor = x.addMethodDescriptor;481if (y.addMethodDescriptor != null) {482addMethodDescriptor = y.addMethodDescriptor;483}484485removeMethodDescriptor = x.removeMethodDescriptor;486if (y.removeMethodDescriptor != null) {487removeMethodDescriptor = y.removeMethodDescriptor;488}489490getMethodDescriptor = x.getMethodDescriptor;491if (y.getMethodDescriptor != null) {492getMethodDescriptor = y.getMethodDescriptor;493}494495unicast = y.unicast;496if (!x.inDefaultEventSet || !y.inDefaultEventSet) {497inDefaultEventSet = false;498}499}500501/*502* Package-private dup constructor503* This must isolate the new object from any changes to the old object.504*/505EventSetDescriptor(EventSetDescriptor old) {506super(old);507if (old.listenerMethodDescriptors != null) {508int len = old.listenerMethodDescriptors.length;509listenerMethodDescriptors = new MethodDescriptor[len];510for (int i = 0; i < len; i++) {511listenerMethodDescriptors[i] = new MethodDescriptor(512old.listenerMethodDescriptors[i]);513}514}515listenerTypeRef = old.listenerTypeRef;516517addMethodDescriptor = old.addMethodDescriptor;518removeMethodDescriptor = old.removeMethodDescriptor;519getMethodDescriptor = old.getMethodDescriptor;520521unicast = old.unicast;522inDefaultEventSet = old.inDefaultEventSet;523}524525void appendTo(StringBuilder sb) {526appendTo(sb, "unicast", this.unicast);527appendTo(sb, "inDefaultEventSet", this.inDefaultEventSet);528appendTo(sb, "listenerType", this.listenerTypeRef);529appendTo(sb, "getListenerMethod", getMethod(this.getMethodDescriptor));530appendTo(sb, "addListenerMethod", getMethod(this.addMethodDescriptor));531appendTo(sb, "removeListenerMethod", getMethod(this.removeMethodDescriptor));532}533534private static Method getMethod(MethodDescriptor descriptor) {535return (descriptor != null)536? descriptor.getMethod()537: null;538}539}540541542