/* * JBoss, Home of Professional Open Source. * Copyright 2013, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.capedwarf.aspects.proxy; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.jboss.capedwarf.aspects.Aspect; import org.jboss.capedwarf.aspects.AspectAdapter; import org.jboss.capedwarf.aspects.DisableSocketsAspect; import org.jboss.capedwarf.aspects.GlobalTimeLimitAspect; import org.jboss.capedwarf.aspects.InvocationTimeLimitAspect; import org.jboss.capedwarf.shared.reflection.ReflectionUtils; /** * @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a> */ public final class AspectRegistry { private static final AspectWrapperComparator COMPARATOR = new AspectWrapperComparator(); private static final Map<Key, AspectWrapper[]> aspectsMap = new ConcurrentHashMap<Key, AspectWrapper[]>(); private static final Set<AspectWrapper> defaultAspects = new HashSet<AspectWrapper>(); private static final Map<Class<? extends Annotation>, Aspect> aspectsPerAnnotation = new HashMap<Class<? extends Annotation>, Aspect>(); static { // default aspects addDefaultAspect(new GlobalTimeLimitAspect()); addDefaultAspect(new DisableSocketsAspect()); // per annotation aspects addAspect(new InvocationTimeLimitAspect()); } public static <T extends Annotation> void addDefaultAspect(Aspect<T> aspect) { defaultAspects.add(new AspectWrapper(aspect)); } public static <T extends Annotation> void addAspect(Aspect<T> aspect) { aspectsPerAnnotation.put(aspect.annotation(), aspect); } static AspectWrapper[] findAspects(AspectInfo info) { final Key key = new Key(info.getApiInterface(), info.getMethod()); AspectWrapper[] aspects = aspectsMap.get(key); if (aspects == null) { aspects = buildAspects(info); aspectsMap.put(key, aspects); } return aspects; } private static AspectWrapper[] buildAspects(AspectInfo info) { final Set<AspectWrapper> aspects = new HashSet<AspectWrapper>(); aspects.addAll(defaultAspects); Method interfaceMethod = info.getMethod(); Class<?> clazz = info.getApiImpl().getClass(); Method method = ReflectionUtils.getMethod(clazz, interfaceMethod); Annotation[] annotations = method.getAnnotations(); aspects.addAll(buildAspects(annotations)); annotations = clazz.getAnnotations(); aspects.addAll(buildAspects(annotations)); List<AspectWrapper> list = new ArrayList<AspectWrapper>(aspects); Collections.sort(list, COMPARATOR); return list.toArray(new AspectWrapper[list.size()]); } private static Collection<? extends AspectWrapper> buildAspects(Annotation... annotations) { Set<AspectWrapper> aspects = new HashSet<AspectWrapper>(); for (Annotation annotation : annotations) { Aspect aspect = aspectsPerAnnotation.get(annotation.annotationType()); if (aspect != null) { if (aspect instanceof AspectAdapter) { //noinspection unchecked aspect = AspectAdapter.class.cast(aspect).adapt(annotation); } aspects.add(new AspectWrapper(aspect, annotation)); } } return aspects; } private static class Key { private Class<?> apiInterface; private String methodName; private Class<?>[]parameterTypes; private Class<?> returnType; private Key(Class<?> apiInterface, Method method) { this.apiInterface = apiInterface; this.methodName = method.getName(); this.parameterTypes = method.getParameterTypes(); this.returnType = method.getReturnType(); } public int hashCode() { int hash = 0; hash += apiInterface.hashCode(); hash += 3 * methodName.hashCode(); hash += 7 * Arrays.hashCode(parameterTypes); hash += 11 * returnType.hashCode(); return hash; } @SuppressWarnings("RedundantIfStatement") public boolean equals(Object obj) { if (obj instanceof Key == false) return false; Key other = (Key) obj; if (apiInterface.equals(other.apiInterface) == false) return false; if (methodName.equals(other.methodName) == false) return false; if (Arrays.equals(parameterTypes, other.parameterTypes) == false) return false; if (returnType.equals(other.returnType) == false) return false; return true; } } private static class AspectWrapperComparator implements Comparator<AspectWrapper> { public int compare(AspectWrapper a1, AspectWrapper a2) { return a1.priority() - a2.priority(); } } }