/* * (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.sg.generator; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.velocity.VelocityContext; import org.openflexo.foundation.DataFlexoObserver; import org.openflexo.foundation.FlexoModelObject; import org.openflexo.foundation.cg.CGFile; import org.openflexo.foundation.cg.generator.GeneratedCodeResult; import org.openflexo.foundation.cg.generator.IFlexoResourceGenerator; import org.openflexo.foundation.cg.templates.CGTemplate; import org.openflexo.foundation.rm.cg.CGRepositoryFileResource; import org.openflexo.foundation.sg.SourceRepository; import org.openflexo.foundation.sg.implmodel.TechnologyModuleDefinition; import org.openflexo.foundation.sg.implmodel.TechnologyModuleImplementation; import org.openflexo.foundation.utils.FlexoModelObjectReference; import org.openflexo.generator.Generator; import org.openflexo.generator.exception.TemplateNotFoundException; import org.openflexo.logging.FlexoLogger; import org.openflexo.sg.formatter.Formatter; import org.openflexo.sg.formatter.FormatterFactory; import org.openflexo.sg.formatter.exception.FormattingException; import org.openflexo.sg.generationdef.ContextEntry; import org.openflexo.sg.generationdef.FileEntry; import org.openflexo.toolbox.FileFormat; public abstract class SGGenerator<T extends FlexoModelObject, CR extends GeneratedCodeResult> extends Generator<T, SourceRepository> implements DataFlexoObserver, IFlexoResourceGenerator { private static final Logger logger = FlexoLogger.getLogger(SGGenerator.class.getPackage().getName()); protected CR generatedCode; private FileEntry fileEntry; protected ModuleGenerator moduleGenerator; protected FormattingException formattingException; public SGGenerator(ModuleGenerator moduleGenerator, FileEntry fileEntry) { this(moduleGenerator, fileEntry, null); } public SGGenerator(ModuleGenerator moduleGenerator, FileEntry fileEntry, T object) { super(moduleGenerator.getProjectGenerator(), object); this.fileEntry = fileEntry; this.moduleGenerator = moduleGenerator; } @Override public ProjectGenerator getProjectGenerator() { return (ProjectGenerator) super.getProjectGenerator(); } @Override public CR getGeneratedCode() { return generatedCode; } public FileEntry getFileEntry() { return fileEntry; } @Override protected final VelocityContext defaultContext() { VelocityContext returned = super.defaultContext(); returned.put("implementationModel", getRepository().getImplementationModel()); // Add the technology module and all its required modules in context for (TechnologyModuleDefinition moduleDefinition : moduleGenerator.getTechnologyModule().getTechnologyModuleDefinition() .getAllRequiredModules()) { TechnologyModuleImplementation implementation = getRepository().getImplementationModel().getTechnologyModule(moduleDefinition); if (implementation != null) { returned.put(ModuleGenerator.getTechnologyImplementationVelocityName(implementation), implementation); } } // Add the compatible technology modules in context for (TechnologyModuleDefinition moduleDefinition : moduleGenerator.getTechnologyModule().getTechnologyModuleDefinition() .getCompatibleModules()) { TechnologyModuleImplementation implementation = getRepository().getImplementationModel().getTechnologyModule(moduleDefinition); if (implementation != null) { returned.put(ModuleGenerator.getTechnologyImplementationVelocityName(implementation), implementation); } } for (ContextEntry ce : getFileEntry().template.contexts) { FlexoModelObjectReference<?> ref = new FlexoModelObjectReference<FlexoModelObject>(getProject(), ce.value); FlexoModelObject object = ref.getObject(true); if (object != null) { returned.put(ce.name, object); } } return returned; } /** * Calculate if a generation is needed. It will also clean the cross module cache if the file is marked as deleted. * * @param forceRegenerate * @return true if a generation must proceed, false otherwise. */ public boolean needGeneration(boolean forceRegenerate) { if (isResourceMarkedAsDeleted()) { formattingException = null; cleanCrossModuleDate(); return false; } return forceRegenerate || needsGeneration(); } /** * {@inheritDoc} */ @Override public void startGeneration() { super.startGeneration(); formattingException = null; cleanCrossModuleDate(); } /** * Clean the cross module data added by previous generation of this generator. */ protected void cleanCrossModuleDate() { // Clean cross module data for (ModuleGenerator moduleGenerator : getProjectGenerator().getAllModuleGenerators()) { moduleGenerator.cleanCrossModuleDataForGenerator(this); } } /** * Format the specified text according to the generator file format. If no formatter is found for this format the text is unchanged. * * @param text * @return the formatted text. */ protected String formatGeneration(String text) { Formatter formatter = FormatterFactory.getFormater(getFileFormat()); if (formatter != null) { try { return formatter.format(text); } catch (FormattingException e) { formattingException = e; } } return text; } /** * {@inheritDoc} */ @Override public boolean hasFormattingException() { return formattingException != null; } public ModuleGenerator getModuleGenerator() { return moduleGenerator; } public String getTemplateName() { return moduleGenerator.getTemplatesFolder() + getFileEntry().template.templateFile; } public FileFormat getFileFormat() { return getFileEntry().getFormat(); } /** * @see #getVelocityMacroTemplates(Generator, ModuleGenerator) */ @Override public List<CGTemplate> getVelocityMacroTemplates() { return getVelocityMacroTemplates(this, getModuleGenerator()); } /** * Takes all macro from current module, all its required modules (recursively) and all its compatible modules (NOT recursively). <br> * Order is as follow: deepest required modules to most direct one, then compatible modules then current module. * * @return the taken macro templates. */ public static List<CGTemplate> getVelocityMacroTemplates(Generator<?, ?> currentGenerator, ModuleGenerator moduleGenerator) { List<CGTemplate> macros = new ArrayList<CGTemplate>(); TechnologyModuleDefinition currentModuleDefinition = moduleGenerator.getTechnologyModule().getTechnologyModuleDefinition(); // Add required modules Map<Integer, LinkedHashSet<TechnologyModuleDefinition>> requiredModuleByLevel = currentModuleDefinition .getAllRequiredModulesByLevel(); List<Integer> orderedLevels = new ArrayList<Integer>(requiredModuleByLevel.keySet()); Collections.sort(orderedLevels); Collections.reverse(orderedLevels); for (Integer key : orderedLevels) { for (TechnologyModuleDefinition definition : requiredModuleByLevel.get(key)) { if (definition != currentModuleDefinition) // Will add current one after compatible modules { ModuleGenerator definitionModuleGenerator = moduleGenerator.getProjectGenerator().getModuleGenerator(definition); if (definitionModuleGenerator != null) { try { macros.add(currentGenerator.templateWithName(definitionModuleGenerator.getTemplatesFolder() + "VM_global_library.vm")); } catch (TemplateNotFoundException e) { if (logger.isLoggable(Level.FINE)) { logger.fine("Specific velocity macro library '" + definitionModuleGenerator.getTemplatesFolder() + "VM_global_library.vm" + "' not found in module."); e.printStackTrace(); } } } } } } // Add compatible modules for (TechnologyModuleDefinition definition : currentModuleDefinition.getCompatibleModules()) { ModuleGenerator definitionModuleGenerator = moduleGenerator.getProjectGenerator().getModuleGenerator(definition); if (definitionModuleGenerator != null) { try { macros.add(currentGenerator.templateWithName(definitionModuleGenerator.getTemplatesFolder() + "VM_global_library.vm")); } catch (TemplateNotFoundException e) { if (logger.isLoggable(Level.FINE)) { logger.fine("Specific velocity macro library '" + definitionModuleGenerator.getTemplatesFolder() + "VM_global_library.vm" + "' not found in module."); e.printStackTrace(); } } } } // Add current module try { macros.add(currentGenerator.templateWithName(moduleGenerator.getTemplatesFolder() + "VM_global_library.vm")); } catch (TemplateNotFoundException e) { if (logger.isLoggable(Level.FINE)) { logger.fine("Specific velocity macro library '" + moduleGenerator.getTemplatesFolder() + "VM_global_library.vm" + "' not found in module."); e.printStackTrace(); } } return macros; } protected CGRepositoryFileResource<?, ?, ? extends CGFile> getGeneratedResource() { if (getGeneratedResources().size() == 0) { return null; } if (getGeneratedResources().size() > 1) { logger.warning("getGeneratedResource in SGGenerator retrieved more than 1 resource. A SGGenerator is supposed to generate only 1 resource ! Number of retrieved resources: " + getGeneratedResources().size() + ". Returning the first one"); } return getGeneratedResources().get(0); } protected boolean isResourceMarkedAsDeleted() { CGRepositoryFileResource<?, ?, ? extends CGFile> resource = getGeneratedResource(); if (resource == null) { return false; } CGFile cgFile = resource.getCGFile(); return cgFile != null && cgFile.isMarkedForDeletion(); } }