001: package com.teamkonzept.webman;
002:
003: import java.io.*;
004: import java.net.*;
005:
006: import com.teamkonzept.lib.*;
007: import com.teamkonzept.web.TKEvent;
008: import com.teamkonzept.web.TKHttpInterface;
009: import org.apache.log4j.Category;
010:
011: /**
012: * Starts an external java process.
013: * <p>
014: * To use the ProcessStarter create an instance of the class, then call "start".
015: * All output of the running process to stdout and stderr can be redirected
016: * to some PrintWriters specified in the constructor.
017: * @author $Author: gregor $
018: * @version $Revision: 1.16 $
019: */
020: public class ProcessStarter {
021:
022: /** Logging Category */
023: private static Category cat = Category
024: .getInstance(ProcessStarter.class.getName());
025:
026: /** Setze SocketTimeout deswegen so hoch (30 min), weil der Stager (d.h. SiteTransmitter)
027: u.U. über einen laaangen Zeitraum nichts an den ProcessStarter sendet (nämlich beim Übertragen der Site)
028: Bricht dann der ProcessStarter während dessen die Verbindung ab, wird der Socket also nicht mehr ausgelesen,
029: so schreibt der SiteTransmitter, wenn er die Site fertig übertragen hat, seine Ausgaben trotzdem weiter in den Socket
030: -> Buffer is irgendwann voll -> SiteTransmitter kann nich mehr schreiben -> SiteTransmitter hängt, wird nich mehr fertig
031: Da dieses Timeout ziemlich hoch ist, sollte versucht werden, es davon abhängig zu setzen, ob nun der Generator oder der
032: Stager gestartet wird*/
033: private final static int SOCKET_TIME_OUT = 1800000;
034:
035: /** ... */
036: private PrintWriter out;
037: private PrintWriter err;
038:
039: /**
040: * a tag used to identified a keep alive log message send from the
041: * generator
042: **/
043: public final static String KEEP_ALIVE_TAG = "-- keep alive --";
044:
045: /**
046: Constructor.
047: @param out a PrintWriter to which stdout messages of the process are redirected.
048: @param err a PrintWriter to which stderr messages of the process are redirected.
049: */
050: public ProcessStarter(PrintWriter out, PrintWriter err) {
051: this .out = out;
052: this .err = err;
053: }
054:
055: /**
056: Starts the process. The default classpath will be the the classpath as given
057: by System.getProperty("java.class.path") of the parent process.
058: @param startClassname the name of the java class to start (should
059: contain a main-method)
060: @param arguments the (optional) argument string given to the proces
061: @param addClasspath some additional classpath strings added to the default
062: classpath. The string should start with a classpath separator.
063: */
064: public boolean start(String startClassname, String arguments,
065: String addClasspath) {
066: Runtime rt = Runtime.getRuntime();
067: Process proc = null;
068: ServerSocket server = null;
069: try {
070: // Serversocket starten - welcher Port ???
071: server = new ServerSocket(0);
072: int port = server.getLocalPort();
073: String startCmd = genStartCmd(startClassname, arguments
074: + " port=" + port, addClasspath);
075: ProcessStarter.cat.debug(startCmd);
076: proc = rt.exec(startCmd);
077: Socket socket = server.accept();
078: //Kommentar zum SocketTimeout s.o.
079: socket.setSoTimeout(SOCKET_TIME_OUT);
080: InputStream in = socket.getInputStream();
081: BufferedReader reader = new BufferedReader(
082: new InputStreamReader(in));
083: String line;
084: while ((line = reader.readLine()) != null) {
085: if (!line.endsWith(KEEP_ALIVE_TAG)) {
086: out.println(line);
087: out.flush();
088: }
089:
090: /*
091: try {
092: Thread.sleep(100);
093: } catch (InterruptedException e) {
094: out.println(e.toString());
095: }
096: */
097: }
098: /*
099: reader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
100: while ((line = reader.readLine()) != null) {
101: err.println(line);
102: err.flush();
103: }
104: */
105: } catch (Exception e) {
106: ProcessStarter.cat.error("Processstarter.start", e);
107: } finally {
108: try {
109: server.close();
110: } catch (Exception e) {
111: ProcessStarter.cat.warn("Processstarter.start.finally",
112: e);
113: }
114: }
115: try {
116: if (proc != null)
117: proc.waitFor();
118: } catch (InterruptedException e) {
119: ProcessStarter.cat.warn("Processstarter.start.waitfor", e);
120: }
121:
122: int exitValue = proc.exitValue();
123:
124: proc.destroy();
125:
126: return exitValue == 0;
127: }
128:
129: /**
130: Determines the path to the webman classes.
131: The returned string is of the form:
132: "docRoot/WEB-INF/classes;docRoot/WEB-INF/classes/webman.zip"
133: ("WEB-INF/classes" accords with the Java Servlet 2.2 recommendation.)
134: @param docRoot the absolute path to the document root of the web application
135: */
136: // TODO: put this method in a a web application interface class?
137: public static String getWMClasspath(String docRoot) {
138: String pathSeparator = System.getProperty("path.separator");
139: String servletDir = pathSeparator + docRoot + File.separator
140: + "WEB-INF" + File.separator + "classes";
141: // there should be a WEB-INF/lib dir with some jar files...
142: String addPath = "";
143: String libDir = docRoot + "WEB-INF" + File.separator + "lib";
144: File d = new File(libDir);
145: libDir = pathSeparator + libDir + File.separator;
146: if (d.isDirectory()) {
147: String[] list = d.list();
148: for (int i = 0; i < list.length; i++)
149: if (list[i].endsWith(".jar")
150: || list[i].endsWith(".zip"))
151: addPath += libDir + list[i];
152: }
153: // hier Spezial fuer Tomcat 4.0 und servlet.jar
154: String privateDir = docRoot + "WEB-INF" + File.separator
155: + "lib" + File.separator + "webman-only";
156: libDir = pathSeparator + privateDir + File.separator;
157: d = new File(privateDir);
158: if (d.isDirectory()) {
159: String[] list = d.list();
160: for (int i = 0; i < list.length; i++)
161: if (list[i].endsWith(".jar")
162: || list[i].endsWith(".zip"))
163: addPath += libDir + list[i];
164: }
165: return servletDir + addPath;
166: }
167:
168: /**
169: Generates the start string which can be passed to the Runtime.exec() method.
170: @see ProcessStarter.start()
171: @return the generated string
172: */
173: protected String genStartCmd(String startClassname,
174: String arguments, String addClasspath) {
175: String javaHome = System.getProperty("java.home");
176: String javaProg = javaHome + File.separator + "bin"
177: + File.separator + "java";
178: String javaClasspath = System.getProperty("java.class.path")
179: + addClasspath;
180:
181: // Memory Einstellungen für den Start !
182: String memory = getMemoryProps();
183: String cmd = javaProg + memory + " -classpath " + javaClasspath
184: + " " + startClassname + " " + arguments;
185:
186: String os = System.getProperty("os.name");
187: if (os.equalsIgnoreCase("Windows NT")) {
188: cmd = "cmd.exe /c " + cmd;
189: }
190: ProcessStarter.cat.debug(cmd);
191: return cmd;
192: }
193:
194: private String getMemoryProps() {
195: try {
196: PropertyManager man = PropertyManager
197: .getPropertyManager("MEMORY_EXTERNAL");
198: String initial = man.getValue("INITIAL_HEAP", null);
199: String max = man.getValue("MAX_HEAP", null);
200: String back = " ";
201: if (initial != null)
202: back += "-Xms" + initial + " ";
203: if (max != null)
204: back += "-Xmx" + max + " ";
205: return back;
206: } catch (Exception e) {
207: ProcessStarter.cat
208: .info("getMemoryProps(): exception caught");
209: }
210: return "";
211: }
212:
213: /**
214: Determine if the host operating system is a Microsoft OS
215:
216: private static boolean isMSOS()
217: {
218: // TODO: Abfrage vollstaendig machen...
219: String os = System.getProperty("os.name");
220: if (os.equalsIgnoreCase("Windows NT") ||
221: os.equalsIgnoreCase("Windows 95") ||
222: os.equalsIgnoreCase("Windows 98")) {
223: return true;
224: }
225: else {
226: return false;
227: }
228: }*/
229:
230: }
|