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