1 29 30 package com.caucho.java; 31 32 import com.caucho.bytecode.ByteCodeParser; 33 import com.caucho.bytecode.JavaClass; 34 import com.caucho.bytecode.SourceDebugExtensionAttribute; 35 import com.caucho.loader.DynamicClassLoader; 36 import com.caucho.log.Log; 37 import com.caucho.make.Make; 38 import com.caucho.server.util.CauchoSystem; 39 import com.caucho.util.CharBuffer; 40 import com.caucho.util.L10N; 41 import com.caucho.vfs.Encoding; 42 import com.caucho.vfs.IOExceptionWrapper; 43 import com.caucho.vfs.Path; 44 import com.caucho.vfs.ReadStream; 45 import com.caucho.vfs.WriteStream; 46 47 import java.io.IOException ; 48 import java.util.ArrayList ; 49 import java.util.Arrays ; 50 import java.util.logging.Level ; 51 import java.util.logging.Logger ; 52 import java.util.regex.Pattern ; 53 54 57 public class JavaCompiler { 58 static final L10N L = new L10N(JavaCompiler.class); 59 static final Logger log = Log.open(JavaCompiler.class); 60 61 private static final Object LOCK = new Object (); 62 63 private ClassLoader _loader; 65 66 private String _compiler; 68 69 private String _sourceExt = ".java"; 70 71 private Path _classDir; 72 private Path _sourceDir; 73 74 private boolean _compileParent = true; 75 76 private String _extraClassPath; 77 private String _classPath; 78 79 protected String _charEncoding; 80 protected ArrayList <String > _args; 81 82 private int _maxBatch = 64; 83 protected long _maxCompileTime = 120 * 1000L; 84 85 private JavaCompiler() 86 { 87 } 88 89 94 public static JavaCompiler create() 95 { 96 return create(Thread.currentThread().getContextClassLoader()); 97 } 98 99 104 public static JavaCompiler create(ClassLoader loader) 105 { 106 JavacConfig config = JavacConfig.getLocalConfig(); 107 108 String javac = config.getCompiler(); 109 110 JavaCompiler javaCompiler = new JavaCompiler(); 111 112 if (loader == null) 113 loader = Thread.currentThread().getContextClassLoader(); 114 115 javaCompiler.setClassLoader(loader); 116 javaCompiler.setCompiler(javac); 117 javaCompiler.setArgs(config.getArgs()); 118 javaCompiler.setEncoding(config.getEncoding()); 119 javaCompiler.setMaxBatch(config.getMaxBatch()); 120 121 return javaCompiler; 122 } 123 124 128 public void setClassLoader(ClassLoader loader) 129 { 130 _loader = loader; 131 } 132 133 137 public ClassLoader getClassLoader() 138 { 139 return _loader; 140 } 141 142 145 public void setCompiler(String compiler) 146 { 147 _compiler = compiler; 148 } 149 150 153 public String getCompiler() 154 { 155 if (_compiler == null) 156 _compiler = "javac"; 157 158 return _compiler; 159 } 160 161 166 public void setClassDir(Path path) 167 { 168 try { 169 path.mkdirs(); 170 } catch (IOException e) { 171 } 172 173 _classDir = path; 174 } 175 176 179 Path getClassDir() 180 { 181 if (_classDir != null) 182 return _classDir; 183 else 184 return CauchoSystem.getWorkPath(); 185 } 186 187 190 String getClassDirName() 191 { 192 return getClassDir().getNativePath(); 193 } 194 195 200 public void setSourceDir(Path path) 201 { 202 _sourceDir = path; 203 } 204 205 208 public Path getSourceDir() 209 { 210 if (_sourceDir != null) 211 return _sourceDir; 212 else 213 return getClassDir(); 214 } 215 216 219 String getSourceDirName() 220 { 221 return getSourceDir().getNativePath(); 222 } 223 224 227 public void setSourceExtension(String ext) 228 { 229 _sourceExt = ext; 230 } 231 232 235 public String getSourceExtension() 236 { 237 return _sourceExt; 238 } 239 240 244 public void setClassPath(String classPath) 245 { 246 _classPath = classPath; 247 } 248 249 252 public void setExtraClassPath(String classPath) 253 { 254 _extraClassPath = classPath; 255 } 256 257 public void setCompileParent(boolean compileParent) 258 { 259 _compileParent = compileParent; 260 } 261 262 265 public String getClassPath() 266 { 267 String classPath = null; 269 if (classPath != null) 270 return classPath; 271 272 if (classPath == null && _loader instanceof DynamicClassLoader) { 273 classPath = ((DynamicClassLoader) _loader).getClassPath(); 274 } 275 else if (classPath == null) 276 classPath = CauchoSystem.getClassPath(); 277 278 String srcDirName = getSourceDirName(); 279 String classDirName = getClassDirName(); 280 281 char sep = CauchoSystem.getPathSeparatorChar(); 282 283 if (_extraClassPath != null) 284 classPath = classPath + sep + _extraClassPath; 285 286 if (! srcDirName.equals(classDirName)) 288 classPath = srcDirName + sep + classPath; 289 classPath = classDirName + sep + classPath; 290 291 return classPath; 292 } 293 294 297 public void setArgs(String argString) 298 { 299 try { 300 if (argString != null) { 301 String []args = Pattern.compile("[\\s,]+").split(argString); 302 303 _args = new ArrayList <String >(); 304 305 for (int i = 0; i < args.length; i++) { 306 if (! args[i].equals("")) 307 _args.add(args[i]); 308 } 309 } 310 } catch (Exception e) { 311 log.log(Level.WARNING, e.toString(), e); 312 } 313 } 314 315 318 public ArrayList <String > getArgs() 319 { 320 return _args; 321 } 322 323 326 public void setEncoding(String encoding) 327 { 328 _charEncoding = encoding; 329 330 String javaEncoding = Encoding.getJavaName(encoding); 331 332 if ("ISO8859_1".equals(javaEncoding)) 333 _charEncoding = null; 334 } 335 336 339 public String getEncoding() 340 { 341 return _charEncoding; 342 } 343 344 347 public long getMaxCompileTime() 348 { 349 return _maxCompileTime; 350 } 351 352 355 public void setMaxCompileTime(long maxCompileTime) 356 { 357 _maxCompileTime = maxCompileTime; 358 } 359 360 363 public void setMaxBatch(int maxBatch) 364 { 365 _maxBatch = maxBatch; 366 } 367 368 371 public static String mangleName(String name) 372 { 373 boolean toLower = CauchoSystem.isCaseInsensitive(); 374 375 CharBuffer cb = new CharBuffer(); 376 cb.append("_"); 377 378 for (int i = 0; i < name.length(); i++) { 379 char ch = name.charAt(i); 380 381 if (ch == '/' || ch == CauchoSystem.getPathSeparatorChar()) { 382 if (i == 0) { 383 } 384 else if (cb.charAt(cb.length() - 1) != '.' && 385 (i + 1 < name.length() && name.charAt(i + 1) != '/')) 386 cb.append("._"); 387 } 388 else if (ch == '.') 389 cb.append("__"); 390 else if (ch == '_') 391 cb.append("_0"); 392 else if (Character.isJavaIdentifierPart(ch)) 393 cb.append(toLower ? Character.toLowerCase(ch) : ch); 394 else if (ch <= 256) 395 cb.append("_2" + encodeHex(ch >> 4) + encodeHex(ch)); 396 else 397 cb.append("_4" + encodeHex(ch >> 12) + encodeHex(ch >> 8) + 398 encodeHex(ch >> 4) + encodeHex(ch)); 399 } 400 401 if (cb.length() == 0) 402 cb.append("_z"); 403 404 return cb.toString(); 405 } 406 407 private static char encodeHex(int i) 408 { 409 i &= 0xf; 410 411 if (i < 10) 412 return (char) (i + '0'); 413 else 414 return (char) (i - 10 + 'a'); 415 } 416 417 public void setArgs(ArrayList <String > args) 418 { 419 if (args == null) 420 return; 421 if (_args == null) 422 _args = new ArrayList <String >(); 423 424 _args.addAll(args); 425 } 426 427 436 public void compile(String fileName, LineMap lineMap) 437 throws IOException , ClassNotFoundException 438 { 439 compile(fileName, lineMap, false); 440 } 441 442 451 public void compileIfModified(String fileName, LineMap lineMap) 452 throws IOException , ClassNotFoundException 453 { 454 compile(fileName, lineMap, true); 455 } 456 457 467 public void compile(String fileName, LineMap lineMap, 468 boolean ifModified) 469 throws IOException , ClassNotFoundException 470 { 471 if (_compileParent) { 472 try { 473 if (_loader instanceof Make) 474 ((Make) _loader).make(); 475 } catch (Exception e) { 476 throw new IOExceptionWrapper(e); 477 } 478 } 479 480 int p = fileName.lastIndexOf('.'); 481 String path = fileName.substring(0, p); 482 String javaName = path + _sourceExt; 483 Path javaPath = getSourceDir().lookup(javaName); 484 485 String className = path + ".class"; 486 Path classPath = getClassDir().lookup(className); 487 488 synchronized (LOCK) { 489 if (ifModified && 490 javaPath.getLastModified() <= classPath.getLastModified()) 491 return; 492 493 if (javaPath.canRead() && classPath.exists()) 494 classPath.remove(); 495 496 compileInt(new String [] { fileName }, lineMap); 497 498 } 504 } 505 506 511 public void compileBatch(String []files) 512 throws IOException , ClassNotFoundException 513 { 514 if (_compileParent) { 515 try { 516 if (_loader instanceof Make) 517 ((Make) _loader).make(); 518 } catch (Exception e) { 519 throw new IOExceptionWrapper(e); 520 } 521 } 522 523 if (files.length == 0) 524 return; 525 526 528 int batchCount = _maxBatch; 529 if (batchCount < 0) 530 batchCount = Integer.MAX_VALUE / 2; 531 else if (batchCount == 0) 532 batchCount = 1; 533 534 IOException exn = null; 535 536 ArrayList <String > uniqueFiles = new ArrayList <String >(); 537 for (int i = 0; i < files.length; i++) { 538 if (! uniqueFiles.contains(files[i])) 539 uniqueFiles.add(files[i]); 540 } 541 files = new String [uniqueFiles.size()]; 542 uniqueFiles.toArray(files); 543 544 synchronized (LOCK) { 545 for (int i = 0; i < files.length; i += batchCount) { 546 int len = files.length - i; 547 548 if (batchCount < len) 549 len = batchCount; 550 551 String []batchFiles = new String [len]; 552 553 System.arraycopy(files, i, batchFiles, 0, len); 554 555 Arrays.sort(batchFiles); 556 557 try { 558 compileInt(batchFiles, null); 559 } catch (IOException e) { 560 if (exn == null) 561 exn = e; 562 else 563 log.log(Level.WARNING, e.toString(), e); 564 } 565 } 566 } 567 568 if (exn != null) 569 throw exn; 570 } 571 572 protected void compileInt(String []path, LineMap lineMap) 573 throws IOException , JavaCompileException 574 { 575 AbstractJavaCompiler compiler; 576 577 for (int i = 0; i < path.length; i++) 578 log.config("Compiling " + path[i]); 579 580 if (_compiler.equals("internal")) 581 compiler = new InternalCompiler(this); 582 else if (_compiler.equals("eclipse")) 583 compiler = new EclipseCompiler(this); 584 else if (_compiler.equals("groovyc")) 585 compiler = new GroovyCompiler(this); 586 else 587 compiler = new ExternalCompiler(this); 588 589 compiler.setPath(path); 590 compiler.setLineMap(lineMap); 591 592 Thread thread = new Thread (compiler); 594 595 thread.start(); 596 597 synchronized (compiler) { 598 long endTime = System.currentTimeMillis() + _maxCompileTime; 599 600 while (! compiler.isDone() && System.currentTimeMillis() <= endTime) { 601 try { 602 compiler.wait(endTime - System.currentTimeMillis()); 603 } catch (InterruptedException e) { 604 Thread.currentThread().interrupted(); 605 log.log(Level.WARNING, e.toString(), e); 606 } 607 } 608 } 609 610 if (! compiler.isDone()) { 611 log.warning("compilation timed out"); 612 thread.interrupt(); 613 compiler.abort(); 614 } 615 616 Throwable exn = compiler.getException(); 617 618 if (exn == null) { 619 } 620 else if (exn instanceof IOException ) 621 throw (IOException ) exn; 622 else if (exn instanceof JavaCompileException) 623 throw (JavaCompileException) exn; 624 else if (exn instanceof RuntimeException ) 625 throw (RuntimeException ) exn; 626 else if (exn instanceof Error ) 627 throw (Error ) exn; 628 else 629 throw new IOExceptionWrapper(exn); 630 631 for (int i = 0; i < path.length; i++) { 632 Path javaPath = getSourceDir().lookup(path[i]); 633 634 if (! path[i].endsWith(".java")) 635 continue; 636 637 String className = path[i].substring(0, path[i].length() - 5) + ".class"; 638 Path classPath = getClassDir().lookup(className); 639 Path smapPath = getSourceDir().lookup(path[i] + ".smap"); 640 641 if (classPath.canRead() && smapPath.canRead()) 642 mergeSmap(classPath, smapPath); 643 } 644 } 645 646 public void mergeSmap(Path classPath, Path smapPath) 647 { 648 try { 649 log.fine("merging .smap for " + classPath.getTail()); 650 651 ByteCodeParser parser = new ByteCodeParser(); 652 JavaClass javaClass; 653 654 ReadStream is = classPath.openRead(); 655 try { 656 javaClass = parser.parse(is); 657 } finally { 658 is.close(); 659 } 660 661 CharBuffer smap = new CharBuffer(); 662 663 is = smapPath.openRead(); 664 try { 665 int ch; 666 667 while ((ch = is.read()) >= 0) { 668 smap.append((char) ch); 669 } 670 } finally { 671 is.close(); 672 } 673 674 SourceDebugExtensionAttribute attr; 675 676 attr = new SourceDebugExtensionAttribute(smap.toString()); 677 678 javaClass.addAttribute(attr); 679 680 WriteStream os = classPath.openWrite(); 681 try { 682 javaClass.write(os); 683 } finally { 684 os.close(); 685 } 686 } catch (Exception e) { 687 log.log(Level.WARNING, e.toString(), e); 688 } 689 } 690 } 691 | Popular Tags |