001package net.gdface.codegen.webclient; 002 003import java.beans.PropertyDescriptor; 004import java.io.File; 005import java.io.IOException; 006import java.lang.reflect.Method; 007import java.util.HashMap; 008import java.util.Map; 009import java.util.Map.Entry; 010import java.util.Set; 011import java.util.regex.Matcher; 012import java.util.regex.Pattern; 013 014import org.slf4j.Logger; 015import org.slf4j.LoggerFactory; 016 017import net.gdface.codegen.CodeGenUtils; 018import net.gdface.utils.Assert; 019import net.gdface.utils.BeanPropertyUtils; 020import net.gdface.utils.Configuration; 021import net.gdface.utils.FaceUtilits; 022import net.gdface.utils.Judge; 023 024/** 025 * 用于从soapcpp2生成的gsoap stub头文件中解析读取生成C++代码所需要的数据 026 * @author guyadong 027 * 028 */ 029public class GSoapHeaderHelper implements GSoapConstants,WebClientConstants{ 030 private static final Logger logger = LoggerFactory.getLogger(GSoapClient.class); 031 /** 032 * gsoap properties 033 */ 034 private static final Configuration prop=GSoapProperties.getInstance(); 035 /** 036 * gsoap代码中下划线符号的替换字符串 037 */ 038 private static final String underscore; 039 static { 040 underscore=prop.getProperty(PROP_UNDERSCORE).trim(); 041 Assert.notEmpty(underscore, "underscore"); 042 } 043 /** 044 * gsoap stub头文件文本内容(xxxxStub.h) 045 */ 046 private final String stubHeader; 047 /** 048 * namespace->prefix映射 049 */ 050 private final Map<String, String> gsoapNamespaceMap; 051 /** 052 * 所有wsdl名称-->stub类型映射 053 */ 054 private final Map<String, String> typeNameMap; 055 /** 056 * 所有引用类型的java Class-->stub类型映射 057 */ 058 private final Map<Class<?>, String> referenceClassMap; 059 060 /** 061 * 引用类型的属性映射 062 */ 063 private final Map<Class<?>,Map<String, PropertyDescriptor>> refClassPropertiesMap; 064 /** 065 * stub类型的属性映射 066 */ 067 private Map<String, Map<String, String>> stubClassProppertiesMap; 068 /** 069 * gsoap stub源代码文件前缀 070 */ 071 private final String stubPrefix; 072 073 /** 074 * gsoapstub源代码文件夹位置 075 */ 076 private final File stubFolder; 077 private final Class<?> serviceClass; 078 079 /** 080 * @param stubFolder gsoap stub代码文件夹 081 * @param serviceClass TODO 082 * @param stubPrefix gsoap stub代码文件前缀 083 */ 084 public GSoapHeaderHelper(File stubFolder, Class<?> serviceClass, String stubPrefix) { 085 Assert.notNull(stubFolder, "stubFolder"); 086 Assert.notNull(serviceClass, "serviceClass"); 087 this.serviceClass=serviceClass; 088 this.stubFolder= stubFolder; 089 this.stubPrefix= Judge.isEmpty(stubPrefix) ?this.serviceClass.getSimpleName().toLowerCase():stubPrefix; 090 this.stubHeader=load(new File(this.stubFolder,this.stubPrefix+"Stub.h")); 091 this.gsoapNamespaceMap=createGSoapNamespaceMap(stubHeader); 092 this.typeNameMap=createTypeNameMap(stubHeader); 093 this.referenceClassMap=createReferenceClassMap(stubHeader); 094 this.refClassPropertiesMap=createBeanClassPropertiesMap(referenceClassMap.keySet()); 095 this.stubClassProppertiesMap=createStubClassPropDefMap(CodeGenUtils.toSet(referenceClassMap.values())); 096 } 097 /** 098 * @return referenceClassMap 099 */ 100 public Map<Class<?>, String> getReferenceClassMap() { 101 return referenceClassMap; 102 } 103 104 /** 105 * @return 所有Bean类型映射 106 */ 107 public Map<Class<?>, String> getBeanClassMap() { 108 Map<Class<?>, String> beanMap=new HashMap<Class<?>, String>(); 109 for(Entry<Class<?>, String> entry:referenceClassMap.entrySet()){ 110 if(!Exception.class.isAssignableFrom(entry.getKey())){ 111 beanMap.put(entry.getKey(), entry.getValue()); 112 } 113 } 114 return beanMap; 115 } 116 /** 117 * @param method 118 * @param prefix 119 * @param suffix 120 * @return 121 * @see #getStubPortName(String, String, String) 122 */ 123 public String getStubPortName(Method method,String prefix,String suffix){ 124 Assert.notNull(method, "method"); 125 return getStubPortName(method.getName(),prefix,suffix); 126 } 127 /** 128 * 返回指定方法的在stub中对应的名字 129 * @param methodName 方法名 130 * @param prefix 方法名前缀 131 * @param suffix 方法名后缀 132 * @return 133 */ 134 public String getStubPortName(String methodName,String prefix,String suffix){ 135 Assert.notEmpty(methodName, "methodName"); 136 StringBuilder sb=new StringBuilder(); 137 if(!Judge.isEmpty(prefix)) 138 sb.append(prefix); 139 sb.append(methodName); 140 if(!Judge.isEmpty(suffix)) 141 sb.append(suffix); 142 return typeNameMap.get(sb.toString()); 143 } 144 /** 145 * 将header文件加载到内存 146 * @param gsoapHeader 147 * @return 返回文件所有文本内容的字符串 148 */ 149 private static String load(File gsoapHeader){ 150 Assert.notNull(gsoapHeader, "gsoapHeader"); 151 Assert.isTrue(gsoapHeader.isFile(), "gsoapHeader.isFile()"); 152 try { 153 return new String(FaceUtilits.getBytesNotEmpty(gsoapHeader)); 154 } catch (IOException e) { 155 throw new RuntimeException(e); 156 } 157 } 158 public String getStubClassName(Class<?> clazz){ 159 String prefix = getNamespacePrefix(clazz); 160 if(null!=prefix) 161 return String.format("%s__%s",prefix,clazz.getSimpleName()); 162 return null; 163 } 164 public String getNamespacePrefix(Class<?> clazz){ 165 Assert.notNull(clazz, "clazz"); 166 String namespace = NAMESPACEGENERATOR.schemaNamespaceFromPackageName(clazz.getPackage().getName()).toString(); 167 String prefix = gsoapNamespaceMap.get(namespace); 168 if(null==prefix){ 169 namespace=NAMESPACEGENERATOR.namespaceFromPackageName(clazz.getPackage().getName()).toString(); 170 prefix = gsoapNamespaceMap.get(namespace); 171 } 172 return prefix; 173 } 174 175 /** 176 * 分析gsoap .h文件,创建实际的namespace prefix与namespace的映射表 177 * @param gsaopHeader 178 * @return 179 */ 180 protected static Map<String, String> createGSoapNamespaceMap(String header){ 181 String regexpString = GSoapProperties.getInstance().getProperty(PROP_REGEXP_NAMESPACE).trim(); 182 Assert.notEmpty(regexpString, "regexpString"); 183 Pattern pattern = Pattern.compile(regexpString,Pattern.MULTILINE); 184 Matcher matcher = pattern.matcher(header); 185 Map<String,String>map=new HashMap<String,String>(); 186 while (matcher.find()) { 187 map.put(matcher.group(2),matcher.group(1)); 188 logger.debug("namespace {} = {}",matcher.group(1),matcher.group(2)); 189 } 190 Assert.isTrue(!map.isEmpty(), "!map.isEmpty()"); 191 return map; 192 } 193 /** 194 * 分析gsoap .h文件,创建实际的原始类名与gosap stub代码中的类名映射表 195 * @param gsaopHeader 196 * @return 197 */ 198 protected static Map<String, String> createTypeNameMap(String headerFile){ 199 String regexpString = prop.getProperty(PROP_REGEXP_CLASSMAP).trim(); 200 Assert.notEmpty(regexpString, "regexpString"); 201 Pattern pattern = Pattern.compile(regexpString,Pattern.MULTILINE); 202 Matcher matcher = pattern.matcher(headerFile); 203 Map<String,String>map=new HashMap<String,String>(); 204 while (matcher.find()) { 205 String stubClassName=matcher.group(1); 206 // 将_USCORE替换为_ 207 String cppClassName=matcher.group(3).replace(underscore, "_"); 208 map.put(cppClassName, stubClassName); 209 logger.debug("type name map {} = {}",cppClassName,stubClassName); 210 } 211 Assert.isTrue(!map.isEmpty(), "!map.isEmpty()"); 212 return map; 213 } 214 /** 215 * 分析gsoap .h文件,创建引用类型名与gosap stub代码中的类名映射表 216 * @param gsaopHeader 217 * @return 218 */ 219 protected Map<Class<?>, String> createReferenceClassMap(String headerFile){ 220 String regexpString = prop.getProperty(PROP_REFERENCE_CLASS).trim(); 221 Assert.notEmpty(regexpString, "regexpString"); 222 Pattern pattern = Pattern.compile(regexpString,Pattern.MULTILINE); 223 Matcher matcher = pattern.matcher(headerFile); 224 Map<Class<?>, String>map=new HashMap<Class<?>,String>(); 225 while (matcher.find()) { 226 String stubClassName=matcher.group(1); 227 // 将_USCORE替换为_ 228 Class<?> clazz = classFromStubClassName(stubClassName.replace(underscore, "_")); 229 map.put(clazz, stubClassName); 230 logger.debug("reference class map {} = {}",clazz.getName(),stubClassName); 231 } 232 if(map.isEmpty()) 233 logger.info("no reference class defined"); 234 return map; 235 } 236 237 /** 238 * 创建所有引用 239 * @param classSet 240 * @return 241 */ 242 private static Map<Class<?>, Map<String, PropertyDescriptor>> createBeanClassPropertiesMap( 243 Set<Class<?>> classSet) { 244 Map<Class<?>, Map<String, PropertyDescriptor>> map = new HashMap<Class<?>, Map<String, PropertyDescriptor>>(); 245 for (Class<?> refClass : classSet) { 246 map.put(refClass, BeanPropertyUtils.getProperties(refClass, 3)); 247 } 248 return map; 249 } 250 251 /** 252 * 253 * 分析gsoap .h文件,获取所有stub类型的属性定义 254 * @param stubClassSet 255 * @return 256 */ 257 private Map<String, Map<String, String>> createStubClassPropDefMap(Set<String> stubClassSet){ 258 Assert.notNull(stubClassSet, "stubClassSet"); 259 Map<String,Map<String,String>>map=new HashMap<String,Map<String,String>>(); 260 String regClassDef = prop.getProperty(PROP_REGEXP_CLASSDEF); 261 String regPropDef = prop.getProperty(PROP_REGEXP_PROPDEF); 262 Assert.notEmpty(regClassDef, "regClassDef"); 263 Assert.notEmpty(regPropDef, "regPropDef"); 264 Pattern pattern=Pattern.compile(regPropDef, Pattern.MULTILINE); 265 for(String type:stubClassSet){ 266 logger.debug("class {}{",type); 267 Matcher mc = Pattern.compile(regClassDef.replace("$CLASS_NAME$",type), Pattern.MULTILINE).matcher(stubHeader); 268 if(!mc.find()) 269 throw new IllegalArgumentException(String.format("regexp not match Class Definition of %s in header file",type)); 270 String props=mc.group(1); 271 Matcher matcher = pattern.matcher(props); 272 Map<String,String> propMap=new HashMap<String,String>(); 273 while(matcher.find()){ 274 propMap.put(matcher.group(2).trim(), matcher.group(1).trim()); 275 logger.debug("\t{} : {}",matcher.group(1),matcher.group(2)); 276 } 277 logger.debug("}",type); 278 map.put(type, propMap); 279 } 280 return map; 281 } 282 283 /** 284 * 将gsoap stub中的类名转换为java Class 285 * @param stubClassName gsoap stub中的类名 286 * @return 287 */ 288 public Class<?> classFromStubClassName(String stubClassName){ 289 Pattern pattern = Pattern.compile("^\\b([a-zA-Z\\d]+\\d+)__([a-zA-Z\\d]+)?$"); 290 // 正则匹配前先将_USCORE替换为_ 291 Matcher matcher = pattern.matcher(stubClassName.replace(underscore, "_")); 292 if(matcher.find()){ 293 String namespace = CodeGenUtils.getKey(this.gsoapNamespaceMap,matcher.group(1)); 294 return CodeGenUtils.classFromNamespaceAndClassName(namespace,matcher.group(2)); 295 }else 296 throw new IllegalArgumentException("invalid stubClassName"); 297 } 298 299 /** 300 * 将指定的变量名下划线用 {@value #underscore}替换返回stub类中的变量名 301 * @param name 302 * @return 303 */ 304 public String toStubName(String name){ 305 Assert.notNull(name, "name"); 306 return name.replace("_", underscore); 307 } 308 /** 309 * @return typeNameMap 310 */ 311 public Map<String, String> getTypeNameMap() { 312 return typeNameMap; 313 } 314 315 /** 316 * @return refClassPropertiesMap 317 */ 318 public Map<Class<?>, Map<String, PropertyDescriptor>> getRefClassPropertiesMap() { 319 return refClassPropertiesMap; 320 } 321 322 boolean isPointer(String stubClassName){ 323 Assert.notEmpty(stubClassName, "stubClassName"); 324 return stubClassName.endsWith("*"); 325 } 326 /** 327 * 返回指定属性的类型 328 * @param prop 329 * @return 330 */ 331 public static Class<?> getClassOfProperty(PropertyDescriptor prop){ 332 Assert.notNull(prop,"prop"); 333 Method method = prop.getReadMethod(); 334 if(null==method) 335 throw new IllegalArgumentException(String.format("not found read method for %s",prop.getName())); 336 return method.getReturnType(); 337 } 338 /** 339 * 获取stubClass中指定属性prop的类型描述 340 * @param stubClassName 341 * @param prop 342 * @return 343 */ 344 public Entry<String, String> getStubPropertyDefine(String stubClassName,String prop){ 345 Assert.notEmpty(stubClassName, "className"); 346 Assert.notEmpty(prop, "prop"); 347 Map<String, String> properties = stubClassProppertiesMap.get(stubClassName); 348 //String stubPropName=stubClassName.replace("_", underscore); 349 for( Entry<String, String> entry:properties.entrySet()){ 350 if(entry.getKey().matches("^"+prop+"_?$")) 351 return entry; 352 } 353 throw new IllegalArgumentException(String.format("not found property %s for %s",prop,stubClassName)); 354 } 355 /** 356 * 返回stub类型中的属性名在引用类型(refClass)对应的{@link PropertyDescriptor}对象 357 * @param refClass 引用类型 358 * @param stubProp stub类型中的属性名 359 * @return 360 */ 361 public PropertyDescriptor getPropertyDescriptor(Class<?> refClass,String stubProp){ 362 Assert.notNull(refClass, "refClass"); 363 Assert.notEmpty(stubProp, "stubProp"); 364 Map<String, PropertyDescriptor> properties = refClassPropertiesMap.get(refClass); 365 if(null==properties) 366 throw new IllegalArgumentException(String.format("%s not a reference class(不是引用类型)",refClass.getName())); 367 String stubPropName=stubProp.replace(underscore, "_"); 368 for( Entry<String, PropertyDescriptor> entry:properties.entrySet()){ 369 if(stubPropName.matches("^"+entry.getKey()+"_?$")) 370 return entry.getValue(); 371 } 372 throw new IllegalArgumentException(String.format("not found property %s for %s",stubProp,refClass.getName())); 373 } 374 /** 375 * java类名转为cpp的类名(包括namespace) 376 * @param className 377 * @return 378 */ 379 public static String toCppFullName(String className){ 380 Assert.notEmpty(className, "className"); 381 return className.replaceAll("\\.", "::"); 382 } 383 /** 384 * @param clazz 385 * @return 386 * @see #toCppFullName(String) 387 */ 388 public static String toCppFullName(Class<?> clazz){ 389 Assert.notNull(clazz, "className"); 390 return toCppFullName(clazz.getName()); 391 } 392 /** 393 * java基本数据类型与cpp类型的映射表 394 */ 395 private static final Map<Class<?>, String> BASE_TYPE_MAP = new HashMap<Class<?>, String>() { 396 /** 397 * 398 */ 399 private static final long serialVersionUID = 1L; 400 { 401 put(void.class,"void"); 402 put(int.class,"int"); 403 put(long.class,"long"); 404 put(byte.class,"char"); 405 put(double.class,"double"); 406 put(float.class,""); 407 put(char.class,"char"); 408 put(short.class,"short"); 409 put(boolean.class,"bool"); 410 put(Integer.class,"std::shared_ptr<int>"); 411 put(Long.class,"std::shared_ptr<long>"); 412 put(Byte.class,"std::shared_ptr<char>"); 413 put(Double.class,"std::shared_ptr<double>"); 414 put(Float.class,"std::shared_ptr<float>"); 415 put(Character.class,"std::shared_ptr<<char>"); 416 put(Short.class,"std::shared_ptr<short>"); 417 put(Boolean.class,"std::shared_ptr<bool>"); 418 put(String.class,"std::string"); 419 put(byte[].class,"std::shared_ptr<std::vector<char>>"); 420 } 421 }; 422 /** 423 * 返回java类对应的cpp类名 424 * primitive类型void类型原样输出 425 * byte[]转为std::shared_ptr<std::vector<char>><br> 426 * String转为std::string<br> 427 * 数组类型用std::vector封装<br> 428 * 普通Object类型使用std::shared_ptr封装<br> 429 * @param clazz 430 * @param full 是否要包含namespace的cpp类名 431 * @return 432 */ 433 public static String toCppType(Class<?> clazz,boolean full){ 434 Assert.notNull(clazz, "clazz"); 435 if(BASE_TYPE_MAP.containsKey(clazz))return BASE_TYPE_MAP.get(clazz); 436 else if(clazz.isArray())return String.format("std::vector<%s>", toCppType(clazz.getComponentType(),full));// 递归 437 else return String.format("std::shared_ptr<%s>", full?toCppFullName(clazz):clazz.getSimpleName()); 438 } 439 /** 440 * @param clazz 441 * @return 442 * @see #toCppType(Class, boolean) 443 */ 444 public static String toCppType(Class<?> clazz){ 445 return toCppType(clazz,false); 446 } 447 /** 448 * 返回java类型对应的cpp参数类型 449 * @param clazz 450 * @param full 451 * @return 452 * @see #toCppType(Class, boolean) 453 */ 454 public static String toCppParameterType(Class<?> clazz,boolean full){ 455 String typeName = toCppType(clazz,full); 456 if(typeName.startsWith("std::")){ 457 typeName="const "+typeName+"&"; 458 } 459 return typeName; 460 } 461 /** 462 * @param clazz 463 * @return 464 * @see #toCppParameterType(Class, boolean) 465 */ 466 public static String toCppParameterType(Class<?> clazz){ 467 return toCppParameterType(clazz,false); 468 } 469 /** 470 * 返回基础缩进量 471 * @param packageName 472 * @return 473 */ 474 public static String getBaseIndentTabs(String packageName){ 475 if(Judge.isEmpty(packageName))return ""; 476 String[] names = packageName.split("\\."); 477 byte[] ba = new byte[names.length]; 478 for(int i=0;i<ba.length;++i)ba[i]='\t'; 479 return new String(ba,0,ba.length-1); 480 } 481 public static String getBaseIndentTabs(Class<?> clazz){ 482 Assert.notNull(clazz, "clazz"); 483 return getBaseIndentTabs(clazz.getPackage().getName()); 484 } 485 private static ThreadLocal<String[]> _packageName=new ThreadLocal<String[]>() ; 486 public static String namespaceBegin(String packageName){ 487 if(Judge.isEmpty(packageName))return ""; 488 String[] names = packageName.split("\\."); 489 _packageName.set(names); 490 StringBuilder builder=new StringBuilder(); 491 byte[] ba = new byte[names.length]; 492 for(int i=0;i<ba.length;++i)ba[i]='\t'; 493 for(int i=0;i<names.length;++i){ 494 String tabs = new String(ba,0,i); 495 builder.append(String.format("%snamespace %s\n%s{\n",tabs,names[i],tabs)); 496 } 497 return builder.toString(); 498 } 499 public static String namespaceBegin(Class<?> clazz){ 500 Assert.notNull(clazz, "clazz"); 501 return namespaceBegin(clazz.getPackage().getName()); 502 } 503 504 public static String namespaceEnd(){ 505 String[] names = _packageName.get(); 506 if(Judge.isEmpty(names))return ""; 507 StringBuilder builder=new StringBuilder(); 508 byte[] ba = new byte[names.length]; 509 for(int i=0;i<ba.length;++i)ba[i]='\t'; 510 for(int i=names.length;i>0;--i){ 511 String tabs = new String(ba,0,i-1); 512 builder.append(String.format("%s} /* namespace %s */\n",tabs,names[i-1])); 513 } 514 _packageName.set(null); 515 return builder.toString(); 516 } 517 518 /** 519 * @return stubClassProppertiesMap 520 */ 521 public Map<String, Map<String, String>> getStubClassProppertiesMap() { 522 return stubClassProppertiesMap; 523 } 524 public boolean isReferenceClass(Class<?>type){ 525 Assert.notNull(type, "type"); 526 return this.referenceClassMap.containsKey(type); 527 } 528 /** 529 * @return stubPrefix 530 */ 531 public String getStubPrefix() { 532 return stubPrefix; 533 } 534 /** 535 * @return stubFolder 536 */ 537 public File getStubFolder() { 538 return stubFolder; 539 } 540 public final String toStubExpectionClassName(Class<? extends Throwable> expection) { 541 Assert.notNull(expection, "expection"); 542 return String.format("%s__%s%s", getNamespacePrefix(this.serviceClass),this.serviceClass.getSimpleName(),expection.getSimpleName()); 543 } 544}