1. /*
  2. * @(#)EventSetDescriptor.java 1.55 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.beans;
  8. import java.lang.reflect.*;
  9. /**
  10. * An EventSetDescriptor describes a group of events that a given Java
  11. * bean fires.
  12. * <P>
  13. * The given group of events are all delivered as method calls on a single
  14. * event listener interface, and an event listener object can be registered
  15. * via a call on a registration method supplied by the event source.
  16. */
  17. public class EventSetDescriptor extends FeatureDescriptor {
  18. private Class listenerType;
  19. private Method[] listenerMethods;
  20. private MethodDescriptor[] listenerMethodDescriptors;
  21. private Method addMethod;
  22. private Method removeMethod;
  23. private Method getListenerMethod;
  24. private boolean unicast;
  25. private boolean inDefaultEventSet = true;
  26. /**
  27. * Creates an <TT>EventSetDescriptor</TT> assuming that you are
  28. * following the most simple standard design pattern where a named
  29. * event "fred" is (1) delivered as a call on the single method of
  30. * interface FredListener, (2) has a single argument of type FredEvent,
  31. * and (3) where the FredListener may be registered with a call on an
  32. * addFredListener method of the source component and removed with a
  33. * call on a removeFredListener method.
  34. *
  35. * @param sourceClass The class firing the event.
  36. * @param eventSetName The programmatic name of the event. E.g. "fred".
  37. * Note that this should normally start with a lower-case character.
  38. * @param listenerType The target interface that events
  39. * will get delivered to.
  40. * @param listenerMethodName The method that will get called when the event gets
  41. * delivered to its target listener interface.
  42. * @exception IntrospectionException if an exception occurs during
  43. * introspection.
  44. */
  45. public EventSetDescriptor(Class sourceClass, String eventSetName,
  46. Class listenerType, String listenerMethodName)
  47. throws IntrospectionException {
  48. setName(eventSetName);
  49. // Get a Class object for the listener class.
  50. this.listenerType = listenerType;
  51. char chars[] = eventSetName.toCharArray();
  52. chars[0] = Character.toUpperCase(eventSetName.charAt(0));
  53. String eventName = new String(chars);
  54. eventName += "Event";
  55. listenerMethods = new Method[1];
  56. listenerMethods[0] = Introspector.findMethod(listenerType,
  57. listenerMethodName, 1);
  58. Class[] args = listenerMethods[0].getParameterTypes();
  59. // Check for EventSet compliance. Special case for vetoableChange. See 4529996
  60. if (!"vetoableChange".equals(eventSetName) && !args[0].getName().endsWith(eventName)) {
  61. throw new IntrospectionException("Method \"" + listenerMethodName +
  62. "\" should have argument \"" +
  63. eventName + "\"");
  64. }
  65. String listenerClassName = listenerType.getName();
  66. String tail = listenerClassName.substring(listenerClassName.lastIndexOf('.') + 1);
  67. String addMethodName = "add" + tail;
  68. addMethod = Introspector.findMethod(sourceClass, addMethodName, 1);
  69. String removeMethodName = "remove" + tail;
  70. removeMethod = Introspector.findMethod(sourceClass, removeMethodName, 1);
  71. // Look for get<Foo>Listeners method. This was ammended to the JavaBeans
  72. // spec for 1.4 and it's a bonus if it exists but it's not enforced.
  73. String getMethodName = "get" + tail + "s";
  74. try {
  75. getListenerMethod = Introspector.findMethod(sourceClass, getMethodName, 0);
  76. } catch (IntrospectionException ex) {
  77. // Just catch and fall through if it doesn't exist.
  78. }
  79. }
  80. /**
  81. * Creates an <TT>EventSetDescriptor</TT> from scratch using
  82. * string names.
  83. *
  84. * @param sourceClass The class firing the event.
  85. * @param eventSetName The programmatic name of the event set.
  86. * Note that this should normally start with a lower-case character.
  87. * @param listenerType The Class of the target interface that events
  88. * will get delivered to.
  89. * @param listenerMethodNames The names of the methods that will get called
  90. * when the event gets delivered to its target listener interface.
  91. * @param addListenerMethodName The name of the method on the event source
  92. * that can be used to register an event listener object.
  93. * @param removeListenerMethodName The name of the method on the event source
  94. * that can be used to de-register an event listener object.
  95. * @exception IntrospectionException if an exception occurs during
  96. * introspection.
  97. */
  98. public EventSetDescriptor(Class sourceClass,
  99. String eventSetName,
  100. Class listenerType,
  101. String listenerMethodNames[],
  102. String addListenerMethodName,
  103. String removeListenerMethodName)
  104. throws IntrospectionException {
  105. this(sourceClass, eventSetName, listenerType,
  106. listenerMethodNames, addListenerMethodName,
  107. removeListenerMethodName, "");
  108. }
  109. /**
  110. * This constructor creates an EventSetDescriptor from scratch using
  111. * string names.
  112. *
  113. * @param sourceClass The class firing the event.
  114. * @param eventSetName The programmatic name of the event set.
  115. * Note that this should normally start with a lower-case character.
  116. * @param listenerType The Class of the target interface that events
  117. * will get delivered to.
  118. * @param listenerMethodNames The names of the methods that will get called
  119. * when the event gets delivered to its target listener interface.
  120. * @param addListenerMethodName The name of the method on the event source
  121. * that can be used to register an event listener object.
  122. * @param removeListenerMethodName The name of the method on the event source
  123. * that can be used to de-register an event listener object.
  124. * @param getListenerMethodName The method on the event source that
  125. * can be used to access the array of event listener objects.
  126. * @exception IntrospectionException if an exception occurs during
  127. * introspection.
  128. * @since 1.4
  129. */
  130. public EventSetDescriptor(Class sourceClass,
  131. String eventSetName,
  132. Class listenerType,
  133. String listenerMethodNames[],
  134. String addListenerMethodName,
  135. String removeListenerMethodName,
  136. String getListenerMethodName)
  137. throws IntrospectionException {
  138. setName(eventSetName);
  139. listenerMethods = new Method[listenerMethodNames.length];
  140. for (int i = 0; i < listenerMethods.length; i++) {
  141. String listenerName = listenerMethodNames[i];
  142. if (listenerName == null) {
  143. throw new NullPointerException();
  144. }
  145. listenerMethods[i] = Introspector.findMethod(listenerType,
  146. listenerName, 1);
  147. }
  148. this.addMethod = Introspector.findMethod(sourceClass,
  149. addListenerMethodName, 1);
  150. this.removeMethod = Introspector.findMethod(sourceClass,
  151. removeListenerMethodName, 1);
  152. if (getListenerMethodName != null && !getListenerMethodName.equals("")) {
  153. this.getListenerMethod = Introspector.findMethod(sourceClass,
  154. getListenerMethodName, 1);
  155. }
  156. this.listenerType = listenerType;
  157. }
  158. /**
  159. * Creates an <TT>EventSetDescriptor</TT> from scratch using
  160. * <TT>java.lang.reflect.Method</TT> and <TT>java.lang.Class</TT> objects.
  161. *
  162. * @param eventSetName The programmatic name of the event set.
  163. * @param listenerType The Class for the listener interface.
  164. * @param listenerMethods An array of Method objects describing each
  165. * of the event handling methods in the target listener.
  166. * @param addListenerMethod The method on the event source
  167. * that can be used to register an event listener object.
  168. * @param removeListenerMethod The method on the event source
  169. * that can be used to de-register an event listener object.
  170. * @exception IntrospectionException if an exception occurs during
  171. * introspection.
  172. */
  173. public EventSetDescriptor(String eventSetName,
  174. Class listenerType,
  175. Method listenerMethods[],
  176. Method addListenerMethod,
  177. Method removeListenerMethod)
  178. throws IntrospectionException {
  179. this(eventSetName, listenerType, listenerMethods,
  180. addListenerMethod, removeListenerMethod, null);
  181. }
  182. /**
  183. * This constructor creates an EventSetDescriptor from scratch using
  184. * java.lang.reflect.Method and java.lang.Class objects.
  185. *
  186. * @param eventSetName The programmatic name of the event set.
  187. * @param listenerType The Class for the listener interface.
  188. * @param listenerMethods An array of Method objects describing each
  189. * of the event handling methods in the target listener.
  190. * @param addListenerMethod The method on the event source
  191. * that can be used to register an event listener object.
  192. * @param removeListenerMethod The method on the event source
  193. * that can be used to de-register an event listener object.
  194. * @param getListenerMethod The method on the event source
  195. * that can be used to access the array of event listener objects.
  196. * @exception IntrospectionException if an exception occurs during
  197. * introspection.
  198. * @since 1.4
  199. */
  200. public EventSetDescriptor(String eventSetName,
  201. Class listenerType,
  202. Method listenerMethods[],
  203. Method addListenerMethod,
  204. Method removeListenerMethod,
  205. Method getListenerMethod)
  206. throws IntrospectionException {
  207. setName(eventSetName);
  208. this.listenerMethods = listenerMethods;
  209. this.addMethod = addListenerMethod;
  210. this.removeMethod = removeListenerMethod;
  211. this.getListenerMethod = getListenerMethod;
  212. this.listenerType = listenerType;
  213. }
  214. /**
  215. * Creates an <TT>EventSetDescriptor</TT> from scratch using
  216. * <TT>java.lang.reflect.MethodDescriptor</TT> and <TT>java.lang.Class</TT>
  217. * objects.
  218. *
  219. * @param eventSetName The programmatic name of the event set.
  220. * @param listenerType The Class for the listener interface.
  221. * @param listenerMethodDescriptors An array of MethodDescriptor objects
  222. * describing each of the event handling methods in the
  223. * target listener.
  224. * @param addListenerMethod The method on the event source
  225. * that can be used to register an event listener object.
  226. * @param removeListenerMethod The method on the event source
  227. * that can be used to de-register an event listener object.
  228. * @exception IntrospectionException if an exception occurs during
  229. * introspection.
  230. */
  231. public EventSetDescriptor(String eventSetName,
  232. Class listenerType,
  233. MethodDescriptor listenerMethodDescriptors[],
  234. Method addListenerMethod,
  235. Method removeListenerMethod)
  236. throws IntrospectionException {
  237. setName(eventSetName);
  238. this.listenerMethodDescriptors = listenerMethodDescriptors;
  239. this.addMethod = addListenerMethod;
  240. this.removeMethod = removeListenerMethod;
  241. this.listenerType = listenerType;
  242. }
  243. /**
  244. * Gets the <TT>Class</TT> object for the target interface.
  245. *
  246. * @return The Class object for the target interface that will
  247. * get invoked when the event is fired.
  248. */
  249. public Class getListenerType() {
  250. return listenerType;
  251. }
  252. /**
  253. * Gets the methods of the target listener interface.
  254. *
  255. * @return An array of <TT>Method</TT> objects for the target methods
  256. * within the target listener interface that will get called when
  257. * events are fired.
  258. */
  259. public Method[] getListenerMethods() {
  260. if (listenerMethods == null && listenerMethodDescriptors != null) {
  261. // Create Method array from MethodDescriptor array.
  262. listenerMethods = new Method[listenerMethodDescriptors.length];
  263. for (int i = 0; i < listenerMethods.length; i++) {
  264. listenerMethods[i] = listenerMethodDescriptors[i].getMethod();
  265. }
  266. }
  267. return listenerMethods;
  268. }
  269. /**
  270. * Gets the <code>MethodDescriptor</code>s of the target listener interface.
  271. *
  272. * @return An array of <code>MethodDescriptor</code> objects for the target methods
  273. * within the target listener interface that will get called when
  274. * events are fired.
  275. */
  276. public MethodDescriptor[] getListenerMethodDescriptors() {
  277. if (listenerMethodDescriptors == null && listenerMethods != null) {
  278. // Create MethodDescriptor array from Method array.
  279. listenerMethodDescriptors =
  280. new MethodDescriptor[listenerMethods.length];
  281. for (int i = 0; i < listenerMethods.length; i++) {
  282. listenerMethodDescriptors[i] =
  283. new MethodDescriptor(listenerMethods[i]);
  284. }
  285. }
  286. return listenerMethodDescriptors;
  287. }
  288. /**
  289. * Gets the method used to add event listeners.
  290. *
  291. * @return The method used to register a listener at the event source.
  292. */
  293. public Method getAddListenerMethod() {
  294. return addMethod;
  295. }
  296. /**
  297. * Gets the method used to remove event listeners.
  298. *
  299. * @return The method used to remove a listener at the event source.
  300. */
  301. public Method getRemoveListenerMethod() {
  302. return removeMethod;
  303. }
  304. /**
  305. * Gets the method used to access the registered event listeners.
  306. *
  307. * @return The method used to access the array of listeners at the event
  308. * source or null if it doesn't exist.
  309. * @since 1.4
  310. */
  311. public Method getGetListenerMethod() {
  312. return getListenerMethod;
  313. }
  314. /**
  315. * Mark an event set as unicast (or not).
  316. *
  317. * @param unicast True if the event set is unicast.
  318. */
  319. public void setUnicast(boolean unicast) {
  320. this.unicast = unicast;
  321. }
  322. /**
  323. * Normally event sources are multicast. However there are some
  324. * exceptions that are strictly unicast.
  325. *
  326. * @return <TT>true</TT> if the event set is unicast.
  327. * Defaults to <TT>false</TT>.
  328. */
  329. public boolean isUnicast() {
  330. return unicast;
  331. }
  332. /**
  333. * Marks an event set as being in the "default" set (or not).
  334. * By default this is <TT>true</TT>.
  335. *
  336. * @param inDefaultEventSet <code>true</code> if the event set is in
  337. * the "default" set,
  338. * <code>false</code> if not
  339. */
  340. public void setInDefaultEventSet(boolean inDefaultEventSet) {
  341. this.inDefaultEventSet = inDefaultEventSet;
  342. }
  343. /**
  344. * Reports if an event set is in the "default" set.
  345. *
  346. * @return <TT>true</TT> if the event set is in
  347. * the "default" set. Defaults to <TT>true</TT>.
  348. */
  349. public boolean isInDefaultEventSet() {
  350. return inDefaultEventSet;
  351. }
  352. /*
  353. * Package-private constructor
  354. * Merge two event set descriptors. Where they conflict, give the
  355. * second argument (y) priority over the first argument (x).
  356. *
  357. * @param x The first (lower priority) EventSetDescriptor
  358. * @param y The second (higher priority) EventSetDescriptor
  359. */
  360. EventSetDescriptor(EventSetDescriptor x, EventSetDescriptor y) {
  361. super(x,y);
  362. listenerMethodDescriptors = x.listenerMethodDescriptors;
  363. if (y.listenerMethodDescriptors != null) {
  364. listenerMethodDescriptors = y.listenerMethodDescriptors;
  365. }
  366. if (listenerMethodDescriptors == null) {
  367. listenerMethods = y.listenerMethods;
  368. }
  369. addMethod = y.addMethod;
  370. removeMethod = y.removeMethod;
  371. unicast = y.unicast;
  372. listenerType = y.listenerType;
  373. if (!x.inDefaultEventSet || !y.inDefaultEventSet) {
  374. inDefaultEventSet = false;
  375. }
  376. }
  377. /*
  378. * Package-private dup constructor
  379. * This must isolate the new object from any changes to the old object.
  380. */
  381. EventSetDescriptor(EventSetDescriptor old) {
  382. super(old);
  383. if (old.listenerMethodDescriptors != null) {
  384. int len = old.listenerMethodDescriptors.length;
  385. listenerMethodDescriptors = new MethodDescriptor[len];
  386. for (int i = 0; i < len; i++) {
  387. listenerMethodDescriptors[i] = new MethodDescriptor(
  388. old.listenerMethodDescriptors[i]);
  389. }
  390. }
  391. if (old.listenerMethods != null) {
  392. int len = old.listenerMethods.length;
  393. listenerMethods = new Method[len];
  394. for (int i = 0; i < len; i++) {
  395. listenerMethods[i] = old.listenerMethods[i];
  396. }
  397. }
  398. addMethod = old.addMethod;
  399. removeMethod = old.removeMethod;
  400. unicast = old.unicast;
  401. listenerType = old.listenerType;
  402. inDefaultEventSet = old.inDefaultEventSet;
  403. }
  404. }