Monday, 10 August 2009

Starting JBoss And Tomcat Blocking Till Boot Is Completed

Our build is maven based. The jBPM project contains a bunch of modules. We have several integration test suites. Using the maven plugins to set up integration testing turned out to be insufficient. In order to keep our continuous integration builds platform independent we use a combination of ant scripts and mvn builds.

The strategy of our integration testing is that we start from a distribution that we unpack. Scripts like installing jBPM on JBoss are also interesting for our users. So they are included in the distribution. Then our Continuous Integration (CI) scripts leverage those scripts from the distribution. That way also those jBPM installer scripts also get validated by the CI.

For JBoss the CI build works as follows:
  • Build a distribution (mvn -Pdistro clean install)
  • Unzip the jBPM distribution file
  • Unzip JBoss
  • Use the install script from the distribution to install jBPM in JBoss
  • Customzie the jBPM installation for execution of the test suite
  • Start JBoss
  • Recreate the jBPM database schema
  • Run the integration test suite remotely
    • jBPM testsuite uses the plain jBPM API
    • Instead of executing the commands in the testrun itself, jBPM is configured to translate all invocations to remote EJB calls transparantly
  • Drop the jBPM database schema
  • Shut down JBoss
Since jBPM 3 we have an ant task that starts a JBoss instance in the background, but waits for the server boot to complete before the ant task finishes. That way we're sure that after the
task completes, that the server is up and running and ready to serve requests. We've done this in ant for a long time with an ant task and a Launcher. The StartJBossTask will create a Launcher thread, starts it and joins for it to complete.
public class StartJBossTask extends Task {

private static final String END_MESSAGE = " Started in ";

public void execute() throws BuildException {
try {
// build the command string
String command = ...build the command string...;

// launch the command and wait till the END_MESSAGE appears
Thread launcher = new Launcher(this, command, END_MESSAGE, null);
launcher.start();
launcher.join();

} catch (Exception e) {
e.printStackTrace();
}
}
...

The Launcher is a thread that spawns a process and listens to its InputStream till a certain message is displayed on the console by the spawned process.

public class Launcher extends Thread {

Task task;
String command;
String endMsg;
File dir;

public Launcher(Task task, String command, String endMsg, String dir) {
this.task = task;
this.command = command;
this.endMsg = endMsg;
this.dir = (dir!=null ? new File(dir) : null);
}

public void run() {
try {
task.log("starting '" + command + "'...");
Process process = new ProcessBuilder(command)
.directory(dir)
.start();

BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while (line.indexOf(endMsg) == -1) {
line = reader.readLine();
task.log(line);
}

task.log("'" + command + "' started.");
} catch (IOException e) {
throw new BuildException("couldn't start '" + command + "'", e);
}
}
}

Last week I wanted to do the same for Tomcat. When leveraging that code just the same way as works for JBoss, Tomcat only showed environment variables and then hanged:
Using CATALINA_BASE:   C:\Software\apache-tomcat-6.0.20
Using CATALINA_HOME: C:\Software\apache-tomcat-6.0.20
Using CATALINA_TMPDIR: C:\Software\apache-tomcat-6.0.20\temp
Using JRE_HOME: C:\Software\jdk1.5.0_11
Can you spot what is wrong ? Well... it took quite some time for me and that is why I'm sharing it here.

The clue is that Tomcat logging used not only standard output, but also standard error as output for logging. I could fix it by adding the .redirectErrorStream(true) like this:
      Process process = new ProcessBuilder(command)
.redirectErrorStream(true)
.directory(dir)
.start();
So now we have Tomcat up and running, we couldn't leverage the same remote EJB configuration as we did with JBoss. So for Tomcat CI, we leverage cactus and run the tests in the webapp.

Conclusion: When you fork a process in Java and you see it hangs unexpectedly, check if you're reading both input *and* its error stream. Or if it is for starting JBoss or Tomcat with ant, simply look in the jBPM sources.

2 comments:

  1. 3
    酒店兼差、西、日各餐廳廚師們臥虎藏龍,報名參加國內外廚藝 酒店兼職大賽,得到不錯的成績,中廚的蔣文正、日 酒店工作廚的板前長陳建憲及西廚的二廚李尚耕分別獲得香港國際 酒店上班美食大獎銅牌及美國美食創意廚藝比賽冠軍殊榮。


    老爺飯店 寒假打工明宮粵菜廳中餐廚師蔣文正,學習廚藝不過5年, 暑假打工但已多次參加2009年香港國際美食大獎,今年獲得西式烹調『餐前小食』銅牌獎, 酒店PT蔣師傅以『針菇芒果酪梨蟹肉塔』、『野菇海鮮凍佐乾燒醬 禮服酒店、『燻蝦釀芝麻海鮮球』 兼差等六道菜色參賽,他認為精緻的開胃菜是廚藝表現的極致,以營養學的方向 打工思考菜單的設計,從生活中枝末細微的地方啟發新的靈感,再不 台北酒店經紀斷的吸收最新的資訊,就是他持續成長的秘訣。


    此外,中山日本 酒店經紀料理板前長陳建憲及【咖啡廳】二廚李尚耕,共同組隊參加由 酒店打工美國在台協會」農業辦事處主辦的2009年美國美食喝花酒創意廚藝比賽,在四十多隊競爭中獲得冠軍的殊交際應酬。此次賽事以美國農產食材搭配台灣當地食材發揮創意為主題,兩位師傅以目前流行的養生輕食粉味風格,作為創意的發想,結合日本料理的概念,決賽時以創意的主菜及三道前菜,在酒店喝酒南港世貿食品展PK賽中獲得佳績。陳建憲板前長表示,比賽過程中最難克服的就是時間的掌控,因此在賽前與李師傅不斷的練習及改進,才能 酒店有此佳績。
    酒店經紀 酒店經紀

    ReplyDelete