001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.beans;
019:
020: import java.lang.reflect.Method;
021: import java.util.ArrayList;
022: import java.util.TooManyListenersException;
023: import org.apache.harmony.beans.internal.nls.Messages;
024:
025: public class EventSetDescriptor extends FeatureDescriptor {
026: private Class<?> listenerType;
027:
028: private ArrayList<MethodDescriptor> listenerMethodDescriptors;
029:
030: private Method[] listenerMethods;
031:
032: private Method getListenerMethod;
033:
034: private Method addListenerMethod;
035:
036: private Method removeListenerMethod;
037:
038: private boolean unicast;
039:
040: private boolean inDefaultEventSet = true;
041:
042: public EventSetDescriptor(Class<?> sourceClass,
043: String eventSetName, Class<?> listenerType,
044: String listenerMethodName) throws IntrospectionException {
045: Method m;
046:
047: checkNotNull(sourceClass, eventSetName, listenerType,
048: listenerMethodName);
049:
050: setName(eventSetName);
051: this .listenerType = listenerType;
052: m = findListenerMethodByName(listenerMethodName);
053: checkEventType(eventSetName, m);
054: listenerMethodDescriptors = new ArrayList<MethodDescriptor>();
055: listenerMethodDescriptors.add(new MethodDescriptor(m));
056: addListenerMethod = findMethodByPrefix(sourceClass, "add", ""); //$NON-NLS-1$ //$NON-NLS-2$
057: removeListenerMethod = findMethodByPrefix(sourceClass,
058: "remove", ""); //$NON-NLS-1$ //$NON-NLS-2$
059:
060: if (addListenerMethod == null || removeListenerMethod == null) {
061: throw new IntrospectionException(Messages
062: .getString("beans.38")); //$NON-NLS-1$
063: }
064:
065: getListenerMethod = findMethodByPrefix(sourceClass, "get", "s"); //$NON-NLS-1$ //$NON-NLS-2$
066: unicast = isUnicastByDefault(addListenerMethod);
067: }
068:
069: public EventSetDescriptor(Class<?> sourceClass,
070: String eventSetName, Class<?> listenerType,
071: String[] listenerMethodNames, String addListenerMethodName,
072: String removeListenerMethodName)
073: throws IntrospectionException {
074: this (sourceClass, eventSetName, listenerType,
075: listenerMethodNames, addListenerMethodName,
076: removeListenerMethodName, null);
077:
078: }
079:
080: public EventSetDescriptor(Class<?> sourceClass,
081: String eventSetName, Class<?> listenerType,
082: String[] listenerMethodNames, String addListenerMethodName,
083: String removeListenerMethodName,
084: String getListenerMethodName) throws IntrospectionException {
085:
086: checkNotNull(sourceClass, eventSetName, listenerType,
087: listenerMethodNames);
088:
089: setName(eventSetName);
090: this .listenerType = listenerType;
091:
092: listenerMethodDescriptors = new ArrayList<MethodDescriptor>();
093: for (String element : listenerMethodNames) {
094: Method m = findListenerMethodByName(element);
095:
096: // checkEventType(eventSetName, m);
097: listenerMethodDescriptors.add(new MethodDescriptor(m));
098: }
099:
100: if (addListenerMethodName != null) {
101: this .addListenerMethod = findAddRemoveListenerMethod(
102: sourceClass, addListenerMethodName);
103: }
104: if (removeListenerMethodName != null) {
105: this .removeListenerMethod = findAddRemoveListenerMethod(
106: sourceClass, removeListenerMethodName);
107: }
108: if (getListenerMethodName != null) {
109: this .getListenerMethod = findGetListenerMethod(sourceClass,
110: getListenerMethodName);
111: }
112: this .unicast = isUnicastByDefault(addListenerMethod);
113: }
114:
115: private Method findListenerMethodByName(String listenerMethodName)
116: throws IntrospectionException {
117: Method method = null;
118: Method[] methods = listenerType.getMethods();
119: for (Method m : methods) {
120: if (listenerMethodName.equals(m.getName())) {
121: Class[] paramTypes = m.getParameterTypes();
122: if (paramTypes.length == 1
123: && paramTypes[0].getName().endsWith("Event")) { //$NON-NLS-1$
124: method = m;
125: break;
126: }
127:
128: }
129: }
130: if (null == method) {
131: throw new IntrospectionException(Messages.getString(
132: "beans.31", //$NON-NLS-1$
133: listenerMethodName, listenerType.getName()));
134: }
135: return method;
136: }
137:
138: public EventSetDescriptor(String eventSetName,
139: Class<?> listenerType, Method[] listenerMethods,
140: Method addListenerMethod, Method removeListenerMethod)
141: throws IntrospectionException {
142:
143: this (eventSetName, listenerType, listenerMethods,
144: addListenerMethod, removeListenerMethod, null);
145: }
146:
147: public EventSetDescriptor(String eventSetName,
148: Class<?> listenerType, Method[] listenerMethods,
149: Method addListenerMethod, Method removeListenerMethod,
150: Method getListenerMethod) throws IntrospectionException {
151:
152: setName(eventSetName);
153: this .listenerType = listenerType;
154:
155: this .listenerMethods = listenerMethods;
156: if (listenerMethods != null) {
157: listenerMethodDescriptors = new ArrayList<MethodDescriptor>();
158:
159: for (Method element : listenerMethods) {
160: // XXX do we need this check?
161: // checkEventType(eventSetName, element);
162: // if (checkMethod(listenerType, element)) {
163: this .listenerMethodDescriptors
164: .add(new MethodDescriptor(element));
165: // }
166: }
167: }
168:
169: this .addListenerMethod = addListenerMethod;
170: this .removeListenerMethod = removeListenerMethod;
171: this .getListenerMethod = getListenerMethod;
172: this .unicast = isUnicastByDefault(addListenerMethod);
173: }
174:
175: public EventSetDescriptor(String eventSetName,
176: Class<?> listenerType,
177: MethodDescriptor[] listenerMethodDescriptors,
178: Method addListenerMethod, Method removeListenerMethod)
179: throws IntrospectionException {
180:
181: this (eventSetName, listenerType, null, addListenerMethod,
182: removeListenerMethod, null);
183:
184: if (listenerMethodDescriptors != null) {
185: this .listenerMethodDescriptors = new ArrayList<MethodDescriptor>();
186:
187: for (MethodDescriptor element : listenerMethodDescriptors) {
188: element.getMethod();
189: this .listenerMethodDescriptors.add(element);
190: }
191: }
192: }
193:
194: // ensures that there is no nulls
195: @SuppressWarnings("nls")
196: private void checkNotNull(Object sourceClass, Object eventSetName,
197: Object alistenerType, Object listenerMethodName) {
198: if (sourceClass == null) {
199: throw new NullPointerException(Messages
200: .getString("beans.0C"));
201: }
202: if (eventSetName == null) {
203: throw new NullPointerException(Messages
204: .getString("beans.53"));
205: }
206: if (alistenerType == null) {
207: throw new NullPointerException(Messages
208: .getString("beans.54"));
209: }
210: if (listenerMethodName == null) {
211: throw new NullPointerException(Messages
212: .getString("beans.52"));
213: }
214: }
215:
216: /**
217: * Checks that given listener method has an argument of the valid type.
218: *
219: * @param eventSetName
220: * event set name
221: * @param listenerMethod
222: * listener method
223: * @throws IntrospectionException
224: * if check fails
225: */
226: private static void checkEventType(String eventSetName,
227: Method listenerMethod) throws IntrospectionException {
228: Class<?>[] params = listenerMethod.getParameterTypes();
229: String firstParamTypeName = null;
230: String eventTypeName = prepareEventTypeName(eventSetName);
231:
232: if (params.length > 0) {
233: firstParamTypeName = extractShortClassName(params[0]
234: .getName());
235: }
236:
237: if (firstParamTypeName == null
238: || !firstParamTypeName.equals(eventTypeName)) {
239: throw new IntrospectionException(Messages.getString(
240: "beans.51", //$NON-NLS-1$
241: listenerMethod.getName(), eventTypeName));
242: }
243: }
244:
245: /**
246: * @param fullClassName full name of the class
247: * @return name with package and encapsulating class info omitted
248: */
249: private static String extractShortClassName(String fullClassName) {
250: int k = fullClassName.lastIndexOf('$');
251:
252: k = (k == -1 ? fullClassName.lastIndexOf('.') : k);
253: return fullClassName.substring(k + 1);
254: }
255:
256: private static String prepareEventTypeName(String eventSetName) {
257: StringBuilder sb = new StringBuilder();
258:
259: if (eventSetName != null && eventSetName.length() > 0) {
260: sb.append(Character.toUpperCase(eventSetName.charAt(0)));
261:
262: if (eventSetName.length() > 1) {
263: sb.append(eventSetName.substring(1));
264: }
265: }
266:
267: sb.append("Event"); //$NON-NLS-1$
268: return sb.toString();
269: }
270:
271: public Method[] getListenerMethods() {
272: int i = 0;
273:
274: if (listenerMethods != null) {
275: return listenerMethods;
276: }
277:
278: if (listenerMethodDescriptors != null) {
279: listenerMethods = new Method[listenerMethodDescriptors
280: .size()];
281: for (MethodDescriptor md : listenerMethodDescriptors) {
282: listenerMethods[i++] = md.getMethod();
283: }
284: return listenerMethods;
285: }
286:
287: return null;
288: }
289:
290: public MethodDescriptor[] getListenerMethodDescriptors() {
291: return listenerMethodDescriptors == null ? null
292: : listenerMethodDescriptors
293: .toArray(new MethodDescriptor[listenerMethodDescriptors
294: .size()]);
295: }
296:
297: public Method getRemoveListenerMethod() {
298: return removeListenerMethod;
299: }
300:
301: public Method getGetListenerMethod() {
302: return getListenerMethod;
303: }
304:
305: public Method getAddListenerMethod() {
306: return addListenerMethod;
307: }
308:
309: public Class<?> getListenerType() {
310: return listenerType;
311: }
312:
313: public void setUnicast(boolean unicast) {
314: this .unicast = unicast;
315: }
316:
317: public void setInDefaultEventSet(boolean inDefaultEventSet) {
318: this .inDefaultEventSet = inDefaultEventSet;
319: }
320:
321: public boolean isUnicast() {
322: return unicast;
323: }
324:
325: public boolean isInDefaultEventSet() {
326: return inDefaultEventSet;
327: }
328:
329: /**
330: * Searches for {add|remove}Listener methods in the event source. Parameter
331: * check is also performed.
332: *
333: * @param sourceClass
334: * event source class
335: * @param methodName
336: * method name to search
337: * @return found method
338: * @throws IntrospectionException
339: * if no valid method found
340: */
341: private Method findAddRemoveListenerMethod(Class<?> sourceClass,
342: String methodName) throws IntrospectionException {
343: try {
344: return sourceClass.getMethod(methodName, listenerType);
345: } catch (NoSuchMethodException e) {
346: return findAddRemoveListnerMethodWithLessCheck(sourceClass,
347: methodName);
348: } catch (Exception e) {
349: throw new IntrospectionException(Messages.getString(
350: "beans.31", //$NON-NLS-1$
351: methodName, listenerType.getName()));
352: }
353: }
354:
355: private Method findAddRemoveListnerMethodWithLessCheck(
356: Class<?> sourceClass, String methodName)
357: throws IntrospectionException {
358: String expectedListenerTypeName = listenerType.getName();
359: expectedListenerTypeName = expectedListenerTypeName
360: .substring(expectedListenerTypeName.lastIndexOf(".") + 1); //$NON-NLS-1$
361: Method method = null;
362: Method[] methods = sourceClass.getMethods();
363: for (Method m : methods) {
364: if (m.getName().equals(methodName)) {
365: Class[] paramTypes = m.getParameterTypes();
366: if (paramTypes.length == 1) {
367: method = m;
368: break;
369: }
370: }
371: }
372: if (null == method) {
373: throw new IntrospectionException(Messages.getString(
374: "beans.31", //$NON-NLS-1$
375: methodName, listenerType.getName()));
376: }
377: return method;
378: }
379:
380: /**
381: * @param sourceClass
382: * class of event source
383: * @param methodName
384: * name of the custom getListeners() method
385: * @return found Method object for custom getListener or null if nothing is
386: * found
387: */
388: private Method findGetListenerMethod(Class<?> sourceClass,
389: String methodName) {
390: try {
391: return sourceClass.getMethod(methodName);
392: } catch (Exception e) {
393: // RI keeps silence here and just returns null
394: return null;
395: }
396: }
397:
398: private Method findMethodByPrefix(Class<?> sourceClass,
399: String prefix, String postfix) {
400: String shortName = listenerType.getName();
401: if (listenerType.getPackage() != null) {
402: shortName = shortName.substring(listenerType.getPackage()
403: .getName().length() + 1);
404: }
405: String methodName = prefix + shortName + postfix;
406: try {
407: if (prefix.equals("get")) { //$NON-NLS-1$
408: return sourceClass.getMethod(methodName);
409: }
410: } catch (NoSuchMethodException nsme) {
411: return null;
412: }
413: Method[] m = sourceClass.getMethods();
414: for (int i = 0; i < m.length; i++) {
415: if (m[i].getName().equals(methodName)) {
416: Class[] paramTypes = m[i].getParameterTypes();
417: if (paramTypes.length == 1) {
418: return m[i];
419: }
420: }
421: }
422: return null;
423: }
424:
425: private static boolean isUnicastByDefault(Method addMethod) {
426: if (addMethod != null) {
427: Class<?>[] exceptionTypes = addMethod.getExceptionTypes();
428: for (Class<?> element : exceptionTypes) {
429: if (element.equals(TooManyListenersException.class)) {
430: return true;
431: }
432: }
433: }
434: return false;
435: }
436:
437: void merge(EventSetDescriptor event) {
438: super.merge(event);
439: if (addListenerMethod == null) {
440: addListenerMethod = event.addListenerMethod;
441: }
442: if (getListenerMethod == null) {
443: getListenerMethod = event.getListenerMethod;
444: }
445: if (listenerMethodDescriptors == null) {
446: listenerMethodDescriptors = event.listenerMethodDescriptors;
447: }
448: if (listenerMethods == null) {
449: listenerMethods = event.listenerMethods;
450: }
451: if (listenerType == null) {
452: listenerType = event.listenerType;
453: }
454:
455: if (removeListenerMethod == null) {
456: removeListenerMethod = event.removeListenerMethod;
457: }
458: inDefaultEventSet &= event.inDefaultEventSet;
459: }
460: }
|