diff --git a/pom.xml b/pom.xml index 3aeed51a6..b74b5d507 100644 --- a/pom.xml +++ b/pom.xml @@ -156,6 +156,7 @@ symphony-bdk-core-invokers symphony-bdk-examples symphony-bdk-spring + symphony-bdk-template diff --git a/symphony-bdk-bom/pom.xml b/symphony-bdk-bom/pom.xml index 123dc7494..4d6e0888d 100644 --- a/symphony-bdk-bom/pom.xml +++ b/symphony-bdk-bom/pom.xml @@ -67,6 +67,16 @@ symphony-bdk-core-spring-boot-starter ${project.version} + + com.symphony.platformsolutions + symphony-bdk-template-api + ${project.version} + + + com.symphony.platformsolutions + symphony-bdk-template-freemarker + ${project.version} + diff --git a/symphony-bdk-examples/bdk-template-examples/pom.xml b/symphony-bdk-examples/bdk-template-examples/pom.xml new file mode 100644 index 000000000..e21f1bea3 --- /dev/null +++ b/symphony-bdk-examples/bdk-template-examples/pom.xml @@ -0,0 +1,49 @@ + + + + symphony-bdk-examples + com.symphony.platformsolutions + 1.2.0-SNAPSHOT + + 4.0.0 + + symphony-bdk-template-examples + Symphony Java BDK Examples - Template + Symphony Java BDK Examples for the Template module + + + + + com.symphony.platformsolutions + symphony-bdk-bom + ${project.version} + pom + import + + + + + + + com.symphony.platformsolutions + symphony-bdk-template-freemarker + + + org.projectlombok + lombok + provided + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + + diff --git a/symphony-bdk-examples/bdk-template-examples/src/main/java/com/symphony/template/examples/FreeMarkerExample.java b/symphony-bdk-examples/bdk-template-examples/src/main/java/com/symphony/template/examples/FreeMarkerExample.java new file mode 100644 index 000000000..11ea433d0 --- /dev/null +++ b/symphony-bdk-examples/bdk-template-examples/src/main/java/com/symphony/template/examples/FreeMarkerExample.java @@ -0,0 +1,37 @@ +package com.symphony.template.examples; + +import com.symphony.bdk.template.api.Template; +import com.symphony.bdk.template.api.TemplateEngine; +import com.symphony.bdk.template.api.TemplateException; + +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; + +/** + * Sample class showing usage of FreeMarker templates. + */ +@Slf4j +public class FreeMarkerExample { + public static void main(String[] args) throws TemplateException { + log.info("String generated from built-in template: {}", getStringFromBuiltInTemplate()); + log.info("String generated from custom template: {}", getStringFromCustomTemplate()); + } + + private static String getStringFromBuiltInTemplate() throws TemplateException { + Template template = TemplateEngine.getDefaultImplementation().newBuiltInTemplate("simpleMML"); + final String message = template.process(new HashMap() {{ + put("message", "Hello World !"); + }}); + return message; + } + + private static String getStringFromCustomTemplate() throws TemplateException { + Template template = TemplateEngine.getDefaultImplementation() + .newTemplateFromClasspath("templates/customTemplate.ftl"); + final String message = template.process(new HashMap() {{ + put("message", "Hello World"); + }}); + return message; + } +} diff --git a/symphony-bdk-examples/bdk-template-examples/src/main/resources/templates/customTemplate.ftl b/symphony-bdk-examples/bdk-template-examples/src/main/resources/templates/customTemplate.ftl new file mode 100644 index 000000000..8dd7b7358 --- /dev/null +++ b/symphony-bdk-examples/bdk-template-examples/src/main/resources/templates/customTemplate.ftl @@ -0,0 +1 @@ +${message} from custom template ! diff --git a/symphony-bdk-examples/pom.xml b/symphony-bdk-examples/pom.xml index 0cc1544f1..91cac6004 100644 --- a/symphony-bdk-examples/pom.xml +++ b/symphony-bdk-examples/pom.xml @@ -17,6 +17,7 @@ bdk-core-examples bdk-spring-boot-example + bdk-template-examples diff --git a/symphony-bdk-template/pom.xml b/symphony-bdk-template/pom.xml new file mode 100644 index 000000000..2dea93d4a --- /dev/null +++ b/symphony-bdk-template/pom.xml @@ -0,0 +1,22 @@ + + + + 4.0.0 + + symphony-api-client-java-parent + com.symphony.platformsolutions + 1.2.0-SNAPSHOT + + + symphony-bdk-template + Symphony Java BDK Template + Symphony Java BDK Template Module + pom + + + symphony-bdk-template-api + symphony-bdk-template-freemarker + + + diff --git a/symphony-bdk-template/symphony-bdk-template-api/pom.xml b/symphony-bdk-template/symphony-bdk-template-api/pom.xml new file mode 100644 index 000000000..611fe1f42 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-api/pom.xml @@ -0,0 +1,45 @@ + + + + symphony-bdk-template + com.symphony.platformsolutions + 1.2.0-SNAPSHOT + + 4.0.0 + + symphony-bdk-template-api + Symphony Java BDK Template API + Symphony Java BDK Template API module + + + + + com.symphony.platformsolutions + symphony-bdk-bom + ${project.version} + pom + import + + + + + + + org.apiguardian + apiguardian-api + + + org.slf4j + slf4j-api + + + org.junit.jupiter + junit-jupiter + test + + + + + diff --git a/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/Template.java b/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/Template.java new file mode 100644 index 000000000..80f9f5ec8 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/Template.java @@ -0,0 +1,21 @@ +package com.symphony.bdk.template.api; + +import org.apiguardian.api.API; + +/** + * Interface to represent a template. + * A template takes parameters in input and outputs a string. + */ +@API(status = API.Status.STABLE) +public interface Template { + + /** + * Produces the string from this template using the given parameters passed in input. + * @param parameters the object which contains the parameters to be used by the template. + * The actual type depends on the concrete implementation. + * Checking the actual type passed in parameter will be the responsibility of each concrete implementation. + * @return the generated string where each parameter is replaced by its value provided in the map + * @throws TemplateException in case of issues during the string generation, e.g. missing parameter + */ + String process(Object parameters) throws TemplateException; +} diff --git a/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/TemplateEngine.java b/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/TemplateEngine.java new file mode 100644 index 000000000..aabeee25b --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/TemplateEngine.java @@ -0,0 +1,72 @@ +package com.symphony.bdk.template.api; + +import org.apiguardian.api.API; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * Interface to represent a specific template engine backed by a specific technology. + * It creates {@link Template} instances based on a file provided in the file system, in the classpath or as a URL + */ +@API(status = API.Status.STABLE) +public interface TemplateEngine { + + /** + * Returns the names of built-in templates which can be retrieved by calling {@link #newBuiltInTemplate(String)} + * @return the names of available built-in templates + */ + Set getBuiltInTemplates(); + + /** + * Creates a new {@link Template} from the built-in template name. + * @param template the name of one of the built-in templates returned by {@link #getBuiltInTemplates()} + * @return a new {@link Template} instantiated from the provided template name + * @throws TemplateException if template not found + */ + Template newBuiltInTemplate(String template) throws TemplateException; + + /** + * Create a {@link Template} instance from a file on the file system + * @param templatePath path to a template file on the file system + * @return a new {@link Template} instantiated from the provided file + * @throws TemplateException when template cannot be loaded, e.g. file not accessible + */ + Template newTemplateFromFile(String templatePath) throws TemplateException; + + /** + * Create a {@link Template} instance from a file in the classpath + * @param templatePath full path to a template file in the classpath + * @returna a new {@link Template} instantiated from the provided classpath resource + * @throws TemplateException when template cannot be loaded, e.g. resource not accessible + */ + Template newTemplateFromClasspath(String templatePath) throws TemplateException; + + /** + * Creates a template from a URL to a template file + * @param url the url where to fetch the template file + * @return a new {@link Template} instantiated from the provided url, should be a valid {@link java.net.URL} string. + * @throws TemplateException when template cannot be loaded, e.g. url not accessible + */ + Template newTemplateFromUrl(String url) throws TemplateException; + + static TemplateEngine getDefaultImplementation() { + final ServiceLoader engineServiceLoader = ServiceLoader.load(TemplateEngine.class); + + final List templateEngines = StreamSupport.stream(engineServiceLoader.spliterator(), false) + .collect(Collectors.toList()); + + if (templateEngines.isEmpty()) { + throw new IllegalStateException("No TemplateEngine implementation found in classpath."); + } else if (templateEngines.size() > 1) { + LoggerFactory.getLogger(TemplateEngine.class) + .warn("More than 1 TemplateEngine implementation found in classpath, will use : {}", + templateEngines.stream().findFirst().get()); + } + return templateEngines.stream().findFirst().get(); + } +} diff --git a/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/TemplateException.java b/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/TemplateException.java new file mode 100644 index 000000000..d93a37d17 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-api/src/main/java/com/symphony/bdk/template/api/TemplateException.java @@ -0,0 +1,17 @@ +package com.symphony.bdk.template.api; + +import org.apiguardian.api.API; + + +/** + * Exception thrown when instantiating a {@link Template} through {@link TemplateEngine} + * or when calling {@link Template#process(Object)}. + * This can be triggered when template cannot be loaded, + * if template is malformed or if some parameters are missing when calling {@link Template#process(Object)} + */ +@API(status = API.Status.STABLE) +public class TemplateException extends Exception { + public TemplateException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/pom.xml b/symphony-bdk-template/symphony-bdk-template-freemarker/pom.xml new file mode 100644 index 000000000..b404c3983 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/pom.xml @@ -0,0 +1,53 @@ + + + + symphony-bdk-template + com.symphony.platformsolutions + 1.2.0-SNAPSHOT + + 4.0.0 + + symphony-bdk-template-freemarker + Symphony Java BDK Template Freemarker + Symphony Java BDK Template Freemarker Module + + + + + com.symphony.platformsolutions + symphony-bdk-bom + ${project.version} + pom + import + + + + + + + org.freemarker + freemarker + 2.3.30 + + + org.reflections + reflections + 0.9.12 + + + commons-io + commons-io + + + com.symphony.platformsolutions + symphony-bdk-template-api + + + org.junit.jupiter + junit-jupiter + test + + + diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/FreeMarkerEngine.java b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/FreeMarkerEngine.java new file mode 100644 index 000000000..7456d660a --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/FreeMarkerEngine.java @@ -0,0 +1,127 @@ +package com.symphony.bdk.template.freemarker; + +import com.symphony.bdk.template.api.Template; +import com.symphony.bdk.template.api.TemplateEngine; +import com.symphony.bdk.template.api.TemplateException; + +import freemarker.template.Configuration; +import freemarker.template.TemplateExceptionHandler; +import org.apache.commons.io.FilenameUtils; +import org.apiguardian.api.API; +import org.reflections.Reflections; +import org.reflections.scanners.ResourcesScanner; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * FreeMarker specific implementation of {@link TemplateEngine}. Instantiates {@link FreeMarkerTemplate} objects. + */ +@API(status = API.Status.INTERNAL) +public class FreeMarkerEngine implements TemplateEngine { + + public static final String FREEMARKER_EXTENSION = ".ftl"; + + private static Configuration configuration = createConfiguration(); + private static Map builtInTemplates = getBuiltInTemplateMap(); + + /** + * {@inheritDoc} + */ + @Override + public Set getBuiltInTemplates() { + return builtInTemplates.keySet(); + } + + /** + * {@inheritDoc} + */ + @Override + public Template newBuiltInTemplate(String template) throws TemplateException { + if (!builtInTemplates.containsKey(template)) { + throw new TemplateException("Template " + template + " not found", null); + } + return newTemplateFromClasspath(builtInTemplates.get(template)); + } + + /** + * {@inheritDoc} + */ + @Override + public Template newTemplateFromFile(String templatePath) throws TemplateException { + try { + return getTemplateFromFile(templatePath); + } catch (IOException e) { + throw new TemplateException("Unable to open template file", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Template newTemplateFromClasspath(String templatePath) throws TemplateException { + try { + configuration.setClassForTemplateLoading(getClass(), "/"); + return new FreeMarkerTemplate(configuration.getTemplate(templatePath)); + } catch (IOException e) { + throw new TemplateException("Unable to load template from classpath", e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Template newTemplateFromUrl(String url) throws TemplateException { + try { + return getTemplateFromUrl(url); + } catch (IOException e) { + throw new TemplateException("Unable to load template from url", e); + } + } + + + private FreeMarkerTemplate getTemplateFromFile(String templatePath) throws IOException { + String directory = FilenameUtils.getFullPathNoEndSeparator(templatePath); + String file = FilenameUtils.getName(templatePath); + + configuration.setDirectoryForTemplateLoading(new File(directory)); + return new FreeMarkerTemplate(configuration.getTemplate(file)); + } + + private Template getTemplateFromUrl(String url) throws IOException { + String baseUrl = FilenameUtils.getFullPathNoEndSeparator(url); + String file = FilenameUtils.getName(url); + + configuration.setTemplateLoader(new UrlTemplateLoader(baseUrl)); + return new FreeMarkerTemplate(configuration.getTemplate(file)); + } + + private static Configuration createConfiguration() { + Configuration cfg = new Configuration(Configuration.VERSION_2_3_29); + cfg.setDefaultEncoding("UTF-8"); + cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + cfg.setLogTemplateExceptions(false); + cfg.setWrapUncheckedExceptions(true); + cfg.setFallbackOnNullLoopVariable(false); + return cfg; + } + + private static Map getBuiltInTemplateMap() { + Reflections reflections = new Reflections(FreeMarkerEngine.class.getPackage().getName(), new ResourcesScanner()); + + final Set resources = reflections.getResources(n -> n.endsWith(FREEMARKER_EXTENSION)); + return resources.stream().collect(Collectors.toMap(r -> extractTemplateName(r), Function.identity())); + } + + private static String extractTemplateName(String templatePath) { + // remove the path part until the last '/' and the FREEMARKER_EXTENSION + return templatePath.substring(templatePath.lastIndexOf('/') + 1, + templatePath.length() - FREEMARKER_EXTENSION.length()); + } +} diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/FreeMarkerTemplate.java b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/FreeMarkerTemplate.java new file mode 100644 index 000000000..0d872d095 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/FreeMarkerTemplate.java @@ -0,0 +1,44 @@ +package com.symphony.bdk.template.freemarker; + + +import com.symphony.bdk.template.api.Template; +import com.symphony.bdk.template.api.TemplateException; + +import org.apiguardian.api.API; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Map; + +/** + * FreeMarker specific implementation of {@link Template} + */ +@API(status = API.Status.INTERNAL) +public class FreeMarkerTemplate implements Template { + + private final freemarker.template.Template template; + + public FreeMarkerTemplate(freemarker.template.Template template) { + this.template = template; + } + + /** + * Produces the string from this template using the given parameters passed in input. + * @param parameters the object which contains the parameters to be used by the template. + * Checlk FreeMarker documentation to know more about accepted objects: + * @see Create the data model + * @return the generated string where each parameter is replaced by its value provided in the map + * @throws TemplateException in case of issues during the string generation, e.g. missing parameter + */ + @Override + public String process(Object parameters) throws TemplateException { + try { + Writer out = new StringWriter(); + template.process(parameters, out); + return out.toString(); + } catch (freemarker.template.TemplateException | IOException e) { + throw new TemplateException("Could not generate string from template", e); + } + } +} diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/UrlTemplateLoader.java b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/UrlTemplateLoader.java new file mode 100644 index 000000000..9db8bb2bb --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/java/com/symphony/bdk/template/freemarker/UrlTemplateLoader.java @@ -0,0 +1,40 @@ +package com.symphony.bdk.template.freemarker; + +import freemarker.cache.URLTemplateLoader; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Internal class used when instantiating a {@link FreeMarkerTemplate} with {@link FreeMarkerEngine#newTemplateFromUrl(String)} + */ +class UrlTemplateLoader extends URLTemplateLoader { + + private String baseUrl; + + public UrlTemplateLoader(String baseUrl) { + this.baseUrl = baseUrl; + } + + @Override + protected URL getURL(String s) { + try { + URL url = new URL(baseUrl + "/" + s); + if (resourceCanBeAccessed(url)) { + return url; + } + } catch (MalformedURLException e) { + } + return null; + } + + private boolean resourceCanBeAccessed(URL url) { + try (InputStream ignored = url.openStream()) { + } catch (IOException e) { + return false; + } + return true; + } +} diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/resources/META-INF/services/com.symphony.bdk.template.api.TemplateEngine b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/resources/META-INF/services/com.symphony.bdk.template.api.TemplateEngine new file mode 100644 index 000000000..f49001433 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/resources/META-INF/services/com.symphony.bdk.template.api.TemplateEngine @@ -0,0 +1 @@ +com.symphony.bdk.template.freemarker.FreeMarkerEngine diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/resources/com/symphony/bdk/template/freemarker/simpleMML.ftl b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/resources/com/symphony/bdk/template/freemarker/simpleMML.ftl new file mode 100644 index 000000000..8dd569228 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/main/resources/com/symphony/bdk/template/freemarker/simpleMML.ftl @@ -0,0 +1 @@ +${message} diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/java/com/symphony/bdk/template/freemarker/FreeMarkerTemplateTest.java b/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/java/com/symphony/bdk/template/freemarker/FreeMarkerTemplateTest.java new file mode 100644 index 000000000..b58e3e152 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/java/com/symphony/bdk/template/freemarker/FreeMarkerTemplateTest.java @@ -0,0 +1,128 @@ +package com.symphony.bdk.template.freemarker; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.symphony.bdk.template.api.Template; +import com.symphony.bdk.template.api.TemplateEngine; +import com.symphony.bdk.template.api.TemplateException; + +import org.junit.jupiter.api.Test; + +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Test class for {@link FreeMarkerEngine} and {@link FreeMarkerTemplate} + */ +public class FreeMarkerTemplateTest { + + @Test + public void testDefaultImplementation() { + TemplateEngine defaultImplementation = TemplateEngine.getDefaultImplementation(); + assertEquals(FreeMarkerEngine.class, defaultImplementation.getClass()); + } + + @Test + public void testFromFile() throws TemplateException { + Template freeMarkerTemplate = new FreeMarkerEngine().newTemplateFromFile("./src/test/resources/subFolder/test.ftl"); + assertTemplateProducesOutput(freeMarkerTemplate); + } + + @Test + public void testFromFileWithInclude() throws TemplateException { + Template freeMarkerTemplate = new FreeMarkerEngine() + .newTemplateFromFile("./src/test/resources/subFolder/testWithInclude.ftl"); + assertTemplateProducesOutput(freeMarkerTemplate, new HashMap<>(), + "Template with include\nHello from included file!\n"); + } + + @Test + public void testFromNotFoundFile() { + assertThrows(TemplateException.class, () -> new FreeMarkerEngine().newTemplateFromFile("./not/found.ftl")); + } + + @Test + public void testFromClasspath() throws TemplateException { + Template freeMarkerTemplate = new FreeMarkerEngine().newTemplateFromClasspath("/subFolder/test.ftl"); + assertTemplateProducesOutput(freeMarkerTemplate); + } + + @Test + public void testFromClasspathRelativePath() throws TemplateException { + Template freeMarkerTemplate = new FreeMarkerEngine().newTemplateFromClasspath("subFolder/test.ftl"); + assertTemplateProducesOutput(freeMarkerTemplate); + } + + @Test + public void testFromClasspathRelativePathNoSlash() throws TemplateException { + Template freeMarkerTemplate = new FreeMarkerEngine().newTemplateFromClasspath("subFolder/test.ftl"); + assertTemplateProducesOutput(freeMarkerTemplate); + } + + @Test + public void testFromClasspatWithInclude() throws TemplateException { + Template freeMarkerTemplate = new FreeMarkerEngine().newTemplateFromClasspath("/subFolder/testWithInclude.ftl"); + assertTemplateProducesOutput(freeMarkerTemplate, new HashMap<>(), + "Template with include\nHello from included file!\n"); + } + + @Test + public void testWithNotFoundResource() { + assertThrows(TemplateException.class, () -> new FreeMarkerEngine().newTemplateFromClasspath("./not/found.ftl")); + } + + @Test + public void testFromUrl() throws TemplateException { + URL baseUrl = getClass().getResource("/subFolder/test.ftl"); + + Template freeMarkerTemplate = new FreeMarkerEngine().newTemplateFromUrl(baseUrl.toString()); + assertTemplateProducesOutput(freeMarkerTemplate); + } + + @Test + public void testFromUrlWithInclude() throws TemplateException { + URL baseUrl = getClass().getResource("/subFolder/testWithInclude.ftl"); + + Template freeMarkerTemplate = new FreeMarkerEngine().newTemplateFromUrl(baseUrl.toString()); + assertTemplateProducesOutput(freeMarkerTemplate, new HashMap<>(), + "Template with include\nHello from included file!\n"); + } + + @Test + public void testFromUrlWithNotFoundResource() { + assertThrows(TemplateException.class, () -> new FreeMarkerEngine().newTemplateFromUrl("file:/not/found/file.ftl")); + } + + private void assertTemplateProducesOutput(Template freeMarkerTemplate) throws TemplateException { + Map parameters = new HashMap<>(); + parameters.put("message", "Hello World!"); + + assertTemplateProducesOutput(freeMarkerTemplate, parameters, "Hello World!\n"); + } + + @Test + public void testgetBuiltInTemplates() { + assertEquals(Collections.singleton("simpleMML"), new FreeMarkerEngine().getBuiltInTemplates()); + } + + @Test + public void testFromBuiltInTemplate() throws TemplateException { + final Template simpleMML = new FreeMarkerEngine().newBuiltInTemplate("simpleMML"); + assertTemplateProducesOutput(simpleMML); + } + + @Test + public void testFromNonExistingBuiltInTemplate() { + assertThrows(TemplateException.class, () -> new FreeMarkerEngine().newBuiltInTemplate("notFound")); + } + + private void assertTemplateProducesOutput(Template freeMarkerTemplate, Object parameters, String expectedOutput) + throws TemplateException { + assertEquals(FreeMarkerTemplate.class, freeMarkerTemplate.getClass()); + assertEquals(expectedOutput, freeMarkerTemplate.process(parameters)); + } + +} diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/included.ftl b/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/included.ftl new file mode 100644 index 000000000..ddf249336 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/included.ftl @@ -0,0 +1 @@ +Hello from included file! diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/test.ftl b/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/test.ftl new file mode 100644 index 000000000..8dd569228 --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/test.ftl @@ -0,0 +1 @@ +${message} diff --git a/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/testWithInclude.ftl b/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/testWithInclude.ftl new file mode 100644 index 000000000..d49285f6c --- /dev/null +++ b/symphony-bdk-template/symphony-bdk-template-freemarker/src/test/resources/subFolder/testWithInclude.ftl @@ -0,0 +1,2 @@ +Template with include +<#include "included.ftl">