/* * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.test.db; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Arrays; import org.h2.test.utils.SelfDestructor; import org.h2.util.Task; import org.h2.util.StringUtils; /** * A task that is run as an external process. This class communicates over * standard input / output with the process. The standard error stream of the * process is directly send to the standard error stream of this process. */ public class TaskProcess { private final TaskDef taskDef; private Process process; private BufferedReader reader; private BufferedWriter writer; /** * Construct a new task process. The process is not started yet. * * @param taskDef the task */ public TaskProcess(TaskDef taskDef) { this.taskDef = taskDef; } /** * Start the task with the given arguments. * * @param args the arguments, or null */ public void start(String... args) { try { String selfDestruct = SelfDestructor.getPropertyString(60); ArrayList<String> list = new ArrayList<String>(); list.add("java"); list.add(selfDestruct); list.add("-cp"); list.add("bin" + File.pathSeparator + "."); list.add(TaskDef.class.getName()); list.add(taskDef.getClass().getName()); if (args != null && args.length > 0) { list.addAll(Arrays.asList(args)); } String[] procDef = new String[list.size()]; list.toArray(procDef); traceOperation("start: " + StringUtils.arrayCombine(procDef, ' ')); process = Runtime.getRuntime().exec(procDef); copyInThread(process.getErrorStream(), System.err); reader = new BufferedReader(new InputStreamReader(process.getInputStream())); writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); String line = reader.readLine(); if (line == null) { throw new RuntimeException("No reply from process, command: " + StringUtils.arrayCombine(procDef, ' ')); } else if (line.startsWith("running")) { traceOperation("got reply: " + line); } else if (line.startsWith("init error")) { throw new RuntimeException(line); } } catch (Throwable t) { throw new RuntimeException("Error starting task", t); } } private static void copyInThread(final InputStream in, final OutputStream out) { new Task() { public void call() throws IOException { while (true) { int x = in.read(); if (x < 0) { return; } if (out != null) { out.write(x); } } } }.execute(); } /** * Receive a message from the process over the standard output. * * @return the message */ public String receive() { try { return reader.readLine(); } catch (IOException e) { throw new RuntimeException("Error reading", e); } } /** * Send a message to the process over the standard input. * * @param message the message */ public void send(String message) { try { writer.write(message + "\n"); writer.flush(); } catch (IOException e) { throw new RuntimeException("Error writing " + message, e); } } /** * Kill the process if it still runs. */ public void destroy() { process.destroy(); } /** * Trace the operation. Tracing is disabled by default. * * @param s the string to print */ private void traceOperation(String s) { // ignore } }