package net.sf.minuteProject.application;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import net.sf.minuteProject.configuration.bean.AbstractConfiguration;
import net.sf.minuteProject.configuration.bean.AbstractConfigurationRoot;
import net.sf.minuteProject.configuration.bean.Configuration;
import net.sf.minuteProject.configuration.bean.GeneratorBean;
import net.sf.minuteProject.configuration.bean.Target;
import net.sf.minuteProject.configuration.bean.Template;
import net.sf.minuteProject.configuration.bean.TemplateTarget;
import net.sf.minuteProject.configuration.bean.model.data.DataModelFactory;
import net.sf.minuteProject.configuration.bean.model.data.Table;
import net.sf.minuteProject.configuration.bean.system.Plugin;
import net.sf.minuteProject.exception.MinuteProjectException;
import net.sf.minuteProject.integration.bean.BasicIntegrationConfiguration;
import net.sf.minuteProject.utils.BslaLibraryUtils;
import net.sf.minuteProject.utils.CommonUtils;
import net.sf.minuteProject.utils.ConvertUtils;
import net.sf.minuteProject.utils.DatabaseUtils;
import net.sf.minuteProject.utils.FormatUtils;
import net.sf.minuteProject.utils.ModelUtils;
import net.sf.minuteProject.utils.TemplateUtils;
import net.sf.minuteProject.utils.ViewUtils;
import net.sf.minuteProject.utils.io.FileUtils;
import net.sf.minuteProject.utils.property.PropertyUtils;
import org.apache.commons.collections.ExtendedProperties;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
/**
* @author Florian Adler
*
*/
public abstract class AbstractGenerator implements Generator {
protected static final String SCOPE_DATAMODEL_FUNCTION = "function";
protected static final String SCOPE_DATAMODEL_ENTITY = "entity";
protected static final String SCOPE_DATAMODEL_FIELD = "field";
protected static final String SCOPE_DATAMODEL_PACKAGE = "package";
protected static final String SCOPE_DATAMODEL_APPLICATION = "application";
protected static final String SCOPE_DATAMODEL_MODEL = "model";
protected static final String SCOPE_DATAMODEL_FUNCTION_INPUT = "function-input-entity";
protected static final String SCOPE_DATAMODEL_FUNCTION_OUTPUT = "function-output-entity";
protected static final String SCOPE_TARGET_TEMPLATE = "target";
protected static final String SCOPE_TRANSFER_ENTITY_TEMPLATE = "transfer-entity";
protected static final String SCOPE_ACTION_TEMPLATE="action";
protected static final String QUERY_ACTION_TEMPLATE="query";
protected static final String SCOPE_WSDL="wsdl";
protected static final String SCOPE_WSDL_ENTITY="wsdl-entity";
protected static final String SCOPE_WSDL_SERVICE="wsdl-service";
protected static final String SDD_INPUT_BEAN_TEMPLATE="sdd-input-bean";
protected static final String SDD_COMPOSITE_TEMPLATE ="composite";
protected static final String SDD_INPUT_COMPOSITE_TEMPLATE ="sdd-input-composite-bean";
protected static final String SDD_OUTPUT_COMPOSITE_TEMPLATE ="sdd-output-composite-bean";
protected static final String SDD_OUTPUT_BEAN_TEMPLATE="sdd-output-bean";
private static Logger logger = Logger.getLogger(AbstractGenerator.class);
private String configurationFile;
private String templatePath;
private String templateLibPath;
private Boolean isTemplateLibPathToReset = true;
private Boolean isTemplatePathToReset = true;
private BasicIntegrationConfiguration bic;
/**
* The default constructor get the value of the configuration to which the generator is associated
* @param configurationFile
*/
public AbstractGenerator (String configurationFile) {
this.configurationFile = configurationFile;
resetTemplatePath();
}
public AbstractGenerator(BasicIntegrationConfiguration bic) {
this.bic = bic;
resetTemplatePath();
}
/**
* gets the configuration file that is to be loaded
* @return String
*/
public String getConfigurationFile() {
return this.configurationFile;
}
/**
* gets the configuration rule file that is to be loaded
* @return
*/
public abstract String getConfigurationRulesFile();
/**
* gets the configuration rule file that is to be loaded
* @return
*/
public abstract String getPropertyConfigurationRulesFile();
/**
* gets the configuration root element
* @return AbstractConfiguration
*/
public abstract AbstractConfiguration getConfigurationRoot();
// protected abstract void generate(Configuration configuration) throws Exception;
/* (non-Javadoc)
* @see net.sf.minuteProject.application.Generator#load(java.lang.String, java.lang.String)
*/
public final AbstractConfiguration load (String configuration, String rules) throws Exception{
AbstractConfiguration abstractConfiguration = getConfigurationRoot();
abstractConfiguration.setConfigurationFileInClassPath(configuration);
loadConfiguration(abstractConfiguration, getConfigurationInputStream(configuration), rules);
return abstractConfiguration;
}
private InputStream getConfigurationInputStream (String configurationFileName) {
return getClass().getClassLoader().getSystemResourceAsStream(configurationFileName);
}
public void loadTarget (AbstractConfigurationRoot abstractConfigurationRoot, Target target) throws MinuteProjectException {
try {
loadConfiguration(abstractConfigurationRoot, getTargetConfigurationInputStream(abstractConfigurationRoot, target), GENERATOR_TARGET_RULES);
} catch (Exception e) {
throwException(e, "CANNOT LOAD TARGET FILE "+resolveFileAbsolutePath(abstractConfigurationRoot, target)+" - CHECK IT IS IN THE CLASSPATH AND WELL FORMATTED");
}
complementWithTargetInfo(abstractConfigurationRoot, target);
}
public void copyAndComplementWithTargetInfo (AbstractConfigurationRoot abstractConfigurationRoot, Target target) throws Exception {
// target = new Target();//(abstractConfigurationRoot, target);
Target target2 = abstractConfigurationRoot.getTarget();
target.setTemplateTargets(target2.getTemplateTargets());
target.setAbstractConfigurationRoot(target2.getAbstractConfigurationRoot());
target.setArchitectureTarget(target2.getArchitectureTarget());
target.setPlugins(target2.getPlugins());
// for (Target target2 : abstractConfigurationRoot.getTargets().getTargets()) {
// if (target2==target) {
// target2.setDir(target.getDir());
// target2.setCanonicalDir(target.getCanonicalDir());
// target2.setOutputdirRoot(target.getOutputdirRoot());
// target2.setTemplatedirRoot(target.getTemplatedirRoot());
// }
// }
}
public void complementWithTargetInfo (AbstractConfigurationRoot abstractConfigurationRoot, Target target) {
Target target2 = abstractConfigurationRoot.getTarget();
target2.setDir(target.getDir());
target2.setCanonicalDir(target.getCanonicalDir());
target2.setOutputdirRoot(target.getOutputdirRoot());
target2.setTemplatedirRoot(target.getTemplatedirRoot());
target2.getProperties().addAll(target.getProperties());
target.setAbstractConfigurationRoot(abstractConfigurationRoot);
}
protected InputStream getTargetConfigurationInputStream (AbstractConfigurationRoot abstractConfigurationRoot, Target target) throws FileNotFoundException {
String filePath = resolveFileAbsolutePath(abstractConfigurationRoot, target);
String dirPath = FileUtils.stripFileName(filePath);
target.setCanonicalDir(dirPath);
return new FileInputStream (new File (filePath));
}
private String resolveFileAbsolutePath(AbstractConfigurationRoot abstractConfigurationRoot, Target target) {
String dir = target.getDir();
if (dir!=null) { // absolute path provided
return dir+"/"+target.getFileName();
}
else {//relative path
String result = FileUtils.getFileFullPath(abstractConfigurationRoot.getConfigurationFileInClassPath(), dir, target.getFileName());
return result;
}
}
protected void loadConfiguration (Object object, InputStream input, String rules) throws Exception {
URL rulesURL = getClass().getClassLoader().getResource(rules);
Digester digester = DigesterLoader.createDigester(rulesURL);
digester.push(object);
digester.parse(input);
}
/**
* load the configuration root element
* @return AbstractConfiguration
* @throws Exception
* @throws Exception
*/
public final AbstractConfiguration load() throws MinuteProjectException {
if (getConfigurationFile()!=null)
return loadFromConfigurationFile();
return loadFromObject();
}
public final AbstractConfiguration loadFromConfigurationFile() throws MinuteProjectException {
AbstractConfiguration abstractConfiguration = null;
try {
abstractConfiguration = load(getConfigurationFile(), getConfigurationRulesFile());
} catch (Exception e) {
throwException(e, "CANNOT LOAD CONFIGURATION FILE "+getConfigurationFile()+" - CHECK IT IS IN THE CLASSPATH");
}
return abstractConfiguration;
}
public final AbstractConfiguration loadFromObject() throws MinuteProjectException {
AbstractConfiguration abstractConfiguration = null;
if (bic!=null)
abstractConfiguration = bic.getConfiguration();
else
throwException("NO CONFIGURATION PROVIDED");
return abstractConfiguration;
}
/* (non-Javadoc)
* @see net.sf.minuteProject.application.Generator#generate(net.sf.minuteProject.configuration.bean.AbstractConfiguration, net.sf.minuteProject.configuration.bean.Target)
*/
public void generate (Target target) throws MinuteProjectException {
if (target.isGenerable()) {
for (TemplateTarget templateTarget : target.getTemplateTargets()) {
if (templateTarget.isGenerable()) {
logger.info(">template target set: "+templateTarget.getName()+" in "+templateTarget.getOutputdir());
if (templateTarget!=null && templateTarget.getTemplates()!=null) {
for (Template template : templateTarget.getTemplates()) {
logger.info(">>template: "+template.getName()+" in "+template.getOutputdir());
this.generate(template);
}
}
}
}
}
}
public void getSolutionPortfolio (String solutionPortfolioFileName) {
}
protected VelocityContext getVelocityContext(Template template) {
// Properties p = new Properties();
// Velocity.clearProperty(Velocity.FILE_RESOURCE_LOADER_PATH);
// Velocity.clearProperty(Velocity.VM_LIBRARY);
// p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH,getTemplatePath(template));
// p.setProperty(Velocity.VM_LIBRARY,getTemplateRelativeLibPath(template));
VelocityContext context = new VelocityContext();
try {
Velocity.setExtendedProperties(getExtendedProperties(template));
// Velocity.addProperty(Velocity.FILE_RESOURCE_LOADER_PATH,getTemplatePath(template));
// Velocity.addProperty(Velocity.VM_LIBRARY,getTemplateRelativeLibPath(template));
// Velocity.init(p);
} catch (Exception e) {
e.printStackTrace();
}
return context;
}
private ExtendedProperties getExtendedProperties(Template template) {
ExtendedProperties extendedProperties = new ExtendedProperties();
extendedProperties.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH,getTemplatePath(template));
extendedProperties.setProperty(Velocity.VM_LIBRARY,getTemplateRelativeLibPath(template));
return extendedProperties;
}
protected void putPluginContextObject (VelocityContext context, Template template) {
List <Plugin> plugins = template.getTemplateTarget().getTarget().getPlugins();
for (Plugin plugin : plugins) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
try {
Class clazz = cl.loadClass(plugin.getClassName());
Object velocityObject = clazz.newInstance();
context.put(plugin.getName(), velocityObject);
} catch (ClassNotFoundException e) {
logger.info("cannot find plugin "+plugin.getName()+" via class "+plugin.getClassName());
e.printStackTrace();
} catch (InstantiationException e) {
logger.info("cannot instantiate plugin "+plugin.getName()+" via class "+plugin.getClassName());
} catch (IllegalAccessException e) {
logger.info("cannot access plugin "+plugin.getName()+" via class "+plugin.getClassName());
}
}
}
protected String getTemplatePath (Template template) {
if ((templatePath==null || templatePath.equals("")) && isTemplatePathToReset) {
isTemplatePathToReset = false;
Configuration c = (Configuration)template.getTemplateTarget().getTarget().getAbstractConfigurationRoot();
Hashtable<String, String> ht = new Hashtable<String, String>();
TemplateTarget templateTarget = template.getTemplateTarget();
Target target = templateTarget.getTarget();
for (TemplateTarget templateTarget2 : target.getTemplateTargets()) {
String absoluteRootDir = templateTarget2.getAbsoluteRootDir();
if (absoluteRootDir!=null) {
ht.put(absoluteRootDir, absoluteRootDir);
}
String templateFullDir = templateTarget2.getTemplateFullDir();
if (templateFullDir!=null) {
ht.put(templateFullDir, templateFullDir);
}
}
for (String templateAssociated : target.getTemplatedirRefs()) {
for (String absoluteRootDir :target.getAbsoluteRootDirs(templateAssociated))
ht.put(absoluteRootDir, absoluteRootDir);
}
templatePath = getVelocityPath(ht,null);//getVelocityPath(ht, c.getCatalogDir());
}
return templatePath;
}
private String getTemplateRelativeLibPath (Template template) {
if (templateLibPath==null && isTemplateLibPathToReset) {
isTemplateLibPathToReset = false;
Configuration c = (Configuration)template.getTemplateTarget().getTarget().getAbstractConfigurationRoot();
Hashtable<String, String> ht = new Hashtable<String, String>();
TemplateTarget templateTarget = template.getTemplateTarget();
Target target = templateTarget.getTarget();
// StringBuffer sb = new StringBuffer();
for (TemplateTarget templateTarget2 : target.getTemplateTargets()) {
String libdir = templateTarget2.getLibdir();
if (libdir!=null && !libdir.equals("")) {
ht.put(libdir, libdir);
// sb.append(templateTarget2.getLibdir());
// sb.append(","); //TODO change for last element
}
}
templateLibPath = getVelocityPath(ht, null);
}
return templateLibPath;
}
private String getVelocityPath (Hashtable<String, String> ht, String prefix) {
StringBuffer sb = new StringBuffer();
Enumeration<String> e = ht.elements();
while (e.hasMoreElements()) {
if (prefix!=null)
sb.append(prefix+"/");
sb.append(e.nextElement());
if (e.hasMoreElements())
sb.append(",");
}
return sb.toString();
}
protected void produce(VelocityContext context, Template template, String outputFilename) throws Exception{
org.apache.velocity.Template velocityTemplate = getVelocityTemplate(template, outputFilename);
writeFile(context, velocityTemplate, outputFilename, template);
writeFilePostProcessing (template, outputFilename);
template.increaseNumberOfGeneratedArtifacts ();
}
private void writeFilePostProcessing(Template template, String outputFilename) {
String chmod = template.getChmod();
if (chmod!=null && !chmod.equals("")) {
File file = new File(outputFilename);
try {
Runtime.getRuntime().exec("chmod "+chmod+" "+file.getCanonicalPath());
} catch (IOException e) {
//do nothing example on windows chmod does not exist
}
}
}
private org.apache.velocity.Template getVelocityTemplate (Template template, String outputFilename) throws Exception {
org.apache.velocity.Template velocityTemplate = null;
try {
velocityTemplate = Velocity.getTemplate(template.getTemplateFileName());
}
catch( ResourceNotFoundException rnfe )
{
System.out.println("Error : cannot find template " + template.getTemplateFileName() );
}
catch( ParseErrorException pee )
{
System.out.println("Error : Syntax error in template " + template.getTemplateFileName() + ":" + pee );
}
return velocityTemplate;
}
private void writeFile (VelocityContext context, org.apache.velocity.Template velocityTemplate, String outputFilename, Template template) throws Exception {
FileOutputStream fos = new FileOutputStream(outputFilename);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos));
String licence = template.getLicence();
if (template.isLicenceAtBeginning() && licence!=null)
writer.append(licence);
if ( velocityTemplate != null)
velocityTemplate.merge(context, writer);
if (!template.isLicenceAtBeginning() && licence!=null)
writer.append(licence);
writer.flush();
writer.close();
}
protected String getAbstractBeanName (GeneratorBean bean) {
String beanName = StringUtils.lowerCase(bean.getClass().getName());
beanName = StringUtils.substring(beanName,
beanName.lastIndexOf(".") + 1);
// TODO change
if (beanName.equals("tableddlutils") || beanName.equals("tableumlnotation"))
return "table";
if (beanName.equals("columnddlutils"))
return "column";
if (beanName.equals("viewddlutils"))
return "view";
if (beanName.equals("componentddlutils"))
return "component";
if (beanName.equals("functionddlutils"))
return "function";
if (beanName.equals("wsdlmodelmetro"))
return "wsdlmodel";
return beanName;
}
protected Table getDecoratedTable (Table table) {
return DataModelFactory.getTable(table);
}
protected void writeTemplateResult(GeneratorBean bean, Template template) throws MinuteProjectException{
String outputFilename = template.getGeneratorOutputFileNameForConfigurationBean(bean, template);
VelocityContext context = getVelocityContext(template);
String beanName = getAbstractBeanName(bean);
context.put(beanName, bean);
context.put("template", template);
putCommonContextObject(context, template);
try {
produce(context, template, outputFilename);
} catch (Exception e) {
// TODO Auto-generated catch block
logger.error("ERROR on template "+template.getName()+" - on bean "+bean.getName());
throwException(e, e.getMessage());
}
}
protected void putCommonContextObject(VelocityContext context, Template template) {
putStandardContextObject(context);
putPluginContextObject(context, template);
}
protected void putStandardContextObject(VelocityContext context) {
context.put("convertUtils", new ConvertUtils());
context.put("commonUtils", new CommonUtils());
context.put("viewUtils", new ViewUtils());
context.put("formatUtils", new FormatUtils());
context.put("bslaLibraryUtils", new BslaLibraryUtils());
context.put("databaseUtils", new DatabaseUtils());
context.put("modelUtils", new ModelUtils());
context.put("templateUtils", new TemplateUtils());
context.put("propertyUtils", new PropertyUtils());
}
protected void exit (String message) {
// logger.error(message);
System.exit(-1);
}
protected void throwException (Exception e, String error) throws MinuteProjectException {
logger.error(error);
MinuteProjectException mpe = new MinuteProjectException();
mpe.setError(error);
if (e!=null)
mpe.setMessage(e.getMessage());
throw mpe;
}
protected void throwException (String error) throws MinuteProjectException {
throwException(null, error);
}
public void resetTemplatePath() {
isTemplateLibPathToReset = true;
isTemplatePathToReset = true;
}
}