From 29a6e7d91c893dc4b7e386a2dbd38c30a063b5f7 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 15 May 2020 12:21:50 +0300 Subject: [PATCH] Replace Velocity with Freemarker --- application/pom.xml | 8 +- .../ThingsboardMessageConfiguration.java | 127 ------------------ .../service/mail/DefaultMailService.java | 64 ++++----- ...unt.activated.vm => account.activated.ftl} | 36 ++--- ...account.lockout.vm => account.lockout.ftl} | 36 ++--- .../{activation.vm => activation.ftl} | 36 ++--- ...rd.was.reset.vm => password.was.reset.ftl} | 36 ++--- .../{reset.password.vm => reset.password.ftl} | 36 ++--- .../resources/templates/{test.vm => test.ftl} | 34 ++--- pom.xml | 28 +--- 10 files changed, 143 insertions(+), 298 deletions(-) rename application/src/main/resources/templates/{account.activated.vm => account.activated.ftl} (83%) rename application/src/main/resources/templates/{account.lockout.vm => account.lockout.ftl} (85%) rename application/src/main/resources/templates/{activation.vm => activation.ftl} (83%) rename application/src/main/resources/templates/{password.was.reset.vm => password.was.reset.ftl} (83%) rename application/src/main/resources/templates/{reset.password.vm => reset.password.ftl} (83%) rename application/src/main/resources/templates/{test.vm => test.ftl} (87%) diff --git a/application/pom.xml b/application/pom.xml index 269e1d9dac..c8e0d36593 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -153,12 +153,8 @@ jjwt - org.apache.velocity - velocity - - - org.apache.velocity - velocity-tools + org.freemarker + freemarker commons-io diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java index 9b00c15a7e..aec5fc2d8f 100644 --- a/application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java @@ -15,28 +15,11 @@ */ package org.thingsboard.server.config; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections.ExtendedProperties; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.exception.ResourceNotFoundException; -import org.apache.velocity.runtime.RuntimeConstants; -import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.context.support.ResourceBundleMessageSource; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.util.StringUtils; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; @Configuration public class ThingsboardMessageConfiguration { @@ -49,114 +32,4 @@ public class ThingsboardMessageConfiguration { messageSource.setDefaultEncoding("UTF-8"); return messageSource; } - - private static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:/templates/"; - - private ResourceLoader resourceLoader = new DefaultResourceLoader(); - - @Bean - public VelocityEngine velocityEngine() { - VelocityEngine velocityEngine = new VelocityEngine(); - try { - Resource resource = resourceLoader.getResource(DEFAULT_RESOURCE_LOADER_PATH); - File file = resource.getFile(); - velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "file"); - velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true"); - velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, file.getAbsolutePath()); - } catch (IOException e) { - initSpringResourceLoader(velocityEngine, DEFAULT_RESOURCE_LOADER_PATH); - } - velocityEngine.init(); - return velocityEngine; - } - - private void initSpringResourceLoader(VelocityEngine velocityEngine, String resourceLoaderPath) { - velocityEngine.setProperty( - RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME); - velocityEngine.setProperty( - SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, SpringResourceLoader.class.getName()); - velocityEngine.setProperty( - SpringResourceLoader.SPRING_RESOURCE_LOADER_CACHE, "true"); - velocityEngine.setApplicationAttribute( - SpringResourceLoader.SPRING_RESOURCE_LOADER, resourceLoader); - velocityEngine.setApplicationAttribute( - SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPath); - } - - @Slf4j - public static class SpringResourceLoader extends org.apache.velocity.runtime.resource.loader.ResourceLoader { - - public static final String NAME = "spring"; - - public static final String SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; - - public static final String SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; - - public static final String SPRING_RESOURCE_LOADER = "spring.resource.loader"; - - public static final String SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; - - private org.springframework.core.io.ResourceLoader resourceLoader; - - private String[] resourceLoaderPaths; - - - @Override - public void init(ExtendedProperties configuration) { - this.resourceLoader = (org.springframework.core.io.ResourceLoader) - this.rsvc.getApplicationAttribute(SPRING_RESOURCE_LOADER); - String resourceLoaderPath = (String) this.rsvc.getApplicationAttribute(SPRING_RESOURCE_LOADER_PATH); - if (this.resourceLoader == null) { - throw new IllegalArgumentException( - "'resourceLoader' application attribute must be present for SpringResourceLoader"); - } - if (resourceLoaderPath == null) { - throw new IllegalArgumentException( - "'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); - } - this.resourceLoaderPaths = StringUtils.commaDelimitedListToStringArray(resourceLoaderPath); - for (int i = 0; i < this.resourceLoaderPaths.length; i++) { - String path = this.resourceLoaderPaths[i]; - if (!path.endsWith("/")) { - this.resourceLoaderPaths[i] = path + "/"; - } - } - if (log.isInfoEnabled()) { - log.info("SpringResourceLoader for Velocity: using resource loader [" + this.resourceLoader + - "] and resource loader paths " + Arrays.asList(this.resourceLoaderPaths)); - } - } - - @Override - public InputStream getResourceStream(String source) throws ResourceNotFoundException { - if (log.isDebugEnabled()) { - log.debug("Looking for Velocity resource with name [" + source + "]"); - } - for (String resourceLoaderPath : this.resourceLoaderPaths) { - org.springframework.core.io.Resource resource = - this.resourceLoader.getResource(resourceLoaderPath + source); - try { - return resource.getInputStream(); - } - catch (IOException ex) { - if (log.isDebugEnabled()) { - log.debug("Could not find Velocity resource: " + resource); - } - } - } - throw new ResourceNotFoundException( - "Could not find resource [" + source + "] in Spring resource loader path"); - } - - @Override - public boolean isSourceModified(org.apache.velocity.runtime.resource.Resource resource) { - return false; - } - - @Override - public long getLastModified(org.apache.velocity.runtime.resource.Resource resource) { - return 0; - } - - } } diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java index bd01b9eb26..e5cf19ff03 100644 --- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java +++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java @@ -16,18 +16,17 @@ package org.thingsboard.server.service.mail; import com.fasterxml.jackson.databind.JsonNode; +import freemarker.template.Configuration; +import freemarker.template.Template; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.exception.VelocityException; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.MessageSource; import org.springframework.core.NestedRuntimeException; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; +import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; import org.thingsboard.rule.engine.api.MailService; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; @@ -40,8 +39,6 @@ import org.thingsboard.server.dao.settings.AdminSettingsService; import javax.annotation.PostConstruct; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; -import java.io.StringWriter; -import java.io.Writer; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -58,8 +55,7 @@ public class DefaultMailService implements MailService { private MessageSource messages; @Autowired - @Qualifier("velocityEngine") - private VelocityEngine engine; + private Configuration freemarkerConfig; private JavaMailSenderImpl mailSender; @@ -140,11 +136,10 @@ public class DefaultMailService implements MailService { String mailFrom = jsonConfig.get("mailFrom").asText(); String subject = messages.getMessage("test.message.subject", null, Locale.US); - Map model = new HashMap(); + Map model = new HashMap<>(); model.put(TARGET_EMAIL, email); - String message = mergeTemplateIntoString(this.engine, - "test.vm", UTF_8, model); + String message = mergeTemplateIntoString("test.ftl", model); sendMail(testMailSender, mailFrom, email, subject, message); } @@ -154,12 +149,11 @@ public class DefaultMailService implements MailService { String subject = messages.getMessage("activation.subject", null, Locale.US); - Map model = new HashMap(); + Map model = new HashMap<>(); model.put("activationLink", activationLink); model.put(TARGET_EMAIL, email); - String message = mergeTemplateIntoString(this.engine, - "activation.vm", UTF_8, model); + String message = mergeTemplateIntoString("activation.ftl", model); sendMail(mailSender, mailFrom, email, subject, message); } @@ -169,12 +163,11 @@ public class DefaultMailService implements MailService { String subject = messages.getMessage("account.activated.subject", null, Locale.US); - Map model = new HashMap(); + Map model = new HashMap<>(); model.put("loginLink", loginLink); model.put(TARGET_EMAIL, email); - String message = mergeTemplateIntoString(this.engine, - "account.activated.vm", UTF_8, model); + String message = mergeTemplateIntoString("account.activated.ftl", model); sendMail(mailSender, mailFrom, email, subject, message); } @@ -184,12 +177,11 @@ public class DefaultMailService implements MailService { String subject = messages.getMessage("reset.password.subject", null, Locale.US); - Map model = new HashMap(); + Map model = new HashMap<>(); model.put("passwordResetLink", passwordResetLink); model.put(TARGET_EMAIL, email); - String message = mergeTemplateIntoString(this.engine, - "reset.password.vm", UTF_8, model); + String message = mergeTemplateIntoString("reset.password.ftl", model); sendMail(mailSender, mailFrom, email, subject, message); } @@ -199,12 +191,11 @@ public class DefaultMailService implements MailService { String subject = messages.getMessage("password.was.reset.subject", null, Locale.US); - Map model = new HashMap(); + Map model = new HashMap<>(); model.put("loginLink", loginLink); model.put(TARGET_EMAIL, email); - String message = mergeTemplateIntoString(this.engine, - "password.was.reset.vm", UTF_8, model); + String message = mergeTemplateIntoString("password.was.reset.ftl", model); sendMail(mailSender, mailFrom, email, subject, message); } @@ -230,13 +221,12 @@ public class DefaultMailService implements MailService { public void sendAccountLockoutEmail(String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException { String subject = messages.getMessage("account.lockout.subject", null, Locale.US); - Map model = new HashMap(); + Map model = new HashMap<>(); model.put("lockoutAccount", lockoutEmail); model.put("maxFailedLoginAttempts", maxFailedLoginAttempts); model.put(TARGET_EMAIL, email); - String message = mergeTemplateIntoString(this.engine, - "account.lockout.vm", UTF_8, model); + String message = mergeTemplateIntoString("account.lockout.ftl", model); sendMail(mailSender, mailFrom, email, subject, message); } @@ -257,20 +247,14 @@ public class DefaultMailService implements MailService { } } - private static String mergeTemplateIntoString(VelocityEngine velocityEngine, String templateLocation, - String encoding, Map model) throws VelocityException { - - StringWriter result = new StringWriter(); - mergeTemplate(velocityEngine, templateLocation, encoding, model, result); - return result.toString(); - } - - private static void mergeTemplate( - VelocityEngine velocityEngine, String templateLocation, String encoding, - Map model, Writer writer) throws VelocityException { - - VelocityContext velocityContext = new VelocityContext(model); - velocityEngine.mergeTemplate(templateLocation, encoding, velocityContext, writer); + private String mergeTemplateIntoString(String templateLocation, + Map model) throws ThingsboardException { + try { + Template template = freemarkerConfig.getTemplate(templateLocation); + return FreeMarkerTemplateUtils.processTemplateIntoString(template, model); + } catch (Exception e) { + throw handleException(e); + } } protected ThingsboardException handleException(Exception exception) { diff --git a/application/src/main/resources/templates/account.activated.vm b/application/src/main/resources/templates/account.activated.ftl similarity index 83% rename from application/src/main/resources/templates/account.activated.vm rename to application/src/main/resources/templates/account.activated.ftl index b5dcf927dd..55683743de 100644 --- a/application/src/main/resources/templates/account.activated.vm +++ b/application/src/main/resources/templates/account.activated.ftl @@ -1,18 +1,20 @@ -#* - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# +<#-- + + Copyright © 2016-2020 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> @@ -96,7 +98,7 @@ background-color: #f6f6f6; - + @@ -109,7 +111,7 @@ background-color: #f6f6f6; diff --git a/application/src/main/resources/templates/account.lockout.vm b/application/src/main/resources/templates/account.lockout.ftl similarity index 85% rename from application/src/main/resources/templates/account.lockout.vm rename to application/src/main/resources/templates/account.lockout.ftl index 08ce236cf9..15214aad50 100644 --- a/application/src/main/resources/templates/account.lockout.vm +++ b/application/src/main/resources/templates/account.lockout.ftl @@ -1,18 +1,20 @@ -#* - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# +<#-- + + Copyright © 2016-2020 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> @@ -86,7 +88,7 @@ background-color: #f6f6f6; - Thingsboard user account $lockoutAccount has been lockout due to failed credentials were provided more than $maxFailedLoginAttempts times. + Thingsboard user account ${lockoutAccount} has been lockout due to failed credentials were provided more than ${maxFailedLoginAttempts} times. @@ -99,7 +101,7 @@ background-color: #f6f6f6; diff --git a/application/src/main/resources/templates/activation.vm b/application/src/main/resources/templates/activation.ftl similarity index 83% rename from application/src/main/resources/templates/activation.vm rename to application/src/main/resources/templates/activation.ftl index 5002903545..ae89bd6342 100644 --- a/application/src/main/resources/templates/activation.vm +++ b/application/src/main/resources/templates/activation.ftl @@ -1,18 +1,20 @@ -#* - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# +<#-- + + Copyright © 2016-2020 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> @@ -96,7 +98,7 @@ background-color: #f6f6f6; - + @@ -109,7 +111,7 @@ background-color: #f6f6f6; diff --git a/application/src/main/resources/templates/password.was.reset.vm b/application/src/main/resources/templates/password.was.reset.ftl similarity index 83% rename from application/src/main/resources/templates/password.was.reset.vm rename to application/src/main/resources/templates/password.was.reset.ftl index f7303b375c..15e5c9bd0b 100644 --- a/application/src/main/resources/templates/password.was.reset.vm +++ b/application/src/main/resources/templates/password.was.reset.ftl @@ -1,18 +1,20 @@ -#* - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# +<#-- + + Copyright © 2016-2020 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> @@ -96,7 +98,7 @@ background-color: #f6f6f6; - + @@ -109,7 +111,7 @@ background-color: #f6f6f6; diff --git a/application/src/main/resources/templates/reset.password.vm b/application/src/main/resources/templates/reset.password.ftl similarity index 83% rename from application/src/main/resources/templates/reset.password.vm rename to application/src/main/resources/templates/reset.password.ftl index 117a2dd17e..fdd1e07e0f 100644 --- a/application/src/main/resources/templates/reset.password.vm +++ b/application/src/main/resources/templates/reset.password.ftl @@ -1,18 +1,20 @@ -#* - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# +<#-- + + Copyright © 2016-2020 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> @@ -96,7 +98,7 @@ background-color: #f6f6f6; - + @@ -109,7 +111,7 @@ background-color: #f6f6f6; diff --git a/application/src/main/resources/templates/test.vm b/application/src/main/resources/templates/test.ftl similarity index 87% rename from application/src/main/resources/templates/test.vm rename to application/src/main/resources/templates/test.ftl index e0631dfb5d..7a5d50b1b6 100644 --- a/application/src/main/resources/templates/test.vm +++ b/application/src/main/resources/templates/test.ftl @@ -1,18 +1,20 @@ -#* - * Copyright © 2016-2020 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *# +<#-- + + Copyright © 2016-2020 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> @@ -99,7 +101,7 @@ background-color: #f6f6f6; diff --git a/pom.xml b/pom.xml index 27fc6fca91..e17a555c24 100755 --- a/pom.xml +++ b/pom.xml @@ -61,8 +61,7 @@ 2.6.3 1.0.2 2.6.2 - 1.7 - 2.0 + 2.3.30 1.6.2 4.2.0 3.5.5 @@ -565,28 +564,9 @@ ${jjwt.version} - org.apache.velocity - velocity - ${velocity.version} - - - org.apache.velocity - velocity-tools - ${velocity-tools.version} - - - javax.servlet - servlet-api - - - dom4j - dom4j - - - antlr - antlr - - + org.freemarker + freemarker + ${freemarker.version} org.yaml