Mercurial > hg > Members > sugi > MessagePack-java
diff src/main/java/org/msgpack/template/builder/beans/EventSetDescriptor.java @ 0:cb825acd883a
first commit
author | sugi |
---|---|
date | Sat, 18 Oct 2014 15:06:15 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/msgpack/template/builder/beans/EventSetDescriptor.java Sat Oct 18 15:06:15 2014 +0900 @@ -0,0 +1,432 @@ +// MODIFIED FOR THE MSGPACK PROJECT +// 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.msgpack.template.builder.beans; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.TooManyListenersException; +import org.apache.harmony.beans.internal.nls.Messages; + +public class EventSetDescriptor extends FeatureDescriptor { + private Class<?> listenerType; + + private ArrayList<MethodDescriptor> listenerMethodDescriptors; + + private Method[] listenerMethods; + + private Method getListenerMethod; + + private Method addListenerMethod; + + private Method removeListenerMethod; + + private boolean unicast; + + private boolean inDefaultEventSet = true; + + public EventSetDescriptor(Class<?> sourceClass, String eventSetName, + Class<?> listenerType, String listenerMethodName) + throws IntrospectionException { + checkNotNull(sourceClass, eventSetName, listenerType, + listenerMethodName); + setName(eventSetName); + this.listenerType = listenerType; + + Method method = findListenerMethodByName(listenerMethodName); + checkEventType(eventSetName, method); + listenerMethodDescriptors = new ArrayList<MethodDescriptor>(); + listenerMethodDescriptors.add(new MethodDescriptor(method)); + addListenerMethod = findMethodByPrefix(sourceClass, "add", ""); //$NON-NLS-1$ //$NON-NLS-2$ + removeListenerMethod = findMethodByPrefix(sourceClass, "remove", ""); //$NON-NLS-1$ //$NON-NLS-2$ + + if (addListenerMethod == null || removeListenerMethod == null) { + throw new IntrospectionException(Messages.getString("custom.beans.38")); //$NON-NLS-1$ + } + + getListenerMethod = findMethodByPrefix(sourceClass, "get", "s"); //$NON-NLS-1$ //$NON-NLS-2$ + unicast = isUnicastByDefault(addListenerMethod); + } + + public EventSetDescriptor(Class<?> sourceClass, String eventSetName, + Class<?> listenerType, String[] listenerMethodNames, + String addListenerMethodName, String removeListenerMethodName) + throws IntrospectionException { + this(sourceClass, eventSetName, listenerType, listenerMethodNames, + addListenerMethodName, removeListenerMethodName, null); + + } + + public EventSetDescriptor(Class<?> sourceClass, String eventSetName, + Class<?> listenerType, String[] listenerMethodNames, + String addListenerMethodName, String removeListenerMethodName, + String getListenerMethodName) throws IntrospectionException { + + checkNotNull(sourceClass, eventSetName, listenerType, + listenerMethodNames); + + setName(eventSetName); + this.listenerType = listenerType; + + listenerMethodDescriptors = new ArrayList<MethodDescriptor>(); + for (String element : listenerMethodNames) { + Method m = findListenerMethodByName(element); + + // checkEventType(eventSetName, m); + listenerMethodDescriptors.add(new MethodDescriptor(m)); + } + + if (addListenerMethodName != null) { + this.addListenerMethod = findAddRemoveListenerMethod(sourceClass, + addListenerMethodName); + } + if (removeListenerMethodName != null) { + this.removeListenerMethod = findAddRemoveListenerMethod( + sourceClass, removeListenerMethodName); + } + if (getListenerMethodName != null) { + this.getListenerMethod = findGetListenerMethod(sourceClass, + getListenerMethodName); + } + this.unicast = isUnicastByDefault(addListenerMethod); + } + + private Method findListenerMethodByName(String listenerMethodName) + throws IntrospectionException { + Method result = null; + Method[] methods = listenerType.getMethods(); + for (Method method : methods) { + if (listenerMethodName.equals(method.getName())) { + Class<?>[] paramTypes = method.getParameterTypes(); + if (paramTypes.length == 1 + && paramTypes[0].getName().endsWith("Event")) { //$NON-NLS-1$ + result = method; + break; + } + + } + } + if (null == result) { + throw new IntrospectionException(Messages.getString("custom.beans.31", //$NON-NLS-1$ + listenerMethodName, listenerType.getName())); + } + return result; + } + + public EventSetDescriptor(String eventSetName, Class<?> listenerType, + Method[] listenerMethods, Method addListenerMethod, + Method removeListenerMethod) throws IntrospectionException { + + this(eventSetName, listenerType, listenerMethods, addListenerMethod, + removeListenerMethod, null); + } + + public EventSetDescriptor(String eventSetName, Class<?> listenerType, + Method[] listenerMethods, Method addListenerMethod, + Method removeListenerMethod, Method getListenerMethod) + throws IntrospectionException { + + setName(eventSetName); + this.listenerType = listenerType; + + this.listenerMethods = listenerMethods; + if (listenerMethods != null) { + listenerMethodDescriptors = new ArrayList<MethodDescriptor>(); + + for (Method element : listenerMethods) { + // XXX do we need this check? + // checkEventType(eventSetName, element); + // if (checkMethod(listenerType, element)) { + this.listenerMethodDescriptors + .add(new MethodDescriptor(element)); + // } + } + } + + this.addListenerMethod = addListenerMethod; + this.removeListenerMethod = removeListenerMethod; + this.getListenerMethod = getListenerMethod; + this.unicast = isUnicastByDefault(addListenerMethod); + } + + public EventSetDescriptor(String eventSetName, Class<?> listenerType, + MethodDescriptor[] listenerMethodDescriptors, + Method addListenerMethod, Method removeListenerMethod) + throws IntrospectionException { + + this(eventSetName, listenerType, null, addListenerMethod, + removeListenerMethod, null); + + if (listenerMethodDescriptors != null) { + this.listenerMethodDescriptors = new ArrayList<MethodDescriptor>(); + + for (MethodDescriptor element : listenerMethodDescriptors) { + this.listenerMethodDescriptors.add(element); + } + } + } + + // ensures that there is no nulls + @SuppressWarnings("nls") + private void checkNotNull(Object sourceClass, Object eventSetName, + Object alistenerType, Object listenerMethodName) { + if (sourceClass == null) { + throw new NullPointerException(Messages.getString("custom.beans.0C")); + } + if (eventSetName == null) { + throw new NullPointerException(Messages.getString("custom.beans.53")); + } + if (alistenerType == null) { + throw new NullPointerException(Messages.getString("custom.beans.54")); + } + if (listenerMethodName == null) { + throw new NullPointerException(Messages.getString("custom.beans.52")); + } + } + + /** + * Checks that given listener method has an argument of the valid type. + * + * @param eventSetName + * event set name + * @param listenerMethod + * listener method + * @throws IntrospectionException + * if check fails + */ + private static void checkEventType(String eventSetName, + Method listenerMethod) throws IntrospectionException { + Class<?>[] params = listenerMethod.getParameterTypes(); + String firstParamTypeName = null; + String eventTypeName = prepareEventTypeName(eventSetName); + + if (params.length > 0) { + firstParamTypeName = extractShortClassName(params[0] + .getName()); + } + + if (firstParamTypeName == null + || !firstParamTypeName.equals(eventTypeName)) { + throw new IntrospectionException(Messages.getString("custom.beans.51", //$NON-NLS-1$ + listenerMethod.getName(), eventTypeName)); + } + } + + /** + * @param fullClassName full name of the class + * @return name with package and encapsulating class info omitted + */ + private static String extractShortClassName(String fullClassName) { + int k = fullClassName.lastIndexOf('$'); + k = (k == -1 ? fullClassName.lastIndexOf('.') : k); + return fullClassName.substring(k + 1); + } + + private static String prepareEventTypeName(String eventSetName) { + StringBuilder sb = new StringBuilder(); + + if (eventSetName != null && eventSetName.length() > 0) { + sb.append(Character.toUpperCase(eventSetName.charAt(0))); + + if (eventSetName.length() > 1) { + sb.append(eventSetName.substring(1)); + } + } + + sb.append("Event"); //$NON-NLS-1$ + return sb.toString(); + } + + public Method[] getListenerMethods() { + if (listenerMethods != null) { + return listenerMethods; + } + + if (listenerMethodDescriptors != null) { + listenerMethods = new Method[listenerMethodDescriptors.size()]; + int index = 0; + for (MethodDescriptor md : listenerMethodDescriptors) { + listenerMethods[index++] = md.getMethod(); + } + return listenerMethods; + } + return null; + } + + public MethodDescriptor[] getListenerMethodDescriptors() { + return listenerMethodDescriptors == null ? null + : listenerMethodDescriptors.toArray(new MethodDescriptor[0]); + } + + public Method getRemoveListenerMethod() { + return removeListenerMethod; + } + + public Method getGetListenerMethod() { + return getListenerMethod; + } + + public Method getAddListenerMethod() { + return addListenerMethod; + } + + public Class<?> getListenerType() { + return listenerType; + } + + public void setUnicast(boolean unicast) { + this.unicast = unicast; + } + + public void setInDefaultEventSet(boolean inDefaultEventSet) { + this.inDefaultEventSet = inDefaultEventSet; + } + + public boolean isUnicast() { + return unicast; + } + + public boolean isInDefaultEventSet() { + return inDefaultEventSet; + } + + /** + * Searches for {add|remove}Listener methods in the event source. Parameter + * check is also performed. + * + * @param sourceClass + * event source class + * @param methodName + * method name to search + * @return found method + * @throws IntrospectionException + * if no valid method found + */ + private Method findAddRemoveListenerMethod(Class<?> sourceClass, + String methodName) throws IntrospectionException { + try { + return sourceClass.getMethod(methodName, listenerType); + } catch (NoSuchMethodException e) { + return findAddRemoveListnerMethodWithLessCheck(sourceClass, + methodName); + } catch (Exception e) { + throw new IntrospectionException(Messages.getString("custom.beans.31", //$NON-NLS-1$ + methodName, listenerType.getName())); + } + } + + private Method findAddRemoveListnerMethodWithLessCheck( + Class<?> sourceClass, String methodName) + throws IntrospectionException { + Method[] methods = sourceClass.getMethods(); + Method result = null; + for (Method method : methods) { + if (method.getName().equals(methodName)) { + Class<?>[] paramTypes = method.getParameterTypes(); + if (paramTypes.length == 1) { + result = method; + break; + } + } + } + if (null == result) { + throw new IntrospectionException(Messages.getString("custom.beans.31", //$NON-NLS-1$ + methodName, listenerType.getName())); + } + return result; + } + + /** + * @param sourceClass + * class of event source + * @param methodName + * name of the custom getListeners() method + * @return found Method object for custom getListener or null if nothing is + * found + */ + private Method findGetListenerMethod(Class<?> sourceClass, String methodName) { + try { + return sourceClass.getMethod(methodName); + } catch (Exception e) { + // RI keeps silence here and just returns null + return null; + } + } + + private Method findMethodByPrefix(Class<?> sourceClass, String prefix, + String postfix) { + String shortName = listenerType.getName(); + if (listenerType.getPackage() != null) { + shortName = shortName.substring(listenerType.getPackage().getName() + .length() + 1); + } + String methodName = prefix + shortName + postfix; + try { + if ("get".equals(prefix)) { //$NON-NLS-1$ + return sourceClass.getMethod(methodName); + } + } catch (NoSuchMethodException nsme) { + return null; + } + Method[] methods = sourceClass.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(methodName)) { + Class<?>[] paramTypes = methods[i].getParameterTypes(); + if (paramTypes.length == 1) { + return methods[i]; + } + } + } + return null; + } + + private static boolean isUnicastByDefault(Method addMethod) { + if (addMethod != null) { + Class<?>[] exceptionTypes = addMethod.getExceptionTypes(); + for (Class<?> element : exceptionTypes) { + if (element.equals(TooManyListenersException.class)) { + return true; + } + } + } + return false; + } + + void merge(EventSetDescriptor event) { + super.merge(event); + if (addListenerMethod == null) { + addListenerMethod = event.addListenerMethod; + } + if (getListenerMethod == null) { + getListenerMethod = event.getListenerMethod; + } + if (listenerMethodDescriptors == null) { + listenerMethodDescriptors = event.listenerMethodDescriptors; + } + if (listenerMethods == null) { + listenerMethods = event.listenerMethods; + } + if (listenerType == null) { + listenerType = event.listenerType; + } + + if (removeListenerMethod == null) { + removeListenerMethod = event.removeListenerMethod; + } + inDefaultEventSet &= event.inDefaultEventSet; + } +}