/* * Copyright 2012 Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.core.dart2js; import com.google.dart.tools.core.DartCore; import com.google.dart.tools.core.model.DartSdkManager; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** * Start and manage the JSON server process. * * @coverage dart.tools.core.dart2js */ public class JsonServerProcess { private static final String STARTUP_TOKEN = "accepting connections"; // TODO: /** @return the path to the the JSON server script, relative to the SDK directory */ private static final String SERVER_PATH = "server/server.dart"; // 20 seconds private static final int MAX_STARTUP_WAIT = 20000; private int port; private Process process; private boolean serverRunning; public JsonServerProcess() { this(JsonServerManager.AUTO_BIND_PORT); } public JsonServerProcess(int port) { if (port == -1) { throw new IllegalArgumentException("port cannot == -1"); } this.port = port; } public int getPort() { return port; } public boolean isServerRunning() { return serverRunning; } public void killProcess() { if (process != null) { if (!hasStopped()) { process.destroy(); } process = null; } } public void startProcess() throws IOException { if (DartSdkManager.getManager().getSdk() == null) { throw new IOException("Unable to start json server - no dart-sdk found"); } ProcessBuilder builder = new ProcessBuilder(); builder.command( JsonServerManager.getDartVmExecutablePath(), SERVER_PATH, JsonServerManager.LOCALHOST_ADDRESS, Integer.toString(getPort())); builder.directory(DartSdkManager.getManager().getSdk().getLibraryDirectory()); builder.redirectErrorStream(true); process = builder.start(); final CountDownLatch latch = new CountDownLatch(1); // We need to consume the text the VM writes to its stdout / stderr so that the process does not // stall out trying to write to stdout. Thread readerThread = new Thread(new Runnable() { @Override public void run() { InputStream in = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); try { String line = reader.readLine(); while (line != null) { // if (DartCoreDebug.VERBOSE) { // DartCore.logInformation("json: [" + line.trim() + "]"); // } if (line.contains(STARTUP_TOKEN)) { serverRunning = true; port = parseServerPort(line); latch.countDown(); } // Log any internal json server problems if (line.equals("Unhandled exception:") || line.contains("Error: line")) { StringWriter message = new StringWriter(1000); PrintWriter writer = new PrintWriter(message); writer.println("Internal json server exception:"); while (true) { writer.println(line); if (message.getBuffer().length() > 2000) { break; } line = reader.readLine(); if (line == null || line.trim().length() == 0) { break; } // if (DartCoreDebug.VERBOSE) { // DartCore.logInformation("json: [" + line.trim() + "]"); // } } DartCore.logError(message.toString()); } line = reader.readLine(); } latch.countDown(); } catch (IOException exception) { // The process has terminated. latch.countDown(); } } }); readerThread.start(); // If we didn't start up normally, then throw an exception. try { latch.await(MAX_STARTUP_WAIT, TimeUnit.MILLISECONDS); } catch (InterruptedException exception) { } if (!serverRunning) { throw new IOException("unable to start json server"); } if (port == -1) { // Kill the server - it is unreachable at this point. killProcess(); throw new IOException("unable to retrieve server port"); } } protected boolean hasStopped() { if (process == null) { return true; } try { process.exitValue(); return true; } catch (IllegalThreadStateException exception) { // The process is still running. return false; } } protected int parseServerPort(String line) { // "STARTUP_TOKEN on host:port" final String START_TOKEN = " on "; int index = line.indexOf(START_TOKEN); if (index != -1) { line = line.substring(index + START_TOKEN.length()); } String[] strs = line.split(":"); if (strs.length >= 2) { try { return Integer.parseInt(strs[1]); } catch (NumberFormatException nfe) { } } return -1; } }