001package net.gdface.codegen.thrift; 002 003import java.lang.reflect.Type; 004import java.util.ArrayList; 005import java.util.Arrays; 006import java.util.List; 007import java.util.Map; 008import java.util.Set; 009 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013import com.facebook.swift.codec.metadata.DecoratorThriftFieldMetadata; 014import com.facebook.swift.codec.metadata.DecoratorThriftServiceMetadata; 015import com.facebook.swift.codec.metadata.ErpcType; 016import com.facebook.swift.codec.metadata.ThriftCatalogWithTransformer; 017import com.facebook.swift.codec.metadata.ThriftFieldMetadata; 018import com.facebook.swift.service.metadata.ThriftMethodMetadata; 019import com.google.common.base.Function; 020import com.google.common.base.MoreObjects; 021import com.google.common.base.Predicate; 022import com.google.common.base.Predicates; 023import com.google.common.collect.ImmutableList; 024import com.google.common.collect.Iterables; 025import com.google.common.collect.Lists; 026import com.google.common.collect.Maps; 027import com.google.common.collect.Sets; 028import com.google.common.reflect.TypeToken; 029import net.gdface.annotation.AnnotationException; 030import net.gdface.annotation.AnnotationRuntimeException; 031import net.gdface.annotation.DeriveMethod; 032import net.gdface.annotation.ServicePort; 033import net.gdface.codegen.AnnotationUtils; 034import net.gdface.codegen.InvalidAnnotationDefineException; 035import net.gdface.codegen.InvalidNameException; 036import net.gdface.codegen.Method; 037import net.gdface.codegen.NewSourceInfoAbstract; 038import net.gdface.codegen.ServiceInfo; 039import net.gdface.codegen.thrift.ThriftServiceDecoratorConfiguration.TaskType; 040import net.gdface.codegen.thrift.metadata.CodegenPreAllocFilter; 041import net.gdface.codegen.Method.Parameter; 042import net.gdface.codegen.generator.GeneratorUtils; 043import net.gdface.thrift.ThriftUtils; 044import net.gdface.thrift.TypeTransformer; 045import net.gdface.thrift.exception.ServiceRuntimeException; 046import net.gdface.utils.NameStringUtils; 047 048import static com.google.common.base.Preconditions.*; 049 050/** 051 * thrift service 生成{@code NewSourceInfo}实现 052 * @author guyadong 053 * 054 * @param <T> 055 */ 056public class ThriftServiceDecorator<T> extends NewSourceInfoAbstract<T> implements ThriftConstants { 057 private static final Logger logger = LoggerFactory.getLogger(ThriftServiceDecorator.class); 058 private ServiceInfo serviceInfo; 059 private final Map<Method,String> servicePorts = Maps.newHashMap(); 060 private final TypeHelper typeHelper = new TypeHelper(this); 061 private String generatePackage; 062 private String clientInterfaceName; 063 private Boolean isUseStringInService = null; 064 private Boolean isUseBinaryInService = null; 065 private Boolean isUseVectorInService = null; 066 private Boolean isUseExceptionInService = null; 067 /** 068 * 记录接口中用到的所有容器类型List,Map,Set 069 */ 070 private final Set<CxxTypeMeta> containerTypes = Sets.newHashSet( 071 CxxType.getThriftType(ThriftUtils.mapToken(TypeToken.of(String.class), TypeToken.of(String.class)).getType()).getStubType()); 072 073 private final Set<ErpcType> collectionTypes = Sets.newLinkedHashSet(); 074 private final Predicate<Class<?>> findMap = new Predicate<Class<?>>(){ 075 076 @Override 077 public boolean apply(Class<?> input) { 078 return null == input ? false :Map.class.isAssignableFrom(input); 079 }}; 080 private final Predicate<Class<?>> findSet = new Predicate<Class<?>>(){ 081 082 @Override 083 public boolean apply(Class<?> input) { 084 return null == input ? false :Set.class.isAssignableFrom(input); 085 }}; 086 private final CxxType cxxType; 087 private final CxxTypeMeta stubCxxTypeMeta; 088 private final String thriftClientPackage; 089 private final Predicate<Method> tagsFilter; 090 private volatile DecoratorThriftServiceMetadata thriftServiceMetadata; 091 private Class<?> thriftServiceClass; 092 public ThriftServiceDecorator(Class<T> interfaceClass, Class<? extends T> refClass) { 093 super(interfaceClass, refClass, null); 094 TypeHelper.VERIFYTYPE_MONITOR.set(new Predicate<Type>(){ 095 096 @Override 097 public boolean apply(Type input) { 098 if(null ==isUseVectorInService){ 099 Class<?> rawType = TypeToken.of(input).getRawType(); 100 if((rawType.isArray() && rawType.getComponentType()!=byte.class) || List.class.isAssignableFrom(rawType)){ 101 isUseVectorInService = Boolean.TRUE; 102 } 103 } 104 if(input instanceof Class<?>){ 105 if(null == isUseStringInService){ 106 if(GeneratorUtils.isBinary(input)){ 107 isUseStringInService = Boolean.TRUE; 108 } 109 } 110 if(null ==isUseBinaryInService && TaskType.ERPC_PROXY.equals(ThriftServiceDecoratorConfiguration.INSTANCE.getTaskType())){ 111 if(GeneratorUtils.isBinary(input)){ 112 isUseBinaryInService = Boolean.TRUE; 113 } 114 } 115 if(null ==isUseExceptionInService){ 116 if(Exception.class.isAssignableFrom((Class<?>) input)){ 117 isUseExceptionInService = Boolean.TRUE; 118 } 119 } 120 } 121 try{ 122 CxxTypeMeta meta = CxxType.getThriftType(input).getUiType(); 123 if(meta.isContainer()){ 124 containerTypes.add(meta); 125 } 126 }catch(Exception e){ 127 logger.debug(e.getMessage()); 128 } 129 return false; 130 }}); 131 thriftClientPackage = ThriftServiceDecoratorConfiguration.INSTANCE.getThriftClientPackage(); 132 clientInterfaceName = thriftClientPackage + "." + this.interfaceClass.getSimpleName(); 133 cxxType = CxxType.struct(interfaceClass); 134 stubCxxTypeMeta = cxxType.getStubType().cast("::"+CxxHelper.cxxNamespace(clientInterfaceName,true)); 135 tagsFilter = new Predicate<Method>(){ 136 @Override 137 public boolean apply(Method input) { 138 return input.tagsMatched(ThriftServiceDecoratorConfiguration.INSTANCE.getReqiredTags()); 139 }}; 140 } 141 142 @Override 143 public boolean compile() { 144 boolean compileOk=false; 145 try{ 146 super.compile(); 147 serviceInfo=new ServiceInfo(AnnotationUtils.getServiceAnnotation(interfaceClass)); 148 for (Method method : methodsNeedGenerated) { 149 compile(method); 150 } 151 if(typeHelper.needTransformer()){ 152 addImportedClass(TypeTransformer.class); 153 } 154 addImportedClass(ServiceRuntimeException.class); 155 compileOk = true; 156 TypeHelper.VERIFYTYPE_MONITOR.remove(); 157 } catch (AnnotationException e) { 158 logger.error(e.toString()); 159 } catch(AnnotationRuntimeException e){ 160 logger.error(e.toString()); 161 } 162 return compileOk; 163 } 164 private final void compile(Method method) throws InvalidNameException { 165 TypeHelper.checkNotGeneric(method); 166 checkPortSuffix(method); 167 String portName = getPortName(method); 168 // 检查方法是否重名 169 if(servicePorts.containsKey(portName)){ 170 throw new InvalidNameException(String.format("duplicated method name %s", portName)); 171 } 172 typeHelper.checkType(method); 173 typeHelper.addReferTypes(method); 174 servicePorts.put(method,portName); 175 if(NameStringUtils.isThriftReserved( portName)){ 176 logger.warn("portName(method name) '{}' of '{}' is thrift IDL reserved word", portName,this.getInterfaceClass().getName()); 177 } 178 for (Parameter param : method.getParameters()) { 179 if(NameStringUtils.isThriftReserved( param.getName())){ 180 logger.warn("parameter name '{}' of method '{}' is thrift IDL reserved word", param.getName(),portName); 181 } 182 } 183 } 184 185 private static void checkPortSuffix(Method method) throws InvalidNameException{ 186 ServicePort servicePort = method.getAnnotation(ServicePort.class); 187 if (null != servicePort) { 188 // 检查名字是否合法,不允许包含空格,只能是数字字母下划线 189 if (!(servicePort.suffix().isEmpty() || servicePort.suffix().matches(AnnotationUtils.PATTERN_NOT_BLANK))){ 190 throw new InvalidNameException( 191 String.format("the suffix of annotation [%s] in method %s of %s must not have space char ", 192 ServicePort.class.getSimpleName(), 193 method.getName(), 194 method.getDeclaringClass().getSimpleName())); 195 } 196 } 197 } 198 199 @Override 200 protected void checkClass(Class<T> interfaceClass, Class<? extends T> refClass, Class<? extends T> baseClass) { 201 checkNotNull(interfaceClass,"interfaceClass is null"); 202 if (!interfaceClass.isInterface()){ 203 throw new IllegalArgumentException("interfaceClass must be Interface(必须是接口)"); 204 } 205 TypeHelper.checkNotGeneric(interfaceClass); 206 if(null != refClass ){ 207 if ( !interfaceClass.isAssignableFrom(refClass) 208 || refClass.isInterface()){ 209 throw new IllegalArgumentException(String.format( 210 "refClass must implement of [%s] (必须实现接口)", interfaceClass.getName())); 211 } 212 if (!isFullImplemented(interfaceClass,refClass)){ 213 logger.warn("{} not implement all methods of [{}] (没有实现接口所有方法)", 214 refClass.getName(), 215 interfaceClass.getName()); 216 } 217 } 218 } 219 220 @Override 221 protected void createMethodsNeedGenerated() { 222 List<Method> methods = Lists.transform(Arrays.asList(interfaceClass.getMethods()), 223 new Function<java.lang.reflect.Method, Method>() { 224 @Override 225 public Method apply(java.lang.reflect.Method input) { 226 return new Method(input, 227 paramTable.getParameterNamesUnchecked(input.getName(), input.getParameterTypes())); 228 } 229 }); 230 231 // tags 过滤 232 Iterable<Method> filteredByTags = Iterables.filter(methods, tagsFilter); 233 ArrayList<Method> filtered = 234 Lists.newArrayList( 235 Iterables.filter(filteredByTags, Predicates.compose(new MethodFilter(interfaceClass), Method.TO_REFLECT_METHOD))); 236 methodsNeedGenerated.addAll(filtered); 237 } 238 239 public ServiceInfo getServiceInfo() { 240 return serviceInfo; 241 } 242 public boolean isTargetType(Class<?> type){ 243 return serviceInfo.getTargetType()==type; 244 } 245 public List<ThriftStructDecorator> getDecorateTypes() { 246 return typeHelper.getDecorateTypes(); 247 } 248 public List<ThriftStructDecorator> getThriftTypes() { 249 return typeHelper.getThriftTypes(); 250 } 251 public String toThriftType(Type type) { 252 return typeHelper.toThriftType(type); 253 } 254 public String toClientThriftType(Type type) { 255 return typeHelper.toClientThriftType(type); 256 } 257 public String toClientThriftyType(Type type) { 258 return typeHelper.toClientThriftyType(type); 259 } 260 public boolean isClientThriftType(Type type) { 261 return typeHelper.isClientThriftType(type); 262 } 263 264 public String toThriftyDecoratorType(Type type) { 265 return typeHelper.toThriftyDecoratorType(type); 266 } 267 268 public String getClientInterfaceName(){ 269 return clientInterfaceName; 270 } 271 public String getPortName(Method method){ 272 ServicePort servicePort = method.getAnnotation(ServicePort.class); 273 String portName = method.getName(); 274 if (null != servicePort) { 275 portName += servicePort.suffix(); 276 } 277 return portName; 278 } 279 280 public String getGeneratePackage() { 281 return generatePackage; 282 } 283 284 public void setGeneratePackage(String generatePackage) { 285 this.generatePackage = generatePackage; 286 } 287 public void removeDecorateTypesFromImports(){ 288 // 排除枚举类型 289 Iterable<Class<?>> it = Iterables.filter(typeHelper.getTypesWithDecorator(),new Predicate<Class<?>>() { 290 @Override 291 public boolean apply(Class<?> input) { 292 return !input.isEnum(); 293 } 294 }); 295 ArrayList<Class<?>> types = Lists.newArrayList(it); 296 this.removeClassFromImports(types); 297 } 298 public void removeExceptionsFromImports(){ 299 this.removeClassFromImports(typeHelper.getReferExceptions()); 300 } 301 302 public List<Class<?>> getReferExceptions() { 303 return typeHelper.getReferExceptions(); 304 } 305 public boolean isUseStringInService(){ 306 return Boolean.TRUE.equals(isUseStringInService); 307 } 308 public boolean isUseBinaryInService(){ 309 return Boolean.TRUE.equals(isUseBinaryInService); 310 } 311 public boolean isUseMapInService(){ 312 return Iterables.tryFind(getImportedList().values(), findMap ).isPresent(); 313 } 314 public boolean isUseSetInService(){ 315 return Iterables.tryFind(getImportedList().values(), findSet).isPresent(); 316 } 317 public boolean isUseVectorInService(){ 318 return Boolean.TRUE.equals(isUseVectorInService); 319 } 320 public boolean isUseExceptionInService(){ 321 return Boolean.TRUE.equals(isUseExceptionInService); 322 } 323 /** 324 * 以接口名为基础创建不同后缀的{@link CxxTypeMeta} 325 * @param suffix 326 * @return 327 */ 328 public CxxTypeMeta makeStubCxxTypeMetaBySuffix(String suffix){ 329 suffix = MoreObjects.firstNonNull(suffix, ""); 330 return stubCxxTypeMeta.castName(this.getInterfaceClass().getSimpleName()+suffix); 331 } 332 333 public CxxType getCxxType() { 334 return cxxType; 335 } 336 337 public CxxTypeMeta getStubCxxTypeMeta() { 338 return stubCxxTypeMeta; 339 } 340 341 public String getThriftClientNamespace() { 342 return "::"+CxxHelper.cxxNamespace(thriftClientPackage); 343 } 344 345 public Set<CxxTypeMeta> getContainerTypes() { 346 return containerTypes; 347 } 348 public DeriveMethod getDeriveMethodAnnotation(Method method) { 349 try { 350 return AnnotationUtils.getDeriveMethodAnnotation(method, serviceInfo); 351 } catch (InvalidNameException e) { 352 throw new RuntimeException(e); 353 } catch (InvalidAnnotationDefineException e) { 354 throw new RuntimeException(e); 355 } 356 } 357 /** 358 * 返回 {@link DeriveMethod} 注释指定的方法名后缀,没有则返回空 359 * @param method 360 * @return 361 */ 362 public String methodSuffix(Method method){ 363 DeriveMethod deriveMethod = getDeriveMethodAnnotation(method); 364 if(deriveMethod !=null ){ 365 String[] suffixs = deriveMethod.methodSuffix(); 366 return suffixs != null && suffixs.length>0 ? suffixs[0]:""; 367 } 368 return ""; 369 } 370 371 public DecoratorThriftServiceMetadata getThriftServiceMetadata(){ 372 if(thriftServiceMetadata == null){ 373 synchronized (this) { 374 if(thriftServiceMetadata == null){ 375 thriftServiceMetadata = new DecoratorThriftServiceMetadata(checkNotNull(thriftServiceClass,"thriftServiceClass is uninitialized"), 376 ThriftCatalogWithTransformer.CATALOG, 377 ThriftServiceDecoratorConfiguration.INSTANCE.getExcludeMethods().get(getInterfaceClass()), 378 ThriftServiceDecoratorConfiguration.INSTANCE.getIncludeMethods().get(getInterfaceClass())); 379 } 380 } 381 } 382 return thriftServiceMetadata; 383 } 384 385 public ThriftMethodMetadata getThriftMethodMetadata(Method method){ 386 if(method != null){ 387 String name = method.getName() + methodSuffix(method); 388 return getThriftServiceMetadata().getMethod(name); 389 } 390 return null; 391 } 392 public List<ThriftFieldMetadata> getParameterMetadata(Method method){ 393 ThriftMethodMetadata methodMetadata = getThriftMethodMetadata(method); 394 if(methodMetadata != null){ 395 return methodMetadata.getParameters(); 396 } 397 return ImmutableList.of(); 398 } 399 400 /** 401 * @return thriftServiceClass 402 */ 403 public Class<?> getThriftServiceClass() { 404 return thriftServiceClass; 405 } 406 407 /** 408 * @param thriftServiceClass 要设置的 thriftServiceClass 409 * @return 410 */ 411 public ThriftServiceDecorator<T> setThriftServiceClass(Class<?> thriftServiceClass) { 412 this.thriftServiceClass = thriftServiceClass; 413 return this; 414 } 415 416 public ThriftServiceDecorator<T> erpcProxyInit(){ 417 if(TaskType.ERPC_PROXY.equals(ThriftServiceDecoratorConfiguration.INSTANCE.getTaskType())){ 418 DecoratorThriftServiceMetadata metadata = getThriftServiceMetadata(); 419 for(ThriftMethodMetadata methodMetadata:metadata.getMethods().values()){ 420 for(ThriftFieldMetadata param:methodMetadata.getParameters()){ 421 if(GeneratorUtils.isCollection(param.getThriftType().getJavaType())){ 422 if(!CodegenPreAllocFilter.PREALLOC_FILTER.apply((DecoratorThriftFieldMetadata) param)){ 423 collectionTypes.add(((DecoratorThriftFieldMetadata) param).getErpcType()); 424 } 425 } 426 } 427 if(GeneratorUtils.isCollection(methodMetadata.getReturnType().getJavaType())){ 428 collectionTypes.add(ErpcType.getErpcType(methodMetadata.getReturnType())); 429 } 430 } 431 } 432 return this; 433 } 434 435 /** 436 * @return collectionTypes 437 */ 438 public List<ErpcType> getCollectionTypes() { 439 return Lists.newArrayList(collectionTypes); 440 } 441}