Java tutorial
/* * Copyright 2008 Alin Dreghiciu. * * 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 org.ops4j.pax.runner.platform; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.ops4j.io.Pipe; import org.ops4j.pax.runner.commons.Info; import org.ops4j.pax.runner.platform.internal.CommandLineBuilder; /** * Default Java Runner. * * @author Alin Dreghiciu (adreghiciu@gmail.com) * @since 0.6.1, December 09, 2008 */ public class DefaultJavaRunner implements StoppableJavaRunner { /** * Logger. */ private static final Log LOG = LogFactory.getLog(DefaultJavaRunner.class); /** * If the execution should wait for platform shutdown. */ private final boolean m_wait; /** * Framework process. */ private Process m_frameworkProcess; /** * Shutdown hook. */ private Thread m_shutdownHook; /** * Constructor. */ public DefaultJavaRunner() { this(true); } /** * Constructor. * * @param wait should wait for framework exis */ public DefaultJavaRunner(boolean wait) { m_wait = wait; } public synchronized void exec(final String[] vmOptions, final String[] classpath, final String mainClass, final String[] programOptions, final String javaHome, final File workingDirectory) throws PlatformException { exec(vmOptions, classpath, mainClass, programOptions, javaHome, workingDirectory, new String[0]); } /** * {@inheritDoc} */ public synchronized void exec(final String[] vmOptions, final String[] classpath, final String mainClass, final String[] programOptions, final String javaHome, final File workingDirectory, final String[] envOptions) throws PlatformException { if (m_frameworkProcess != null) { throw new PlatformException("Platform already started"); } final StringBuilder cp = new StringBuilder(); for (String path : classpath) { if (cp.length() != 0) { cp.append(File.pathSeparator); } cp.append(path); } final CommandLineBuilder commandLine = new CommandLineBuilder().append(getJavaExecutable(javaHome)) .append(vmOptions).append("-cp").append(cp.toString()).append(mainClass).append(programOptions); LOG.debug("Start command line [" + Arrays.toString(commandLine.toArray()) + "]"); try { LOG.debug("Starting platform process."); m_frameworkProcess = Runtime.getRuntime().exec(commandLine.toArray(), createEnvironmentVars(envOptions), workingDirectory); } catch (IOException e) { throw new PlatformException("Could not start up the process", e); } m_shutdownHook = createShutdownHook(m_frameworkProcess); Runtime.getRuntime().addShutdownHook(m_shutdownHook); LOG.debug("Added shutdown hook."); LOG.info("Runner has successfully finished his job!"); if (m_wait) { waitForExit(); } else { Info.println(); // print an empty line } } private String[] createEnvironmentVars(String[] envOptions) { List<String> env = new ArrayList<String>(); Map<String, String> getenv = System.getenv(); for (String key : getenv.keySet()) { env.add(key + "=" + getenv.get(key)); } if (envOptions != null) Collections.addAll(env, envOptions); return env.toArray(new String[env.size()]); } /** * {@inheritDoc} */ public void shutdown() { try { if (m_shutdownHook != null) { synchronized (m_shutdownHook) { if (m_shutdownHook != null) { LOG.debug("Shutdown in progress..."); Runtime.getRuntime().removeShutdownHook(m_shutdownHook); m_frameworkProcess = null; m_shutdownHook.run(); m_shutdownHook = null; LOG.info("Platform has been shutdown."); } } } } catch (IllegalStateException ignore) { // just ignore } } /** * Wait till the framework process exits. */ public void waitForExit() { synchronized (m_frameworkProcess) { try { LOG.debug("Waiting for framework exit."); Info.println(); // print an empty line m_frameworkProcess.waitFor(); shutdown(); } catch (Throwable e) { LOG.debug("Early shutdown.", e); shutdown(); } } } /** * Create helper thread to safely shutdown the external framework process * * @param process framework process * * @return stream handler */ private Thread createShutdownHook(final Process process) { LOG.debug("Wrapping stream I/O."); final Pipe errPipe = new Pipe(process.getErrorStream(), System.err).start("Error pipe"); final Pipe outPipe = new Pipe(process.getInputStream(), System.out).start("Out pipe"); final Pipe inPipe = new Pipe(process.getOutputStream(), System.in).start("In pipe"); return new Thread(new Runnable() { public void run() { Info.println(); // print an empty line LOG.debug("Unwrapping stream I/O."); inPipe.stop(); outPipe.stop(); errPipe.stop(); try { process.destroy(); } catch (Exception e) { // ignore if already shutting down } } }, "Pax-Runner shutdown hook"); } /** * Return path to java executable. * * @param javaHome java home directory * * @return path to java executable * * @throws PlatformException if java home could not be located */ static String getJavaExecutable(final String javaHome) throws PlatformException { if (javaHome == null) { throw new PlatformException("JAVA_HOME is not set."); } return javaHome + "/bin/java"; } }