/*******************************************************************************
* Copyright © 2011, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.gen;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.eclipse.edt.compiler.ICompiler;
import org.eclipse.edt.compiler.tools.IRLoader;
import org.eclipse.edt.mof.egl.Part;
import org.eclipse.edt.mof.egl.utils.LoadPartException;
import org.eclipse.edt.mof.serialization.Environment;
import org.eclipse.edt.mof.serialization.IEnvironment;
public abstract class AbstractGeneratorCommand extends CommandProcessor implements GenerationRegistry {
private String templates = "";
private String nativeTypes = "";
private String primitiveTypes = "";
private String EGLMessages = "";
public AbstractGeneratorCommand() {
super();
// define basic command parameters
this.installParameter(true, Constants.parameter_output, new String[] { "output", "out", "o" }, new String[] { null },
"Output must identify the location to write the output");
this.installParameter(true, Constants.parameter_part, new String[] { "part", "p" }, new String[] { null },
"Part must identify the part to be generated, which can contain an * for all matching parts");
this.installParameter(true, Constants.parameter_root, new String[] { "root", "r" }, new String[] { null },
"Root must identify the root location to be used in generation");
this.installParameter(true, Constants.parameter_contribution, new String[] { "contribution", "c" }, new Object[] { null },
"Contribution must identify the contribution classes used in generation");
this.installParameter(false, Constants.parameter_headerFile, new String[] { "headerFile" }, new String[] { null },
"headerFile must be an absolute path to a file");
}
public String getTemplates() {
String[] templateList = getTemplatePath().toArray(new String[getTemplatePath().size()]);
for (String template : templateList) {
templates = templates + template + ";";
}
return templates;
}
public String getNativeTypes() {
String[] nativeTypeList = getNativeTypePath().toArray(new String[getNativeTypePath().size()]);
for (String nativeType : nativeTypeList) {
nativeTypes = nativeTypes + nativeType + ";";
}
return nativeTypes;
}
public String getPrimitiveTypes() {
String[] primitiveTypeList = getPrimitiveTypePath().toArray(new String[getPrimitiveTypePath().size()]);
for (String primitiveType : primitiveTypeList) {
primitiveTypes = primitiveTypes + primitiveType + ";";
}
return primitiveTypes;
}
public String getEGLMessages() {
String[] EGLMessageList = getMessagePath().toArray(new String[getMessagePath().size()]);
EGLMessages = EGLMessages + "org.eclipse.edt.gen.EGLMessages;";
for (String EGLMessage : EGLMessageList) {
EGLMessages = EGLMessages + EGLMessage + ";";
}
return EGLMessages;
}
public void generate(String[] args, Generator generator, IEnvironment environment, ICompiler compiler) {
// process the arguments and load the contributions
if (initialize(args, generator)) {
try {
if (environment != null) {
Environment.pushEnv(environment);
generator.getContext().setEnvironment(environment);
}
// start up the generator, passing the command processor
try {
List<Part> parts = loadEGLParts(compiler);
for (Part part : parts) {
generator.generate(part);
// now try to write out the file, based on the output location and the part's type signature
try {
// only write the data, if there was some (if it's just the header then skip it)
if (generator.getResult() instanceof String && ((String) generator.getResult()).length() > 0
&& (generator.getHeader() == null || generator.getHeader().length() == 0
|| !((String) generator.getResult()).trim().equals(generator.getHeader().trim())))
writeFile(part, generator);
// Always let the generator perform auxiliary tasks
writeAuxiliaryFiles(part, generator);
}
catch (Throwable e) {
e.printStackTrace();
}
}
}
catch (Exception e) {
e.printStackTrace();
if (generator != null)
System.out.print(generator.getResult());
}
generator.dumpErrorMessages();
}
finally {
if (environment != null) {
Environment.popEnv();
}
}
}
}
protected boolean initialize(String[] args, Generator generator) {
// process the arguments and load the contributions
if (processBase(args)) {
// process all of the configuration modules
Object[] contributions = (Object[]) getParameter(Constants.parameter_contribution).getValue();
for (Object contribution : contributions) {
// obtain and load the requested contribution
try {
// load the contribution class
Class<?> clazz = Class.forName((String) contribution, true, getClass().getClassLoader());
// process the configuration module by invoking the configure method
GenerationContributor contributor = (GenerationContributor) clazz.newInstance();
contributor.contribute(this);
}
catch (Exception x) {
System.out.println("Exception: " + x.getMessage());
System.out.println("Unable to load: " + contribution + ". Generation aborted.");
return false;
}
}
// now process the non-base (user) command line options
if (processUser(args)) {
// load the template path and template factories
generator.initialize(this);
return true;
}
}
return false;
}
private void listAllFiles(File parent, List<File> files, String pattern) {
if (parent.isDirectory()) {
File[] children = parent.listFiles();
for (File child : children) {
if (child.isFile()
&& (child.getName().toLowerCase(Locale.ENGLISH).endsWith(".eglxml") || child.getName().toLowerCase(Locale.ENGLISH).endsWith(".ir"))) {
// get the full name of the file
String name = child.getPath();
// get the prefix length to check, which is the amount up to the asterisk (only 1 asterisk allowed)
int prefixLength = pattern.indexOf("*");
// does the file we are trying match up until the asterisk
if (name.length() >= prefixLength && name.substring(0, prefixLength).equalsIgnoreCase(pattern.substring(0, prefixLength))) {
// the prefix matches, so now check to see if there is any suffix and check it as well
if (pattern.length() <= (prefixLength + 1)
|| name.toLowerCase(Locale.ENGLISH).endsWith(pattern.substring(prefixLength + 1) + ".eglxml")
|| name.toLowerCase(Locale.ENGLISH).endsWith(pattern.substring(prefixLength + 1) + ".ir"))
files.add(child);
}
}
listAllFiles(child, files, pattern);
}
}
}
protected List<Part> loadEGLParts(ICompiler compiler) throws LoadPartException {
List<Part> parts = new ArrayList<Part>();
// check to see if the part has an asterisk, indicating that all matching files are desired
String rootName = (String) getParameter(Constants.parameter_root).getValue();
String partName = (String) getParameter(Constants.parameter_part).getValue();
if (partName.indexOf("*") >= 0) {
// we need to locate the root ir location and can it's directory for parts matching the pattern defined
String totalName;
if (rootName.endsWith(File.separator))
totalName = rootName;
else
totalName = rootName + File.separator;
if (partName.startsWith(File.separator))
totalName += partName.substring(File.separator.length());
else
totalName += partName;
totalName = totalName.replace('\\', File.separatorChar);
totalName = totalName.replace('/', File.separatorChar);
totalName = totalName.replace('.', File.separatorChar);
File irRootDirFile = new File(rootName);
List<File> irfiles = new ArrayList<File>();
listAllFiles(irRootDirFile, irfiles, totalName);
for (File irfile : irfiles) {
String irFileRelativePath = irfile.getAbsolutePath().substring(irRootDirFile.getAbsolutePath().length());
if (irFileRelativePath.startsWith(File.separator))
irFileRelativePath = irFileRelativePath.substring(File.separator.length());
parts
// TODO should pass the compiler to IRLoader
.add(IRLoader.loadEGLPart(rootName, irFileRelativePath.substring(0, irFileRelativePath.lastIndexOf(".")).replace(File.separatorChar, '.'),
null));
}
} else
parts.add(IRLoader.loadEGLPart(rootName, partName, compiler));
return parts;
}
protected void writeFile(Part part, Generator generator) throws Exception {
String fileName = ((String) getParameter(Constants.parameter_output).getValue()).replaceAll("\\\\", "/");
if (!fileName.endsWith("/"))
fileName = fileName + "/";
fileName = fileName + generator.getRelativeFileName(part);
int offset = fileName.lastIndexOf("/");
if (offset > 0)
new File(fileName.substring(0, offset)).mkdirs();
FileWriter writer = new FileWriter(fileName);
writer.write(generator.getResult().toString());
writer.close();
// call back to the generator, to see if it wants to do any supplementary tasks
generator.processFile(fileName);
}
protected void writeAuxiliaryFiles(Part part, Generator generator) throws Exception {
// Subclasses should override to perform any additional tasks.
}
public void registerCommandOptions(CommandOption[] options) {
for (CommandOption option : options) {
this.installParameter(option.getParameter().isRequired(), option.getInternalName(), option.getAliases(), option.getParameter().getPossibleValues(),
option.getParameter().getPromptText());
}
}
public void registerTemplatePath(String[] paths) {
for (String path : paths) {
getTemplatePath().add(path);
}
}
public void registerNativeTypePath(String[] paths) {
for (String path : paths) {
getNativeTypePath().add(path);
}
}
public void registerPrimitiveTypePath(String[] paths) {
for (String path : paths) {
getPrimitiveTypePath().add(path);
}
}
public void registerMessagePath(String[] paths) {
for (String path : paths) {
getMessagePath().add(path);
}
}
public void registerSupportedPartTypes(String[] partTypes) {
for (String type : partTypes) {
getSupportedPartTypes().add(type);
}
}
public void registerSupportedStereotypes(String[] stereotypes) {
for (String type : stereotypes) {
getSupportedStereotypes().add(type);
}
}
}