All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.codehaus.mojo.javacc.ForkedJvm Maven / Gradle / Ivy

There is a newer version: 4.1.5
Show newest version
package org.codehaus.mojo.javacc;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;

import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
import org.codehaus.plexus.util.cli.StreamConsumer;

/**
 * Runs the main() method of some tool in a forked JVM.
 *
 * @author Benjamin Bentmann
 * @version $Id: ForkedJvm.java 7758 2008-09-29 20:06:33Z bentmann $
 * @see java
 *      - The Java Application Launcher
 */
class ForkedJvm
{
  /**
   * The consumer for System.out messages.
   */
  private StreamConsumer systemOut;

  /**
   * The consumer for System.err messages.
   */
  private StreamConsumer systemErr;

  /**
   * The executable used to fork the JVM.
   */
  private final String executable;

  /**
   * The working directory for the forked JVM.
   */
  private File workingDirectory;

  /**
   * The class path entries for the forked JVM, given as strings.
   */
  private final Set  m_aClassPathEntries = new LinkedHashSet <> ();

  /**
   * The qualified name of the class on which to invoke the main()
   * method.
   */
  private String mainClass;

  /**
   * The command line arguments to pass to the main() method, given
   * as strings.
   */
  private final List  cmdLineArgs = new ArrayList <> ();

  /**
   * Creates a new configuration to fork a JVM.
   */
  public ForkedJvm ()
  {
    this.executable = _getDefaultExecutable ();
  }

  /**
   * Gets the absolute path to the JVM executable.
   *
   * @return The absolute path to the JVM executable.
   */
  private static String _getDefaultExecutable ()
  {
    return System.getProperty ("java.home") + File.separator + "bin" + File.separator + "java";
  }

  /**
   * Sets the working directory for the forked JVM.
   *
   * @param directory
   *        The working directory for the forked JVM, may be null
   *        to inherit the working directory of the current JVM.
   */
  public void setWorkingDirectory (final File directory)
  {
    this.workingDirectory = directory;
  }

  /**
   * Sets the stream consumer used to handle messages from
   * System.out.
   *
   * @param consumer
   *        The stream consumer, may be null to discard the output.
   */
  public void setSystemOut (final StreamConsumer consumer)
  {
    this.systemOut = consumer;
  }

  /**
   * Sets the stream consumer used to handle messages from
   * System.err.
   *
   * @param consumer
   *        The stream consumer, may be null to discard the output.
   */
  public void setSystemErr (final StreamConsumer consumer)
  {
    this.systemErr = consumer;
  }

  /**
   * Gets the class path for the forked JVM.
   *
   * @return The class path for the forked JVM.
   */
  private String _getClassPath ()
  {
    return StringUtils.join (this.m_aClassPathEntries.iterator (), File.pathSeparator);
  }

  /**
   * Adds the specified path to the class path of the forked JVM.
   *
   * @param path
   *        The path to add, may be null.
   */
  public void addClassPathEntry (final String path)
  {
    if (path != null)
    {
      this.m_aClassPathEntries.add (path);
    }
  }

  /**
   * Adds the specified path to the class path of the forked JVM.
   *
   * @param path
   *        The path to add, may be null.
   */
  public final void addClassPathEntry (@Nullable final File path)
  {
    if (path != null)
      m_aClassPathEntries.add (path.getAbsolutePath ());
  }

  /**
   * Adds the source JAR of the specified class/interface to the class path of
   * the forked JVM.
   *
   * @param type
   *        The class/interface to add, may be null.
   */
  public final void addClassPathEntry (final Class  type)
  {
    addClassPathEntry (_getClassSource (type));
  }

  /**
   * Gets the JAR file or directory that contains the specified class.
   *
   * @param type
   *        The class/interface to find, may be null.
   * @return The absolute path to the class source location or null
   *         if unknown.
   */
  private static File _getClassSource (final Class  type)
  {
    if (type != null)
    {
      final String classResource = type.getName ().replace ('.', '/') + ".class";
      return _getResourceSource (classResource, type.getClassLoader ());
    }
    return null;
  }

  /**
   * Gets the JAR file or directory that contains the specified class.
   *
   * @param className
   *        The qualified name of the class/interface to find, may be
   *        null.
   * @return The absolute path to the class source location or null
   *         if unknown.
   */
  private static File _getClassSource (final String className)
  {
    if (className != null)
    {
      final String classResource = className.replace ('.', '/') + ".class";
      return _getResourceSource (classResource, Thread.currentThread ().getContextClassLoader ());
    }
    return null;
  }

  /**
   * Gets the JAR file or directory that contains the specified resource.
   *
   * @param resource
   *        The absolute name of the resource to find, may be null.
   * @param loader
   *        The class loader to use for searching the resource, may be
   *        null.
   * @return The absolute path to the resource location or null if
   *         unknown.
   */
  @Nullable
  private static File _getResourceSource (final String resource, final ClassLoader loader)
  {
    if (resource != null)
    {
      URL url;
      if (loader != null)
      {
        url = loader.getResource (resource);
      }
      else
      {
        url = ClassLoader.getSystemResource (resource);
      }
      return UrlUtils.getResourceRoot (url, resource);
    }
    return null;
  }

  /**
   * Sets the qualified name of the class on which to invoke the
   * main() method. The source of the specified class will
   * automatically be added to the class path of the forked JVM.
   *
   * @param name
   *        The qualified name of the class on which to invoke the
   *        main() method.
   */
  public void setMainClass (final String name)
  {
    this.mainClass = name;
    addClassPathEntry (_getClassSource (name));
  }

  /**
   * Sets the class on which to invoke the main() method. The
   * source of the specified class will automatically be added to the class path
   * of the forked JVM.
   *
   * @param type
   *        The class on which to invoke the main() method, may be
   *        null.
   */
  public void setMainClass (final Class  type)
  {
    this.mainClass = (type != null) ? type.getName () : null;
    addClassPathEntry (type);
  }

  /**
   * Gets the command line arguments for the main() method.
   *
   * @return The command line arguments for the main() method.
   */
  private String [] _getArguments ()
  {
    return this.cmdLineArgs.toArray (new String [this.cmdLineArgs.size ()]);
  }

  /**
   * Adds the specified argument to the command line for the main()
   * method.
   *
   * @param argument
   *        The argument to add, may be null.
   */
  public void addArgument (final String argument)
  {
    if (argument != null)
    {
      this.cmdLineArgs.add (argument);
    }
  }

  /**
   * Adds the specified file path to the command line for the
   * main() method.
   *
   * @param argument
   *        The argument to add, may be null.
   */
  public void addArgument (final File argument)
  {
    if (argument != null)
    {
      this.cmdLineArgs.add (argument.getAbsolutePath ());
    }
  }

  /**
   * Adds the specified arguments to the command line for the
   * main() method.
   *
   * @param arguments
   *        The arguments to add, may be null.
   */
  public void addArguments (final String [] arguments)
  {
    if (arguments != null)
    {
      for (final String argument : arguments)
      {
        addArgument (argument);
      }
    }
  }

  /**
   * Creates the command line for the new JVM based on the current
   * configuration.
   *
   * @return The command line used to fork the JVM, never null.
   */
  private Commandline _createCommandLine ()
  {
    /*
     * NOTE: This method is designed to work with plexus-utils:1.1 which is used
     * by all Maven versions before 2.0.6 regardless of our plugin dependency.
     * Therefore, we use setWorkingDirectory(String) rather than
     * setWorkingDirectory(File) and addArguments() rather than createArg().
     */

    final Commandline cli = new Commandline ();

    cli.setExecutable (this.executable);

    if (this.workingDirectory != null)
    {
      cli.setWorkingDirectory (this.workingDirectory.getAbsolutePath ());
    }

    final String classPath = _getClassPath ();
    if (classPath != null && classPath.length () > 0)
    {
      cli.addArguments (new String [] { "-cp", classPath });
    }

    if (this.mainClass != null && this.mainClass.length () > 0)
    {
      cli.addArguments (new String [] { this.mainClass });
    }

    cli.addArguments (_getArguments ());

    return cli;
  }

  /**
   * Forks a JVM using the previously set parameters.
   *
   * @return The exit code of the forked JVM.
   * @throws Exception
   *         If the JVM could not be forked.
   */
  public int run () throws Exception
  {
    return CommandLineUtils.executeCommandLine (_createCommandLine (), this.systemOut, this.systemErr);
  }

  /**
   * Gets a string representation of the command line arguments.
   *
   * @return A string representation of the command line arguments.
   */
  @Override
  public String toString ()
  {
    return String.valueOf (_createCommandLine ());
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy