package org.objectweb.speedo.generation.start;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.types.Path;
import org.objectweb.jorm.api.PException;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.generation.AbstractEnhancer;
import org.objectweb.speedo.generation.jdo.JDOEnhancer;
import org.objectweb.speedo.generation.api.SpeedoCompilerParameter;
import org.objectweb.util.monolog.Monolog;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* Main is the starting point for the persistent filter tool.
*/
public class Main
extends Support
{
// return values of main()
static public final int OK = 0;
static public final int USAGE_ERROR = -1;
static public final int METADATA_ERROR = -2;
static public final int INTERNAL_ERROR = -3;
protected Logger logger = null;
private SpeedoCompilerParameter scp = null;
private AbstractEnhancer sc = null;
private Description jdodesc = new Description();
private Description jormdesc = new Description();
private Description awareFiles = new Description();
private Project project = new Project();
/**
* The stream to write messages to.
*/
private final PrintWriter out = new PrintWriter(System.out, true);
/**
* The stream to write error messages to.
*/
private final PrintWriter err = new PrintWriter(System.err, true);
/**
* The command line options.
*/
private final CmdLineOptions opts = new CmdLineOptions();
/**
* Construct a filter tool instance
*/
public Main()
{}
// ----------------------------------------------------------------------
/**
* This is where it all starts.
*/
public static void main(String[] argv)
{
int res;
final Main main = new Main();
main.sc = new JDOEnhancer();
main.scp = main.sc.getSpeedoCompilerParameter();
// added support for timing statistics
try {
res = main.process(argv);
} catch (RuntimeException ex) {
main.out.flush();
main.err.println("Internal error while postprocessing: "
+ ex.getMessage());
ex.printStackTrace(main.err);
main.err.flush();
res = INTERNAL_ERROR;
} finally {
// added support for timing statistics
main.logger.log(BasicLevel.DEBUG, "Timing infos...");
if (main.opts.doTiming) {
Support.timer.print();
}
}
main.logger.log(BasicLevel.DEBUG, "leaving org.objectweb.speedo.start.Main.main(), ret="+res);
System.exit(res);
}
/**
* Process command line options and perform filtering tasks
*/
public int process(String[] argv)
{
int res;
if ((res = opts.processArgs(argv)) != OK) {
printMessage("aborted with errors.");
return res;
}
// added support for timing statistics
try {
if (opts.doTiming) {
timer.push("Main.process(String[])");
}
if ((res = start()) != OK) {
printMessage("aborted with errors.");
return res;
}
printMessage("done.");
return 0;
} finally {
if (opts.doTiming) {
timer.pop();
}
}
}
// ----------------------------------------------------------------------
/**
* A class for holding the command line options.
*/
private class CmdLineOptions
{
String speedoproperties = null;
final List classNames = new ArrayList();
final List classFileNames = new ArrayList();
final List zipFileNames = new ArrayList();
final List jdoFileNames = new ArrayList();
String sourcePath = null;
String destinationDirectory = null;
String propertiesFileName = null;
String logproperties = null;
String inputdir = null;
boolean doTiming = false;
boolean verbose = false;
boolean quiet = false;
boolean forceWrite = false;
boolean noWrite = false;
boolean dumpClass = false;
boolean noAugment = false;
boolean noAnnotate = false;
/**
* Print a usage message to System.err.
*/
public void usage() {
err.println("Usage: main <options> <arguments>...");
err.println("Options:");
err.println(" -h, --help print usage message and exit gently");
err.println(" -v, --verbose print verbose messages");
err.println(" -q, --quiet supress warnings");
err.println(" -i, --input <dir> input dir");
err.println(" -d, --destdir <dir> destination directory for output files");
err.println(" -s, --sourcepath <path> source path");
err.println(" -sp, --speedoproperties <filepath> Absolute path of the Speedo properties file");
err.println(" -log <filepath> Absolute path of the log properties file");
err.println(" -f, --force overwrite output files");
err.println(" -n, --nowrite never write output files");
err.println(" -t, --timing do timing messures");
err.println();
err.println("Debugging Options:");
err.println(" --properties <file> use property file for meta data");
err.println(" --dumpclass print out disassembled code of classes");
err.println(" --noaugment do not enhance for persistence-capability");
err.println(" --noannotate do not enhance for persistence-awareness");
err.println();
err.println("Arguments:");
//err.println(" <class> the fully qualified name of a Java class");
err.println(" <jdofile> the name of a .jdo file");
err.println(" <classfile> the name of a .class file");
//err.println(" <zipfile> the name of a .zip or .jar file");
err.println();
err.println("Returns a non-zero value in case of errors.");
}
/**
* Process command line options.
*/
protected int processArgs(String[] argv)
{
final Collection inputNames = new ArrayList();
for (int i = 0; i < argv.length; i++) {
final String arg = argv[i];
if (arg.equals("-h")
|| arg.equals("--help")) {
usage();
return OK;
}
if (arg.equals("-v")
|| arg.equals("--verbose")) {
verbose = true;
quiet = false;
continue;
}
if (arg.equals("-sp")
|| arg.equals("--speedoproperties")) {
if (argv.length - i < 2) {
printError("Missing argument to the -sp/--speedoproperties option", null);
usage();
return USAGE_ERROR;
}
speedoproperties = argv[++i];
continue;
}
if (arg.equals("-log")) {
if (argv.length - i < 2) {
printError("Missing argument to the -log option", null);
usage();
return USAGE_ERROR;
}
logproperties = argv[++i];
continue;
}
if (arg.equals("-i")
|| arg.equals("--input")) {
if (argv.length - i < 2) {
printError("Missing argument to the -i option", null);
usage();
return USAGE_ERROR;
}
inputdir = argv[++i];
continue;
}
if (arg.equals("-q")
|| arg.equals("--quiet")) {
quiet = true;
verbose = false;
continue;
}
if (arg.equals("-t") ||
arg.equals("--timing")) {
doTiming = true;
continue;
}
if (arg.equals("-f")
|| arg.equals("--force")) {
forceWrite = true;
noWrite = false;
continue;
}
if (arg.equals("-n")
|| arg.equals("--nowrite")) {
noWrite = true;
forceWrite = false;
continue;
}
if (arg.equals("--dumpclass")) {
dumpClass = true;
continue;
}
if (arg.equals("--noaugment")) {
noAugment = true;
continue;
}
if (arg.equals("--noannotate")) {
noAnnotate = true;
continue;
}
if (arg.equals("-s")
|| arg.equals("--sourcepath")) {
if (argv.length - i < 2) {
printError("Missing argument to the -s/--sourcepath option", null);
usage();
return USAGE_ERROR;
}
sourcePath = argv[++i];
continue;
}
if (arg.equals("-d")
|| arg.equals("--destdir")) {
if (argv.length - i < 2) {
printError("Missing argument to the -d/-destdir option", null);
usage();
return USAGE_ERROR;
}
destinationDirectory = argv[++i];
continue;
}
if (arg.equals("--properties")) {
if (argv.length - i < 2) {
printError("Missing argument to the --properties option", null);
usage();
return USAGE_ERROR;
}
propertiesFileName = argv[++i];
continue;
}
if (arg.length() > 0 && arg.charAt(0) == '-') {
printError("Unrecognized option:" + arg, null);
usage();
return USAGE_ERROR;
}
if (arg.length() == 0) {
printMessage("Ignoring empty command line argument.");
continue;
}
inputNames.add(arg);
}
// group input file arguments
for (Iterator names = inputNames.iterator(); names.hasNext();) {
final String name = (String)names.next();
if (isJdoFileName(name)) {
jdoFileNames.add(name);
} else if (isClassFileName(name)) {
classFileNames.add(name);
} else if (isZipFileName(name)) {
zipFileNames.add(name);
} else {
classNames.add(name);
}
}
if (verbose) {
printArgs();
}
return checkArgs();
}
/**
* Check command line options.
*/
protected int checkArgs()
{
// at least one meta-data source must be specified for classfiles
if (classFileNames.size() > 0
&& (jdoFileNames.isEmpty()
&& propertiesFileName == null
&& sourcePath == null)) {
final String msg
= "No JDO meta-data source specified for class files";
printError(msg, null);
usage();
return USAGE_ERROR;
}
// either jdo files or jdo properties specified
if (!jdoFileNames.isEmpty() && propertiesFileName != null) {
final String msg
= "Cannot have both jdo files and properties specified";
printError(msg, null);
usage();
return USAGE_ERROR;
}
return OK;
}
/**
* return command line options.
*/
protected String getArgs() {
String classnames = "";
for (Iterator i = classNames.iterator(); i.hasNext();) {
classnames.concat(" " + i.next());
}
String jdonames = "";
for (Iterator i = jdoFileNames.iterator(); i.hasNext();) {
jdonames.concat(" " + i.next());
}
String classfilenames = "";
for (Iterator i = classFileNames.iterator(); i.hasNext();) {
classfilenames.concat(" " + i.next());
}
String zipnames = "";
for (Iterator i = zipFileNames.iterator(); i.hasNext();) {
zipnames.concat(" " + i.next());
}
return "Enhancer: options:"+"\n"+
" verbose = " + verbose+"\n"+
" quiet = " + quiet+"\n"+
" forceWrite = " + forceWrite+"\n"+
" noWrite = " + noWrite+"\n"+
" inputDirectory = " + inputdir+"\n"+
" destinationDirectory = " + destinationDirectory+"\n"+
" SpeedopropertiesFileName = " + speedoproperties+"\n"+
" doTiming = " + doTiming+"\n"+
" classNames = {"+"\n"+classnames+"\n"+
" }"+"\n"+
" classfilenames = {"+"\n"+classfilenames+"\n"+
" }"+"\n"+
" jdoFileNames = {"+jdonames+"\n"+
" }"+"\n"+
" zipnames = {"+"\n"+zipnames+"\n"+
" }"+"\n"+
" dumpClass = " + dumpClass+"\n"+
" noAugment = " + noAugment+"\n"+
" noAnnotate = " + noAnnotate;
}
/**
* Print command line options.
*/
protected void printArgs() {
out.println("Enhancer: options:");
out.println(" verbose = " + verbose);
out.println(" quiet = " + quiet);
out.println(" forceWrite = " + forceWrite);
out.println(" noWrite = " + noWrite);
out.println(" inputDirectory = " + inputdir);
out.println(" destinationDirectory = " + destinationDirectory);
out.println(" SpeedopropertiesFileName = " + speedoproperties);
out.println(" doTiming = " + doTiming);
out.println(" classNames = {");
for (Iterator i = classNames.iterator(); i.hasNext();) {
out.println(" " + i.next());
}
out.println(" }");
out.println(" jdoFileNames = {");
for (Iterator i = jdoFileNames.iterator(); i.hasNext();) {
out.println(" " + i.next());
}
out.println(" classFileNames = {");
for (Iterator i = classFileNames.iterator(); i.hasNext();) {
out.println(" " + i.next());
}
out.println(" }");
out.println(" zipFileNames = {");
for (Iterator i = zipFileNames.iterator(); i.hasNext();) {
out.println(" " + i.next());
}
out.println(" }");
out.println(" dumpClass = " + dumpClass);
out.println(" noAugment = " + noAugment);
out.println(" noAnnotate = " + noAnnotate);
}
}
private int initParameters()
{
final String propertiesFileName = opts.propertiesFileName;
final List jdoFileNames = opts.jdoFileNames;
final List ClassFileNames = opts.classFileNames;
final String sourcePath = opts.sourcePath;
try {
scp.logPropFile = opts.logproperties;
// Initialize the logger factory if necessary
try {
if (scp.loggerFactory == null) {
if (scp.logPropFile == null) {
scp.loggerFactory = Monolog.initialize();
} else {
scp.loggerFactory = Monolog.getMonologFactory(scp.logPropFile);
}
logger = scp.loggerFactory.getLogger(SpeedoProperties.LOGGER_NAME+".start.Main");
} else if (logger == null) {
logger = scp.loggerFactory.getLogger(SpeedoProperties.LOGGER_NAME+".start.Main");
}
}
catch (Exception e){
e.printStackTrace();
}
logger.log(BasicLevel.DEBUG, "Entering initParameters()");
scp.projectName = "";
// Setting Classpath
scp.classpath = new Path(project, opts.sourcePath);
scp.classpath.append(new Path(project, opts.destinationDirectory));
scp.jormclasspath = new MyArrayList(scp.classpath.list());
// Setting directories (input, output,jdodir jormdir)
if (opts.inputdir != null) scp.input = opts.inputdir;
else scp.input = (new File(".")).getCanonicalPath();
if ( opts.destinationDirectory != null) scp.output = opts.destinationDirectory;
else scp.output = scp.input;
scp.jormDir = scp.input;
scp.xmlDir ="file:/"+ scp.input;
scp.awareFilesDir = scp.input;
// Verifying the accessibility of jorm.properties
if (this.getClass().getClassLoader().getResourceAsStream("jorm.properties") == null) {
throw new BuildException("ERROR: Impossible to " +
"find the 'jorm.properties' file in the classpath, classloader="
+ getClass().getClassLoader());
}
// Build the .pd list.
jormdesc.setDir(new File(scp.input));
jormdesc.setProject(project);
jormdesc.setIncludes("**/*.pd");
ListResourceLocator lrl = new ListResourceLocator(out, true, new MyArrayList(jormdesc.getDirectoryScanner(new File(scp.jormDir)).getIncludedFiles()),scp.output, scp);
scp.jorm = lrl.getCollectionOfFiles();
// search for the .jdo files in output folder if not specified
if (opts.jdoFileNames.size() == 0){
jdodesc.setDir(new File(scp.input));
jdodesc.setProject(new Project());
jdodesc.setIncludes("**/*.jdo");
lrl = new ListResourceLocator(out, true, new MyArrayList(jdodesc.getDirectoryScanner(jdodesc.dir).getIncludedFiles()),scp.input, scp);
scp.xml = lrl.getCollectionOfFiles();
}
else {
scp.xml = opts.jdoFileNames;
}
} catch (Exception e1) {
e1.printStackTrace();
}
Collection awarefiles = new ArrayList();
try {
// classes to enhance must have be specified in the command line.
ListResourceLocator lrl = new ListResourceLocator(out, true, ClassFileNames, scp.output, scp);
awarefiles = lrl.getCollectionOfFiles();
}
catch (IOException e) {
e.printStackTrace();
}
scp.awareFiles = awarefiles;
logger.log(BasicLevel.DEBUG, "leaving initParameters(), ret="+OK);
return OK;
}
private int start()
{
int res = initParameters();
if (res < 0) {
return res;
}
try {
logger.log(BasicLevel.DEBUG, "SpeedoCompiler init");
printMessage("SpeedoCompiler init");
sc.init();
logger.log(BasicLevel.DEBUG, "SpeedoCompiler process");
printMessage("SpeedoCompiler process");
sc.process();
logger.log(BasicLevel.DEBUG, "SpeedoCompiler end");
printMessage("SpeedoCompiler end");
} catch (SpeedoException e) {
e.printStackTrace();
throw new BuildException(getNestedException(e));
}
return res;
}
private Exception getNestedException(Exception e) {
if (e instanceof SpeedoException
&& ((SpeedoException) e).getNestedException() != null) {
return getNestedException(((SpeedoException) e).getNestedException());
} else if (e instanceof PException
&& ((PException) e).getNestedException() != null) {
return getNestedException(((PException) e).getNestedException());
} else
return e;
}
public class Description extends MatchingTask {
public File dir = null;
public void setDir(File dir) {
this.dir = dir;
}
public DirectoryScanner getDirectoryScanner(File p) {
return super.getDirectoryScanner(p);
}
}
class MyArrayList extends ArrayList {
public MyArrayList(Object[] os) {
super(os.length);
for (int i = 0; i < os.length; i++)
add(os[i]);
}
}
/**
* Tests if a filename is a classfile name.
*
* @param filename The name of the file.
* @return Do we have a potential classfile?
*/
static private boolean isClassFileName(String filename)
{
return filename.endsWith(".class");
}
/**
* Tests if a filename is a zipfile (only by testing if the extension -
* ignoring the case - is <code>".zip"</code> or <code>".jar"</code>).
*
* @param filename The name of the file.
* @param Do we have a potential zipfile?
*/
static private boolean isZipFileName(String filename)
{
final int n = filename.length();
if (n < 5) {
return false;
}
final String ext = filename.substring(n - 4);
return ext.equalsIgnoreCase(".zip") || ext.equalsIgnoreCase(".jar");
}
/**
* Tests if a filename is a zipfile (only by testing if the extension -
* ignoring the case - is <code>".jar"</code>).
*
* @param filename The name of the file.
* @param Do we have a potential jarfile?
*/
static private boolean isJarFileName(String filename)
{
final int n = filename.length();
if (n < 5) {
return false;
}
final String ext = filename.substring(n - 4);
return ext.equalsIgnoreCase(".jar");
}
/**
* Tests if a filename is a jdo file name.
*
* @param filename The name of the file.
* @return Do we have a potential jdo file?
*/
static private boolean isJdoFileName(String filename)
{
// currently not case-tolerant
return filename.endsWith(".jdo");
}
/**
* Prints out an error.
*
* @param msg The error message (can be <code>null</code>).
* @param ex An optional exception (can be <code>null</code>).
*/
private void printError(String msg,
Throwable ex)
{
out.flush();
if (msg != null) {
err.println(msg + (ex != null ? ": " + ex.getMessage() : ""));
}
if (ex != null) {
ex.printStackTrace(err);
}
}
/**
* Prints out a message.
*
* @param msg The message.
*/
private void printMessage(String msg)
{
out.println(msg);
}
}