001package gu.sql2java.generator; 002 003import java.io.File; 004import java.io.FileOutputStream; 005import java.io.IOException; 006import java.io.OutputStreamWriter; 007import java.io.PrintWriter; 008import java.io.StringWriter; 009import java.io.Writer; 010import java.lang.reflect.Field; 011import java.net.URLClassLoader; 012import java.util.ArrayList; 013import java.util.Collections; 014import java.util.Date; 015import java.util.Hashtable; 016import java.util.Iterator; 017import java.util.List; 018import java.util.Properties; 019import java.util.StringTokenizer; 020import java.util.Vector; 021import java.util.regex.Matcher; 022import java.util.regex.Pattern; 023 024import org.apache.velocity.VelocityContext; 025import org.apache.velocity.app.FieldMethodizer; 026import org.apache.velocity.app.Velocity; 027import org.apache.velocity.context.Context; 028import org.apache.velocity.exception.ParseErrorException; 029import org.apache.velocity.exception.ResourceNotFoundException; 030import org.apache.velocity.runtime.RuntimeSingleton; 031import org.apache.velocity.tools.generic.EscapeTool; 032import org.apache.velocity.tools.generic.SortTool; 033 034import com.google.common.base.Joiner; 035import com.google.common.base.Predicate; 036import com.google.common.base.Throwables; 037import com.google.common.collect.Iterables; 038import com.google.common.collect.Lists; 039import com.google.common.primitives.Primitives; 040 041import net.gdface.utils.ClassLoaderUtils; 042 043import static com.google.common.base.Preconditions.checkNotNull;; 044 045public class CodeWriter { 046 public static final String NEW_LINE = System.getProperty("line.separator"); 047 protected static final String DEFAULT_BINARY_TYPE = "byte[]"; 048 protected static final String DEFAULT_BITSTAE_TYPE = "int"; 049 private static final String VAR_EXT_PKG = "extensionPkg"; 050 protected static Properties props; 051 public static String MGR_CLASS; 052 protected static String dateClassName; 053 protected static String timeClassName; 054 protected static String timestampClassName; 055 /** type for byte array,default 'byte[]',defined in properties */ 056 public static String binaryClassName; 057 private static String bitStateClassName; 058 private static Class<?> bitStateClass; 059 private static int bitStateClassSize; 060 private static String bitStateConstSuffix; 061 protected static Database db; 062 protected static Hashtable<String, String> includeHash; 063 protected static Hashtable<String, String> excludeHash; 064 protected static String basePackage; 065 /** 参见 {@link Column#getPreparedStatementMethod(String, String)} */ 066 private static final ThreadLocal<Boolean> fillNull = new ThreadLocal<Boolean>(){ 067 @Override 068 protected Boolean initialValue() { 069 return true; 070 }}; 071 protected static String destDir; 072 protected static String optimisticLockType; 073 protected static String optimisticLockColumn; 074 public static String classPrefix; 075 protected VelocityContext vc; 076 public Table table; 077 protected VelocityContext current_vc; 078 String current_fullfilename = ""; 079 String current_filename = ""; 080 /** 是否保存当前文件标志,模板可以通过改写此标志,跳过模板生成 */ 081 boolean save_current_file = true; 082 private static String[] extLibdirs; 083 private static String[] extClasspath; 084 private static URLClassLoader extensionClassLoader; 085 public CodeWriter(Database db, Properties props) { 086 try { 087 CodeWriter.db = db; 088 CodeWriter.props = props; 089 dateClassName = getProperty("jdbc2java.date", "java.sql.Date"); 090 timeClassName = getProperty("jdbc2java.time", "java.sql.Time"); 091 timestampClassName = getProperty("jdbc2java.timestamp", "java.sql.Timestamp"); 092 binaryClassName = getProperty("binary.type", DEFAULT_BINARY_TYPE); 093 bitStateClassName = getProperty("bitstate.type", DEFAULT_BITSTAE_TYPE); 094 bitStateClass = bitStateClassOf(bitStateClassName); 095 bitStateClassSize = bitSizeOf(bitStateClass); 096 bitStateConstSuffix = constSuffixOf(bitStateClassName); 097 basePackage = getPropertyRequired("codewriter.package"); 098 extLibdirs = getPropertyExploded("extension.tools.libdirs"); 099 extClasspath = getPropertyExploded("extension.tools.classpath"); 100 classPrefix = props.getProperty("codewriter.classprefix"); 101 this.setDestinationFolder(getPropertyRequired("codewriter.destdir")); 102 excludeHash = this.setHash(props.getProperty("tables.exclude")); 103 if (excludeHash.size() != 0) { 104 System.out.println("Excluding the following tables: " + props.getProperty("tables.exclude")); 105 } 106 if ((CodeWriter.includeHash = this.setHash(props.getProperty("tables.include"))).size() != 0) { 107 System.out.println("Including only the following tables: " + props.getProperty("tables.include")); 108 } 109 optimisticLockType = props.getProperty("optimisticlock.type", "none"); 110 optimisticLockColumn = props.getProperty("optimisticlock.column"); 111 } catch (Exception e) { 112 System.err.println("Threw an exception in the CodeWriter constructor:" + e.getMessage()); 113 e.printStackTrace(); 114 } 115 } 116 117 public void setDestinationFolder(String destDir) throws Exception { 118 CodeWriter.destDir = destDir; 119 if (destDir == null) { 120 throw new Exception("Missing property: codewriter.destdir"); 121 } 122 File dir = new File(destDir); 123 try { 124 dir.mkdirs(); 125 } catch (Exception e) { 126 // empty catch block 127 } 128 if (!dir.isDirectory() || !dir.canWrite()) { 129 throw new Exception("Cannot write to: " + destDir); 130 } 131 } 132 133 private Hashtable<String, String> setHash(String str) { 134 if (str == null || str.trim().equals("")) { 135 return new Hashtable<String, String>(); 136 } 137 Hashtable<String, String> hash = new Hashtable<String, String>(); 138 StringTokenizer st = new StringTokenizer(str); 139 while (st.hasMoreTokens()) { 140 String val = st.nextToken().toLowerCase(); 141 hash.put(val, val); 142 } 143 return hash; 144 } 145 146 public boolean checkTable(Table newTable) throws Exception { 147 System.out.println(" checking table " + newTable.getName() + " ..."); 148 boolean error = false; 149 Column[] primaryKeys = newTable.getPrimaryKeys(); 150 if (newTable.getColumns().length == 0) { 151 System.err.println(" WARN : no column found !"); 152 error = false; 153 } 154 if (primaryKeys.length == 0) { 155 System.err.println(" WARN : No primary key is defined on table " + newTable.getName()); 156 System.err.println(" Tables without primary key are not fully supported"); 157 error = false; 158 } else if (primaryKeys.length > 1) { 159 System.err.print(" WARN : Composite primary key "); 160 for (int ii = 0; ii < primaryKeys.length; ++ii) { 161 System.err.print(primaryKeys[ii].getFullName() + ", "); 162 } 163 System.err.println(); 164 System.err.println(" Tables with composite primary key are not fully supported"); 165 } else { 166 String normalKey; 167 Column pk = primaryKeys[0]; 168 String pkName = pk.getName(); 169 if (!pkName.equalsIgnoreCase(normalKey = newTable.getName() + "_id")) { 170 System.err.println(" WARN : primary key should be of form <TABLE>_ID"); 171 System.err.println(" found " + pkName + " expected " + normalKey); 172 } 173 if (!pk.isColumnNumeric()) { 174 System.err.println(" WARN : primary key should be a number "); 175 System.err.println(" found " + pk.getJavaType()); 176 } 177 } 178 return error; 179 } 180 181 public void checkDatabase() throws Exception { 182 System.out.println("Checking database tables"); 183 boolean error = false; 184 Table[] tables = db.getTables(); 185 for (int i = 0; i < tables.length; ++i) { 186 if (!CodeWriter.authorizeProcess(tables[i].getName(), "tables.include", "tables.exclude") 187 || !this.checkTable(tables[i])) 188 continue; 189 error = true; 190 } 191 if (error) { 192 System.err.println( 193 " Failed : at least one of the mandatory rule for sql2java is followed by your schema."); 194 System.err.println(" Please check the documentation for more information"); 195 System.exit(-1); 196 } 197 System.out.println(" Passed."); 198 } 199 200 public synchronized void process() throws Exception { 201 if ("true".equalsIgnoreCase(getProperty("check.database"))) { 202 this.checkDatabase(); 203 } 204 if ("true".equalsIgnoreCase(getProperty("check.only.database"))) { 205 return; 206 } 207 Properties vprops = new Properties(); 208 vprops.put(Velocity.RESOURCE_LOADER,"class,file"); 209 vprops.put(Velocity.FILE_RESOURCE_LOADER_PATH, Joiner.on(',').join(this.getLoadingPathExt())); 210 vprops.put("file.resource.loader.class", Sql2javaFileResourceLoader.class.getName()); 211 212 vprops.put("class.resource.loader.description", "Velocity Classpath Resource Loader"); 213 vprops.put("class.resource.loader.class",Sql2javaClasspathResourceLoader.class.getName()); 214 vprops.put("class.resource.loader.prefix", Joiner.on(',').join(this.getClassLoadingPath())); 215 216 vprops.put(Velocity.VM_LIBRARY, "/templates/velocity/includes/macros.include.vm"); 217 vprops.put(Velocity.SET_NULL_ALLOWED, "true"); 218 vprops.put(Velocity.INPUT_ENCODING,"UTF-8"); 219 vprops.put(Velocity.OUTPUT_ENCODING,"UTF-8"); 220 Velocity.init(vprops); 221 this.vc = new VelocityContext(); 222 this.vc.put("CodeWriter", (Object) new FieldMethodizer((Object) this)); 223 this.vc.put("codewriter", (Object) this); 224 this.vc.put("esc", new EscapeTool()); 225 this.vc.put("sorter", new SortTool()); 226 this.vc.put("pkg", (Object) basePackage); 227 this.vc.put(VAR_EXT_PKG,getExtensionPkg()); 228 this.vc.put("isGeneral", Boolean.TRUE); 229 this.vc.put("pkgPath", (Object) basePackage.replace('.', '/')); 230 this.vc.put("strUtil",StringUtilities.getInstance()); 231 this.vc.put("fecha", new Date()); 232 this.current_vc = new VelocityContext((Context) this.vc); 233 generate("velocity.templates"); 234 // 如果定义了扩展模板的输出文件夹就用它替换destDir,用完后恢复 235 String destDirExt = getProperty("codewriter.destdir.extension",""); 236 String oldDest = destDir; 237 if(!destDirExt.isEmpty()){ 238 destDir = destDirExt; 239 } 240 try{ 241 // 生成外部扩展模板代码 242 generate("velocity.templates.extension"); 243 }finally{ 244 destDir = oldDest; 245 } 246 } 247 private void generate(String propName) throws Exception{ 248 if(null == getProperty(propName)) 249 return; 250 String[] schema_templates = this.getSchemaTemplates(propName); 251 for (int i = 0; i < schema_templates.length; ++i) { 252 this.writeComponent(schema_templates[i]); 253 } 254 if ("true".equalsIgnoreCase(getProperty("write.only.per.schema.templates"))) { 255 return; 256 } 257 Table[] tables = db.getTables(); 258 for (int i2 = 0; i2 < tables.length; ++i2) { 259 if (!CodeWriter.authorizeProcess(tables[i2].getName(), "tables.include", "tables.exclude")) 260 continue; 261 this.writeTable(tables[i2], propName); 262 } 263 } 264 private void writeTable(Table currentTable, String propName) throws Exception { 265 if (currentTable.getColumns().length == 0) { 266 return; 267 } 268 this.current_vc = new VelocityContext((Context) this.vc); 269 this.table = currentTable; 270 this.current_vc.put("table", (Object) currentTable); 271 String[] table_templates = this.getTableTemplates(propName); 272 for (int i = 0; i < table_templates.length; ++i) { 273 this.writeComponent(table_templates[i]); 274 } 275 } 276 277 private String clearHeadOfLoadPath(String templateName){ 278 checkNotNull(templateName); 279 List<String> loadPath = getLoadingPathExt(); 280 File template= new File(templateName); 281 for(String path:loadPath){ 282 File pfile = new File(path); 283 try { 284 if(template.getCanonicalPath().startsWith(pfile.getCanonicalPath())){ 285 String tmpl = template.getCanonicalPath().replace(pfile.getCanonicalPath(), "").replace('\\', '/'); 286 if(Velocity.resourceExists(tmpl)){ 287 return tmpl; 288 } 289 } 290 } catch (IOException e) { 291 throw new RuntimeException(e); 292 } 293 } 294 return templateName; 295 } 296 private static final String PREFIX_DESTDIR = "destdir."; 297 private static final String PREFIX_PACKAGE = "package."; 298 private String backupDestDir; 299 private String backupExtensionPkg; 300 /** 301 * 改变脚本支持上下文<br> 302 * 如果为模板定义了目标输出文件夹('destdir.${template name}'属性),则使用指定的位置作为{@link #destDir}<br> 303 * 如果为模板定义包名('package.${template name}'属性),则使用指定的值为引擎上下文的'extensionPkg'属性值 304 * @param templateName 模板文件名 305 */ 306 private void changeContextIfNeeded(String templateName){ 307 String name = templateName.substring(templateName.lastIndexOf("/") + 1); 308 backupDestDir = destDir; 309 backupExtensionPkg = (String) this.vc.get(VAR_EXT_PKG); 310 destDir = getProperty(PREFIX_DESTDIR + name, destDir); 311 this.vc.put(VAR_EXT_PKG,getProperty(PREFIX_PACKAGE + name, backupExtensionPkg)); 312 313 } 314 /** 315 * 恢复脚本支持上下文<br> 316 * 恢复{@link #destDir}的值,<br> 317 * 恢复引擎上下文的'extensionPkg'属性值<br> 318 * 需要与{@link #changeDestDirIfNeeded}成对调用 319 */ 320 private void restoreContext(){ 321 destDir = backupDestDir; 322 this.vc.put(VAR_EXT_PKG,backupExtensionPkg); 323 } 324 325 public void writeComponent(String templateName) throws Exception { 326 try { 327 templateName = clearHeadOfLoadPath(templateName); 328 System.out.println("Generating template " + templateName); 329 Velocity.getTemplate((String) templateName); 330 } catch (ResourceNotFoundException rnfe) { 331 System.err.println("Aborted writing component:" + templateName 332 + (this.table != null 333 ? new StringBuffer().append(" for table:").append(this.table.getName()).toString() 334 : "") 335 + " because Velocity could not find the resource."); 336 return; 337 } catch (ParseErrorException pee) { 338 System.err.println("Aborted writing component:" + templateName 339 + (this.table != null 340 ? new StringBuffer().append(" for table:").append(this.table.getName()).toString() 341 : "") 342 + " because there was a parse error in the resource.\n" + pee.getLocalizedMessage()); 343 return; 344 } catch (Exception e) { 345 System.err.println("Aborted writing component:" + templateName 346 + (this.table != null 347 ? new StringBuffer().append(" for table:").append(this.table.getName()).toString() 348 : "") 349 + " there was an error initializing the template.\n" + e.getLocalizedMessage()); 350 return; 351 } 352 StringWriter sw = new StringWriter(); 353 // reset 354 save_current_file = true; 355 this.current_vc.put("template", new File(templateName).getName()); 356 try { 357 changeContextIfNeeded(templateName); 358 Velocity.mergeTemplate((String) templateName, (String) "UTF-8", (Context) this.current_vc, (Writer) sw); 359 } finally { 360 restoreContext(); 361 } 362 if(save_current_file){ 363 System.out.println(" .... writing to " + this.current_fullfilename); 364 File file = new File(this.current_fullfilename); 365 new File(file.getParent()).mkdirs(); 366 PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(this.current_fullfilename),"UTF-8")); 367 // 换行符归一化:所有换行符替换为当前系统的换行符 368 String content = Pattern.compile("(\r\n|\n|\r)", Pattern.MULTILINE).matcher(sw.toString()).replaceAll(NEW_LINE); 369 writer.write(content); 370 writer.flush(); 371 writer.close(); 372 System.out.println(" " + this.current_filename + " done."); 373 }else 374 System.out.println(" " + this.current_filename + " skip."); 375 } 376 377 public void setCurrentFilename(String relpath_or_package, String fn) throws Exception { 378 this.current_filename = relpath_or_package.replace('.', File.separatorChar) + File.separatorChar + fn; 379 this.current_fullfilename = destDir + File.separatorChar + relpath_or_package.replace('.', File.separatorChar) 380 + File.separatorChar + fn; 381 UserCodeParser uc = new UserCodeParser(this.current_fullfilename); 382 this.current_vc.put("userCode", (Object) uc); 383 } 384 385 public void setCurrentJavaFilename(String relpath_or_package, String fn) throws Exception { 386 this.setCurrentFilename("java" + File.separatorChar + relpath_or_package, fn); 387 } 388 389 public void log(String logStr) { 390 System.out.println(" " + logStr); 391 } 392 393 public static String getClassPrefix() { 394 return classPrefix; 395 } 396 397 public Database getDb() { 398 return db; 399 } 400 401 public List<Table> getTables() { 402 Table[] tabs = db.getTables(); 403 ArrayList<Table> tables = new ArrayList<Table>(tabs.length); 404 for (int i = 0; i < tabs.length; ++i) { 405 tables.add(tabs[i]); 406 } 407 return tables; 408 } 409 410 public Table getTable(String tableName) { 411 return db.getTable(tableName); 412 } 413 414 public List<Table> getRelationTables() { 415 Table[] tabs = db.getTables(); 416 ArrayList<Table> tables = new ArrayList<Table>(tabs.length); 417 for (int i = 0; i < tabs.length; ++i) { 418 if (!tabs[i].isRelationTable()) 419 continue; 420 tables.add(tabs[i]); 421 } 422 return tables; 423 } 424 425 public String tableName() { 426 if (this.table == null) { 427 return ""; 428 } 429 return this.table.getName(); 430 } 431 432 public Table getTable() { 433 return this.table; 434 } 435 436 public static String getProperty(String key) { 437 String s = props.getProperty(key); 438 return s != null ? s.trim() : s; 439 } 440 441 public static String getProperty(String key, String defaultVal) { 442 String s = props.getProperty(key, defaultVal); 443 return s != null ? s.trim() : s; 444 } 445 public static String getPropertyRequired(String property) { 446 return checkNotNull(getProperty(property),"Missing property %s",property).trim(); 447 } 448 public static String[] getPropertyExploded(String key) { 449 return getPropertyExploded(key, ""); 450 } 451 452 public static List<String> getPropertyExplodedAsList(String key) { 453 return getPropertyExplodedAsList(key, ""); 454 } 455 456 public static List<String> getPropertyExplodedAsList(String mkey, String defaultValue) { 457 String v = getProperty(mkey); 458 if (v == null) { 459 v = defaultValue; 460 } 461 return CodeWriter.getExplodedStringAsList(v); 462 } 463 464 public static String[] getPropertyExploded(String mkey, String defaultValue) { 465 return getPropertyExplodedAsList(mkey,defaultValue).toArray(new String[0]); 466 } 467 468 public static List<String> getExplodedStringAsList(String value) { 469 if (value == null) { 470 return Collections.emptyList(); 471 } 472 ArrayList<String> al = new ArrayList<String>(); 473 StringTokenizer st = new StringTokenizer(value, " ,;\t"); 474 while (st.hasMoreTokens()) { 475 al.add(st.nextToken().trim()); 476 } 477 return al; 478 } 479 480 public static String[] getExplodedString(String value) { 481 return getExplodedStringAsList(value).toArray(new String[0]); 482 } 483 484 public static boolean getPropertyBoolean(String value){ 485 try{ 486 Pattern p = Pattern.compile("yes|true|on",Pattern.CASE_INSENSITIVE); 487 Matcher m = p.matcher(getProperty(value,"")); 488 return m.matches(); 489 }catch(Exception e){ 490 return false; 491 } 492 } 493 public List<String> getClassLoadingPath() { 494 return getPropertyExplodedAsList("velocity.templates.loadingpath", "/templates/velocity/includes,/templates/velocity"); 495 } 496 497 public List<String> getLoadingPathExt() { 498 return getPropertyExplodedAsList("velocity.templates.loadingpath.extension", ""); 499 } 500 public String[] getSchemaTemplates(String property) { 501 return this.getTemplates(property, true); 502 } 503 504 public String[] getTableTemplates(String property) { 505 return this.getTemplates(property, false); 506 } 507 508 public String[] getTemplates(String property, boolean perShema) { 509 Vector<String> files = new Vector<String>(); 510 // 支持多个模板路径 511 for(String path:getPropertyExploded(property)){ 512 this.recurseTemplate(files, path, perShema); 513 } 514 return files.toArray(new String[files.size()]); 515 } 516 517 public Vector<String> recurseTemplate(Vector<String> files, String folder, boolean perSchema) { 518 Iterable<String> dirEntries; 519 String schemaOrTable = perSchema ? "perschema" : "pertable"; 520 try { 521 String content = (String) RuntimeSingleton.getContent(folder).getData(); 522 String[] entires = content.split("\n"); 523 dirEntries = Iterables.filter(Lists.newArrayList(entires),new Predicate<String>() { 524 525 @Override 526 public boolean apply(String filename) { 527 if (filename.endsWith("/")) { 528 return true; 529 } 530 if (!filename.endsWith(".vm")) { 531 return false; 532 } 533 return CodeWriter.authorizeProcess(filename, "template.file.include", 534 "template.file.exclude"); 535 } 536 }); 537 } catch (ResourceNotFoundException e) { 538 return files; 539 } 540 541 for (Iterator<String> itor = dirEntries.iterator();itor.hasNext();) { 542 String file = itor.next(); 543 if (file.endsWith(".vm")) { 544 if (!CodeWriter.authorizeFile(folder, schemaOrTable)) 545 continue; 546 files.add(StringUtilities.combinePath(folder,file)); 547 continue; 548 } 549 this.recurseTemplate(files, StringUtilities.combinePath(folder,file), perSchema); 550 } 551 return files; 552 } 553 public static boolean authorizeProcess(String autorizePattern, String includeProperty, String excludeProperty) { 554 boolean accept = true; 555 String[] include = CodeWriter.getPropertyExploded(includeProperty); 556 String[] exclude = CodeWriter.getPropertyExploded(excludeProperty); 557 if (include.length != 0) { 558 if (CodeWriter.isInArray((String[]) include, (String) autorizePattern)) { 559 Velocity.getLog().info("Processing " + autorizePattern + " (specified in " + includeProperty + ")"); 560 return true; 561 } 562 accept = false; 563 } 564 if (exclude.length != 0 && CodeWriter.isInArray((String[]) exclude, (String) autorizePattern)) { 565 Velocity.getLog().info("Skipping " + autorizePattern + " (specified in " + excludeProperty + ")"); 566 return false; 567 } 568 return accept; 569 } 570 571 public static boolean folderContainsPattern(String folder, String[] patterns) { 572 if (patterns == null || folder == null) { 573 return false; 574 } 575 for (int i = 0; i < patterns.length; ++i) { 576 String pattern = "/" + patterns[i].toLowerCase() + "/"; 577 if (folder.toLowerCase().indexOf(pattern) == -1) 578 continue; 579 return true; 580 } 581 return false; 582 } 583 584 public static boolean authorizeFile(String folder, String schemaOrTable) { 585 if (folder.toLowerCase().indexOf(schemaOrTable.toLowerCase()) == -1) { 586 return false; 587 } 588 String[] include = CodeWriter.getPropertyExploded("template.folder.include"); 589 String[] exclude = CodeWriter.getPropertyExploded("template.folder.exclude"); 590 if (include.length != 0) { 591 if (CodeWriter.folderContainsPattern(folder, include)) { 592 return true; 593 } 594 return false; 595 } 596 if (exclude.length != 0) { 597 if (CodeWriter.folderContainsPattern(folder, exclude)) { 598 return false; 599 } 600 return true; 601 } 602 return true; 603 } 604 605 static { 606 MGR_CLASS = "Manager"; 607 classPrefix = ""; 608 } 609 610 public static String getBinaryClassName() { 611 return binaryClassName; 612 } 613 614 public static String getBitStateClassName() { 615 return bitStateClassName; 616 } 617 public static String getBitStateClassWrapName() { 618 return Primitives.wrap(bitStateClass).getSimpleName(); 619 } 620 public Class<?> getBitStateClass() { 621 return bitStateClass; 622 } 623 public static int getBitStateClassSize() { 624 return bitStateClassSize; 625 } 626 private static Class<?> bitStateClassOf(String className) { 627 switch(className){ 628 case "byte": 629 return byte.class; 630 case "short": 631 return short.class; 632 case "int": 633 return int.class; 634 case "long": 635 return long.class; 636 } 637 throw new IllegalArgumentException("INVALID class name for state type [" + className + "]"); 638 } 639 private static int bitSizeOf(Class<?> clazz) { 640 try { 641 // access field such as Integer.SIZE 642 Field size = Primitives.wrap(clazz).getField("SIZE"); 643 return size.getInt(null); 644 } catch (Exception e) { 645 Throwables.throwIfUnchecked(e); 646 throw new RuntimeException(e); 647 } 648 } 649 650 private static String constSuffixOf(String className) { 651 if("byte".equals(className)){ 652 return ""; 653 } 654 if("shot".equals(className)){ 655 return ""; 656 } 657 if("int".equals(className)){ 658 return ""; 659 } 660 if("long".equals(className)){ 661 return "L"; 662 } 663 664 throw new IllegalArgumentException("INVALID class name for state type [" + className + "]"); 665 } 666 667 public static String getBitStateConstSuffix() { 668 return bitStateConstSuffix; 669 } 670 public static int getBitStateMask() { 671 return (1<<Integer.numberOfTrailingZeros(bitStateClassSize))-1; 672 } 673 674 public static String getBitStateMaskHex() { 675 return "0x"+Integer.toHexString(getBitStateMask()); 676 } 677 public static int getBitStateClassShift() { 678 return Integer.numberOfTrailingZeros(bitStateClassSize); 679 } 680 public static boolean binaryIsByteBuffer() { 681 return !DEFAULT_BINARY_TYPE.equals(binaryClassName); 682 } 683 684 public static String getExtensionPkg(){ 685 String extPkg = getProperty("codewriter.package.extension",""); 686 return extPkg.isEmpty()?basePackage : extPkg; 687 } 688 689 public void setSaveCurrentFile(boolean save_current_fullfile) { 690 this.save_current_file = save_current_fullfile; 691 } 692 693 private static Class<?> loadClass(String classname,ClassLoader classLoader) throws ClassNotFoundException{ 694 return null == classLoader? 695 Class.forName(classname) : Class.forName(classname,true,classLoader); 696 } 697 /** 698 * 读取 'extension.tools.libdirs','extension.tools.classpath'分别对应{@code libdirs,classpath}参数<br> 699 * 如果上述property都没有定义则抛出异常 700 * @param classname 701 * @return 702 * @throws ClassNotFoundException 703 * @see {@link #loadExtensionClass(String, boolean, String[], String[])} 704 */ 705 public static Class<?> loadExtensionClass(String classname) throws ClassNotFoundException{ 706 return loadClass(classname,getExtensionClassLoader()); 707 } 708 private static synchronized URLClassLoader getExtensionClassLoader(){ 709 if(null ==extensionClassLoader){ 710 if( 0 == extLibdirs.length && 0 == extClasspath.length) 711 throw new IllegalStateException("property 'extension.tools.libdirs' and 'extension.tools.classpath' is all undefined"); 712 extensionClassLoader = ClassLoaderUtils.makeURLClassLoader(CodeWriter.class.getClassLoader(),true, extLibdirs, extClasspath); 713 } 714 return extensionClassLoader; 715 } 716 /** 717 * 使用当前类的class loader加载工具对象 718 * @param classname 719 * @return 720 * @throws ClassNotFoundException 721 * @throws InstantiationException 722 * @throws IllegalAccessException 723 */ 724 public Object loadTool(String classname) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ 725 Class<?> clazz = loadClass(classname,null); 726 return clazz.newInstance(); 727 } 728 729 private static boolean isInArray(String[] ar, String code) { 730 if (ar == null) { 731 return false; 732 } 733 for (int i = 0; i < ar.length; ++i) { 734 if (!code.equalsIgnoreCase(ar[i])) 735 continue; 736 return true; 737 } 738 return false; 739 } 740 741 /** 742 * 返回类的源文件位置 743 * @param baseDir 源文件夹 744 * @param clazz 745 * @return 746 */ 747 public static String getSourceFile(String baseDir,Class<?> clazz){ 748 if(null == baseDir || null == clazz )return null; 749 return baseDir + File.separatorChar + clazz.getName().replace('.', File.separatorChar) + ".java"; 750 } 751 public static Boolean getFillNull(){ 752 return fillNull.get(); 753 } 754 public static void setFillNull(Boolean fill){ 755 fillNull.set(fill); 756 } 757 758}