Java tutorial
/* * Copyright 2014 TWO SIGMA OPEN SOURCE, LLC * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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.twosigma.beaker.kdb; import com.twosigma.beaker.kdb.utils.ErrorGobbler; import com.twosigma.beaker.kdb.utils.KdbOutputHandler; import org.apache.commons.lang3.SystemUtils; import java.io.File; import java.util.ArrayList; import java.util.List; /** * Wraps a kdb process. */ public final class KdbProcess extends Thread { // Environment variable names. private static final String QHOME = "QHOME"; private static final String QLIC = "QLIC"; private static final String BEAKER_CORE_PASSWORD = "beaker_core_password"; private static final String BEAKER_CORE_PORT = "beaker_core_port"; private static final String SESSION_ID = "session_id"; // Kdb configuration. private final String qhome; private final String qbin; // Session id. private final String sessionId; // The port to have kdb listen on. private final int kdbPort; // interface for stdout and error private KdbOutputHandler outputHandler; private ErrorGobbler errorGobbler; /** * Create a new KdbProcess. * * @param sessionId the session id (for namespace access). * @param kdbPort the port for kdb to listen on. */ public KdbProcess(String sessionId, int kdbPort, String qh) throws Exception { super("kdb-" + sessionId + ":" + kdbPort); this.sessionId = sessionId; this.kdbPort = kdbPort; if (qh == null) { qhome = System.getenv(QHOME); } else { qhome = qh; } // Try to find the q binary. if (qhome == null) { throw new Exception("QHOME is not set"); } { // Get OS-specific candidates. List<String> binaries = new ArrayList<>(); if (SystemUtils.IS_OS_WINDOWS) { binaries.add("w64/q.exe"); binaries.add("w32/q.exe"); } else if (SystemUtils.IS_OS_MAC_OSX) { binaries.add("m64/q"); binaries.add("m32/q"); } else if (SystemUtils.IS_OS_LINUX) { binaries.add("l64/q"); binaries.add("l32/q"); } else { throw new Exception("Unsupported operating system"); } String bin = null; for (String s : binaries) { String f = qhome + File.separator + s; if (new File(f).canExecute()) { bin = f; break; } } if (bin == null) { throw new Exception("Cannot find q binary"); } else { qbin = bin; } } // Beaker calls destroy() on us, so add a shutdown hook to // cleanly shut down kdb at the end. Runtime.getRuntime().addShutdownHook(new Thread("kdb-killer") { @Override public void run() { KdbProcess.this.interrupt(); } }); } @Override public void run() { try { runImpl(); } catch (Exception e) { // TODO e.printStackTrace(); } } public KdbOutputHandler getOutputHandler() { return outputHandler; } public ErrorGobbler getErrorHandler() { return errorGobbler; } private void runImpl() throws Exception { // Guess at QLIC if it's not set. String qlic = System.getenv(QLIC); if (qlic == null) { qlic = qhome + File.separator + "k4.lic"; } // Start kdb. Process kdbProcess = Runtime.getRuntime().exec(new String[] { qbin, "-p", Integer.toString(kdbPort) }, new String[] { QHOME + "=" + qhome, QLIC + "=" + qlic, BEAKER_CORE_PASSWORD + "=" + System.getenv(BEAKER_CORE_PASSWORD), BEAKER_CORE_PORT + "=" + System.getenv(BEAKER_CORE_PORT), SESSION_ID + "=" + sessionId }); errorGobbler = new ErrorGobbler(kdbProcess.getErrorStream()); errorGobbler.start(); outputHandler = new KdbOutputHandler(kdbProcess.getInputStream()); outputHandler.start(); // Wait until kdb exits or we're interrupted. while (true) { try { // Wait for kdb to exit. kdbProcess.waitFor(); break; } catch (InterruptedException e) { // Interrupted - destroy the process. kdbProcess.destroy(); } } } }