001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.test.server.appserver.wasce1x;
005:
006: import org.apache.commons.io.FileUtils;
007: import org.apache.commons.io.IOUtils;
008: import org.codehaus.cargo.container.geronimo.internal.GeronimoUtils;
009: import org.codehaus.cargo.util.log.Logger;
010:
011: import com.tc.process.HeartBeatService;
012: import com.tc.process.StreamAppender;
013: import com.tc.test.TestConfigObject;
014: import com.tc.test.server.ServerParameters;
015: import com.tc.test.server.ServerResult;
016: import com.tc.test.server.appserver.AbstractAppServer;
017: import com.tc.test.server.appserver.AppServerParameters;
018: import com.tc.test.server.appserver.AppServerResult;
019: import com.tc.test.server.appserver.cargo.CargoLinkedChildProcess;
020: import com.tc.test.server.util.AppServerUtil;
021: import com.tc.util.Assert;
022: import com.tc.util.concurrent.ThreadUtil;
023:
024: import java.io.BufferedReader;
025: import java.io.File;
026: import java.io.FileOutputStream;
027: import java.io.FileReader;
028: import java.io.FileWriter;
029: import java.io.IOException;
030: import java.io.PrintWriter;
031: import java.util.Arrays;
032: import java.util.Iterator;
033: import java.util.LinkedList;
034: import java.util.List;
035: import java.util.Map;
036: import java.util.jar.Attributes;
037: import java.util.jar.JarFile;
038: import java.util.jar.Manifest;
039: import java.util.regex.Pattern;
040:
041: /**
042: * Wasce1x AppServer implementation
043: */
044: public final class Wasce1xAppServer extends AbstractAppServer {
045:
046: private static final String JAVA_CMD = System
047: .getProperty("java.home")
048: + File.separator + "bin" + File.separator + "java";
049: private static final String CONFIG_STORE = "config-store";
050: private static final String REPOSITORY = "repository";
051: private static final String VAR = "var";
052: private static final String BIN = "bin" + File.separator;
053: private static final String SERVER_JAR = BIN + "server.jar";
054: private static final String SHUTDOWN_JAR = BIN + "shutdown.jar";
055: private static final String DEPLOYER_JAR = BIN + "deployer.jar";
056: private static final String CONFIG_DIR = VAR + File.separator
057: + "config";
058: private static final String CONFIG = "config.xml";
059:
060: private static final String PORT_ATTRIB = ".*<attribute name=\"port\">\\d{4,6}</attribute>.*";
061: private static final String REDIRECT_PORT_ATTRIB = ".*<attribute name=\"redirectPort\">\\d{4,6}</attribute>.*";
062: private static final String PORT_PREFIX = "ort\">";
063: private static final String WEB_PORT_ATTRIB = ".*<gbean name=\"TomcatWebConnector\">.*";
064: private static final String RMI_PORT_ATTRIB = ".*<gbean name=\"RMIRegistry\">.*";
065: private static final String RMI_PORT_URL = ".*<attribute name=\"namingProviderUrl\">rmi://0.0.0.0:\\d{4,6}</attribute>.*";
066: private static final String RMI_PREFIX = "rmi://0.0.0.0:";
067: private static final String JMX_RMI = ".*<gbean name=\"JMXService\">.*";
068: private static final String JMX_RMI_PREFIX = "service:jmx:rmi://0.0.0.0:";
069: private static final String NAME_TEXT = ".*name=Geronimo.*";
070:
071: private static final String BASE_DIR_PROP = "org.apache.geronimo.base.dir";
072: private static final String TMP_DIR_PROP = "java.io.tmpdir";
073: private static final String ENDORSED_DIR_PROP = "java.endorsed.dirs";
074:
075: private static final String USERNAME = "system";
076: private static final String PASSWORD = "manager";
077:
078: private static final long STARTUP_TIMEOUT = 1000 * 240;
079:
080: private String className, classpath, endorsedPath, installPath;
081: private int rmiPort;
082: private ConsoleLogger consoleLogger;
083: private static final String LOG_CAT = "WASCE 1.0 STARTUP";
084: private String instanceName;
085:
086: public Wasce1xAppServer(Wasce1xAppServerInstallation installation) {
087: super (installation);
088: }
089:
090: private File getHome() {
091: return serverInstallDirectory();
092: }
093:
094: public synchronized ServerResult start(ServerParameters rawParams)
095: throws Exception {
096: TestConfigObject config = TestConfigObject.getInstance();
097: AppServerParameters params = (AppServerParameters) rawParams;
098: int port = AppServerUtil.getPort();
099: instanceName = params.instanceName();
100: final File instance = createInstance(params);
101: File home = getHome();
102: installPath = home.getCanonicalPath();
103: setProperties(params, port, instance);
104:
105: interpretJarManifest(new File(home + File.separator
106: + SERVER_JAR));
107: copyInstanceDirectories(home, instance);
108: parseConfig(new File(instance + File.separator + CONFIG_DIR),
109: port);
110:
111: final List cl = new LinkedList();
112: cl.add(JAVA_CMD);
113: String[] jvmArgs = params.jvmArgs().replaceAll("'", "").split(
114: "\\s");
115: for (int i = 0; i < jvmArgs.length; i++) {
116: if (!("" + jvmArgs[i]).trim().equals(""))
117: cl.add(jvmArgs[i]);
118: }
119:
120: cl.add("-D" + ENDORSED_DIR_PROP + "=" + endorsedPath);
121: cl.add("-D" + TMP_DIR_PROP + "=" + instance.getCanonicalPath()
122: + File.separator + VAR + File.separator + "temp");
123: cl
124: .add("-D" + BASE_DIR_PROP + "="
125: + instance.getCanonicalPath());
126: // cl.add("-Xmx128m");
127: // cl.add("-verbose:gc");
128: cl.add("-classpath");
129: cl.add(classpath + File.pathSeparatorChar
130: + config.linkedChildProcessClasspath());
131: cl.add(CargoLinkedChildProcess.class.getName());
132: cl.add(className);
133: cl.add(String.valueOf(HeartBeatService.listenPort()));
134: cl.add(instance.toString());
135: cl.add("--long"); // wasce args
136:
137: consoleLogger = new ConsoleLogger(params.instanceName());
138: consoleLogger.info(Arrays.asList(cl.toArray(new String[0]))
139: .toString(), LOG_CAT);
140:
141: final Logger logger = consoleLogger;
142: final String logFileName = new File(instance.getParent(),
143: instance.getName() + ".log").getAbsolutePath();
144:
145: Thread t = new Thread() {
146: public void run() {
147: FileOutputStream logFile = null;
148: try {
149: logFile = new FileOutputStream(logFileName);
150: Process process = Runtime.getRuntime().exec(
151: (String[]) cl.toArray(new String[0]), null,
152: instance);
153: StreamAppender appender = new StreamAppender(
154: logFile);
155: appender.writeInput(process.getErrorStream(),
156: process.getInputStream());
157: if (process.waitFor() != 0)
158: logger
159: .warn(
160: "Server exited with exit code other than 0",
161: LOG_CAT);
162: appender.finish();
163: } catch (Exception e) {
164: logger.warn("Server process failed", LOG_CAT);
165: e.printStackTrace();
166: } finally {
167: if (logFile != null) {
168: try {
169: logFile.close();
170: } catch (Exception e) {
171: e.printStackTrace();
172: }
173: }
174: }
175: }
176: };
177: t.start();
178: waitForStartup(port); // blocking
179: deployWars(params.wars());
180:
181: return new AppServerResult(port, this );
182: }
183:
184: private void waitForStartup(int port) throws Exception {
185: final ClassLoader prevLoader = Thread.currentThread()
186: .getContextClassLoader();
187: final long timeout = System.currentTimeMillis()
188: + STARTUP_TIMEOUT;
189:
190: GeronimoUtils utils = new GeronimoUtils();
191: ClassLoader geronimoLoader = utils
192: .createGeronimoURLClassloader(getHome());
193: Thread.currentThread().setContextClassLoader(geronimoLoader);
194: try {
195: while (System.currentTimeMillis() < timeout) {
196: boolean started = utils.isGeronimoStarted("localhost",
197: String.valueOf(rmiPort), USERNAME, PASSWORD);
198: if (started) {
199: return;
200: }
201: ThreadUtil.reallySleep(6000);
202: }
203:
204: throw new Exception("WASCE server failed to start in "
205: + STARTUP_TIMEOUT + " millis");
206: } finally {
207: Thread.currentThread().setContextClassLoader(prevLoader);
208: }
209: }
210:
211: private void deployWars(Map wars) throws Exception {
212: Assert.assertNotNull(wars);
213:
214: for (Iterator iter = wars.values().iterator(); iter.hasNext();) {
215: List cl = new LinkedList();
216: cl.add(JAVA_CMD);
217: cl.add("-jar");
218: cl.add(installPath + File.separator + DEPLOYER_JAR);
219: cl.add("--user");
220: cl.add(USERNAME);
221: cl.add("--password");
222: cl.add(PASSWORD);
223: cl.add("--port");
224: cl.add(String.valueOf(rmiPort));
225: cl.add("deploy");
226: cl.add(((File) iter.next()).toString());
227:
228: consoleLogger
229: .info("Deploying War: "
230: + Arrays.asList(cl.toArray(new String[0])),
231: LOG_CAT);
232:
233: Process process = Runtime.getRuntime().exec(
234: (String[]) cl.toArray(new String[0]));
235: StreamAppender appender = new StreamAppender(System.err);
236: appender.writeInput(process.getErrorStream(), process
237: .getInputStream());
238: if (process.waitFor() != 0)
239: throw new Exception("Failed to Deploy WAR: " + rmiPort);
240: appender.finish();
241: }
242: }
243:
244: public synchronized void stop() throws Exception {
245: Assert.assertTrue(rmiPort > 0);
246: StringBuffer cl = new StringBuffer(JAVA_CMD + " -jar ");
247: cl.append(installPath + File.separator + SHUTDOWN_JAR);
248: cl.append(" --user " + USERNAME + " --password " + PASSWORD
249: + " --port " + rmiPort);
250: Process process = Runtime.getRuntime().exec(cl.toString());
251: StreamAppender appender = new StreamAppender(System.err);
252: appender.writeInput(process.getErrorStream(), process
253: .getInputStream());
254: if (process.waitFor() != 0)
255: throw new Exception("Server Shutdown Failed: " + rmiPort);
256: appender.finish();
257: consoleLogger.info("Server shutdown: " + rmiPort, LOG_CAT);
258: }
259:
260: private void copyInstanceDirectories(File home, File instance)
261: throws IOException {
262: String sep = File.separator;
263: FileUtils.copyDirectory(new File(home + sep + CONFIG_STORE),
264: new File(instance + sep + CONFIG_STORE), false);
265: FileUtils.copyDirectory(new File(home + sep + REPOSITORY),
266: new File(instance + sep + REPOSITORY), false);
267: FileUtils.copyDirectory(new File(home + sep + VAR), new File(
268: instance + sep + VAR), false);
269: }
270:
271: private void parseConfig(File configDir, int port) throws Exception {
272: File tmpConfig = new File(configDir + File.separator
273: + "tmp_config.xml");
274: File config = new File(configDir + File.separator + CONFIG);
275: BufferedReader reader = new BufferedReader(new FileReader(
276: config));
277: PrintWriter writer = new PrintWriter(new FileWriter(tmpConfig));
278: String line;
279: boolean useServerPort = false;
280: boolean useRMIPort = false;
281:
282: while ((line = reader.readLine()) != null) {
283: if (Pattern.matches(RMI_PORT_ATTRIB, line)) {
284: rmiPort = AppServerUtil.getPort();
285: useRMIPort = true;
286: }
287: if (Pattern.matches(NAME_TEXT, line)) {
288: line = "name=Geronimo" + IOUtils.LINE_SEPARATOR
289: + "jvmRoute=" + instanceName;
290: }
291: if (Pattern.matches(WEB_PORT_ATTRIB, line))
292: useServerPort = true;
293: if (Pattern.matches(RMI_PORT_URL, line)) {
294: line = line.replaceAll(RMI_PREFIX + "\\d{4,6}",
295: RMI_PREFIX + rmiPort);
296: }
297: if (Pattern.matches(JMX_RMI, line)) {
298: writer.println(line);
299: line = reader.readLine();
300: String s = "/jndi/rmi://0.0.0.0:";
301: line = line.replaceAll(JMX_RMI_PREFIX + "\\d{4,6}" + s
302: + "\\d{4,6}", JMX_RMI_PREFIX
303: + AppServerUtil.getPort() + s + rmiPort);
304: }
305: if (Pattern.matches(PORT_ATTRIB, line)) {
306: int newPort = (useServerPort) ? port : AppServerUtil
307: .getPort();
308: if (useRMIPort) {
309: newPort = rmiPort;
310: useRMIPort = false;
311: }
312: if (useServerPort)
313: useServerPort = false;
314: line = line.replaceAll(PORT_PREFIX + "\\d{4,6}",
315: PORT_PREFIX + newPort);
316:
317: } else if (Pattern.matches(REDIRECT_PORT_ATTRIB, line)) {
318: line = line.replaceAll(PORT_PREFIX + "\\d{4,6}",
319: PORT_PREFIX + AppServerUtil.getPort());
320: }
321: writer.println(line);
322: }
323: reader.close();
324: writer.flush();
325: writer.close();
326: config.delete();
327: tmpConfig.renameTo(config);
328: }
329:
330: private void interpretJarManifest(File jar) throws IOException {
331: String absPath = jar.getCanonicalFile().getParentFile()
332: .getParent().replace('\\', '/');
333: Manifest manifest = new JarFile(jar).getManifest();
334: Attributes attrib = manifest.getMainAttributes();
335: String classPathAttrib = attrib.getValue("Class-Path");
336: classpath = jar + File.pathSeparator;
337: classpath += classPathAttrib.replaceAll("^\\.\\.", absPath)
338: .replaceAll("\\s\\.\\.",
339: File.pathSeparatorChar + absPath);
340: endorsedPath = absPath + File.separator
341: + attrib.getValue("Endorsed-Dirs");
342: className = attrib.getValue("Main-Class");
343: }
344: }
|