package pt.ist.fenixframework.dml; import java.io.*; import java.net.URL; import java.util.*; import pt.ist.fenixframework.core.DmlFile; import pt.ist.fenixframework.core.Project; import pt.ist.fenixframework.util.Converter; /** * Information about CompilerArgs: * * <table border=1> * <tr><th>Type</th><th>Name</th><th>Command-line flag</th><th>Description</th><th>Required</th> * <tr> * <td><code>boolean</code></td> * <td><code>generateFinals</code></td> * <td><code>gf</code></td> * <td> Whether to add the <code>final</code> keyword to the accessor methods. Default: <code>false</code>.</td> * <td>No</td> * </tr> * * <tr> * <td><code>File</code></td> * <td><code>destDirectoryBase</code></td> * <td><code>db</code></td> * <td>The top level directory where to generate the base classes.</td> * <td>No. Defaults to <code>destDirectory</code></td> * </tr> * * <tr><td><code>File</code></td> * <td><code>destDirectory</code></td> * <td><code>d</code></td> * <td> The top level directory where to generate the non-base classes.</td> * <td>Yes</td> * </tr> * * <tr><td><code>String</code></td> * <td><code>packageName</code></td> * <td><code>p</code></td> * <td>The default package name. Default: <code>""</code>.</td> * <td>No</td> * </tr> * * <tr><td><code>List<URL></code></td> * <td><code>localDomainSpecs</code></td> * <td><code>localDmlSpec</code></td> * <td>The list of project-local DML specifications. For these DML specifications, the compiler will generate base classes (and non-base classes if they do not exist). Default: empty list.</td> * <td rowspan="3">Must provide DML specifications either using <code>localDmlSpecs/externalDmlSpecs</code> or <code>projectName</code> </td> * </tr> * * <tr><td><code>List<URL></code></td> * <td><code>externalDomainSpecs</code></td> * <td><code>externalDmlSpec</code></td> * <td>The list of project-external DML specifications. For these DML specifications, the compiler will generate base classes only. Default: empty list.</td> * </tr> * * <tr><td><code>String</code></td> * <td><code>projectName</code></td> * <td><code>pn</code></td> * <td>The name of the project. The compiler will search for a <projectName>/project.properties file with the local DML files and other project dependencies to set the local/external specs.</td> * </tr> * * <tr><td><code>Class<? extends CodeGenerator></code></td> * <td><code>generatorClass</code></td> * <td><code>generator</code></td> * <td> The code generator to use. Default: <code>DefaultCodeGenerator.class</code>.</td> * <td>No</td> * </tr> * * </ul> */ public class CompilerArgs { boolean generateFinals = false; File destDirectoryBase = null; File destDirectory = null; String packageName = ""; List<URL> localDomainSpecs = new ArrayList<URL>(); List<URL> externalDomainSpecs = new ArrayList<URL>(); Class<? extends CodeGenerator> generatorClass = DefaultCodeGenerator.class; Map<String,String> params = new HashMap<String,String>(); /* * This is not part of the API * if true => add to local * if false => add to external * This value is changed by the method processOption */ private boolean addToLocalDomainSpecs = true; private CompilerArgs(File destDirectory, File destDirectoryBase, String packageName, Boolean generateFinals, Class<? extends CodeGenerator> generatorClass, Map<String,String> params) { this.destDirectory = destDirectory; this.destDirectoryBase = destDirectoryBase; this.packageName = packageName; this.generateFinals = generateFinals; this.generatorClass = generatorClass != null ? generatorClass : DefaultCodeGenerator.class; this.params = new HashMap<String,String>(params); } /** * Create the CompilerArgs using a local and external DML files specification */ public CompilerArgs(File destDirectory, File destDirectoryBase, String packageName, Boolean generateFinals, Class<? extends CodeGenerator> generatorClass, List<URL> localDomainSpecs, List<URL> externalDomainSpecs, Map<String,String> params) { this(destDirectory, destDirectoryBase, packageName, generateFinals, generatorClass, params); if (localDomainSpecs != null) { this.localDomainSpecs.addAll(localDomainSpecs); } if (externalDomainSpecs != null) {this.externalDomainSpecs.addAll(externalDomainSpecs); } checkArguments(); } /** * Create the CompilerArgs using the project name (requires a * <code><projName></code>/project.properties file in the classpath). */ public CompilerArgs(File destDirectory, File destDirectoryBase, String packageName, Boolean generateFinals, Class<? extends CodeGenerator> generatorClass, String projectName, Map<String,String> params) throws DmlCompilerException { this(destDirectory, destDirectoryBase, packageName, generateFinals, generatorClass, params); try { setDmlSpecsFromProjectName(projectName); } catch (Exception e) { throw new DmlCompilerException(e); } checkArguments(); } /** * Create the CompilerArgs using command-line args. */ public CompilerArgs(String[] args) throws DmlCompilerException { try { processCommandLineArgs(args); checkArguments(); } catch (Exception e) { throw new DmlCompilerException(e); } } void checkArguments() { if (destDirectory == null) { error("destination directory is not specified"); } if (!destDirectory.isDirectory()) { error(destDirectory.toString() + " is not a readable directory"); } if (localDomainSpecs.isEmpty() && externalDomainSpecs.isEmpty()) { error("no domainSpec files given (-localDmlSpec and/or -externalDmlSpec) and no project name give (-pn). Must provide one of the alternatives"); } } void processCommandLineArgs(String[] args) throws Exception { int num = 0; while (num < args.length) { num = processOption(args, num); } } int processOption(String[] args, int pos) throws Exception { if (args[pos].equals("-d")) { destDirectory = new File(getNextArgument(args, pos)); return pos + 2; } else if (args[pos].equals("-db")) { destDirectoryBase = new File(getNextArgument(args, pos)); return pos + 2; } else if (args[pos].equals("-p")) { packageName = getNextArgument(args, pos); return pos + 2; } else if (args[pos].equals("-f")) { error("option -f no longer exists (consider -generator instead)"); } else if (args[pos].equals("-gf")) { generateFinals = true; return pos + 1; } else if (args[pos].equals("-generator")) { generatorClass = (Class<? extends CodeGenerator>) Class.forName(getNextArgument(args, pos)); return pos + 2; } else if (args[pos].equals("-domainModelClass")) { error("option -domainModelClass no longer exists"); } else if (args[pos].equals("-localDmlSpec")) { // switch default to local addToLocalDomainSpecs = true; addToDomainSpecs(getNextArgument(args, pos), addToLocalDomainSpecs); return pos + 2; } else if (args[pos].equals("-externalDmlSpec")) { // switch default to external addToLocalDomainSpecs = false; addToDomainSpecs(getNextArgument(args, pos), addToLocalDomainSpecs); return pos + 2; } else if (args[pos].equals("-pn")) { String projectName = getNextArgument(args, pos); setDmlSpecsFromProjectName(projectName); return pos + 2; } else if (args[pos].equals("-param")) { String paramValue = getNextArgument(args, pos); String[] vals = paramValue.split("="); params.put(vals[0],vals[1]); return pos + 2; } else { // use last set default addToDomainSpecs(args[pos], addToLocalDomainSpecs); return pos + 1; } return pos; } String getNextArgument(String[] args, int pos) { int nextPos = pos + 1; if (nextPos < args.length) { return args[nextPos]; } else { error("option " + args[pos] + " requires argument"); } return null; } void addToDomainSpecs(String domainSpecFilename, boolean addToLocal) { URL url = Converter.filenameToURL(domainSpecFilename); if (addToLocal) { localDomainSpecs.add(url); } else { externalDomainSpecs.add(url); } } void error(String msg) { System.err.println("DmlCompiler: " + msg); System.exit(1); } private void setDmlSpecsFromProjectName(String projectName) throws Exception { Project project = Project.fromName(projectName); List<URL> allDmls = new ArrayList<URL>(); for (DmlFile dmlFile : project.getFullDmlSortedList()) { allDmls.add(dmlFile.getUrl()); } List<URL> localDmls = new ArrayList<URL>(); for (DmlFile dmlFile : project.getDmls()) { localDmls.add(dmlFile.getUrl()); } List<URL> externalDmls = new ArrayList<URL>(allDmls); externalDmls.removeAll(localDmls); this.localDomainSpecs = localDmls; this.externalDomainSpecs = externalDmls; } public Class<? extends CodeGenerator> getCodeGenerator() { return generatorClass; } public List<URL> getLocalDomainSpecs() { return Collections.unmodifiableList(localDomainSpecs); } public List<URL> getExternalDomainSpecs() { return Collections.unmodifiableList(externalDomainSpecs); } public boolean isExternalDefinition(URL domainSpec) { return this.externalDomainSpecs.contains(domainSpec); } public Map<String,String> getParams() { return Collections.unmodifiableMap(params); } // static public static List<URL> convertFilenamesToURLs(List<String> filenames) { return Arrays.asList(Converter.filenamesToURLArray(filenames.toArray(new String[filenames.size()]))); } public static URL convertFilenameToURL(String filename) { return Converter.filenameToURL(filename); } }