1 28 29 package com.caucho.java; 30 31 import com.caucho.log.Log; 32 import com.caucho.server.util.CauchoSystem; 33 import com.caucho.util.Alarm; 34 import com.caucho.util.CharBuffer; 35 import com.caucho.vfs.*; 36 37 import java.io.IOException ; 38 import java.io.InputStream ; 39 import java.util.ArrayList ; 40 import java.util.logging.Level ; 41 import java.util.logging.Logger ; 42 43 46 public class ExternalCompiler extends AbstractJavaCompiler { 47 protected static final Logger log = Log.open(ExternalCompiler.class); 48 49 Process _process; 50 String _userPrefix; 51 InputStream _errorStream; 52 InputStream _inputStream; 53 54 boolean _isDead; 55 56 public ExternalCompiler(JavaCompiler compiler) 57 { 58 super(compiler); 59 } 60 61 67 protected void compileInt(String []paths, LineMap lineMap) 68 throws IOException 69 { 70 MemoryStream tempStream = new MemoryStream(); 71 WriteStream error = new WriteStream(tempStream); 72 _inputStream = null; 73 _errorStream = null; 74 boolean chdir = CauchoSystem.isUnix(); 75 76 _process = null; 77 78 try { 79 String javac = _compiler.getCompiler(); 80 String sourceExt = _compiler.getSourceExtension(); 81 82 String path = paths[0]; 83 int tail = path.length() - sourceExt.length(); 84 String className = path.substring(0, tail); 85 Path classFile = _compiler.getClassDir().lookup(className + ".class"); 86 87 ArrayList <String > argList = new ArrayList <String >(); 88 argList.add(javac); 89 90 ArrayList <String > args = _compiler.getArgs(); 91 if (args != null) 92 argList.addAll(args); 93 94 ArrayList <String > envList = new ArrayList (); 95 96 if (javac.endsWith("jikes") || javac.endsWith("jikes.exe")) { 97 argList.add("+E"); 101 102 chdir = false; 103 104 if (_compiler.getEncoding() != null) { 105 argList.add("-encoding"); 106 argList.add(_compiler.getEncoding()); 107 } 108 116 } 117 else if (_compiler.getEncoding() != null) { 118 String encoding = Encoding.getJavaName(_compiler.getEncoding()); 119 argList.add("-encoding"); 120 argList.add(encoding); 121 } 122 123 String classPath = normalizeClassPath(_compiler.getClassPath(), ! chdir); 124 125 envList.add("CLASSPATH=" + classPath); 126 127 if (_compiler.getCompiler().endsWith("groovyc")) { 128 argList.add("--classpath"); 129 argList.add(classPath); 130 } 131 else { 132 argList.add("-classpath"); 133 argList.add(classPath); 134 } 135 136 argList.add("-d"); 137 argList.add(normalizePath(_compiler.getClassDirName(), ! chdir)); 138 139 for (int i = 0; i < paths.length; i++) { 140 if (chdir) 141 argList.add(paths[i]); 142 else { 143 Path javaPath = _compiler.getSourceDir().lookup(paths[i]); 144 argList.add(javaPath.getNativePath()); 145 } 146 } 147 148 if (log.isLoggable(Level.FINE)) 149 log.fine(String.valueOf(argList)); 150 151 _process = executeCompiler(argList, envList, chdir); 152 if (_process != null) { 153 _inputStream = _process.getInputStream(); 154 _errorStream = _process.getErrorStream(); 155 } 156 157 163 164 int status = 666; 165 166 try { 167 waitForErrors(error, _inputStream, _errorStream); 168 169 if (_process != null) { 170 status = _process.waitFor(); 171 _process = null; 172 } 173 } catch (Throwable e) { 174 if (_isDead) 175 throw new JavaCompileException(L.l("The compilation has timed out. You can increase the timeout value by changing the max-compile-time.")); 176 177 throw new IOExceptionWrapper(e); 178 } 179 186 187 if (_process != null) { 188 status = 666; 189 } 190 191 error.close(); 192 tempStream.close(); 193 194 if (log.isLoggable(Level.FINE)) { 195 ReadStream read = tempStream.openRead(); 196 CharBuffer cb = new CharBuffer(); 197 int ch; 198 199 while ((ch = read.read()) >= 0) 200 cb.append((char) ch); 201 read.close(); 202 final String msg = cb.toString(); 203 204 new com.caucho.loader.ClassLoaderContext(_compiler.getClassLoader()) { 205 public void run() 206 { 207 log.fine(msg); 208 } 209 }; 210 } 211 212 ReadStream read = tempStream.openRead(); 213 ErrorParser parser; 214 215 parser = new JavacErrorParser(); 217 218 String errors = parser.parseErrors(read, lineMap); 219 read.close(); 220 221 if (errors != null) 222 errors = errors.trim(); 223 224 if (status == 0 && classFile.getLength() > 0) { 225 if (errors != null && ! errors.equals("")) { 226 final String msg = errors; 227 228 new com.caucho.loader.ClassLoaderContext(_compiler.getClassLoader()) { 229 public void run() 230 { 231 log.warning(msg); 232 } 233 }; 234 } 235 236 return; 237 } 238 239 if (errors == null || errors.equals("")) { 240 CharBuffer cb = new CharBuffer(); 241 242 if (status == 0) { 243 cb.append("Compilation for '" + className + "' did not generate a .class file.\n"); 244 cb.append("Make sure the `package' matches the directory.\n"); 245 } 246 else 247 cb.append("Unknown compiler error executing:\n"); 248 249 for (int i = 0; i < argList.size(); i++) 250 cb.append(" " + argList.get(i) + "\n"); 251 252 read = tempStream.openRead(); 253 int ch; 254 while ((ch = read.read()) >= 0) 255 cb.append((char) ch); 256 read.close(); 257 errors = cb.toString(); 258 } 259 else if (errors.indexOf("command not found") >= 0) { 260 throw new JavaCompileException(L.l("Resin can't execute the compiler `{0}'. This usually means that the compiler is not in the operating system's PATH or the compiler is incorrectly specified in the configuration. You may need to add the full path to <java compiler='{0}'/>.\n\n{1}", argList.get(0), errors)); 261 } 262 263 throw new JavaCompileException(errors); 264 } finally { 265 if (_inputStream != null) { 266 try { 267 _inputStream.close(); 268 } catch (Throwable e) { 269 } 270 } 271 272 if (_errorStream != null) { 273 try { 274 _errorStream.close(); 275 } catch (Throwable e) { 276 } 277 } 278 279 if (_process != null) { 280 try { 281 _process.destroy(); 282 } catch (Throwable e) { 283 log.log(Level.FINE, e.toString(), e); 284 } 285 } 286 287 tempStream.destroy(); 288 } 289 } 290 291 294 private void waitForErrors(WriteStream error, 295 InputStream inputStream, 296 InputStream errorStream) 297 throws IOException 298 { 299 byte []buffer = new byte[256]; 300 int stderrLen; 301 int stdoutLen; 302 303 if (inputStream == null || errorStream == null) 304 return; 305 306 do { 307 while ((stderrLen = errorStream.available()) > 0) { 308 stderrLen = errorStream.read(buffer, 0, buffer.length); 309 if (stderrLen <= 0) 310 break; 311 312 error.write(buffer, 0, stderrLen); 313 } 314 315 while ((stdoutLen = inputStream.available()) > 0) { 316 stdoutLen = inputStream.read(buffer, 0, buffer.length); 317 if (stdoutLen <= 0) 318 break; 319 320 error.write(buffer, 0, stdoutLen); 321 } 322 323 if (stderrLen < 0 && stdoutLen < 0) 324 return; 325 326 if (stderrLen == 0) { 327 stderrLen = errorStream.read(buffer, 0, buffer.length); 328 if (stderrLen > 0) 329 error.write(buffer, 0, stderrLen); 330 } 331 332 if (stderrLen < 0 && stdoutLen == 0) { 333 stdoutLen = inputStream.read(buffer, 0, buffer.length); 334 if (stdoutLen > 0) 335 error.write(buffer, 0, stdoutLen); 336 } 337 } while (! _isDead && (stderrLen >= 0 || stdoutLen >= 0)); 338 } 339 340 346 public void handleAlarm(Alarm alarm) 347 { 348 _isDead = true; 349 abort(); 350 } 351 352 355 public void abort() 356 { 357 if (_inputStream != null) { 358 try { 359 _inputStream.close(); 360 } catch (Throwable e) { 361 } 362 } 363 364 if (_errorStream != null) { 365 try { 366 _errorStream.close(); 367 } catch (Throwable e) { 368 } 369 } 370 371 if (_process != null) { 372 try { 373 _process.destroy(); 374 } catch (Throwable e) { 375 log.log(Level.FINE, e.toString(), e); 376 } 377 } 378 } 379 380 387 private Process executeCompiler(ArrayList <String > argList, 388 ArrayList <String > envList, 389 boolean chdir) 390 throws IOException 391 { 392 String []args; 393 394 if (chdir) { 398 CharBuffer cb = new CharBuffer(); 399 cb.append("cd "); 400 cb.append(_compiler.getSourceDirName()); 401 cb.append(";"); 402 for (int i = 0; i < argList.size(); i++) { 403 cb.append(" "); 404 cb.append(argList.get(i)); 405 } 406 args = new String [3]; 407 args[0] = "/bin/sh"; 408 args[1] = "-c"; 409 args[2] = cb.toString(); 410 } 411 else { 412 args = new String [argList.size()]; 413 argList.toArray(args); 414 } 415 416 String []envp = new String [envList.size()]; 417 envList.toArray(envp); 418 419 if (log.isLoggable(Level.FINE)) { 420 CharBuffer cb = CharBuffer.allocate(); 421 422 for (int i = 0; i < args.length; i++) { 423 if (i != 0) 424 cb.append(" "); 425 cb.append(args[i]); 426 } 427 log.fine(cb.close()); 428 } 429 430 Runtime runtime = Runtime.getRuntime(); 431 432 try { 433 return runtime.exec(args); 434 } catch (Exception e) { 435 throw new JavaCompileException(L.l("Resin can't execute the compiler `{0}'. This usually means that the compiler is not in the operating system's PATH or the compiler is incorrectly specified in the configuration. You may need to add the full path to <java compiler='{0}'/>.\n\n{1}", args[0], String.valueOf(e))); 436 } 437 } 438 439 442 String normalizeClassPath(String classPath, boolean generateRelative) 443 { 444 char sep = CauchoSystem.getPathSeparatorChar(); 445 int head = 0; 446 int tail = 0; 447 448 CharBuffer cb = CharBuffer.allocate(); 449 450 while (head < classPath.length()) { 451 tail = classPath.indexOf(sep, head); 452 if (tail < 0) 453 tail = classPath.length(); 454 455 if (tail > head) { 456 String segment = classPath.substring(head, tail); 457 458 segment = normalizePath(segment, generateRelative); 459 460 if (segment != null) { 461 if (cb.length() != 0) 462 cb.append(sep); 463 464 cb.append(segment); 465 } 466 } 467 468 head = tail + 1; 469 } 470 471 return cb.close(); 472 } 473 476 String normalizePath(String segment, boolean generateRelative) 477 { 478 if (_userPrefix == null) { 479 Path userPath = Vfs.lookup(CauchoSystem.getUserDir()); 480 char sep = CauchoSystem.getFileSeparatorChar(); 481 _userPrefix = userPath.getNativePath(); 482 483 if (_userPrefix.length() == 0 || 484 _userPrefix.charAt(_userPrefix.length() - 1) != sep) { 485 _userPrefix = _userPrefix + sep; 486 } 487 } 488 489 Path path = Vfs.lookup(segment); 490 491 String nativePath = path.getNativePath(); 492 493 if (! generateRelative) 494 return nativePath; 495 496 if (nativePath.startsWith(_userPrefix)) 497 nativePath = nativePath.substring(_userPrefix.length()); 498 499 if (nativePath.equals("")) 500 return "."; 501 else 502 return nativePath; 503 } 504 505 public static class CompilerThread implements Runnable { 506 private volatile boolean _isDone; 507 508 public void run() 509 { 510 try { 511 } finally { 512 _isDone = true; 513 514 synchronized (this) { 515 notifyAll(); 516 } 517 } 518 } 519 } 520 } 521 | Popular Tags |