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}