/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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.asakusafw.compiler.bootstrap;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.asakusafw.compiler.batch.BatchDriver;
import com.asakusafw.compiler.flow.FlowCompilerOptions;
import com.asakusafw.compiler.flow.Location;
import com.asakusafw.compiler.testing.DirectBatchCompiler;
import com.asakusafw.vocabulary.batch.BatchDescription;
/**
* Program entry for compiling a batch class.
* @see AllBatchCompilerDriver
*/
public final class BatchCompilerDriver {
static final Logger LOG = LoggerFactory.getLogger(BatchCompilerDriver.class);
private static final Option OPT_OUTPUT;
private static final Option OPT_PACKAGE;
private static final Option OPT_HADOOPWORK;
private static final Option OPT_COMPILERWORK;
private static final Option OPT_LINK;
private static final Option OPT_PLUGIN;
private static final Option OPT_CLASS;
private static final Options OPTIONS;
static {
OPT_OUTPUT = new Option("output", true, //$NON-NLS-1$
Messages.getString("BatchCompilerDriver.optOutput")); //$NON-NLS-1$
OPT_OUTPUT.setArgName("/path/to/output"); //$NON-NLS-1$
OPT_OUTPUT.setValueSeparator(File.pathSeparatorChar);
OPT_OUTPUT.setRequired(true);
OPT_PACKAGE = new Option("package", true, //$NON-NLS-1$
Messages.getString("BatchCompilerDriver.optPackage")); //$NON-NLS-1$
OPT_PACKAGE.setArgName("pkg.name"); //$NON-NLS-1$
OPT_PACKAGE.setRequired(true);
OPT_HADOOPWORK = new Option("hadoopwork", true, //$NON-NLS-1$
Messages.getString("BatchCompilerDriver.optHadoopwork")); //$NON-NLS-1$
OPT_HADOOPWORK.setArgName("batch/working"); //$NON-NLS-1$
OPT_HADOOPWORK.setRequired(true);
OPT_COMPILERWORK = new Option("compilerwork", true, //$NON-NLS-1$
Messages.getString("BatchCompilerDriver.optCompilerwork")); //$NON-NLS-1$
OPT_COMPILERWORK.setArgName("/path/to/temporary"); //$NON-NLS-1$
OPT_COMPILERWORK.setRequired(false);
OPT_LINK = new Option("link", true, //$NON-NLS-1$
Messages.getString("BatchCompilerDriver.optLink")); //$NON-NLS-1$
OPT_LINK.setArgName("classlib.jar" + File.pathSeparatorChar + "/path/to/classes"); //$NON-NLS-1$ //$NON-NLS-2$
OPT_PLUGIN = new Option("plugin", true, //$NON-NLS-1$
Messages.getString("BatchCompilerDriver.optPlugin")); //$NON-NLS-1$
OPT_PLUGIN.setArgName("plugin-1.jar" + File.pathSeparatorChar + "plugin-2.jar"); //$NON-NLS-1$ //$NON-NLS-2$
OPT_PLUGIN.setRequired(false);
OPT_CLASS = new Option("class", true, //$NON-NLS-1$
Messages.getString("BatchCompilerDriver.optClass")); //$NON-NLS-1$
OPT_CLASS.setArgName("class-name"); //$NON-NLS-1$
OPT_CLASS.setRequired(true);
OPTIONS = new Options();
OPTIONS.addOption(OPT_OUTPUT);
OPTIONS.addOption(OPT_PACKAGE);
OPTIONS.addOption(OPT_HADOOPWORK);
OPTIONS.addOption(OPT_COMPILERWORK);
OPTIONS.addOption(OPT_LINK);
OPTIONS.addOption(OPT_PLUGIN);
OPTIONS.addOption(OPT_CLASS);
}
/**
* The program entry.
* @param args command line arguments
*/
public static void main(String... args) {
try {
if (start(args) == false) {
System.exit(1);
}
} catch (Exception e) {
HelpFormatter formatter = new HelpFormatter();
formatter.setWidth(Integer.MAX_VALUE);
formatter.printHelp(
MessageFormat.format(
"java -classpath ... {0}", //$NON-NLS-1$
BatchCompilerDriver.class.getName()),
OPTIONS,
true);
e.printStackTrace(System.out);
System.exit(1);
}
}
private static boolean start(String[] args) throws Exception {
CommandLineParser parser = new BasicParser();
CommandLine cmd = parser.parse(OPTIONS, args);
String output = cmd.getOptionValue(OPT_OUTPUT.getOpt());
String className = cmd.getOptionValue(OPT_CLASS.getOpt());
String packageName = cmd.getOptionValue(OPT_PACKAGE.getOpt());
String hadoopWork = cmd.getOptionValue(OPT_HADOOPWORK.getOpt());
String compilerWork = cmd.getOptionValue(OPT_COMPILERWORK.getOpt());
String link = cmd.getOptionValue(OPT_LINK.getOpt());
String plugin = cmd.getOptionValue(OPT_PLUGIN.getOpt());
File outputDirectory = new File(output);
Location hadoopWorkLocation = Location.fromPath(hadoopWork, '/');
File compilerWorkDirectory = new File(compilerWork);
List<File> linkingResources = new ArrayList<>();
if (link != null) {
for (String s : link.split(File.pathSeparator)) {
linkingResources.add(new File(s));
}
}
List<URL> pluginLocations = new ArrayList<>();
if (plugin != null) {
for (String s : plugin.split(File.pathSeparator)) {
if (s.trim().isEmpty()) {
continue;
}
try {
File file = new File(s);
if (file.exists() == false) {
throw new FileNotFoundException(file.getAbsolutePath());
}
URL url = file.toURI().toURL();
pluginLocations.add(url);
} catch (IOException e) {
LOG.warn(MessageFormat.format(
Messages.getString("BatchCompilerDriver.warnFailedToLoadPlugin"), //$NON-NLS-1$
s),
e);
}
}
}
Class<? extends BatchDescription> batchDescription =
Class.forName(className).asSubclass(BatchDescription.class);
boolean succeeded = compile(
outputDirectory,
batchDescription,
packageName,
hadoopWorkLocation,
compilerWorkDirectory,
linkingResources,
pluginLocations);
if (succeeded) {
LOG.info(MessageFormat.format(
Messages.getString("BatchCompilerDriver.infoComplete"), //$NON-NLS-1$
batchDescription.getName()));
}
return succeeded;
}
static boolean compile(
File outputDirectory,
Class<? extends BatchDescription> batchDescription,
String packageName,
Location hadoopWorkLocation,
File compilerWorkDirectory,
List<File> linkingResources,
List<URL> pluginLibraries) {
assert outputDirectory != null;
assert batchDescription != null;
assert packageName != null;
assert hadoopWorkLocation != null;
assert compilerWorkDirectory != null;
assert linkingResources != null;
try {
BatchDriver analyzed = BatchDriver.analyze(batchDescription);
if (analyzed.hasError()) {
for (String diagnostic : analyzed.getDiagnostics()) {
LOG.error(diagnostic);
}
return false;
}
String batchId = analyzed.getBatchClass().getConfig().name();
ClassLoader serviceLoader = AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> {
URLClassLoader loader = new URLClassLoader(
pluginLibraries.toArray(new URL[pluginLibraries.size()]),
BatchCompilerDriver.class.getClassLoader());
return loader;
});
DirectBatchCompiler.compile(
analyzed.getDescription(),
packageName,
hadoopWorkLocation,
new File(outputDirectory, batchId),
new File(compilerWorkDirectory, batchId),
linkingResources,
serviceLoader,
FlowCompilerOptions.load(System.getProperties()));
return true;
} catch (Exception e) {
LOG.error(MessageFormat.format(
Messages.getString("BatchCompilerDriver.errorFailedToCompile"), //$NON-NLS-1$
batchDescription.getName()), e);
return false;
}
}
private BatchCompilerDriver() {
return;
}
}