1 29 30 package com.caucho.boot; 31 32 import com.caucho.config.BuilderProgram; 33 import com.caucho.config.ConfigException; 34 import com.caucho.lifecycle.Lifecycle; 35 import com.caucho.log.RotateStream; 36 import com.caucho.management.server.AbstractManagedObject; 37 import com.caucho.management.server.ResinWatchdogMXBean; 38 import com.caucho.server.admin.HessianHmuxProxy; 39 import com.caucho.server.port.Port; 40 import com.caucho.util.*; 41 import com.caucho.Version; 42 import com.caucho.vfs.Path; 43 import com.caucho.vfs.QServerSocket; 44 import com.caucho.vfs.Vfs; 45 import com.caucho.vfs.WriteStream; 46 47 import java.io.File ; 48 import java.io.IOException ; 49 import java.io.InputStream ; 50 import java.io.OutputStream ; 51 import java.lang.reflect.*; 52 import java.net.*; 53 import java.util.ArrayList ; 54 import java.util.Date ; 55 import java.util.HashMap ; 56 import java.util.Map ; 57 import java.util.logging.Level ; 58 import java.util.logging.Logger ; 59 60 63 public class ResinWatchdog extends AbstractManagedObject 64 implements Runnable , ResinWatchdogMXBean 65 { 66 private static final L10N L 67 = new L10N(ResinWatchdog.class); 68 private static final Logger log 69 = Logger.getLogger(ResinWatchdog.class.getName()); 70 71 private ClusterConfig _cluster; 72 73 private String _id = ""; 74 75 private String []_argv; 76 77 private ArrayList <String > _jvmArgs = new ArrayList <String >(); 78 private ArrayList <String > _watchdogArgs = new ArrayList <String >(); 79 80 private boolean _is64bit; 81 private boolean _hasXss; 82 private boolean _hasXmx; 83 84 private Path _pwd; 85 private Path _rootDirectory; 86 87 private Boot _jniBoot; 88 private String _userName; 89 private String _groupName; 90 91 private InetAddress _address; 92 private int _watchdogPort = 6600; 93 94 private ArrayList <Port> _ports = new ArrayList <Port>(); 95 96 private final Lifecycle _lifecycle = new Lifecycle(); 97 98 private long _shutdownWaitTime = 60000L; 99 100 private boolean _isVerbose; 101 102 private boolean _isSingle; 103 104 private Thread _thread; 105 106 private Date _initialStartTime; 108 private Date _lastStartTime; 109 private int _startCount; 110 111 ResinWatchdog(ClusterConfig cluster) 112 { 113 _pwd = Vfs.getPwd(); 114 115 _cluster = cluster; 116 117 try { 118 _address = InetAddress.getByName("127.0.0.1"); 119 } catch (Exception e) { 120 throw new ConfigException(e); 121 } 122 123 _is64bit = "64".equals(System.getProperty("sun.arch.data.model")); 124 } 125 126 public void setId(String id) 127 { 128 _id = id; 129 } 130 131 public String getId() 132 { 133 return _id; 134 } 135 136 public void setVerbose(boolean isVerbose) 137 { 138 _isVerbose = isVerbose; 139 } 140 141 public void setAddress(String address) 142 throws UnknownHostException 143 { 144 _address = InetAddress.getByName(address); 145 } 146 147 public InetAddress getAddress() 148 { 149 return _address; 150 } 151 152 public void setWatchdogPort(int port) 153 { 154 _watchdogPort = port; 155 } 156 157 public int getWatchdogPort() 158 { 159 return _watchdogPort; 160 } 161 162 public void addJvmArg(String arg) 163 { 164 _jvmArgs.add(arg); 165 166 if (arg.equals("-d64")) 167 _is64bit = true; 168 else if (arg.startsWith("-Xss")) 169 _hasXss = true; 170 else if (arg.startsWith("-Xmx")) 171 _hasXmx = true; 172 } 173 174 public void addWatchdogArg(String arg) 175 { 176 _watchdogArgs.add(arg); 177 } 178 179 public ArrayList <String > getJvmArgs() 180 { 181 return _jvmArgs; 182 } 183 184 187 public void addHttp(Port port) 188 throws ConfigException 189 { 190 _ports.add(port); 191 } 192 193 196 public void addProtocol(Port port) 197 throws ConfigException 198 { 199 _ports.add(port); 200 } 201 202 public void setUserName(String user) 203 { 204 _userName = user; 205 } 206 207 public void setGroupName(String group) 208 { 209 _groupName = group; 210 } 211 212 215 public void addBuilderProgram(BuilderProgram program) 216 { 217 } 218 219 public void startWatchdog(String []argv) 220 throws ConfigException, IOException 221 { 222 if (_userName != null && ! hasBoot()) { 223 throw new ConfigException(L.l("<user-name> requires Resin Professional and compiled JNI. Check the $RESIN_HOME/libexec or $RESIN_HOME/libexec64 directory for libresin.so and check for a valid license in $RESIN_HOME/licenses.")); 224 } 225 226 if (_groupName != null && ! hasBoot()) { 227 throw new ConfigException(L.l("<group-name> requires Resin Professional and compiled JNI. Check the $RESIN_HOME/libexec or $RESIN_HOME/libexec64 directory for libresin.so and check for a valid license in $RESIN_HOME/licenses.")); 228 } 229 230 WatchdogAPI watchdog = getProxy(); 231 232 try { 233 watchdog.start(argv); 234 } catch (ConfigException e) { 235 throw e; 236 } catch (IllegalStateException e) { 237 throw e; 238 } catch (Exception e) { 239 log.log(Level.FINE, e.toString(), e); 240 } 241 242 launchManager(argv); 243 } 244 245 public void stopWatchdog() 246 throws IOException 247 { 248 WatchdogAPI watchdog = getProxy(); 249 250 try { 251 watchdog.stop(getId()); 252 } catch (ConfigException e) { 253 throw e; 254 } catch (IllegalStateException e) { 255 throw e; 256 } catch (IOException e) { 257 throw new IllegalStateException (L.l("Can't connect to ResinWatchdogManager.\n{1}", 258 Version.VERSION, e.toString()), 259 e); 260 } catch (Exception e) { 261 log.log(Level.FINE, e.toString(), e); 262 } 263 } 264 265 public void restartWatchdog(String []argv) 266 throws IOException 267 { 268 try { 269 stopWatchdog(); 270 } catch (Exception e) { 271 log.log(Level.FINE, e.toString(), e); 272 } 273 274 startWatchdog(argv); 275 } 276 277 public boolean shutdown() 278 throws IOException 279 { 280 WatchdogAPI watchdog = getProxy(); 281 282 try { 283 return watchdog.shutdown(); 284 } catch (Exception e) { 285 log.log(Level.FINE, e.toString(), e); 286 287 return false; 288 } 289 } 290 291 private WatchdogAPI getProxy() 292 { 293 String url = ("hmux://" + getAddress().getHostAddress() 294 + ":" + getWatchdogPort() 295 + "/watchdog"); 296 297 HashMap <String ,Object > attr = new HashMap <String ,Object >(); 298 attr.put("host", "resin-admin"); 299 300 Path path = Vfs.lookup(url, attr); 301 302 return HessianHmuxProxy.create(path, WatchdogAPI.class); 303 } 304 305 public void launchManager(String []argv) 306 throws IOException 307 { 308 log.fine(this + " starting ResinWatchdogManager"); 309 310 Path resinHome = _cluster.getResin().getResinHome(); 311 Path resinRoot = _cluster.getResin().getRootDirectory(); 312 313 ProcessBuilder builder = new ProcessBuilder (); 314 315 builder.directory(new File (resinRoot.getNativePath())); 316 317 Map <String ,String > env = builder.environment(); 318 319 String classPath = ResinWatchdogManager.calculateClassPath(resinHome); 320 321 env.put("CLASSPATH", classPath); 322 323 if (_is64bit) { 324 env.put("LD_LIBRARY_PATH", 325 resinHome.lookup("libexec64").getNativePath()); 326 env.put("DYLD_LIBRARY_PATH", 327 resinHome.lookup("libexec64").getNativePath()); 328 } 329 else { 330 env.put("LD_LIBRARY_PATH", 331 resinHome.lookup("libexec").getNativePath()); 332 env.put("DYLD_LIBRARY_PATH", 333 resinHome.lookup("libexec").getNativePath()); 334 } 335 336 ArrayList <String > list = new ArrayList <String >(); 337 338 list.add(getJavaExe()); 339 list.add("-Djava.util.logging.manager=com.caucho.log.LogManagerImpl"); 340 list.add("-Djava.system.class.loader=com.caucho.loader.SystemClassLoader"); 341 list.add("-Djava.awt.headless=true"); 342 list.add("-Dresin.home=" + resinHome.getPath()); 343 344 if (! _hasXss) 345 list.add("-Xss1m"); 346 347 list.addAll(_watchdogArgs); 348 349 list.add("com.caucho.boot.ResinWatchdogManager"); 350 351 for (int i = 0; i < argv.length; i++) 352 list.add(argv[i]); 353 354 builder = builder.command(list); 355 356 builder.redirectErrorStream(true); 357 358 Process process = builder.start(); 359 360 InputStream stdIs = process.getInputStream(); 361 OutputStream stdOs = process.getOutputStream(); 362 363 stdIs.close(); 364 stdOs.close(); 365 } 366 367 public void start() 368 { 369 if (! _lifecycle.toActive()) 370 return; 371 372 registerSelf(); 373 374 _thread = new Thread (this, "watchdog-" + _id); 375 _thread.setDaemon(true); 376 377 _thread.start(); 378 } 379 380 public int startSingle(String []argv, Path rootDirectory) 381 { 382 if (! _lifecycle.toActive()) 383 return -1; 384 385 _argv = argv; 386 _rootDirectory = rootDirectory; 387 _isSingle = true; 388 389 _thread = new Thread (this, "watchdog-" + _id); 390 _thread.start(); 391 392 while (_lifecycle.isActive()) { 393 synchronized (_lifecycle) { 394 try { 395 _lifecycle.wait(60000); 396 } catch (Exception e) { 397 log.log(Level.FINER, e.toString(), e); 398 } 399 } 400 } 401 402 return 1; 403 } 404 405 408 public boolean start(String []argv, Path rootDirectory) 409 { 410 if (! _lifecycle.toActive()) 411 return false; 412 413 registerSelf(); 414 415 _argv = argv; 416 _rootDirectory = rootDirectory; 417 418 _thread = new Thread (this, "watchdog-" + _id); 419 420 _thread.start(); 421 422 return true; 423 } 424 425 public void stop() 426 { 427 if (! _lifecycle.toStop()) 428 return; 429 430 Thread thread = _thread; 431 _thread = null; 432 433 synchronized (_lifecycle) { 434 _lifecycle.toStop(); 435 436 _lifecycle.notifyAll(); 437 } 438 439 try { 440 unregisterSelf(); 441 } catch (Exception e) { 442 log.log(Level.WARNING, e.toString(), e); 443 } 444 } 445 446 public void run() 447 { 448 _initialStartTime = new Date (); 449 450 while (_lifecycle.isActive()) { 451 InputStream watchdogIs = null; 452 WriteStream jvmOut = null; 453 454 try { 455 watchdogIs = null; 456 457 ServerSocket ss = new ServerSocket(0, 5, 458 InetAddress.getByName("127.0.0.1")); 459 int port = ss.getLocalPort(); 460 461 Path resinHome = _cluster.getResin().getResinHome(); 462 Path rootDirectory = _cluster.getResin().getRootDirectory(); 463 464 if (! _isSingle) { 465 String name; 466 467 if ("".equals(_id)) 468 name = "jvm-default.log"; 469 else 470 name = "jvm-" + _id + ".log"; 471 472 Path jvmPath = rootDirectory.lookup("log/" + name); 473 474 try { 475 jvmPath.getParent().mkdirs(); 476 } catch (Exception e) { 477 log.log(Level.FINE, e.toString(), e); 478 } 479 480 RotateStream rotateStream = RotateStream.create(jvmPath); 481 rotateStream.init(); 482 jvmOut = rotateStream.getStream(); 483 } 484 else 485 jvmOut = Vfs.openWrite(System.out); 486 487 _lastStartTime = new Date (); 488 _startCount++; 489 490 if (! _isSingle) 491 log.info("starting Resin " + this); 492 493 Path pwd = _pwd; 496 497 Process process = createProcess(pwd, resinHome, rootDirectory, 498 port, jvmOut); 499 500 ss.setSoTimeout(60000); 501 502 Socket s = null; 503 try { 504 s = ss.accept(); 505 } catch (Exception e) { 506 } finally { 507 ss.close(); 508 } 509 510 if (s != null) 511 watchdogIs = s.getInputStream(); 512 513 InputStream stdIs = process.getInputStream(); 514 OutputStream stdOs = process.getOutputStream(); 515 516 byte []data = new byte[1024]; 517 int len; 518 boolean isLive = true; 519 int stdoutTimeoutMax = 10; 520 int stdoutTimeout = stdoutTimeoutMax; 521 522 while (isLive && _lifecycle.isActive()) { 523 int available = 0; 524 525 while ((available = stdIs.available()) > 0) { 526 len = stdIs.read(data, 0, data.length); 527 528 if (len <= 0) 529 break; 530 531 stdoutTimeout = stdoutTimeoutMax; 532 533 jvmOut.write(data, 0, len); 534 jvmOut.flush(); 535 } 536 537 try { 538 int status = process.exitValue(); 539 540 isLive = false; 541 } catch (IllegalThreadStateException e) { 542 } 543 544 try { 545 synchronized (_lifecycle) { 546 if (stdoutTimeout-- > 0) 547 _lifecycle.wait(100 * (stdoutTimeoutMax - stdoutTimeout)); 548 else 549 _lifecycle.wait(100 * stdoutTimeoutMax); 550 } 551 } catch (Exception e) { 552 } 553 } 554 555 try { 556 watchdogIs.close(); 557 } catch (Exception e) { 558 } 559 560 try { 561 stdOs.close(); 562 } catch (Exception e) { 563 } 564 565 long endTime = Alarm.getCurrentTime() + _shutdownWaitTime; 566 isLive = true; 567 568 log.info(this + " stopping Resin"); 569 570 while (isLive && Alarm.getCurrentTime() < endTime) { 571 try { 572 while (stdIs.available() > 0) { 573 len = stdIs.read(data, 0, data.length); 574 575 if (len <= 0) { 576 isLive = false; 577 break; 578 } 579 580 jvmOut.write(data, 0, len); 581 jvmOut.flush(); 582 } 583 } catch (IOException e) { 584 log.log(Level.FINER, e.toString(), e); 585 } 586 587 try { 588 int status = process.exitValue(); 589 590 isLive = false; 591 } catch (IllegalThreadStateException e) { 592 } 593 } 594 595 try { 596 stdIs.close(); 597 } catch (Exception e) { 598 } 599 600 if (isLive) { 601 try { 602 process.destroy(); 603 } catch (Exception e) { 604 log.log(Level.FINE, e.toString(), e); 605 } 606 } 607 608 try { 609 int status = process.waitFor(); 610 } catch (Exception e) { 611 log.log(Level.INFO, e.toString(), e); 612 } 613 } catch (Exception e) { 614 log.log(Level.INFO, e.toString(), e); 615 616 try { 617 Thread.sleep(5000); 618 } catch (Exception e1) { 619 } 620 } finally { 621 if (watchdogIs != null) { 622 try { 623 watchdogIs.close(); 624 } catch (IOException e) { 625 } 626 } 627 628 if (jvmOut != null && ! _isSingle) { 629 try { 630 jvmOut.close(); 631 } catch (IOException e) { 632 } 633 } 634 } 635 } 636 } 637 638 private Process createProcess(Path processPwd, 639 Path resinHome, 640 Path resinRoot, 641 int socketPort, 642 WriteStream out) 643 throws IOException 644 { 645 String classPath = ResinWatchdogManager.calculateClassPath(resinHome); 646 647 HashMap <String ,String > env = new HashMap <String ,String >(); 648 649 env.put("CLASSPATH", classPath); 650 651 if (_is64bit) { 652 env.put("LD_LIBRARY_PATH", 653 resinHome.lookup("libexec64").getNativePath()); 654 env.put("DYLD_LIBRARY_PATH", 655 resinHome.lookup("libexec64").getNativePath()); 656 } 657 else { 658 env.put("LD_LIBRARY_PATH", 659 resinHome.lookup("libexec").getNativePath()); 660 env.put("DYLD_LIBRARY_PATH", 661 resinHome.lookup("libexec").getNativePath()); 662 } 663 664 ArrayList <String > list = new ArrayList <String >(); 665 666 list.add(getJavaExe()); 667 list.add("-Djava.util.logging.manager=com.caucho.log.LogManagerImpl"); 668 list.add("-Djava.system.class.loader=com.caucho.loader.SystemClassLoader"); 669 list.add("-Djava.awt.headless=true"); 670 list.add("-Dresin.home=" + resinHome.getPath()); 671 672 if (! _hasXss) 673 list.add("-Xss1m"); 674 675 if (! _hasXmx) 676 list.add("-Xmx256m"); 677 678 for (String arg : getJvmArgs()) { 679 list.add(arg); 680 } 681 682 ArrayList <String > resinArgs = new ArrayList <String >(); 683 for (int i = 0; i < _argv.length; i++) { 684 if (_argv[i].startsWith("-J")) { 685 list.add(_argv[i].substring(2)); 686 } 687 else 688 resinArgs.add(_argv[i]); 689 } 690 691 list.add("com.caucho.server.resin.Resin"); 692 list.add("-socketwait"); 693 list.add(String.valueOf(socketPort)); 694 695 list.addAll(resinArgs); 696 697 if (_isVerbose) { 698 for (int i = 0; i < list.size(); i++) { 699 if (i > 0) 700 out.print(" "); 701 702 out.print(list.get(i)); 703 704 if (i + 1 < list.size()) 705 out.println(" \\"); 706 else 707 out.println(); 708 } 709 710 for (Map.Entry <String , String > envEntry : env.entrySet()) 711 out.println("" + envEntry.getKey() + ": " + envEntry.getValue()); 712 } 713 714 if (getJniBoot() != null) { 715 ArrayList <QServerSocket> boundSockets = new ArrayList <QServerSocket>(); 716 717 try { 718 if (_userName != null) { 719 for (int j = 0; j < _ports.size(); j++) { 720 Port port = _ports.get(j); 721 722 QServerSocket ss = port.bindForWatchdog(); 723 724 boundSockets.add(ss); 725 726 if (ss.setSaveOnExec()) { 727 list.add("-port"); 728 list.add(String.valueOf(ss.getSystemFD())); 729 list.add(String.valueOf(port.getAddress())); 730 list.add(String.valueOf(port.getPort())); 731 } 732 } 733 } 734 735 Process process = getJniBoot().exec(list, env, 736 processPwd.getNativePath(), 737 _userName, _groupName); 738 739 if (process != null) 740 return process; 741 } catch (Throwable e) { 742 log.log(Level.WARNING, e.toString(), e); 743 } finally { 744 for (int i = 0; i < boundSockets.size(); i++) { 745 try { 746 boundSockets.get(i).close(); 747 } catch (Throwable e) { 748 } 749 } 750 } 751 } 752 753 if (_userName != null) 754 throw new ConfigException(L.l("<user-name> requires Resin Professional and compiled JNI.")); 755 756 if (_groupName != null) 757 throw new ConfigException(L.l("<group-name> requires Resin Professional and compiled JNI.")); 758 759 ProcessBuilder builder = new ProcessBuilder (); 760 761 builder.directory(new File (processPwd.getNativePath())); 762 763 builder.environment().putAll(env); 764 765 builder = builder.command(list); 766 767 builder.redirectErrorStream(true); 768 769 return builder.start(); 770 } 771 772 private String getJavaExe() 773 { 774 Path javaHome = Vfs.lookup(System.getProperty("java.home")); 775 776 if (javaHome.getTail().equals("jre")) 777 javaHome = javaHome.getParent(); 778 779 if (javaHome.lookup("bin/javaw.exe").canRead()) 780 return javaHome.lookup("bin/javaw").getNativePath(); 781 else if (javaHome.lookup("bin/java.exe").canRead()) 782 return javaHome.lookup("bin/java").getNativePath(); 783 else if (javaHome.lookup("bin/java").canRead()) 784 return javaHome.lookup("bin/java").getNativePath(); 785 786 javaHome = Vfs.lookup(System.getProperty("java.home")); 787 788 if (javaHome.lookup("bin/javaw.exe").canRead()) 789 return javaHome.lookup("bin/javaw").getNativePath(); 790 else if (javaHome.lookup("bin/java.exe").canRead()) 791 return javaHome.lookup("bin/java").getNativePath(); 792 else if (javaHome.lookup("bin/java").canRead()) 793 return javaHome.lookup("bin/java").getNativePath(); 794 795 return "java"; 796 } 797 798 802 public String getName() 803 { 804 return getId(); 805 } 806 807 public String getType() 808 { 809 return "Watchdog"; 810 } 811 812 public String getState() 813 { 814 return _lifecycle.getStateName(); 815 } 816 817 public Date getInitialStartTime() 818 { 819 return _initialStartTime; 820 } 821 822 public Date getStartTime() 823 { 824 return _lastStartTime; 825 } 826 827 public int getStartCount() 828 { 829 return _startCount; 830 } 831 832 public String toString() 833 { 834 return "Watchdog[" + getId() + "]"; 835 } 836 837 private Boot getJniBoot() 838 { 839 if (_jniBoot != null) 840 return _jniBoot; 841 842 try { 843 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 844 845 Class cl = Class.forName("com.caucho.boot.JniBoot", false, loader); 846 847 Constructor ctor = cl.getConstructor(new Class [] { Path.class }); 848 849 _jniBoot = (Boot) ctor.newInstance(_cluster.getResin().getResinHome()); 850 } catch (ClassNotFoundException e) { 851 log.fine(e.toString()); 852 } catch (IllegalStateException e) { 853 log.fine(e.toString()); 854 } catch (Throwable e) { 855 log.log(Level.FINE, e.toString(), e); 856 } 857 858 return _jniBoot; 859 } 860 861 private boolean hasBoot() 862 { 863 try { 864 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 865 866 Class cl = Class.forName("com.caucho.boot.JniBoot", false, loader); 867 868 Method method = cl.getMethod("isValid", new Class [] { Path.class }); 869 870 return (Boolean ) method.invoke(null, _cluster.getResin().getResinHome()); 871 } catch (ClassNotFoundException e) { 872 log.finer(e.toString()); 873 } catch (IllegalStateException e) { 874 log.fine(e.toString()); 875 } catch (Throwable e) { 876 log.log(Level.FINE, e.toString(), e); 877 } 878 879 return false; 880 } 881 882 886 894 public static void main(String []argv) 895 { 896 try { 897 ResinBoot boot = new ResinBoot(argv); 898 899 while (boot.start()) { 900 try { 901 synchronized (boot) { 902 boot.wait(5000); 903 } 904 } catch (Throwable e) { 905 } 906 } 907 } catch (ConfigException e) { 908 System.out.println(e.getMessage()); 909 } catch (Exception e) { 910 e.printStackTrace(); 911 } 912 } 913 914 } 915 | Popular Tags |