@Override public <F> F createFilterProxy(Object targetFilter, ClassLoader loader, Class<?>... interfaces) { for (Class<?> i : interfaces) { if (!i.isInstance(targetFilter)) { return (F) Proxy.newProxyInstance(loader, interfaces, new FilterProxy(targetFilter, getFilterDescriptor(interfaces))); } } return (F) targetFilter; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { invoke(this.targetFilter, this.descriptor, method, args); } catch (InvocationTargetException e) { throw e.getCause(); } return null; }
@Override public <F> F createCompositeFilter(Object... filters) { return createCompositeFilter(Thread.currentThread().getContextClassLoader(), filters); }
/** * @param type the class of the filter * @return the descriptor of the filter * @throws IncompatibleFilterException when several methods/events are incompatibles */ private FilterDescriptor createDescriptor(Class<?> type) throws IncompatibleFilterException { // Proxy "loose" various reflection informations (like method parameter names) if (Proxy.isProxyClass(type)) { return getFilterDescriptor(type.getInterfaces()); } else { FilterDescriptor descriptor = new FilterDescriptor(); for (Method method : type.getMethods()) { // Get top most method declaration Set<Method> hierarchy = MethodUtils.getOverrideHierarchy(method, Interfaces.INCLUDE); Method topMethod = IterableUtils.get(hierarchy, hierarchy.size() - 1); // Get element name from method String elementName = getElementName(topMethod); // If a name can be found, continue if (elementName != null) { addElement(elementName, descriptor, topMethod); } } return descriptor; } }
/** * @param elementName the name of the element * @param descriptor the descriptor in which to add the element * @param method the method associated to the element * @throws IncompatibleFilterException when passed method is not compatible with matching filter(s) */ private void addElement(String elementName, FilterDescriptor descriptor, Method method) throws IncompatibleFilterException { String lowerElementName = elementName.toLowerCase(); FilterElementDescriptor element = descriptor.getElements().get(lowerElementName); Type[] methodTypes = method.getGenericParameterTypes(); if (element == null || methodTypes.length > element.getParameters().length) { FilterElementParameterDescriptor<?>[] parameters = new FilterElementParameterDescriptor<?>[methodTypes.length]; for (int i = 0; i < methodTypes.length; ++i) { parameters[i] = createFilterElementParameter(method, i, methodTypes[i]); } // Make sure those parameters are compatible with any other matching element if (element != null) { checkCompatible(element, parameters); } element = new FilterElementDescriptor(elementName, parameters); descriptor.getElements().put(lowerElementName, element); } addMethod(element, method); }
/** * @param method the method * @return the corresponding element name */ public static String getElementName(Method method) { Name name = method.getAnnotation(Name.class); if (name != null) { return name.value(); } return getElementName(method.getName()); }
/** * Call passed begin event if possible. * * @param filter the filter * @param descriptor the descriptor of the filter * @param id the id of the event * @param parameters the parameters of the event * @return true if the event has been sent, false otherwise * @throws FilterException when the passed filter exposes the event but failed anyway */ public static boolean sendBeginEvent(Object filter, FilterDescriptor descriptor, String id, FilterEventParameters parameters) throws FilterException { FilterElementDescriptor elementDescriptor = descriptor.getElement(id); if (elementDescriptor != null && elementDescriptor.getBeginMethod() != null) { sendEvent(elementDescriptor.getBeginMethod(), elementDescriptor, filter, parameters); } else if (filter instanceof UnknownFilter) { ((UnknownFilter) filter).beginUnknwon(id, parameters); } else { return false; } return true; }
@Override public <F> F createFilterProxy(Object targetFilter, Class<?>... interfaces) { return createFilterProxy(targetFilter, Thread.currentThread().getContextClassLoader(), interfaces); }
/** * @param filter the filter to send event to * @param descriptor the descriptor of the filter * @param method the event method called * @param args the arguments of the called method * @exception IllegalAccessException if this <code>Method</code> object enforces Java language access control and * the underlying method is inaccessible. * @exception IllegalArgumentException if the method is an instance method and the specified object argument is not * an instance of the class or interface declaring the underlying method (or of a subclass or * implementor thereof); if the number of actual and formal parameters differ; if an unwrapping * conversion for primitive arguments fails; or if, after possible unwrapping, a parameter value * cannot be converted to the corresponding formal parameter type by a method invocation conversion. * @exception InvocationTargetException if the underlying method throws an exception. * @throws FilterException if the execution of the event failed */ public static void invoke(Object filter, FilterDescriptor descriptor, Method method, Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, FilterException { if (method.getDeclaringClass().isInstance(filter)) { method.invoke(filter, args); } else if (filter instanceof UnknownFilter) { invokeUnkown(filter, descriptor, method, args); } }
/** * @param filters the filters * @param filterManager the filter descriptor manager used to generate passed filter descriptors */ public CompositeFilter(FilterDescriptorManager filterManager, Object... filters) { this.filterManager = filterManager; this.filters = new ArrayList<SubFilter>(filters.length); for (Object filter : filters) { this.filters.add(new SubFilter(filter, this.filterManager.getFilterDescriptor(filter.getClass()))); } }
@Override public <F> F createCompositeFilter(ClassLoader loader, Object... filters) { Set<Class<?>> interfaces = new HashSet<Class<?>>(); for (Object filter : filters) { interfaces.addAll(ClassUtils.getAllInterfaces(filter.getClass())); } return (F) Proxy.newProxyInstance(loader, interfaces.toArray(CLASS_ARRAY), new CompositeFilter(this, filters)); } }
@Override public FilterDescriptor getFilterDescriptor(Class<?>... interfaces) { FilterDescriptor totalDescriptor = null; for (Class<?> i : interfaces) { FilterDescriptor descriptor = this.descriptors.get(i); if (descriptor == null) { try { descriptor = createDescriptor(i); } catch (IncompatibleFilterException e) { this.logger.error("Failed to create descriptor for filter [{}]", i, e); continue; } this.descriptors.put(i, descriptor); } if (totalDescriptor == null) { totalDescriptor = descriptor; } else { totalDescriptor.add(descriptor); } } return totalDescriptor; }
/** * @param method the method * @param searchTopMethod search for top most overridden method * @return the corresponding element name */ public static String getElementName(Method method, boolean searchTopMethod) { Method topMethod = method; if (searchTopMethod) { // Get top most method declaration Set<Method> hierarchy = MethodUtils.getOverrideHierarchy(method, Interfaces.INCLUDE); topMethod = IterableUtils.get(hierarchy, hierarchy.size() - 1); } // Get element name from method return getElementName(topMethod); }
/** * Call passed end event if possible. * * @param filter the filter * @param descriptor the descriptor of the filter * @param id the id of the event * @param parameters the parameters of the event * @return true if the event has been sent, false otherwise * @throws FilterException when the passed filter exposes the event but failed anyway */ public static boolean sendEndEvent(Object filter, FilterDescriptor descriptor, String id, FilterEventParameters parameters) throws FilterException { FilterElementDescriptor elementDescriptor = descriptor.getElement(id); if (elementDescriptor != null && elementDescriptor.getEndMethod() != null) { sendEvent(elementDescriptor.getEndMethod(), elementDescriptor, filter, parameters); } else if (filter instanceof UnknownFilter) { ((UnknownFilter) filter).endUnknwon(id, parameters); } else { return false; } return true; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { for (SubFilter filter : this.filters) { try { FilterProxy.invoke(filter.filter, filter.descriptor, method, args); } catch (InvocationTargetException e) { throw e.getCause(); } } return null; } }
private static void invokeUnkown(Object filter, FilterDescriptor descriptor, Method method, Object[] args) throws FilterException { String id = DefaultFilterDescriptorManager.getElementName(method); if (id != null) { FilterElementDescriptor element = descriptor.getElement(id); if (element != null) { FilterEventParameters metadata = new FilterEventParameters(); for (FilterElementParameterDescriptor<?> parameter : element.getParameters()) { metadata.put( parameter.getName() != null ? parameter.getName() : String.valueOf(parameter.getIndex()), args[parameter.getIndex()]); } UnknownFilter unknownFilter = (UnknownFilter) filter; if (method.getName().startsWith(DefaultFilterDescriptorManager.PREFIX_BEGIN)) { unknownFilter.beginUnknwon(id, metadata); } else if (method.getName().startsWith(DefaultFilterDescriptorManager.PREFIX_END)) { unknownFilter.endUnknwon(id, metadata); } else if (method.getName().startsWith(DefaultFilterDescriptorManager.PREFIX_ON)) { unknownFilter.onUnknwon(id, metadata); } } } } }
/** * Call passed on event if possible. * * @param filter the filter * @param descriptor the descriptor of the filter * @param id the id of the event * @param parameters the parameters of the event * @return true if the event has been sent, false otherwise * @throws FilterException when the passed filter exposes the event but failed anyway */ public static boolean sendOnEvent(Object filter, FilterDescriptor descriptor, String id, FilterEventParameters parameters) throws FilterException { FilterElementDescriptor elementDescriptor = descriptor.getElement(id); if (elementDescriptor != null && elementDescriptor.getOnMethod() != null) { sendEvent(elementDescriptor.getOnMethod(), elementDescriptor, filter, parameters); } else if (filter instanceof UnknownFilter) { ((UnknownFilter) filter).onUnknwon(id, parameters); } else { return false; } return true; } }