/**
 * Copyright 2013 Cloudera Inc.
 *
 * 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.cloudera.cdk.maven.plugins;

import com.google.common.base.Joiner;
import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;

/**
 * Run a Hadoop tool on the local machine.
 */
@Mojo(name = "run-tool", requiresDependencyResolution = ResolutionScope.RUNTIME)
public class RunToolMojo extends AbstractHadoopMojo {

  /**
   * The tool class to run. The specified class must have a standard Java
   * <code>main</code> method.
   */
  @Parameter(property = "cdk.toolClass", required = true)
  private String toolClass;

  /**
   * Arguments to pass to the tool, in addition to those generated by
   * <code>addDependenciesToDistributedCache</code> and <code>hadoopConfiguration</code>.
   */
  @Parameter(property = "cdk.args")
  private String[] args;

  /**
   * Whether to add dependencies in the <i>runtime</i> classpath to Hadoop's distributed
   * cache so that they are added to the classpath for MapReduce tasks
   * (via <code>-libjars</code>).
   */
  @Parameter(property = "cdk.addDependenciesToDistributedCache",
      defaultValue = "true")
  private boolean addDependenciesToDistributedCache;

  /**
   * Hadoop configuration properties.
   */
  @Parameter(property = "cdk.hadoopConfiguration")
  private Properties hadoopConfiguration;

  public void execute() throws MojoExecutionException, MojoFailureException {
    List<String> libJars = new ArrayList<String>();
    List<URL> classpath = new ArrayList<URL>();

    File mainArtifactFile = new File(mavenProject.getBuild().getDirectory(),
        mavenProject.getBuild().getFinalName() + ".jar");
    if (!mainArtifactFile.exists()) {
      throw new MojoExecutionException("Main artifact missing: " + mainArtifactFile);
    }
    libJars.add(mainArtifactFile.toString());
    classpath.add(toURL(mainArtifactFile));
    for (Object a : mavenProject.getRuntimeArtifacts()) {
      File file = ((Artifact) a).getFile();
      classpath.add(toURL(file));
      libJars.add(file.toString());
    }

    final List<String> commandArgs = new ArrayList<String>();
    for (String key : hadoopConfiguration.stringPropertyNames()) {
      String value = hadoopConfiguration.getProperty(key);
      commandArgs.add("-D");
      commandArgs.add(key + "=" + value);
    }
    if (addDependenciesToDistributedCache) {
      commandArgs.add("-libjars");
      commandArgs.add(Joiner.on(',').join(libJars));
    }
    if (args != null) {
      for (String arg : args) {
        commandArgs.add(arg);
      }
    }

    getLog().debug("Running tool with args: " + commandArgs);
    getLog().debug("Running tool with classpath: " + classpath);

    Thread executionThread = new Thread() {
      @Override
      public void run() {
        try {
          Method main = Thread.currentThread().getContextClassLoader().loadClass(toolClass)
              .getMethod("main", new Class[]{ String[].class });
          main.invoke(null, new Object[] { commandArgs.toArray(new String[commandArgs.size()]) });
        } catch (Exception e) {
          Thread.currentThread().getThreadGroup().uncaughtException(
              Thread.currentThread(), e);
        }
      }
    };
    ClassLoader parentClassLoader = getClass().getClassLoader(); // use Maven's classloader, not the system one
    ClassLoader classLoader = new URLClassLoader(
        classpath.toArray(new URL[classpath.size()]), parentClassLoader);
    executionThread.setContextClassLoader(classLoader);
    executionThread.start();
    try {
      executionThread.join();
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      getLog().warn("interrupted while joining against thread " + executionThread, e);
    }
  }

  private URL toURL(File file) throws MojoExecutionException {
    try {
      return file.toURI().toURL();
    } catch (MalformedURLException e) {
      throw new MojoExecutionException("Can't convert file  to URL: " + file, e);
    }
  }
}

@@ -2233,16 +2233,695 @@
 erties.%0A
+   *%0A   * WARNING: This configuration setting is not compatible with the factory%0A   * methods in %7B@link com.cloudera.cdk.data.DatasetRepositories%7D because it%0A   * does not alter the environment configuration. For example, if using%0A   * this to modify the environment's %22fs.defaultFS%22 property in the tool that%0A   * is run by this Mojo, opening a repo by URI will continue to use the%0A   * environment's default FS.%0A   *%0A   * Configuration properties set using this option will only affect the%0A   * %7B@link org.apache.hadoop.conf.Configuration%7D objects passed by%0A   * %7B@link org.apache.hadoop.util.ToolRunner%7D or created by%0A   * %7B@link org.apache.hadoop.util.GenericOptionsParser%7D.%0A
    */%0A  

Add configuration warning to RunToolMojo.