All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jbake.template.TemplateEngines Maven / Gradle / Ivy

Go to download

JBake is a Java based open source static site/blog generator for developers.

There is a newer version: 2.7.0-rc.7
Show newest version
package org.jbake.template;

import org.jbake.app.ContentStore;
import org.jbake.app.configuration.JBakeConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;


/**
 * 

* A singleton class giving access to rendering engines. Rendering engines are loaded based on classpath. New * rendering may be registered either at runtime (not recommanded) or by putting a descriptor file on classpath * (recommanded).

*

The descriptor file must be found in META-INF directory and named * org.jbake.parser.TemplateEngines.properties. The format of the file is easy:

* org.jbake.parser.FreeMarkerRenderer=ftl
org.jbake.parser.GroovyRenderer=groovy,gsp
*

where the key is the class of the engine (must extend {@link AbstractTemplateEngine} and have * a 4-arg constructor and the value is a comma-separated list of file extensions that this engine is capable * of proceeding.

*

Rendering engines are singletons, so are typically used to initialize the underlying template engines. *

* This class loads the engines only if they are found on classpath. If not, the engine is not registered. This allows * JBake to support multiple rendering engines without the explicit need to have them on classpath. This is a better fit * for embedding. *

* * @author Cédric Champeau */ public class TemplateEngines { private static final Logger LOGGER = LoggerFactory.getLogger(TemplateEngines.class); private final Map engines; public Set getRecognizedExtensions() { return Collections.unmodifiableSet(engines.keySet()); } public TemplateEngines(final JBakeConfiguration config, final ContentStore db) { engines = new HashMap<>(); loadEngines(config, db); } private void registerEngine(String fileExtension, AbstractTemplateEngine templateEngine) { AbstractTemplateEngine old = engines.put(fileExtension, templateEngine); if (old != null) { LOGGER.warn("Registered a template engine for extension [.{}] but another one was already defined: {}", fileExtension, old); } } public AbstractTemplateEngine getEngine(String fileExtension) { return engines.get(fileExtension); } /** * This method is used to search for a specific class, telling if loading the engine would succeed. This is * typically used to avoid loading optional modules. * * * @param config the configuration * @param db database instance * @param engineClassName engine class, used both as a hint to find it and to create the engine itself. @return null if the engine is not available, an instance of the engine otherwise */ private static AbstractTemplateEngine tryLoadEngine(final JBakeConfiguration config, final ContentStore db, String engineClassName) { try { @SuppressWarnings("unchecked") Class engineClass = (Class) Class.forName(engineClassName, false, TemplateEngines.class.getClassLoader()); Constructor ctor = engineClass.getConstructor(JBakeConfiguration.class, ContentStore.class); return ctor.newInstance(config, db); } catch (Throwable e) { // not all engines might be necessary, therefore only emit class loading issue with level warn LOGGER.debug("Template engine not available: {}", engineClassName); return null; } } /** * This method is used internally to load markup engines. Markup engines are found using descriptor files on * classpath, so adding an engine is as easy as adding a jar on classpath with the descriptor file included. */ private void loadEngines(final JBakeConfiguration config, final ContentStore db) { try { ClassLoader cl = TemplateEngines.class.getClassLoader(); Enumeration resources = cl.getResources("META-INF/org.jbake.parser.TemplateEngines.properties"); while (resources.hasMoreElements()) { URL url = resources.nextElement(); Properties props = new Properties(); props.load(url.openStream()); for (Map.Entry entry : props.entrySet()) { String className = (String) entry.getKey(); String[] extensions = ((String) entry.getValue()).split(","); registerEngine(config, db, className, extensions); } } } catch (IOException e) { LOGGER.error("Error loading engines", e); } } private void registerEngine(final JBakeConfiguration config, final ContentStore db, String className, String... extensions) { AbstractTemplateEngine engine = tryLoadEngine(config, db, className); if (engine != null) { for (String extension : extensions) { registerEngine(extension, engine); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy