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