001package net.gdface.codegen.thrift;
002
003import java.lang.reflect.Method;
004import java.lang.reflect.ParameterizedType;
005import java.lang.reflect.Type;
006import java.util.ArrayDeque;
007import java.util.ArrayList;
008import java.util.Collection;
009import java.util.Deque;
010import java.util.List;
011import java.util.Map;
012import java.util.Map.Entry;
013import java.util.Set;
014import static com.google.common.base.Preconditions.*;
015
016import com.google.common.base.Optional;
017import com.google.common.base.Predicate;
018import com.google.common.collect.Iterables;
019import com.google.common.collect.LinkedListMultimap;
020import com.google.common.collect.ListMultimap;
021import com.google.common.collect.Lists;
022import com.google.common.collect.Ordering;
023import com.google.common.collect.Sets;
024import com.google.common.reflect.TypeToken;
025
026import net.gdface.thrift.ThriftUtils;
027import net.gdface.thrift.TypeTransformer;
028import net.gdface.thrift.exception.ServiceRuntimeException;
029import net.gdface.utils.BeanRelativeUtilits;
030import net.gdface.utils.NameStringUtils;
031
032/**
033 * @author guyadong
034 *
035 */
036public class ThriftSchema implements ThriftConstants {
037        private final Set<ThriftStructDecorator> thriftStructDecorators = Sets.newLinkedHashSet();
038        private final List<ThriftServiceDecorator<?>> thriftServiceDecorators = Lists.newLinkedList();
039        private final Predicate<ThriftStructDecorator> exceptionFilter = new Predicate<ThriftStructDecorator>(){
040                @Override
041                public boolean apply(ThriftStructDecorator input) {
042                        return input.isException();
043                }};
044        private final Predicate<ThriftStructDecorator> enumFilter = new Predicate<ThriftStructDecorator>(){
045                @Override
046                public boolean apply(ThriftStructDecorator input) {
047                        return input.isEnum();
048                }};
049        private final Predicate<ThriftStructDecorator> beanFilter = new Predicate<ThriftStructDecorator>(){
050                @Override
051                public boolean apply(ThriftStructDecorator input) {
052                        return input.isBean();
053                }};
054        private final Predicate<ThriftStructDecorator> findString = new Predicate<ThriftStructDecorator>(){
055                @Override
056                public boolean apply(ThriftStructDecorator input) {
057                        return null!=input && input.isUseString();
058                }};
059        private final Predicate<ThriftStructDecorator> findMap = new Predicate<ThriftStructDecorator>(){
060                @Override
061                public boolean apply(ThriftStructDecorator input) {
062                        return null!=input && input.isUseMap();
063                }};
064        private final Predicate<ThriftStructDecorator> findSet = new Predicate<ThriftStructDecorator>(){
065                @Override
066                public boolean apply(ThriftStructDecorator input) {
067                        return null!=input && input.isUseSet();
068                }};
069        private final Predicate<ThriftStructDecorator> findVector = new Predicate<ThriftStructDecorator>(){
070                @Override
071                public boolean apply(ThriftStructDecorator input) {
072                        return null!=input && input.isUseVector();
073                }};
074        private final Predicate<ThriftStructDecorator> findException = new Predicate<ThriftStructDecorator>(){
075                @Override
076                public boolean apply(ThriftStructDecorator input) {
077                        return null!=input && input.isException();
078                }};
079        @SuppressWarnings({ "rawtypes", "unchecked" })
080        public ThriftSchema(Map<Class<?>, Class<?>> interfaceClasses) {
081                for(Entry<Class<?>, Class<?>> entry:interfaceClasses.entrySet()){
082                        Class<?> interfaceClass = entry.getKey();
083                        Class<?> refClass = entry.getValue();
084                        if(refClass == ThriftServiceDecoratorConfiguration.DEF_REF_CLASS){
085                                refClass = null;
086                        }
087                        ThriftServiceDecorator service = new ThriftServiceDecorator(interfaceClass,refClass);
088                        thriftServiceDecorators.add(service);
089                }
090                if(!compile()){
091                        throw new IllegalStateException("compile fail");
092                }
093        }
094        public List<ThriftStructDecorator> getAllStructDecorators() {
095                return Lists.newArrayList(thriftStructDecorators);
096        }
097        public List<ThriftStructDecorator> getExceptionDecorators(){
098                return Lists.newArrayList(Sets.filter(thriftStructDecorators, exceptionFilter));
099        }
100        public List<ThriftStructDecorator> getEnumDecorators(){
101                return Lists.newArrayList(Sets.filter(thriftStructDecorators, enumFilter));
102        }
103        public List<ThriftStructDecorator> getBeanDecorators(){
104                return Lists.newArrayList(Sets.filter(thriftStructDecorators, beanFilter));
105        }
106        public List<ThriftServiceDecorator<?>> getThriftServiceDecorators() {
107                return thriftServiceDecorators;
108        }
109        private boolean compile(){
110                for(ThriftServiceDecorator<?> newSourceInfo:getThriftServiceDecorators()){
111                        if (!newSourceInfo.compile()){
112                                return false;
113                        }
114                        thriftStructDecorators.addAll(newSourceInfo.getDecorateTypes());
115                }
116                for(ThriftStructDecorator newSourceInfo:getAllStructDecorators()){
117                        if (!newSourceInfo.compile()){
118                                return false;
119                        }
120                        thriftStructDecorators.addAll(newSourceInfo.getDecorateTypes());
121                }
122                return true;
123        }
124        public boolean isThriftBuildinType(Type type){          
125                return ThriftUtils.isThriftBuildinType(type);
126        }
127        public boolean isCastType(Type type){
128                return  ThriftUtils.isCastType(type);
129        }
130        public boolean isDecoratorType(final Type type) {
131                return getDecoratorType(type) != null;
132        }
133        public ThriftStructDecorator getDecoratorType(final Type type) {
134                Optional<ThriftStructDecorator> result = Iterables.tryFind(thriftStructDecorators, new Predicate<ThriftStructDecorator>(){
135
136                        @Override
137                        public boolean apply(ThriftStructDecorator input) {
138                                return input.getBaseClass().equals(type);
139                        }});
140                return result.isPresent() ? result.get() : null;
141        }
142        public boolean isThriftStruct(Type type){
143                return ThriftUtils.isThriftStruct(type);
144        }
145        public boolean isPrimitivefloat(Type type){
146                return ThriftUtils.isPrimitivefloat(type);
147        }
148        public boolean isfloat(Type type){
149                return ThriftUtils.isfloat(type);
150        }
151        public boolean isPrimitiveArray(Type type){
152                return ThriftUtils.isPrimitiveArray(type);
153        }
154        public boolean isMap(Type type){
155                return TypeToken.of(type).getRawType() == Map.class;
156        }
157        public boolean isList(Type type){
158                return TypeToken.of(type).getRawType() == List.class;
159        }
160        public boolean isSet(Type type){
161                return TypeToken.of(type).getRawType() == Set.class;
162        }
163        public boolean isCollection(Type type){
164                return isList(type) || isSet(type);
165        }
166        public boolean isArray(Type type){
167                return isList(type) || isSet(type);
168        }
169        public boolean isBinary(Type type){
170                return type == byte[].class;
171        }
172        public final Type wrap(Type type){
173                return TypeToken.of(type).wrap().getType();
174        }
175        /**
176         * 对thrift IDL 关键字(binary,list,map,set,i32...)转义,以确保生成的IDL文件中成员名和参数名与thrift关键字不冲突
177         * @param name
178         * @return
179         */
180        public String escapeThrift(String name){
181                return NameStringUtils.isThriftReserved(name)? name + "_" : name;
182        }
183        /**
184         * 字段名转义,避免java,thrift关键字冲突
185         * @param name
186         * @return
187         */
188        public String escapeField(String name){
189                if(NameStringUtils.isJavaReserved(name)){
190                        return "_" + name;
191                }else {
192                        return escapeThrift(name);
193                }
194        }
195        public static boolean isIsLocalMethod(Method method){
196                return ThriftUtils.isIsLocalMethod(method);
197        }
198        public static boolean isIsLocalMethod(net.gdface.codegen.Method method){
199                return ThriftUtils.isIsLocalMethod(method.delegate());
200        }
201        public Type[] getActualTypeArguments(Type type){
202                if( type instanceof ParameterizedType){
203                        return ((ParameterizedType)type).getActualTypeArguments();
204                }
205                return new Type[0];
206        }
207        public Class<?> getServiceRuntimeExceptionClass(){
208                return ServiceRuntimeException.class;
209        }
210        public Class<?> getTypeTransformerClass(){
211                return TypeTransformer.class;
212        }
213        public String toStubType(Class<?> clazz){
214                checkArgument(null !=clazz,"clazz is null");
215                if(isThriftStruct(clazz) || Enum.class.isAssignableFrom(clazz) || this.isDecoratorType(clazz)){
216                        return ThriftServiceDecoratorConfiguration.INSTANCE.getThriftClientPackage() + "." + clazz.getSimpleName();
217                }
218                throw new IllegalArgumentException(String.format("%s is not thrift stub type", clazz.getName()));
219        }
220        public String toStubCxxType(Class<?> clazz){
221                return CxxHelper.cxxNamespace("::"+toStubType(clazz),true);
222        }
223        
224        /**
225         * 返回指定包名下的所有{@link ThriftStructDecorator}对象,,按类名自然排序,没有找到则返回空表
226         * @param pkg
227         * @return
228         */
229        public List<ThriftStructDecorator> getThriftStructDecorator(final String pkg){
230                ArrayList<ThriftStructDecorator> list = Lists.newArrayList(Iterables.filter(this.thriftStructDecorators, new Predicate<ThriftStructDecorator>(){
231                        @Override
232                        public boolean apply(ThriftStructDecorator input) {
233                                return input.getBaseClass().getPackage().getName().equals(pkg);
234                        }}));
235                return Ordering.natural().sortedCopy(list);
236        }
237        /**
238         * 根据{@link ThriftStructDecorator}对象之间的依赖关系返回{@link ThriftStructDecorator}队列
239         * @return
240         */
241        protected List<ThriftStructDecorator> getGenSequence(){
242                List<ThriftStructDecorator> list = BeanRelativeUtilits.sortByField(getAllStructDecorators(),"name");
243                //List<ThriftStructDecorator> list = getAllStructDecorators();
244                ArrayDeque<ThriftStructDecorator> seq = new ArrayDeque<>();
245                for(ThriftStructDecorator struct:list){
246                        traverseMember(struct,seq);
247                }
248                return Lists.newArrayList(seq.descendingIterator());
249        }
250        private void traverseMember(ThriftStructDecorator parent,Deque<ThriftStructDecorator> seq){
251                if(!seq.contains(parent)){
252                        List<ThriftStructDecorator> members = BeanRelativeUtilits.sortByField(parent.getDecorateTypes(),"name");
253                        for(ThriftStructDecorator struct:members){
254                                traverseMember(struct,seq);
255                        }
256                        seq.push(parent);
257                }
258        }
259        /**
260         * 根据{@link ThriftStructDecorator}对象之间的依赖关系返回以package为key的 {@link ListMultimap}映射
261         * @return
262         */
263        public ListMultimap<String,Collection<ThriftStructDecorator>> getStructGenSequenceAsMultimap(){
264                List<ThriftStructDecorator> seqlist = getGenSequence();
265                LinkedListMultimap<String, Collection<ThriftStructDecorator>> seq = LinkedListMultimap.<String, Collection<ThriftStructDecorator>>create();
266                String curPkg=null;
267                List<ThriftStructDecorator> sub = null;
268                for(ThriftStructDecorator struct:seqlist){
269                        String pkg = struct.getPackage();
270                        if(!pkg.equals(curPkg)){
271                                if(null !=curPkg){
272                                        seq.put(curPkg, sub);
273                                }
274                                sub = Lists.newLinkedList();
275                                curPkg = struct.getPackage();
276                        }
277                        sub.add(struct);
278                }
279                if(null !=curPkg){
280                        seq.put(curPkg, sub);
281                }
282                return seq;
283        }
284        public boolean isUseStringInTypes(){
285                return Iterables.tryFind(thriftStructDecorators, findString).isPresent();
286        }
287        public boolean isUseMapInTypes(){
288                return Iterables.tryFind(thriftStructDecorators, findMap).isPresent();
289        }
290        public boolean isUseSetInTypes(){
291                return Iterables.tryFind(thriftStructDecorators, findSet).isPresent();
292        }
293        public boolean isUseVectorInTypes(){
294                return Iterables.tryFind(thriftStructDecorators, findVector).isPresent();
295        }
296        public boolean isUseExceptionInTypes(){
297                return Iterables.tryFind(thriftStructDecorators, findException).isPresent();
298        }
299        public boolean isCanMove(CxxType cxxType){
300                if(null == cxxType){
301                        return false;                   
302                }
303                CxxTypeMeta uiType = cxxType.getUiType();
304                if(uiType.isCanMove() && !uiType.isStruct()){
305                        return true;
306                }
307                ThriftStructDecorator memSturct = getDecoratorType(cxxType.getJavaType());
308                return null !=memSturct && memSturct.isHasCanMoveField();
309        }
310}