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;
014
015import static com.facebook.swift.codec.metadata.DecoratorThriftServiceMetadata.javadocCommentProviderFactory;
016import static com.google.common.base.Preconditions.*;
017
018import com.facebook.swift.codec.metadata.DecoratorThriftEnumMetadata;
019import com.facebook.swift.codec.metadata.DecoratorThriftFieldMetadata;
020import com.facebook.swift.codec.metadata.DecoratorThriftStructMetadata;
021import com.facebook.swift.codec.metadata.ErpcProxyReturnCode;
022import com.facebook.swift.codec.metadata.ErpcType;
023import com.facebook.swift.codec.metadata.ThriftCatalogWithTransformer;
024import com.facebook.swift.codec.metadata.ThriftFieldMetadata;
025import com.facebook.swift.codec.metadata.ThriftStructMetadata;
026import com.facebook.swift.codec.metadata.DecoratorThriftEnumMetadata.ExtensiveEnumItem;
027import com.google.common.base.Optional;
028import com.google.common.base.Predicate;
029import com.google.common.collect.ImmutableList;
030import com.google.common.collect.ImmutableMap;
031import com.google.common.collect.Iterables;
032import com.google.common.collect.LinkedListMultimap;
033import com.google.common.collect.ListMultimap;
034import com.google.common.collect.Lists;
035import com.google.common.collect.Ordering;
036import com.google.common.collect.Sets;
037import com.google.common.reflect.TypeToken;
038
039import net.gdface.codegen.generator.GeneratorUtils;
040import net.gdface.codegen.thrift.ThriftServiceDecoratorConfiguration.TaskType;
041import net.gdface.codegen.thrift.metadata.CodegenPreAllocFilter;
042import net.gdface.thrift.ThriftUtils;
043import net.gdface.thrift.TypeTransformer;
044import net.gdface.thrift.exception.ServiceRuntimeException;
045import net.gdface.utils.BeanRelativeUtilits;
046import net.gdface.utils.NameStringUtils;
047
048/**
049 * @author guyadong
050 *
051 */
052public class ThriftSchema implements ThriftConstants {
053        private final Set<ThriftStructDecorator> thriftStructDecorators = Sets.newLinkedHashSet();
054        private final Set<ThriftStructDecorator> thriftStructs = Sets.newLinkedHashSet();
055        private final Set<ErpcType> collectionStructs = Sets.newTreeSet();
056        private final List<ThriftServiceDecorator<?>> thriftServiceDecorators = Lists.newLinkedList();
057        private final Predicate<ThriftStructDecorator> exceptionFilter = new Predicate<ThriftStructDecorator>(){
058                @Override
059                public boolean apply(ThriftStructDecorator input) {
060                        return input.isException();
061                }};
062        private final Predicate<ThriftStructDecorator> enumFilter = new Predicate<ThriftStructDecorator>(){
063                @Override
064                public boolean apply(ThriftStructDecorator input) {
065                        return input.isEnum();
066                }};
067        private final Predicate<ThriftStructDecorator> beanFilter = new Predicate<ThriftStructDecorator>(){
068                @Override
069                public boolean apply(ThriftStructDecorator input) {
070                        return input.isBean();
071                }};
072        @SuppressWarnings("rawtypes")
073        private final Predicate<ThriftServiceDecorator> findStringInServices = new Predicate<ThriftServiceDecorator>(){
074                @Override
075                public boolean apply(ThriftServiceDecorator input) {
076                        return null!=input && input.isUseStringInService();
077                }};
078        @SuppressWarnings("rawtypes")
079        private final Predicate<ThriftServiceDecorator> findBinaryInServices = new Predicate<ThriftServiceDecorator>(){
080                @Override
081                public boolean apply(ThriftServiceDecorator input) {
082                        return null!=input && input.isUseBinaryInService();
083                }};
084        private final Predicate<ThriftStructDecorator> findString = new Predicate<ThriftStructDecorator>(){
085                @Override
086                public boolean apply(ThriftStructDecorator input) {
087                        return null!=input && input.isUseString();
088                }};
089        private final Predicate<ThriftStructDecorator> findBinary = new Predicate<ThriftStructDecorator>(){
090                @Override
091                public boolean apply(ThriftStructDecorator input) {
092                        return null!=input && input.isUseBinary();
093                }};
094        private final Predicate<ThriftStructDecorator> findMap = new Predicate<ThriftStructDecorator>(){
095                @Override
096                public boolean apply(ThriftStructDecorator input) {
097                        return null!=input && input.isUseMap();
098                }};
099        private final Predicate<ThriftStructDecorator> findSet = new Predicate<ThriftStructDecorator>(){
100                @Override
101                public boolean apply(ThriftStructDecorator input) {
102                        return null!=input && input.isUseSet();
103                }};
104        private final Predicate<ThriftStructDecorator> findVector = new Predicate<ThriftStructDecorator>(){
105                @Override
106                public boolean apply(ThriftStructDecorator input) {
107                        return null!=input && input.isUseVector();
108                }};
109        private final Predicate<ThriftStructDecorator> findException = new Predicate<ThriftStructDecorator>(){
110                @Override
111                public boolean apply(ThriftStructDecorator input) {
112                        return null!=input && input.isException();
113                }};
114        @SuppressWarnings({ "rawtypes", "unchecked" })
115        public ThriftSchema(Map<Class<?>, Class<?>> interfaceClasses) {
116                for(Entry<Class<?>, Class<?>> entry:interfaceClasses.entrySet()){
117                        Class<?> interfaceClass = entry.getKey();
118                        Class<?> refClass = entry.getValue();
119                        if(refClass == ThriftServiceDecoratorConfiguration.DEF_REF_CLASS){
120                                refClass = null;
121                        }
122                        ThriftServiceDecorator service = new ThriftServiceDecorator(interfaceClass,refClass);
123                        thriftServiceDecorators.add(service);
124                }
125                if(!compile()){
126                        throw new IllegalStateException("compile fail");
127                }
128        }
129        public List<ThriftStructDecorator> getAllStructDecorators() {
130                return Lists.newArrayList(thriftStructDecorators);
131        }
132        public List<ThriftStructDecorator> getExceptionDecorators(){
133                return Lists.newArrayList(Sets.filter(thriftStructDecorators, exceptionFilter));
134        }
135        public List<ThriftStructDecorator> getEnumDecorators(){
136                return Lists.newArrayList(Sets.filter(thriftStructDecorators, enumFilter));
137        }
138        public List<ThriftStructDecorator> getBeanDecorators(){
139                return Lists.newArrayList(Sets.filter(thriftStructDecorators, beanFilter));
140        }
141        public List<ThriftServiceDecorator<?>> getThriftServiceDecorators() {
142                return thriftServiceDecorators;
143        }
144        private boolean compile(){
145                for(ThriftServiceDecorator<?> newSourceInfo:getThriftServiceDecorators()){
146                        if (!newSourceInfo.compile()){
147                                return false;
148                        }
149                        thriftStructDecorators.addAll(newSourceInfo.getDecorateTypes());
150                        thriftStructs.addAll(newSourceInfo.getThriftTypes());
151                }
152                for(ThriftStructDecorator newSourceInfo:getAllStructDecorators()){
153                        if (!newSourceInfo.compile()){
154                                return false;
155                        }
156                        thriftStructDecorators.addAll(newSourceInfo.getDecorateTypes());
157                        thriftStructs.addAll(newSourceInfo.getThriftTypes());
158                }
159                return true;
160        }
161        public boolean isThriftBuildinType(Type type){          
162                return ThriftUtils.isThriftBuildinType(type);
163        }
164        public boolean isCastType(Type type){
165                return  ThriftUtils.isCastType(type);
166        }
167        public boolean isDecoratorType(final Type type) {
168                return getDecoratorType(type) != null;
169        }
170        public ThriftStructDecorator getDecoratorType(final Type type) {
171                Optional<ThriftStructDecorator> result = Iterables.tryFind(thriftStructDecorators, new Predicate<ThriftStructDecorator>(){
172
173                        @Override
174                        public boolean apply(ThriftStructDecorator input) {
175                                return input.getBaseClass().equals(type);
176                        }});
177                return result.isPresent() ? result.get() : null;
178        }
179        public boolean isThriftStruct(Type type){
180                return ThriftUtils.isThriftStruct(type);
181        }
182        public boolean isPrimitivefloat(Type type){
183                return ThriftUtils.isPrimitivefloat(type);
184        }
185        public boolean isfloat(Type type){
186                return ThriftUtils.isfloat(type);
187        }
188        public boolean isPrimitiveArray(Type type){
189                return ThriftUtils.isPrimitiveArray(type);
190        }
191        public boolean isMap(Type type){
192                return TypeToken.of(type).getRawType() == Map.class;
193        }
194        public boolean isList(Type type){
195                return TypeToken.of(type).getRawType() == List.class;
196        }
197        public boolean isSet(Type type){
198                return TypeToken.of(type).getRawType() == Set.class;
199        }
200        public boolean isCollection(Type type){
201                return isList(type) || isSet(type);
202        }
203        public boolean isArray(Type type){
204                return isList(type) || isSet(type);
205        }
206        public boolean isBinary(Type type){
207                return type == byte[].class;
208        }
209        public final Type wrap(Type type){
210                return TypeToken.of(type).wrap().getType();
211        }
212        /**
213         * 对thrift IDL 关键字(binary,list,map,set,i32...)转义,以确保生成的IDL文件中成员名和参数名与thrift关键字不冲突
214         * @param name
215         * @return
216         */
217        public String escapeThrift(String name){
218                return NameStringUtils.isThriftReserved(name)? name + "_" : name;
219        }
220        /**
221         * 字段名转义,避免java,thrift关键字冲突
222         * @param name
223         * @return
224         */
225        public String escapeField(String name){
226                if(NameStringUtils.isJavaReserved(name)){
227                        return "_" + name;
228                }else {
229                        return escapeThrift(name);
230                }
231        }
232        public static boolean isIsLocalMethod(Method method){
233                return ThriftUtils.isIsLocalMethod(method);
234        }
235        public static boolean isIsLocalMethod(net.gdface.codegen.Method method){
236                return ThriftUtils.isIsLocalMethod(method.delegate());
237        }
238        public Type[] getActualTypeArguments(Type type){
239                if( type instanceof ParameterizedType){
240                        return ((ParameterizedType)type).getActualTypeArguments();
241                }
242                return new Type[0];
243        }
244        public Class<?> getServiceRuntimeExceptionClass(){
245                return ServiceRuntimeException.class;
246        }
247        public Class<?> getTypeTransformerClass(){
248                return TypeTransformer.class;
249        }
250        public String toStubType(Class<?> clazz){
251                checkArgument(null !=clazz,"clazz is null");
252                if(isThriftStruct(clazz) || Enum.class.isAssignableFrom(clazz) || this.isDecoratorType(clazz)){
253                        return ThriftServiceDecoratorConfiguration.INSTANCE.getThriftClientPackage() + "." + clazz.getSimpleName();
254                }
255                throw new IllegalArgumentException(String.format("%s is not thrift stub type", clazz.getName()));
256        }
257        public String toStubCxxType(Class<?> clazz){
258                return CxxHelper.cxxNamespace("::"+toStubType(clazz),true);
259        }
260        /**
261         * 返回指定包名下的所有{@link ThriftStructDecorator}对象,,按类名自然排序,没有找到则返回空表
262         * @param pkg
263         * @return
264         */
265        public List<ThriftStructDecorator> getThriftStructDecorator(final String pkg){
266                ArrayList<ThriftStructDecorator> list = Lists.newArrayList(Iterables.filter(this.thriftStructDecorators, new Predicate<ThriftStructDecorator>(){
267                        @Override
268                        public boolean apply(ThriftStructDecorator input) {
269                                return input.getBaseClass().getPackage().getName().equals(pkg);
270                        }}));
271                return Ordering.natural().sortedCopy(list);
272        }
273        /**
274         * 根据{@link ThriftStructDecorator}对象之间的依赖关系返回{@link ThriftStructDecorator}队列
275         * @param thriftStructIncluded 是否包含thrift struct 类
276         * @return
277         */
278        protected List<ThriftStructDecorator> getGenSequence(boolean thriftStructIncluded){
279                List<ThriftStructDecorator> types = getAllStructDecorators();
280                if(thriftStructIncluded){
281                        types.addAll(thriftStructs);
282                }
283                List<ThriftStructDecorator> list = BeanRelativeUtilits.sortByField(types,"name");
284                //List<ThriftStructDecorator> list = getAllStructDecorators();
285                ArrayDeque<ThriftStructDecorator> seq = new ArrayDeque<>();
286                for(ThriftStructDecorator struct:list){
287                        traverseMember(struct,seq);
288                }
289                return Lists.newArrayList(seq.descendingIterator());
290        }
291        private void traverseMember(ThriftStructDecorator parent,Deque<ThriftStructDecorator> seq){
292                if(!seq.contains(parent)){
293                        List<ThriftStructDecorator> members = BeanRelativeUtilits.sortByField(parent.getDecorateTypes(),"name");
294                        for(ThriftStructDecorator struct:members){
295                                traverseMember(struct,seq);
296                        }
297                        seq.push(parent);
298                }
299        }
300        /**
301         * 根据{@link ThriftStructDecorator}对象之间的依赖关系返回以package为key的 {@link ListMultimap}映射
302         * @param thriftStructIncluded 是否包含thrift struct 类
303         * @return
304         */
305        public ListMultimap<String,Collection<ThriftStructDecorator>> getStructGenSequenceAsMultimap(boolean thriftStructIncluded){
306                List<ThriftStructDecorator> seqlist = getGenSequence(thriftStructIncluded);
307                seqlist.add(new ThriftStructDecorator(getServiceRuntimeExceptionClass()));
308                LinkedListMultimap<String, Collection<ThriftStructDecorator>> seq = LinkedListMultimap.<String, Collection<ThriftStructDecorator>>create();
309                String curPkg=null;
310                List<ThriftStructDecorator> sub = null;
311                for(ThriftStructDecorator struct:seqlist){
312                        String pkg = struct.getPackage();
313                        if(!pkg.equals(curPkg)){
314                                if(null !=curPkg){
315                                        seq.put(curPkg, sub);
316                                }
317                                sub = Lists.newLinkedList();
318                                curPkg = struct.getPackage();
319                        }
320                        sub.add(struct);
321                }
322                if(null !=curPkg){
323                        seq.put(curPkg, sub);
324                }
325                return seq;
326        }
327        public boolean isUseStringInServices(){
328                return Iterables.tryFind(thriftServiceDecorators, findStringInServices).isPresent();
329        }
330        public boolean isUseBinaryInServices(){
331                return Iterables.tryFind(thriftServiceDecorators, findBinaryInServices).isPresent();
332        }
333        public boolean isUseStringInTypes(){
334                return Iterables.tryFind(thriftStructDecorators, findString).isPresent();
335        }
336        public boolean isUseBinaryInTypes(){
337                return Iterables.tryFind(thriftStructDecorators, findBinary).isPresent();
338        }
339        public boolean isUseMapInTypes(){
340                return Iterables.tryFind(thriftStructDecorators, findMap).isPresent();
341        }
342        public boolean isUseSetInTypes(){
343                return Iterables.tryFind(thriftStructDecorators, findSet).isPresent();
344        }
345        public boolean isUseVectorInTypes(){
346                return Iterables.tryFind(thriftStructDecorators, findVector).isPresent();
347        }
348        public boolean isUseExceptionInTypes(){
349                return Iterables.tryFind(thriftStructDecorators, findException).isPresent();
350        }
351        public boolean isCanMove(CxxType cxxType){
352                if(null == cxxType){
353                        return false;                   
354                }
355                CxxTypeMeta uiType = cxxType.getUiType();
356                if(uiType.isCanMove() && !uiType.isStruct()){
357                        return true;
358                }
359                ThriftStructDecorator memSturct = getDecoratorType(cxxType.getJavaType());
360                return null !=memSturct && memSturct.isHasCanMoveField();
361        }
362        public boolean isCommonType(final Type type){
363                if(type instanceof Class<?>){
364                        Set<String> commonTypes = ThriftServiceDecoratorConfiguration.INSTANCE.getCommonTypes();
365                        return Iterables.tryFind(commonTypes, new Predicate<String>() {
366
367                                @Override
368                                public boolean apply(String input) {
369                                        Class<?> clazz = (Class<?>)type;
370                                        return clazz.getName().equals(input) 
371                                                        || clazz.getSimpleName().equals(input)
372                                                        || clazz.getPackage().getName().startsWith(input);
373                                }
374                        }).isPresent();
375                }
376                return false;
377        }
378        public String getProgramName(){
379                return ThriftServiceDecoratorConfiguration.INSTANCE.getProgramName();
380        }
381        public String getPortPrefix(){
382                return ThriftServiceDecoratorConfiguration.INSTANCE.getPortPrefix();
383        }
384        /**
385         * @param thriftServiceClasses 要设置的 thriftServiceClasses
386         * @return 
387         */
388        public ThriftSchema setThriftServiceClasses(Map<Class<?>, Class<?>> thriftServiceClasses) {
389                if(thriftServiceClasses != null){
390                        for(ThriftServiceDecorator<?> decorator:thriftServiceDecorators){
391                                decorator.setThriftServiceClass(thriftServiceClasses.get(decorator.getInterfaceClass())).erpcProxyInit();
392                        }
393                }
394                return this;
395        }
396        public DecoratorThriftEnumMetadata<?> getThriftEnumMetadata(Type type){
397                if(type instanceof Class<?>){
398                        return (DecoratorThriftEnumMetadata<?>) ThriftCatalogWithTransformer.CATALOG.getThriftEnumMetadata((Class<?>) type);
399                }
400                return null;
401        }
402        public DecoratorThriftEnumMetadata<?> getThriftEnumMetadata(String className) throws ClassNotFoundException{
403                return getThriftEnumMetadata(Class.forName(className));
404        }
405        public DecoratorThriftStructMetadata getThriftStructMetadata(Type type){
406                return (DecoratorThriftStructMetadata) ThriftCatalogWithTransformer.CATALOG.getThriftStructMetadata(type);
407        }
408        public DecoratorThriftStructMetadata getThriftStructMetadata(String className) throws ClassNotFoundException{
409                return getThriftStructMetadata(Class.forName(className));
410        }
411        /**
412         * @return collectionStructs
413         */
414        public List<ErpcType> getCollectionStructs() {
415                return Lists.newArrayList(collectionStructs);
416        }
417        /**
418         * @return collectionStructs
419         */
420        public List<ErpcType> getCollectionStructs(final boolean structElement) {
421                Iterable<ErpcType> filtered = Iterables.filter(collectionStructs, new Predicate<ErpcType>() {
422
423                        @Override
424                        public boolean apply(ErpcType input) {
425                                boolean isStruct = isThriftStruct(input.getValueType().getJavaType());
426                                return  structElement ? isStruct : !isStruct;
427                        }
428                });
429                ArrayList<ErpcType> types = Lists.newArrayList(filtered);               
430                return types;
431        }
432        
433        public int getExistsListString(){
434                return Iterables.tryFind(collectionStructs, new Predicate<ErpcType>(){
435
436                        @Override
437                        public boolean apply(ErpcType input) {
438                                return input.getValueType().getProtocolType().isString();
439                        }}).isPresent() ? 1 : 0;
440        }
441        public int getExistsListBinary(){
442                return Iterables.tryFind(collectionStructs, new Predicate<ErpcType>(){
443
444                        @Override
445                        public boolean apply(ErpcType input) {
446                                return input.getValueType().getProtocolType().isBinary();
447                        }}).isPresent() ? 1 : 0;
448        }
449        public ThriftSchema erpcProxyInit(){
450                if(TaskType.ERPC_PROXY.equals(ThriftServiceDecoratorConfiguration.INSTANCE.getTaskType())){
451                        for(ThriftServiceDecorator<?> newSourceInfo:getThriftServiceDecorators()){
452                                collectionStructs.addAll(newSourceInfo.getCollectionTypes());
453                        }
454                        for(ThriftStructDecorator struct : thriftStructs){
455                                ThriftStructMetadata structMetadata = ThriftCatalogWithTransformer.CATALOG.getThriftStructMetadata(struct.getBaseClass());
456                                for(ThriftFieldMetadata field : structMetadata.getFields()){
457                                        if(GeneratorUtils.isCollection(field.getThriftType().getJavaType())){
458                                                if(!CodegenPreAllocFilter.PREALLOC_FILTER.apply((DecoratorThriftFieldMetadata) field)){
459                                                        collectionStructs.add(((DecoratorThriftFieldMetadata) field).getErpcType());
460                                                }
461                                        }       
462                                }                       
463                        }
464                        DecoratorThriftEnumMetadata.beforeExtensiveEnumItems = createBeforeExtensiveEnumItem();
465                        // 添加到列表头部
466                        thriftStructs.add(new ThriftStructDecorator(ErpcProxyReturnCode.class));
467                }
468                return this;
469        }
470        private ImmutableMap<Class<? extends Enum<?>>, List<ExtensiveEnumItem>> createBeforeExtensiveEnumItem(){
471                ArrayList<ExtensiveEnumItem> items = Lists.newArrayList();
472                for(ThriftStructDecorator type:thriftStructDecorators){
473                        Class<?> javaType = type.getBaseClass();
474                        if(javaType instanceof Class<?> && Exception.class.isAssignableFrom(javaType)){
475                                 ImmutableList<String> comment = null;
476                                if(javadocCommentProviderFactory != null){
477                                        comment =  javadocCommentProviderFactory.apply(javaType).commentOfClass();
478                                }
479                                items.add(new ExtensiveEnumItem(javaType.getSimpleName(),null,comment));
480                        }
481                }
482                return ImmutableMap.<Class<? extends Enum<?>>, List<ExtensiveEnumItem>>of(ErpcProxyReturnCode.class,items);
483        }
484        public int getErpcForwardPort(){
485                return ThriftServiceDecoratorConfiguration.INSTANCE.getErpcForwardPort();
486        }
487        public int getErpcProxyPort(){
488                return ThriftServiceDecoratorConfiguration.INSTANCE.getErpcProxyPort();
489        }
490        public int getDefaultMaxLength(){
491                return ThriftServiceDecoratorConfiguration.INSTANCE.getDefaultMaxLength();
492        }
493        public int getErrmsgMaxLength(){
494                return ThriftServiceDecoratorConfiguration.INSTANCE.getErrmsgMaxLength();
495        }
496        public int getBinaryOutputSize(){
497                return ThriftServiceDecoratorConfiguration.INSTANCE.getBinaryOutputSize();
498        }
499}