001package net.gdface.codegen.thrift;
002
003import org.apache.commons.configuration2.Configuration;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007import com.facebook.swift.codec.metadata.PatternFilter;
008import com.google.common.base.Function;
009import com.google.common.base.Joiner;
010import com.google.common.base.Predicate;
011import com.google.common.collect.ImmutableMap;
012import com.google.common.collect.Maps;
013import com.google.common.collect.Sets;
014
015import net.gdface.annotation.DeriveMethod;
016
017import static com.google.common.base.Preconditions.*;
018import static net.gdface.utils.MiscellaneousUtils.*;
019
020import java.lang.reflect.Method;
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.List;
024import java.util.Map;
025import java.util.Map.Entry;
026import java.util.Set;
027
028/**
029 * 根据配置文件提供的过滤参数对接口中的方法进行过滤
030 * @author guyadong
031 *
032 */
033public class MethodFilter implements Predicate<Method>{
034        private static final Logger logger = LoggerFactory.getLogger(MethodFilter.class);
035        private static final String SUFFIX_INCLUDE =".include";
036        private static final String SUFFIX_EXCLUDE =".exclude";
037
038        private final Configuration configuration = ThriftServiceDecoratorConfiguration.INSTANCE.getConfig();
039        private Set<Method> includeMethods;
040        private Set<Method> excludeMethods;
041        public MethodFilter(Class<?> interfaceClass) {
042                checkArgument(interfaceClass != null,"interfaceClass is null");
043                ImmutableMap<String, Method> methods = Maps.uniqueIndex(Arrays.asList(interfaceClass.getDeclaredMethods()), new Function<Method, String>() {
044
045                        @Override
046                        public String apply(Method input) {
047                                StringBuffer buffer = new StringBuffer(input.getName());
048                                DeriveMethod dm = input.getAnnotation(DeriveMethod.class);
049                                if(dm != null && dm.methodSuffix().length > 0){
050                                        buffer.append('.').append(dm.methodSuffix()[0]);
051                                }
052                                return buffer.toString();
053                        }
054                });
055                String includeKey = interfaceClass.getName() + SUFFIX_INCLUDE;
056                String excludeKey = interfaceClass.getName() + SUFFIX_EXCLUDE;
057                includeMethods = getMethodList(includeKey,interfaceClass,methods,false);
058                excludeMethods = getMethodList(excludeKey,interfaceClass,methods,true);
059                if(excludeMethods.isEmpty()){
060                        excludeMethods = getExcludeMethodList(interfaceClass,methods);
061                }
062                if(includeMethods.isEmpty()){
063                        includeMethods = getIncludeMethodList(interfaceClass,methods);
064                }
065                if(!includeMethods.isEmpty() && !excludeMethods.isEmpty()){
066                        logger.warn("{} and {} all defined, this first used preferentially",includeKey,excludeKey);
067                }
068        }
069        private List<Method> findMethod(String pattern,Map<String, Method> methods,boolean startsWithAsTrue){
070                List<Method> found = new ArrayList<>();         
071                for(Entry<String, Method> entry:methods.entrySet()){
072                        String key = entry.getKey();
073                        String port = key;
074                        if(key.indexOf(".") >= 0){
075                                port=Joiner.on("").join(key.split("\\."));
076                        }
077                        if(PatternFilter.filter(pattern, port,startsWithAsTrue)){
078                                found.add(entry.getValue());
079                        }
080                }
081                return found;
082        }
083        private Set<Method> getMethodList(String key,Class<?> interfaceClass,Map<String, Method> methods,boolean startsWithAsTrue){
084                Set<Method> sets = Sets.newHashSet();
085                if(configuration.containsKey(key)){
086                        for(String name:elementsOf(configuration.getString(key))){
087                                List<Method> found = findMethod(name,methods,startsWithAsTrue);
088                                if(found.isEmpty()){
089                                        logger.warn("NOT FOUND Method named '{}' in {}",name,interfaceClass.getName());                         
090                                        continue;
091                                }                       
092                                sets.addAll(found);
093                        }
094                }
095                return sets;
096        }
097        private Set<Method> getExcludeMethodList(Class<?> interfaceClass,Map<String, Method> methods){
098                Set<Method> sets = Sets.newHashSet();
099                List<String> names = ThriftServiceDecoratorConfiguration.INSTANCE.getExcludeMethods().get(interfaceClass);
100                if(names != null){
101                        for(String name:names){
102                                List<Method> found = findMethod(name,methods,true);
103                                if(found.isEmpty()){
104                                        logger.warn("NOT FOUND Method named '{}' in {}",name,interfaceClass.getName());                         
105                                        continue;
106                                }                       
107                                sets.addAll(found);
108                        }
109                }
110                return sets;
111        }
112        private Set<Method> getIncludeMethodList(Class<?> interfaceClass,Map<String, Method> methods){
113                Set<Method> sets = Sets.newHashSet();
114                List<String> names = ThriftServiceDecoratorConfiguration.INSTANCE.getIncludeMethods().get(interfaceClass);
115                if(names != null){
116                        for(String name:names){
117                                List<Method> found = findMethod(name,methods,false);
118                                if(found.isEmpty()){
119                                        logger.warn("NOT FOUND Method named '{}' in {}",name,interfaceClass.getName());                         
120                                        continue;
121                                }                       
122                                sets.addAll(found);
123                        }
124                }
125                return sets;
126        }
127        @Override
128        public boolean apply(Method input) {
129                if(!includeMethods.isEmpty()){
130                        return includeMethods.contains(input);
131                }
132                if(!excludeMethods.isEmpty()){
133                        return !excludeMethods.contains(input);
134                }
135                return true;
136        }
137        
138        
139}