Search in sources :

Example 1 with TextTemplateEngine

use of com.devonfw.cobigen.api.extension.TextTemplateEngine in project cobigen by devonfw.

the class TemplateEngineRegistry method getEngine.

/**
 * Returns a {@link TextTemplateEngine template engine} based on its name.
 *
 * @param name of the {@link TextTemplateEngine template engine}
 * @return the {@link TextTemplateEngine template engine} or {@code null} if no template engine has been registered
 *         with the name.
 */
public static TextTemplateEngine getEngine(String name) {
    TextTemplateEngine templateEngine = registeredEngines.get(name);
    if (templateEngine == null) {
        for (Class<? extends TextTemplateEngine> engine : ClassServiceLoader.getTemplateEngineClasses()) {
            if (engine.isAnnotationPresent(Name.class)) {
                Name engineNameAnnotation = engine.getAnnotation(Name.class);
                String engineName = engineNameAnnotation.value();
                if (name.equals(engineName)) {
                    register(engine, engineName);
                    break;
                }
            } else {
                LOG.warn("Template engine '{}' should have a name specified by @Name annotation.", engine.getClass().getCanonicalName());
            }
        }
    }
    templateEngine = registeredEngines.get(name);
    if (templateEngine == null) {
        throw new CobiGenRuntimeException("No template engine with name '" + name + "' registered.");
    }
    return ProxyFactory.getProxy(templateEngine);
}
Also used : CobiGenRuntimeException(com.devonfw.cobigen.api.exception.CobiGenRuntimeException) TextTemplateEngine(com.devonfw.cobigen.api.extension.TextTemplateEngine) Name(com.devonfw.cobigen.api.annotation.Name)

Example 2 with TextTemplateEngine

use of com.devonfw.cobigen.api.extension.TextTemplateEngine in project cobigen by devonfw.

the class TemplatesConfigurationReader method scanTemplates.

/**
 * Recursively scans the templates specified by the given {@link TemplateScan} and adds them to the given
 * <code>templates</code> {@link Map}.
 *
 * @param templateFolder the {@link TemplateFolder} pointing to the current directory to scan.
 * @param currentPath the current path relative to the top-level directory where we started the scan.
 * @param scan is the {@link TemplateScan} configuration.
 * @param templates is the {@link Map} where to add the templates.
 * @param trigger the templates are from
 * @param observedTemplateNames observed template name during template scan. Needed for conflict detection
 */
private void scanTemplates(TemplateFolder templateFolder, String currentPath, TemplateScan scan, Map<String, Template> templates, Trigger trigger, HashSet<String> observedTemplateNames) {
    String currentPathWithSlash = currentPath;
    if (!currentPathWithSlash.isEmpty()) {
        currentPathWithSlash = currentPathWithSlash + "/";
    }
    for (TemplatePath child : templateFolder.getChildren()) {
        if (child.isFolder()) {
            scanTemplates((TemplateFolder) child, currentPathWithSlash + child.getFileName(), scan, templates, trigger, observedTemplateNames);
        } else {
            String templateFileName = child.getFileName();
            if (StringUtils.isEmpty(currentPath) && templateFileName.equals("templates.xml")) {
                continue;
            }
            String templateNameWithoutExtension = stripTemplateFileending(templateFileName);
            TextTemplateEngine templateEngine = TemplateEngineRegistry.getEngine(getTemplateEngine());
            if (!StringUtils.isEmpty(templateEngine.getTemplateFileEnding()) && templateFileName.endsWith(templateEngine.getTemplateFileEnding())) {
                templateNameWithoutExtension = templateFileName.substring(0, templateFileName.length() - templateEngine.getTemplateFileEnding().length());
            }
            String templateName = (scan.getTemplateNamePrefix() != null ? scan.getTemplateNamePrefix() : "") + templateNameWithoutExtension;
            if (observedTemplateNames.contains(templateName)) {
                throw new InvalidConfigurationException("TemplateScan has detected two files with the same file name (" + child + ") and thus with the same " + "template name. Continuing would result in an indeterministic behavior.\n" + "For now, multiple files with the same name are not supported to be automatically " + "configured with templateScans.");
            }
            observedTemplateNames.add(templateName);
            if (!templates.containsKey(templateName)) {
                String destinationPath = "";
                if (!StringUtils.isEmpty(scan.getDestinationPath())) {
                    destinationPath = scan.getDestinationPath() + "/";
                }
                destinationPath += currentPathWithSlash + templateNameWithoutExtension;
                String mergeStratgey = scan.getMergeStrategy();
                Template template = createTemplate((TemplateFile) child, templateName, destinationPath, mergeStratgey, scan.getTargetCharset(), scan.getTemplatePath());
                templates.put(templateName, template);
                if (this.templateScanTemplates.get(scan.getName()) != null) {
                    this.templateScanTemplates.get(scan.getName()).add(templateName);
                }
            }
        }
    }
}
Also used : TemplatePath(com.devonfw.cobigen.impl.config.entity.TemplatePath) TextTemplateEngine(com.devonfw.cobigen.api.extension.TextTemplateEngine) InvalidConfigurationException(com.devonfw.cobigen.api.exception.InvalidConfigurationException) Template(com.devonfw.cobigen.impl.config.entity.Template)

Example 3 with TextTemplateEngine

use of com.devonfw.cobigen.api.extension.TextTemplateEngine in project cobigen by devonfw.

the class TemplatesConfigurationReader method stripTemplateFileending.

/**
 * Strips the file ending provided by the template engine from the file name.
 *
 * @param templateFileName file name of the template
 * @return the file name without the template file ending
 */
private String stripTemplateFileending(String templateFileName) {
    String templateNameWithoutExtension = templateFileName;
    TextTemplateEngine templateEngine = TemplateEngineRegistry.getEngine(getTemplateEngine());
    if (!StringUtils.isEmpty(templateEngine.getTemplateFileEnding()) && templateFileName.endsWith(templateEngine.getTemplateFileEnding())) {
        templateNameWithoutExtension = templateFileName.substring(0, templateFileName.length() - templateEngine.getTemplateFileEnding().length());
    }
    return templateNameWithoutExtension;
}
Also used : TextTemplateEngine(com.devonfw.cobigen.api.extension.TextTemplateEngine)

Example 4 with TextTemplateEngine

use of com.devonfw.cobigen.api.extension.TextTemplateEngine in project cobigen by devonfw.

the class GenerationProcessorImpl method generate.

/**
 * Generates code for the given input with the given template and the given {@link TriggerInterpreter} to the
 * destination specified by the templates configuration.
 *
 * @param template to be processed for generation
 * @param triggerInterpreter {@link TriggerInterpreter} to be used for reading the input and creating the model
 * @param origToTmpFileTrace the mapping of temporary generated files to their original target destination to
 *        eventually finalizing the generation process
 * @param progressCallback to track progress
 * @throws InvalidConfigurationException if the inputs do not fit to the configuration or there are some configuration
 *         failures
 */
private void generate(TemplateTo template, TriggerInterpreter triggerInterpreter, Map<File, File> origToTmpFileTrace, BiConsumer<String, Integer> progressCallback) {
    Trigger trigger = this.configurationHolder.readContextConfiguration().getTrigger(template.getTriggerId());
    InputReader inputReader = triggerInterpreter.getInputReader();
    if (!inputReader.isValidInput(this.input)) {
        throw new CobiGenRuntimeException("An invalid input of type " + this.input.getClass() + " has been passed to " + inputReader.getClass() + " (derived from trigger '" + trigger.getId() + "')");
    }
    List<Object> inputObjects = this.inputResolver.resolveContainerElements(this.input, trigger);
    TemplatesConfiguration tConfig = this.configurationHolder.readTemplatesConfiguration(trigger);
    String templateEngineName = tConfig.getTemplateEngine();
    TextTemplateEngine templateEngine = TemplateEngineRegistry.getEngine(templateEngineName);
    templateEngine.setTemplateFolder(this.configurationHolder.readContextConfiguration().getConfigurationPath().resolve(trigger.getTemplateFolder()));
    Template templateEty = tConfig.getTemplate(template.getId());
    if (templateEty == null) {
        throw new UnknownTemplateException(template.getId());
    }
    for (Object generatorInput : inputObjects) {
        progressCallback.accept("Building template model for input " + generatorInput, 1);
        Map<String, Object> model = buildModel(triggerInterpreter, trigger, generatorInput, templateEty);
        String targetCharset = templateEty.getTargetCharset();
        // resolve temporary file paths
        @SuppressWarnings("unchecked") PathExpressionResolver pathExpressionResolver = new PathExpressionResolver(Variables.fromMap((Map<String, String>) model.get(ModelBuilderImpl.NS_VARIABLES)));
        String resolvedTargetDestinationPath = pathExpressionResolver.evaluateExpressions(templateEty.getUnresolvedTargetPath());
        String resolvedTmpDestinationPath = pathExpressionResolver.evaluateExpressions(templateEty.getUnresolvedTemplatePath());
        File originalFile = this.targetRootPath.resolve(resolvedTargetDestinationPath).toFile();
        File tmpOriginalFile;
        if (origToTmpFileTrace.containsKey(originalFile)) {
            // use the available temporary file
            tmpOriginalFile = origToTmpFileTrace.get(originalFile);
        } else {
            tmpOriginalFile = this.tmpTargetRootPath.resolve(resolvedTmpDestinationPath).toFile();
            // remember mapping to later on copy the generated resources to its target destinations
            origToTmpFileTrace.put(originalFile, tmpOriginalFile);
        }
        if (originalFile.exists() || tmpOriginalFile.exists()) {
            if (!tmpOriginalFile.exists()) {
                try {
                    FileUtils.copyFile(originalFile, tmpOriginalFile);
                } catch (IOException e) {
                    throw new CobiGenRuntimeException("Could not copy file " + originalFile.getPath() + " to tmp generation directory! Generation skipped.", e);
                }
            }
            if ((this.forceOverride || template.isForceOverride()) && templateEty.getMergeStrategy() == null || ConfigurationConstants.MERGE_STRATEGY_OVERRIDE.equals(templateEty.getMergeStrategy())) {
                try (Formatter formatter = new Formatter()) {
                    formatter.format("Overriding %1$-40s FROM %2$-50s TO %3$s ...", originalFile.getName(), templateEty.getName(), resolvedTargetDestinationPath);
                    LOG.info(formatter.out().toString());
                    progressCallback.accept(formatter.out().toString(), 1);
                }
                progressCallback.accept("Generating " + template.getId() + " for " + generatorInput, 1);
                generateTemplateAndWriteFile(tmpOriginalFile, templateEty, templateEngine, model, targetCharset);
            } else if (templateEty.getMergeStrategy() != null) {
                try (Formatter formatter = new Formatter()) {
                    formatter.format("Merging    %1$-40s FROM %2$-50s TO %3$s ...", originalFile.getName(), templateEty.getName(), resolvedTargetDestinationPath);
                    LOG.info(formatter.out().toString());
                    progressCallback.accept(formatter.out().toString(), 1);
                }
                String patch = null;
                try (Writer out = new StringWriter()) {
                    templateEngine.process(templateEty, model, out, targetCharset);
                    patch = out.toString();
                    String mergeResult = null;
                    Merger merger = PluginRegistry.getMerger(templateEty.getMergeStrategy());
                    if (merger != null) {
                        mergeResult = merger.merge(tmpOriginalFile, patch, targetCharset);
                    } else {
                        throw new PluginNotAvailableException("merge strategy '" + templateEty.getMergeStrategy() + "'", null);
                    }
                    if (mergeResult != null) {
                        LOG.debug("Merge {} with char set {}.", tmpOriginalFile.getName(), targetCharset);
                        FileUtils.writeStringToFile(tmpOriginalFile, mergeResult, targetCharset);
                    } else {
                        throw new PluginProcessingException("Merger " + merger.getType() + " returned null on merge(...), which is not allowed.");
                    }
                } catch (MergeException e) {
                    writeBrokenPatchFile(targetCharset, tmpOriginalFile, patch);
                    // enrich merge exception to provide template ID
                    throw new MergeException(e, templateEty.getAbsoluteTemplatePath());
                } catch (IOException e) {
                    throw new CobiGenRuntimeException("Could not write file " + tmpOriginalFile.toPath() + " after merge.", e);
                }
            }
        } else {
            try (Formatter formatter = new Formatter()) {
                formatter.format("Generating %1$-40s FROM %2$-50s TO %3$s ...", originalFile.getName(), templateEty.getName(), resolvedTargetDestinationPath);
                LOG.info(formatter.out().toString());
                progressCallback.accept(formatter.out().toString(), 1);
            }
            generateTemplateAndWriteFile(tmpOriginalFile, templateEty, templateEngine, model, targetCharset);
        }
    }
}
Also used : CobiGenRuntimeException(com.devonfw.cobigen.api.exception.CobiGenRuntimeException) Formatter(java.util.Formatter) IOException(java.io.IOException) PluginNotAvailableException(com.devonfw.cobigen.api.exception.PluginNotAvailableException) PluginProcessingException(com.devonfw.cobigen.impl.exceptions.PluginProcessingException) TemplatesConfiguration(com.devonfw.cobigen.impl.config.TemplatesConfiguration) Template(com.devonfw.cobigen.impl.config.entity.Template) InputReader(com.devonfw.cobigen.api.extension.InputReader) Trigger(com.devonfw.cobigen.impl.config.entity.Trigger) Merger(com.devonfw.cobigen.api.extension.Merger) StringWriter(java.io.StringWriter) TextTemplateEngine(com.devonfw.cobigen.api.extension.TextTemplateEngine) MergeException(com.devonfw.cobigen.api.exception.MergeException) UnknownTemplateException(com.devonfw.cobigen.impl.exceptions.UnknownTemplateException) Map(java.util.Map) File(java.io.File) PathExpressionResolver(com.devonfw.cobigen.impl.config.resolver.PathExpressionResolver) Writer(java.io.Writer) StringWriter(java.io.StringWriter)

Example 5 with TextTemplateEngine

use of com.devonfw.cobigen.api.extension.TextTemplateEngine in project cobigen by devonfw.

the class TemplateEngineRegistry method register.

/**
 * Registers a new {@link TextTemplateEngine template engine}
 *
 * @param <T> type of the {@link TextTemplateEngine template engine} to be registered
 * @param templateEngine {@link TextTemplateEngine template engine} to be registered
 * @param name of the template engine
 */
public static <T extends TextTemplateEngine> void register(Class<T> templateEngine, String name) {
    try {
        TextTemplateEngine engine = templateEngine.newInstance();
        LOG.info("Register template engine '{}'.", templateEngine.getCanonicalName());
        if (StringUtils.isNotBlank(name)) {
            if (registeredEngines.containsKey(name)) {
                throw new CobiGenRuntimeException("An template engine with name " + name + " has already been registered.");
            }
            registeredEngines.put(name, engine);
        } else {
            throw new CobiGenRuntimeException("Cannot register a template engine without a type.");
        }
    } catch (InstantiationException | IllegalAccessException e) {
        throw new CobiGenRuntimeException("Could not intantiate TemplateEngine '" + templateEngine.getCanonicalName(), e);
    }
}
Also used : CobiGenRuntimeException(com.devonfw.cobigen.api.exception.CobiGenRuntimeException) TextTemplateEngine(com.devonfw.cobigen.api.extension.TextTemplateEngine)

Aggregations

TextTemplateEngine (com.devonfw.cobigen.api.extension.TextTemplateEngine)5 CobiGenRuntimeException (com.devonfw.cobigen.api.exception.CobiGenRuntimeException)3 Template (com.devonfw.cobigen.impl.config.entity.Template)2 Name (com.devonfw.cobigen.api.annotation.Name)1 InvalidConfigurationException (com.devonfw.cobigen.api.exception.InvalidConfigurationException)1 MergeException (com.devonfw.cobigen.api.exception.MergeException)1 PluginNotAvailableException (com.devonfw.cobigen.api.exception.PluginNotAvailableException)1 InputReader (com.devonfw.cobigen.api.extension.InputReader)1 Merger (com.devonfw.cobigen.api.extension.Merger)1 TemplatesConfiguration (com.devonfw.cobigen.impl.config.TemplatesConfiguration)1 TemplatePath (com.devonfw.cobigen.impl.config.entity.TemplatePath)1 Trigger (com.devonfw.cobigen.impl.config.entity.Trigger)1 PathExpressionResolver (com.devonfw.cobigen.impl.config.resolver.PathExpressionResolver)1 PluginProcessingException (com.devonfw.cobigen.impl.exceptions.PluginProcessingException)1 UnknownTemplateException (com.devonfw.cobigen.impl.exceptions.UnknownTemplateException)1 File (java.io.File)1 IOException (java.io.IOException)1 StringWriter (java.io.StringWriter)1 Writer (java.io.Writer)1 Formatter (java.util.Formatter)1