/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.generator; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.tools.ant.BuildEvent; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildListener; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectHelper; import org.openflexo.foundation.CodeType; import org.openflexo.foundation.bpel.BPELWriter; import org.openflexo.foundation.cg.CGRepository; import org.openflexo.foundation.cg.templates.CGTemplate; import org.openflexo.foundation.cg.templates.CGTemplates; import org.openflexo.foundation.dm.DMEntity; import org.openflexo.foundation.dm.DMPackage; import org.openflexo.foundation.ie.IEWOComponent; import org.openflexo.foundation.ie.ProjectInstanceTree; import org.openflexo.foundation.ie.cl.ComponentDefinition; import org.openflexo.foundation.rm.FlexoProject; import org.openflexo.foundation.rm.cg.CGRepositoryFileResource; import org.openflexo.foundation.wkf.FlexoProcess; import org.openflexo.generator.bpel.BPELGenerator; import org.openflexo.generator.dm.DataModelGenerator; import org.openflexo.generator.exception.GenerationException; import org.openflexo.generator.exception.PermissionDeniedException; import org.openflexo.generator.exception.TemplateNotFoundException; import org.openflexo.generator.ie.ComponentsGenerator; import org.openflexo.generator.utils.BuildXmlGenerator; import org.openflexo.generator.utils.FlexoReaderGenerator; import org.openflexo.generator.utils.PrototypeProcessBusinessDataSamplesCreator; import org.openflexo.generator.utils.ResourceGenerator; import org.openflexo.generator.wkf.ControlGraphsGenerator; import org.openflexo.generator.wkf.WorkflowContextGenerator; import org.openflexo.toolbox.FileResource; import org.openflexo.toolbox.FileUtils; import org.openflexo.toolbox.FileUtils.CopyStrategy; /** * Controller for Generator module * * @author sguerin */ public class ProjectGenerator extends AbstractProjectGenerator<CGRepository> implements BuildListener { private static final FileResource WOPROJECT_JAR = new FileResource("Config/Generator/Libraries/woproject.jar"); protected static final Logger logger = Logger.getLogger(ProjectGenerator.class.getPackage().getName()); private static final FileResource ZIPPED_API_FILE = new FileResource("Config/Generator/Libraries/api-proto.zip"); private static final FileResource ZIPPED_FRAMEWORK_FILE = new FileResource("Config/Generator/Libraries/framework-proto.zip"); private static final String CG_MACRO_LIBRARY_NAME = "VM_global_library.vm"; private static final String GENERATE_COMPONENTS = "generate_page_components"; private static final String GENERATE_UTILS = "generate_util_classes"; private static final String GENERATE_APPLICATION_RESOURCES = "generate_application_resources"; private static final String GENERATE_DATA_MODEL = "generating_data_model"; private static final String GENERATE_READER = "generate_reader"; private static final String GENERATE_WORKFLOW = "generate_workflow"; private static final String GENERATE_CONTROL_GRAPHS = "generating_control_graph"; private Hashtable<FlexoProcess, BPELWriter> processes = new Hashtable<FlexoProcess, BPELWriter>(); private ComponentsGenerator componentsGenerator; private UtilsGenerator utilsGenerator; private ResourceGenerator resourceGenerator; private DataModelGenerator dataModelGenerator; private FlexoReaderGenerator readerGenerator; private ControlGraphsGenerator controlGraphsGenerator; private BPELGenerator bpelGenerator; private WorkflowContextGenerator workflowGenerator; protected FlexoProcess _currentProcess; private boolean hasBeenInitialized = false; private ProjectInstanceTree _projectInstanceTree = null; private Vector<BuildListener> buildListeners; // ============================================================= // ======================== Constructor ======================== // ============================================================= /** * Default constructor * * @param workflowFile * @throws Exception */ public ProjectGenerator(FlexoProject project, CGRepository repository) throws GenerationException { super(project, repository); if (repository == null) { if (logger.isLoggable(Level.FINE)) { logger.fine("No target repository, this may happen during dynamic invocation of code generator within the context of the Data model edition"); } } if (repository != null) { if (repository.getTargetType() == CodeType.BPEL) { bpelGenerator = new BPELGenerator(this); } else { dataModelGenerator = new DataModelGenerator(this); componentsGenerator = new ComponentsGenerator(this); utilsGenerator = new UtilsGenerator(this); resourceGenerator = new ResourceGenerator(this); if (repository.includeReader()) { readerGenerator = new FlexoReaderGenerator(this); } workflowGenerator = new WorkflowContextGenerator(this); // Not used yet controlGraphsGenerator = new ControlGraphsGenerator(this); } } if (getRootOutputDirectory() != null) { if (!getResourceOutputDirectory().exists()) { getRootOutputDirectory().mkdirs(); } if (!getRootOutputDirectory().canWrite()) { throw new PermissionDeniedException(getRootOutputDirectory(), this); } } buildListeners = new Vector<BuildListener>(); } public boolean isPrototype() { return getTarget() == CodeType.PROTOTYPE; } @Override public CGTemplates getDefaultTemplates() { return getProject().getGeneratedCode().getTemplates(); } @Override public CodeType getTarget() { return (CodeType) super.getTarget(); } public ProjectInstanceTree getProjectInstanceTree() { if (_projectInstanceTree == null) { _projectInstanceTree = new ProjectInstanceTree(getProject()); } return _projectInstanceTree; } @Override public Logger getGeneratorLogger() { return logger; } /** * This method is very important, because it is the way we must identify or build all resources involved in code generation. After this * list has been built, we just let ResourceManager do the work. * * @param repository * : repository where resources should be retrieved or built * @param resources * : the list of resources we must retrieve or build */ @Override public void buildResourcesAndSetGenerators(CGRepository repository, Vector<CGRepositoryFileResource> resources) { hasBeenInitialized = true; if (componentsGenerator != null) { refreshProgressWindow(GENERATE_COMPONENTS, true); componentsGenerator.buildResourcesAndSetGenerators(repository, resources); } if (utilsGenerator != null) { refreshProgressWindow(GENERATE_UTILS, true); utilsGenerator.buildResourcesAndSetGenerators(repository, resources); } if (resourceGenerator != null) { refreshProgressWindow(GENERATE_APPLICATION_RESOURCES, true); resourceGenerator.buildResourcesAndSetGenerators(repository, resources); } if (dataModelGenerator != null) { refreshProgressWindow(GENERATE_DATA_MODEL, true); dataModelGenerator.buildResourcesAndSetGenerators(repository, resources); } if (readerGenerator != null) { refreshProgressWindow(GENERATE_READER, true); readerGenerator.buildResourcesAndSetGenerators(repository, resources); } if (workflowGenerator != null) { refreshProgressWindow(GENERATE_WORKFLOW, true); workflowGenerator.buildResourcesAndSetGenerators(repository, resources); } /*if (controlGraphsGenerator != null) { controlGraphsGenerator.buildResourcesAndSetGenerators(repository, resources); }*/ if (bpelGenerator != null) { bpelGenerator.buildResourcesAndSetGenerators(repository, resources); } } @Override public boolean hasBeenInitialized() { return hasBeenInitialized; } public File generateWar(boolean cleanImmediately) throws GenerationException { final File distDirectory = getRepository().getWarDirectory(); if (distDirectory == null) { throw new GenerationException("You MUST define a target directory. Sorry."); } if (!distDirectory.exists()) { distDirectory.mkdirs(); } final File tmpOutputDir; try { tmpOutputDir = File.createTempFile("WAR-build-" + FileUtils.getValidFileName(getProject().getName()), null); } catch (IOException e2) { e2.printStackTrace(); throw new GenerationException("Error while creating temporary war output directory in temporary directory", "error_while_generating", null, e2); } if (tmpOutputDir.exists()) { FileUtils.recursiveDeleteFile(tmpOutputDir); } tmpOutputDir.mkdirs(); final File genTempOutputDir = new File(tmpOutputDir, getPrefix() + "Application"); if (!genTempOutputDir.exists()) { genTempOutputDir.mkdir(); } Map<String, String> defaultProperties = new HashMap<String, String>(); File warFile = new File(distDirectory, getRepository().getWarName() + ".war"); defaultProperties.put("war.file", warFile.getAbsolutePath()); defaultProperties.put("zipped.api.file", ZIPPED_API_FILE.getAbsolutePath()); defaultProperties.put("zipped.framework.file", ZIPPED_FRAMEWORK_FILE.getAbsolutePath()); File[] listFiles = getProject().getFrameworksToEmbedDirectory().listFiles(); if (listFiles != null && listFiles.length > 0) { defaultProperties.put("flexo.framework.dir", getProject().getFrameworksToEmbedDirectory().getAbsolutePath()); } defaultProperties.put("woproject.lib", WOPROJECT_JAR.getAbsolutePath()); if (logger.isLoggable(Level.INFO)) { logger.info("Copying repository (" + getRepository().getDirectory().getAbsolutePath() + ") to temp dir: " + genTempOutputDir.getAbsolutePath()); } try { FileUtils.copyContentDirToDir(getRepository().getDirectory(), genTempOutputDir, CopyStrategy.REPLACE, new FileFilter() { @Override public boolean accept(File pathname) { return pathname.isDirectory() || !pathname.getName().endsWith(".class"); } }); } catch (IOException e1) { e1.printStackTrace(); throw new RuntimeException(); } Project project = new Project(); project.init(); File buildFile = new File(genTempOutputDir, BuildXmlGenerator.FILE_NAME); try { ProjectHelper.getProjectHelper().parse(project, buildFile); project.setBaseDir(genTempOutputDir); } catch (BuildException e) { e.printStackTrace(); setGenerationException(new WARBuildingException(new Exception("Configuration file " + buildFile + " is invalid, or cannot be read.", e))); } if (logger.isLoggable(Level.INFO)) { logger.info("Launching war creation. Working directory is " + tmpOutputDir.getAbsolutePath()); } for (Entry<String, String> e : defaultProperties.entrySet()) { project.setUserProperty(e.getKey(), e.getValue()); } project.addBuildListener(this); if (logger.isLoggable(Level.INFO)) { logger.info("Ant file is " + project.getProperty("ant.file")); } try { project.executeTarget(project.getDefaultTarget()); } catch (BuildException e) { e.printStackTrace(); setGenerationException(new WARBuildingException(e)); } project.removeBuildListener(this); clean(genTempOutputDir, cleanImmediately); if (getGenerationException() != null) { GenerationException e = getGenerationException(); resetGenerationException(); throw e; } return warFile; } private void clean(final File genTempOutputDir, boolean cleanImmediately) { Thread t = new Thread(new Runnable() { @Override public void run() { try { if (logger.isLoggable(Level.INFO)) { logger.info("Deleting " + genTempOutputDir.getAbsolutePath()); } FileUtils.recursiveDeleteFile(genTempOutputDir); if (logger.isLoggable(Level.INFO)) { logger.info("Done deleting " + genTempOutputDir.getAbsolutePath()); } } catch (Exception e) { e.printStackTrace(); } finally { } } }); t.setPriority(Thread.MIN_PRIORITY); t.start(); if (cleanImmediately) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * Generates the data model classes. Resources are not copied. * * @return - true */ protected boolean generateDataModel(boolean forceRegenerate) throws GenerationException { if (dataModelGenerator != null) { refreshProgressWindow(GENERATE_DATA_MODEL, true); dataModelGenerator.generate(forceRegenerate); return true; } return false; } protected boolean generateControlGraphs(boolean forceRegenerate) throws GenerationException { if (dataModelGenerator != null) { refreshProgressWindow(GENERATE_CONTROL_GRAPHS, true); controlGraphsGenerator.generate(forceRegenerate); return true; } return false; } /** * Generates the workflow: screens, popups, utils classes and copies resources. * * @return - true if the workflow is effectively generated. */ public boolean generateWorkflow(boolean forceRegenerate) throws GenerationException { if (componentsGenerator != null) { refreshProgressWindow(GENERATE_COMPONENTS, true); componentsGenerator.generate(forceRegenerate); } /* if (popupsGenerator != null) { refreshProgressWindow(GENERATE_POPUPS,true); popupsGenerator.generate(forceRegenerate); } if (tabsGenerator != null) { refreshProgressWindow(GENERATE_TABS,true); tabsGenerator.generate(forceRegenerate); } */ if (utilsGenerator != null) { refreshProgressWindow(GENERATE_UTILS, true); utilsGenerator.generate(forceRegenerate); } if (resourceGenerator != null) { refreshProgressWindow(GENERATE_APPLICATION_RESOURCES, true); resourceGenerator.generate(forceRegenerate); } return true; } public Properties collectComponentHelp() { Properties p = new Properties(); Enumeration<ComponentDefinition> en = getProject().getFlexoComponentLibrary().getAllComponentList().elements(); ComponentDefinition cd = null; IEWOComponent comp = null; while (en.hasMoreElements()) { cd = en.nextElement(); comp = cd.getWOComponent(); if (comp != null) { if (comp.hasHelpText()) { p.put(cd.getComponentName(), comp.getHelpText()); } } } return p; } public String getAfterLoginDA() { // return utilsGenerator.getDirectActionGenerator().getGeneratedClassName() + "/open" // + nameForOperation(getProject().getFlexoNavigationMenu().getRootMenu().getOperation()); if (getProject().getFlexoNavigationMenu().getRootMenu().getOperation() == null) { if (getProject().getFlexoWorkflow() != null && getProject().getFlexoWorkflow().getRootFlexoProcess().getAllOperationNodesWithComponent().size() > 0) { return getProject().getFlexoWorkflow().getRootFlexoProcess().getAllOperationNodesWithComponent().get(0) .getStaticDirectActionUrl(); } else { return "null"; } } return getProject().getFlexoNavigationMenu().getRootMenu().getOperation().getStaticDirectActionUrl(); } // public WorkflowGenerator getWorkflowGenerator() // { // return workflowGenerator; // } public ComponentsGenerator getComponentsGenerator() { return componentsGenerator; } public DataModelGenerator getDataModelGenerator() { return dataModelGenerator; } public File getResourceOutputDirectory() { return getRootOutputDirectory(); } public File getWebResourceOutputDirectory() { return getRepository().getWebResourcesSymbolicDirectory().getDirectory().getFile(); } @Override public File getRootOutputDirectory() { if (getRepository() == null) { return null; } return getRepository().getDirectory(); } public void addBuildListener(BuildListener listener) { buildListeners.add(listener); } public void removeBuildListener(BuildListener listener) { buildListeners.remove(listener); } public UtilsGenerator getUtilsGenerator() { return utilsGenerator; } public BPELWriter getInstance(FlexoProcess p, boolean forceNew) { if (processes.containsKey(p) && !forceNew) { System.out.println("returning old BPELWriter for process : " + p.getName()); return processes.get(p); } else { System.out.println("returning new BPELWriter for process : " + p.getName()); if (processes.containsKey(p) && forceNew) { processes.remove(p); } BPELWriter newWriter = new BPELWriter(p); processes.put(p, newWriter); return newWriter; } } /** * {@inheritDoc} */ @Override public List<CGTemplate> getVelocityMacroTemplates() { List<CGTemplate> result = new ArrayList<CGTemplate>(); try { result.add(templateWithName(CG_MACRO_LIBRARY_NAME)); } catch (TemplateNotFoundException e) { logger.warning("Should include velocity macro template for project generator but template is not found '" + CG_MACRO_LIBRARY_NAME + "'"); e.printStackTrace(); } return result; } public String getPrototypeProcessInstance_Id_Key() { return PrototypeProcessBusinessDataSamplesCreator.PROCESSINSTANCE_ID_KEY; } public String getPrototypeProcessInstance_Status_Key() { return FlexoProcess.PROCESSINSTANCE_STATUS_KEY; } public String getPrototypeProcessInstance_CreationDate_Key() { return FlexoProcess.PROCESSINSTANCE_CREATIONDATE_KEY; } public String getPrototypeProcessInstance_LastUpdateDate_Key() { return FlexoProcess.PROCESSINSTANCE_LASTUPDATEDATE_KEY; } public String getWorkflowClassPackage() { return WorkflowContextGenerator.PACKAGENAME; } public DMEntity getProcessBusinessDataBaseEntity() { return getProject().getDataModel().getProcessBusinessDataRepository().getProcessBusinessDataEntity(); } public String getProcessBusinessDataPackageImports() { StringBuilder sb = new StringBuilder(); for (DMPackage dmPackage : getProject().getDataModel().getProcessBusinessDataRepository().getPackages().values()) { if (!dmPackage.isDefaultPackage()) { sb.append("import " + dmPackage.getFullyQualifiedName() + ".*;"); } } return sb.toString(); } @Override public void buildStarted(BuildEvent event) { for (BuildListener l : buildListeners) { l.buildStarted(event); } } @Override public void buildFinished(BuildEvent event) { for (BuildListener l : buildListeners) { l.buildFinished(event); } } @Override public void targetStarted(BuildEvent event) { for (BuildListener l : buildListeners) { l.targetStarted(event); } } @Override public void targetFinished(BuildEvent event) { for (BuildListener l : buildListeners) { l.targetFinished(event); } } @Override public void taskStarted(BuildEvent event) { for (BuildListener l : buildListeners) { l.taskStarted(event); } } @Override public void taskFinished(BuildEvent event) { for (BuildListener l : buildListeners) { l.taskFinished(event); } } @Override public void messageLogged(BuildEvent event) { for (BuildListener l : buildListeners) { l.messageLogged(event); } } }