/* * #%~ * VDM Code Generator * %% * Copyright (C) 2008 - 2014 Overture * %% * This program 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. * * This program 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 this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.codegen.merging; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.HashMap; import org.apache.velocity.Template; import org.apache.velocity.runtime.RuntimeServices; import org.apache.velocity.runtime.RuntimeSingleton; import org.apache.velocity.runtime.parser.ParseException; import org.apache.velocity.runtime.parser.node.SimpleNode; import org.overture.codegen.ir.INode; import org.overture.codegen.utils.GeneralUtils; public class TemplateManager { public static final String TEMPLATE_FILE_EXTENSION = ".vm"; /** * Relative paths for user-defined template files */ protected HashMap<Class<? extends INode>, TemplateData> userDefinedPaths; /** * cache */ final protected HashMap<Class<? extends INode>, Template> cache = new HashMap<Class<? extends INode>, Template>(); protected String root; private Class<?> templateLoadRef = null; /** * Not for use with extensions. Use {@link #TemplateManager(String, Class)} instead. * * @param root * The template root folder */ public TemplateManager(String root) { this(root, null); } /** * This is an extensibility version of the template manager constructor for the benefit of OSGi extensions. <br> * <br> * Because of the way classloaders work in OSGi, the template lookups fail if the templates are located in another * bundle. This provides a workaround by using templateLoadRef to provide a specific class. Just pass it any class * that is native to the extension bundle and it should work. * * @param root * The template root folder * @param templateLoadRef */ public TemplateManager(String root, Class<?> templateLoadRef) { this.root = root; if (templateLoadRef != null) { this.templateLoadRef = templateLoadRef; } else { this.templateLoadRef = this.getClass(); } initNodeTemplateFileNames(); } public Class<?> getTemplateLoaderRef() { return templateLoadRef; } public String getRoot() { return root; } protected void initNodeTemplateFileNames() { this.userDefinedPaths = new HashMap<>(); } public Template getTemplate(Class<? extends INode> nodeClass) throws ParseException { if (cache.containsKey(nodeClass)) { return cache.get(nodeClass); } try { TemplateData td = getTemplateData(nodeClass); StringBuffer buffer = GeneralUtils.readFromFile(td.getTemplatePath(), td.getTemplateLoaderRef()); if (buffer == null) { return null; } Template template = constructTemplate(td.getTemplatePath(), buffer); cache.put(nodeClass, template); return template; } catch (IOException e) { return null; } } public String getTemplatePath(Class<? extends INode> nodeClass) { return getTemplateData(nodeClass).getTemplatePath(); } public TemplateData getTemplateData(Class<? extends INode> nodeClass) { if (isUserDefined(nodeClass)) { return userDefinedPaths.get(nodeClass); } else { return new TemplateData(templateLoadRef, derivePath(root, nodeClass)); } } protected Template constructTemplate(String name, StringBuffer buffer) throws ParseException { Template template = new Template(); RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices(); StringReader reader = new StringReader(buffer.toString()); SimpleNode simpleNode = runtimeServices.parse(reader, name); template.setRuntimeServices(runtimeServices); template.setData(simpleNode); template.initDocument(); return template; } public void setUserTemplatePath(Class<?> templateLoaderRef, Class<? extends INode> nodeClass, String templatePath) { userDefinedPaths.put(nodeClass, new TemplateData(templateLoadRef, templatePath)); } public boolean isUserDefined(Class<? extends INode> nodeClass) { return userDefinedPaths.containsKey(nodeClass); } public static String derivePath(String root, Class<? extends INode> nodeClass) { return root + File.separatorChar + nodeClass.getName().replace('.', File.separatorChar) + TEMPLATE_FILE_EXTENSION; } }