watchdogprocess.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 639 行

JAVA
639
字号
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * *   Free Software Foundation, Inc. *   59 Temple Place, Suite 330 *   Boston, MA 02111-1307  USA * * @author Scott Ferguson */package com.caucho.boot;import com.caucho.config.ConfigException;import com.caucho.lifecycle.Lifecycle;import com.caucho.log.RotateStream;import com.caucho.server.port.Port;import com.caucho.util.*;import com.caucho.server.util.*;import com.caucho.vfs.Path;import com.caucho.vfs.QServerSocket;import com.caucho.vfs.Vfs;import com.caucho.vfs.WriteStream;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.lang.reflect.*;import java.net.*;import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import java.util.logging.Level;import java.util.logging.Logger;/** * Encapsulation of the process running resin. */class WatchdogProcess{  private static final L10N L = new L10N(WatchdogProcess.class);  private static final Logger log    = Logger.getLogger(WatchdogProcess.class.getName());  private static Boot _jniBoot;  private final String _id;  private final Watchdog _watchdog;  private final Lifecycle _lifecycle = new Lifecycle();  private ServerSocket _ss;  private Process _process;  WatchdogProcess(String id, Watchdog watchdog)  {    _id = id;    _watchdog = watchdog;  }  public void run()  {    if (! _lifecycle.toActive())      return;        WriteStream jvmOut = null;    try {      _ss = new ServerSocket(0, 5, InetAddress.getByName("127.0.0.1"));      int port = _ss.getLocalPort();            log.config(this + " starting Resin");      jvmOut = createJvmOut();      _process = createProcess(port, jvmOut);      if (_process != null) {	try {	  runInstance(jvmOut, _ss, _process);	} finally {	  destroy();	}      }    } catch (Exception e) {      log.log(Level.INFO, e.toString(), e);      try {	Thread.sleep(5000);      } catch (Exception e1) {      }    } finally {      if (jvmOut != null && ! _watchdog.isSingle()) {	try {	  jvmOut.close();	} catch (IOException e) {	}      }    }  }  void stop()  {    _lifecycle.toDestroy();  }  void destroy()  {    if (_process != null) {      try {	_process.destroy();      } catch (Exception e) {	log.log(Level.FINE, e.toString(), e);      }      try {	_process.waitFor();	_process = null;      } catch (Exception e) {	log.log(Level.INFO, e.toString(), e);      }    }  }  private void runInstance(WriteStream jvmOut,			   ServerSocket ss,			   Process process)    throws IOException  {    InputStream stdIs = null;     OutputStream stdOs = null;    InputStream watchdogIs = null;    Socket s = null;    try {      stdIs = process.getInputStream();      stdOs = process.getOutputStream();      ss.setSoTimeout(1000);	      boolean isLive = true;      int stdoutTimeoutMax = 10;      int stdoutTimeout = stdoutTimeoutMax;      byte []data = new byte[1024];      int len;      s = connectToChild(ss, stdIs, jvmOut, process, data);      if (s == null)	log.warning(this + " watchdog socket timed out");	        if (s != null)	watchdogIs = s.getInputStream();      runInstance(stdIs, jvmOut, process, data);      try {	if (watchdogIs != null)	  watchdogIs.close();      } catch (Exception e) {	log.log(Level.WARNING, e.toString(), e);      }      try {	if (s != null)	  s.close();      } catch (Exception e) {	log.log(Level.WARNING, e.toString(), e);      }      try {	stdOs.close();      } catch (Exception e) {	log.log(Level.WARNING, e.toString(), e);      }      log.info(this + " stopping Resin");      closeInstance(stdIs, jvmOut, process, data);    } finally {      if (watchdogIs != null) {	try {	  watchdogIs.close();	} catch (IOException e) {	}      }	      try {	if (s != null)	  s.close();      } catch (Exception e) {	log.log(Level.WARNING, e.toString(), e);      }    }  }  private WriteStream createJvmOut()    throws IOException  {    if (! _watchdog.isSingle()) {      String name;      String id = _watchdog.getId();      Path jvmPath = _watchdog.getLogPath();      try {	Path dir = jvmPath.getParent();	    	if (! dir.exists()) {	  dir.mkdirs();	  String userName = _watchdog.getUserName();	  if (userName != null)	    dir.changeOwner(userName);	  String groupName = _watchdog.getGroupName();	  if (groupName != null)	    dir.changeGroup(groupName);	}      } catch (Exception e) {	log.log(Level.FINE, e.toString(), e);      }      RotateStream rotateStream = RotateStream.create(jvmPath);      _watchdog.getConfig().logInit(rotateStream);      rotateStream.init();      return rotateStream.getStream();    }    else      return Vfs.openWrite(System.out);  }  private Socket connectToChild(ServerSocket ss,				InputStream stdIs,				WriteStream jvmOut,				Process process,				byte []data)    throws IOException  {    try {      Socket s = null;      for (int i = 0; i < 120 && s == null; i++) {	try {	  s = ss.accept();	} catch (SocketTimeoutException e) {	}	while (stdIs.available() > 0) {	  int len = stdIs.read(data, 0, data.length);	  if (len < 0)	    break;	      	  jvmOut.write(data, 0, len);	  jvmOut.flush();	}	try {	  int status = process.exitValue();	  if (s != null)	    s.close();	  return null;	} catch (IllegalThreadStateException e) {	}      }      return s;    } catch (Exception e) {      log.log(Level.WARNING, e.toString(), e);      return null;    } finally {      ss.close();    }  }  private void closeInstance(InputStream stdIs,			     WriteStream jvmOut,			     Process process,			     byte []data)  {    long endTime = Alarm.getCurrentTime() + _watchdog.getShutdownWaitTime();    boolean isLive = true;    while (isLive && Alarm.getCurrentTime() < endTime) {      try {	while (stdIs.available() > 0) {	  int len = stdIs.read(data, 0, data.length);	  if (len <= 0) {	    isLive = false;	    break;	  }	  	  jvmOut.write(data, 0, len);	  jvmOut.flush();	}      } catch (IOException e) {	log.log(Level.FINER, e.toString(), e);      }      try {	int status = process.exitValue();	isLive = false;      } catch (IllegalThreadStateException e) {      }    }    try {      stdIs.close();    } catch (Exception e) {    }  }  private void runInstance(InputStream stdIs,			   WriteStream jvmOut,			   Process process,			   byte []data)    throws IOException  {    boolean isLive = true;    int stdoutTimeoutMax = 10;    int stdoutTimeout = stdoutTimeoutMax;        while (isLive && _lifecycle.isActive()) {      while (stdIs.available() > 0) {	int len = stdIs.read(data, 0, data.length);	if (len <= 0)	  break;	    	stdoutTimeout = stdoutTimeoutMax;	    	jvmOut.write(data, 0, len);	jvmOut.flush();      }      try {	process.exitValue();	isLive = false;      } catch (IllegalThreadStateException e) {      }      try {	synchronized (_lifecycle) {	  if (stdoutTimeout-- > 0)	    _lifecycle.wait(100 * (stdoutTimeoutMax - stdoutTimeout));	  else	    _lifecycle.wait(100 * stdoutTimeoutMax);	}      } catch (Exception e) {      }    }  }  private Process createProcess(int socketPort, WriteStream out)    throws IOException  {    // watchdog/0210    // Path pwd = rootDirectory;    Path chroot = _watchdog.getChroot();    Path processPwd = _watchdog.getPwd();    Path resinHome = _watchdog.getResinHome();    Path resinRoot = _watchdog.getResinRoot();    ArrayList<String> classPathList = new ArrayList<String>();    classPathList.addAll(_watchdog.getJvmClasspath());    String classPath      = WatchdogArgs.calculateClassPath(classPathList, resinHome);    HashMap<String,String> env = new HashMap<String,String>();    env.putAll(System.getenv());        env.put("CLASSPATH", classPath);    if (_watchdog.is64bit()) {      appendEnvPath(env,                    "LD_LIBRARY_PATH",                    resinHome.lookup("libexec64").getNativePath());      appendEnvPath(env,                    "DYLD_LIBRARY_PATH",                    resinHome.lookup("libexec64").getNativePath());      appendEnvPath(env,                    "PATH",                    resinHome.lookup("win64").getNativePath());    }    else {      appendEnvPath(env,                    "LD_LIBRARY_PATH",                    resinHome.lookup("libexec").getNativePath());      appendEnvPath(env,                    "DYLD_LIBRARY_PATH",                    resinHome.lookup("libexec").getNativePath());      appendEnvPath(env,                    "PATH",                    resinHome.lookup("win32").getNativePath());    }    ArrayList<String> list = new ArrayList<String>();    list.add(_watchdog.getJavaExe());    list.add("-Djava.util.logging.manager=com.caucho.log.LogManagerImpl");        // This is needed for JMX to work correctly.    list.add("-Djava.system.class.loader=com.caucho.loader.SystemClassLoader");    // #2567    list.add("-Djavax.management.builder.initial=com.caucho.jmx.MBeanServerBuilderImpl");    list.add("-Djava.awt.headless=true");    list.add("-Dresin.home=" + resinHome.getFullPath());    if (! _watchdog.hasXss())      list.add("-Xss1m");        if (! _watchdog.hasXmx())      list.add("-Xmx256m");    if (! list.contains("-d32") && ! list.contains("-d64")	&& _watchdog.is64bit() && ! CauchoSystem.isWindows())      list.add("-d64");    for (String arg : _watchdog.getJvmArgs()) {      if (! arg.startsWith("-Djava.class.path"))	list.add(arg);    }    ArrayList<String> resinArgs = new ArrayList<String>();    String []argv = _watchdog.getArgv();    for (int i = 0; i < argv.length; i++) {      if (argv[i].equals("-conf")) {	// resin conf handled below	i++;      }      else if (argv[i].startsWith("-Djava.class.path=")) {	// IBM JDK startup issues      }      else if (argv[i].startsWith("-J")) {	list.add(argv[i].substring(2));      }      else if (argv[i].startsWith("-Djava.class.path")) {      }      else	resinArgs.add(argv[i]);    }        list.add("com.caucho.server.resin.Resin");        if (resinRoot != null) {      list.add("--root-directory");      list.add(resinRoot.getFullPath());    }    if (_watchdog.getResinConf() != null) {      list.add("-conf");      list.add(_watchdog.getResinConf().getNativePath());    }          list.add("-socketwait");    list.add(String.valueOf(socketPort));    list.addAll(resinArgs);    if (_watchdog.isVerbose()) {      for (int i = 0; i < list.size(); i++) {	if (i > 0)	  out.print("  ");		out.print(list.get(i));	if (i + 1 < list.size())	  out.println(" \\");	else	  out.println();      }      for (Map.Entry<String, String> envEntry : env.entrySet()) {	String key = envEntry.getKey();	String value = envEntry.getValue();	if ("CLASSPATH".equals(key)	    || "LD_LIBRARY_PATH".equals(key)	    || "DYLD_LIBRARY_PATH".equals(key)) {	  out.println(key + ": ");	  	  int len = (key + ": ").length();	  for (String v : value.split("[" + File.pathSeparatorChar + "]")) {	    for (int i = 0; i < len; i++)	      out.print(" ");	    out.println(v);	  }	}	else	  out.println("" + key + ": " + value);      }    }    Boot boot = getJniBoot();    if (boot != null) {      boot.clearSaveOnExec();            ArrayList<QServerSocket> boundSockets = new ArrayList<QServerSocket>();      try {	if (_watchdog.getUserName() != null) {	  for (Port port : _watchdog.getPorts()) {	    QServerSocket ss = port.bindForWatchdog();	    if (ss == null)	      continue;	    boundSockets.add(ss);	    	    if (ss.setSaveOnExec()) {	      list.add("-port");	      list.add(String.valueOf(ss.getSystemFD()));	      list.add(String.valueOf(port.getAddress()));	      list.add(String.valueOf(port.getPort()));	    }	  }	}	String chrootPath = null;	if (chroot != null)	  chrootPath = chroot.getNativePath();	Process process = boot.exec(list, env,				    chrootPath,				    processPwd.getNativePath(),				    _watchdog.getUserName(),				    _watchdog.getGroupName());	if (process != null)	  return process;      } catch (ConfigException e) {	log.warning(e.getMessage());      } catch (Throwable e) {	log.log(Level.WARNING, e.toString(), e);      } finally {	for (int i = 0; i < boundSockets.size(); i++) {	  try {	    boundSockets.get(i).close();	  } catch (Throwable e) {	  }	}      }    }    if (_watchdog.getUserName() != null) {      if (_watchdog.isSingle())	throw new ConfigException(L.l("<user-name> requires compiled JNI started with 'start'.  Resin cannot use <user-name> when started as a foreground process."));      else	throw new ConfigException(L.l("<user-name> requires compiled JNI."));    }          if (_watchdog.getGroupName() != null) {      if (_watchdog.isSingle())	throw new ConfigException(L.l("<group-name> compiled JNI started with 'start'.  Resin cannot use <group-name> when started as a foreground process."));      else	throw new ConfigException(L.l("<group-name> compiled JNI."));    }    ProcessBuilder builder = new ProcessBuilder();    builder.directory(new File(processPwd.getNativePath()));    builder.environment().putAll(env);        builder = builder.command(list);    builder.redirectErrorStream(true);    return builder.start();  }  private void appendEnvPath(Map<String,String> env,                             String prop,                             String value)  {    String oldValue = env.get(prop);    if (oldValue != null && ! "".equals(oldValue))      value = value + File.pathSeparator + oldValue;    env.put(prop, value);  }  public String toString()  {    return getClass().getSimpleName() + "[" + _watchdog + "," + _id + "]";  }  Boot getJniBoot()  {    if (_jniBoot != null)      return _jniBoot.isValid() ? _jniBoot : null;        try {      ClassLoader loader = Thread.currentThread().getContextClassLoader();            Class cl = Class.forName("com.caucho.bootjni.JniBoot", false, loader);      _jniBoot = (Boot) cl.newInstance();    } catch (ClassNotFoundException e) {      log.fine(e.toString());    } catch (IllegalStateException e) {      log.fine(e.toString());    } catch (Throwable e) {      log.log(Level.FINE, e.toString(), e);    }    return _jniBoot != null && _jniBoot.isValid() ? _jniBoot : null;  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?