/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.portal.template.velocity.internal;
import com.liferay.portal.configuration.metatype.bnd.util.ConfigurableUtil;
import com.liferay.portal.kernel.cache.MultiVMPool;
import com.liferay.portal.kernel.cache.SingleVMPool;
import com.liferay.portal.kernel.concurrent.ConcurrentHashSet;
import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
import com.liferay.portal.kernel.template.StringTemplateResource;
import com.liferay.portal.kernel.template.Template;
import com.liferay.portal.kernel.template.TemplateConstants;
import com.liferay.portal.kernel.template.TemplateException;
import com.liferay.portal.kernel.template.TemplateResource;
import com.liferay.portal.kernel.template.TemplateResourceLoader;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.template.ClassLoaderResourceParser;
import com.liferay.portal.template.TemplateContextHelper;
import com.liferay.portal.template.TemplateResourceParser;
import com.liferay.portal.template.velocity.configuration.VelocityEngineConfiguration;
import com.liferay.portal.tools.ToolDependencies;
import com.liferay.portal.util.FileImpl;
import com.liferay.registry.Registry;
import com.liferay.registry.RegistryUtil;
import com.liferay.registry.ServiceRegistration;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Reader;
import java.io.StringReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.util.introspection.SecureUberspector;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* @author Tina Tian
* @author Raymond Augé
*/
public class VelocityTemplateTest {
@BeforeClass
public static void setUpClass() throws Exception {
ToolDependencies.wireCaches();
FileUtil fileUtil = new FileUtil();
fileUtil.setFile(new FileImpl());
_templateResourceLoader = new MockTemplateResourceLoader();
_templateResourceLoader.activate(
Collections.<String, Object>emptyMap());
Registry registry = RegistryUtil.getRegistry();
_serviceRegistrations.add(
registry.registerService(
TemplateResourceLoader.class, _templateResourceLoader));
_serviceRegistrations.add(
registry.registerService(
TemplateResourceParser.class, new ClassLoaderResourceParser(),
Collections.<String, Object>singletonMap(
"lang.type", TemplateConstants.LANG_TYPE_VM)));
}
@AfterClass
public static void tearDownClass() {
for (ServiceRegistration<?> serviceRegistration :
_serviceRegistrations) {
serviceRegistration.unregister();
}
_serviceRegistrations.clear();
}
@Before
public void setUp() throws Exception {
VelocityEngineConfiguration velocityEngineConfiguration =
ConfigurableUtil.createConfigurable(
VelocityEngineConfiguration.class, Collections.emptyMap());
_templateContextHelper = new MockTemplateContextHelper();
_velocityEngine = new VelocityEngine();
boolean cacheEnabled = false;
ExtendedProperties extendedProperties = new FastExtendedProperties();
extendedProperties.setProperty(
VelocityEngine.DIRECTIVE_IF_TOSTRING_NULLCHECK,
String.valueOf(
velocityEngineConfiguration.directiveIfToStringNullCheck()));
extendedProperties.setProperty(
VelocityEngine.EVENTHANDLER_METHODEXCEPTION,
LiferayMethodExceptionEventHandler.class.getName());
extendedProperties.setProperty(
RuntimeConstants.INTROSPECTOR_RESTRICT_CLASSES,
StringUtil.merge(velocityEngineConfiguration.restrictedClasses()));
extendedProperties.setProperty(
RuntimeConstants.INTROSPECTOR_RESTRICT_PACKAGES,
StringUtil.merge(velocityEngineConfiguration.restrictedPackages()));
extendedProperties.setProperty(
VelocityEngine.RESOURCE_LOADER, "liferay");
extendedProperties.setProperty(
"liferay." + VelocityEngine.RESOURCE_LOADER + ".cache",
String.valueOf(cacheEnabled));
extendedProperties.setProperty(
"liferay." + VelocityEngine.RESOURCE_LOADER +
".resourceModificationCheckInterval",
velocityEngineConfiguration.resourceModificationCheckInterval() +
"");
extendedProperties.setProperty(
"liferay." + VelocityEngine.RESOURCE_LOADER + ".class",
LiferayResourceLoader.class.getName());
extendedProperties.setProperty(
VelocityEngine.RESOURCE_MANAGER_CLASS,
LiferayResourceManager.class.getName());
extendedProperties.setProperty(
"liferay." + VelocityEngine.RESOURCE_MANAGER_CLASS +
".resourceModificationCheckInterval",
velocityEngineConfiguration.resourceModificationCheckInterval() +
"");
extendedProperties.setProperty(
VelocityTemplateResourceLoader.class.getName(),
_templateResourceLoader);
extendedProperties.setProperty(
VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS,
velocityEngineConfiguration.logger());
extendedProperties.setProperty(
VelocityEngine.RUNTIME_LOG_LOGSYSTEM + ".log4j.category",
velocityEngineConfiguration.loggerCategory());
extendedProperties.setProperty(
RuntimeConstants.UBERSPECT_CLASSNAME,
SecureUberspector.class.getName());
extendedProperties.setProperty(
VelocityEngine.VM_LIBRARY,
StringUtil.merge(velocityEngineConfiguration.velocimacroLibrary()));
extendedProperties.setProperty(
VelocityEngine.VM_LIBRARY_AUTORELOAD,
String.valueOf(!cacheEnabled));
extendedProperties.setProperty(
VelocityEngine.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL,
String.valueOf(!cacheEnabled));
_velocityEngine.setExtendedProperties(extendedProperties);
_velocityEngine.init();
}
@Test
public void testGet() throws Exception {
Template template = new VelocityTemplate(
new MockTemplateResource(_TEMPLATE_FILE_NAME), null, null,
_velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
Object result = template.get(_TEST_KEY);
Assert.assertNotNull(result);
Assert.assertTrue(result instanceof String);
String stringResult = (String)result;
Assert.assertEquals(_TEST_VALUE, stringResult);
}
@Test
public void testPrepare() throws Exception {
Template template = new VelocityTemplate(
new MockTemplateResource(_TEMPLATE_FILE_NAME), null, null,
_velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
template.prepare(null);
Object result = template.get(_TEST_VALUE);
Assert.assertNotNull(result);
Assert.assertTrue(result instanceof String);
String stringResult = (String)result;
Assert.assertEquals(_TEST_VALUE, stringResult);
}
@Test
public void testProcessTemplate1() throws Exception {
Template template = new VelocityTemplate(
new MockTemplateResource(_TEMPLATE_FILE_NAME), null, null,
_velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
template.processTemplate(unsyncStringWriter);
String result = unsyncStringWriter.toString();
Assert.assertEquals(_TEST_VALUE, result);
}
@Test
public void testProcessTemplate2() throws Exception {
Template template = new VelocityTemplate(
new MockTemplateResource(_WRONG_TEMPLATE_ID), null, null,
_velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
try {
template.processTemplate(unsyncStringWriter);
Assert.fail();
}
catch (TemplateException te) {
String message = te.getMessage();
Assert.assertTrue(message.contains(_WRONG_TEMPLATE_ID));
}
}
@Test
public void testProcessTemplate3() throws Exception {
Template template = new VelocityTemplate(
new StringTemplateResource(
_WRONG_TEMPLATE_ID, _TEST_TEMPLATE_CONTENT),
null, null, _velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
template.processTemplate(unsyncStringWriter);
String result = unsyncStringWriter.toString();
Assert.assertEquals(_TEST_VALUE, result);
}
@Test
public void testProcessTemplate4() throws Exception {
Template template = new VelocityTemplate(
new MockTemplateResource(_TEMPLATE_FILE_NAME),
new MockTemplateResource(_WRONG_ERROR_TEMPLATE_ID), null,
_velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
template.processTemplate(unsyncStringWriter);
String result = unsyncStringWriter.toString();
Assert.assertEquals(_TEST_VALUE, result);
}
@Test
public void testProcessTemplate5() throws Exception {
Template template = new VelocityTemplate(
new MockTemplateResource(_WRONG_TEMPLATE_ID),
new MockTemplateResource(_TEMPLATE_FILE_NAME), null,
_velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
template.processTemplate(unsyncStringWriter);
String result = unsyncStringWriter.toString();
Assert.assertEquals(_TEST_VALUE, result);
}
@Test
public void testProcessTemplate6() throws Exception {
Template template = new VelocityTemplate(
new MockTemplateResource(_WRONG_TEMPLATE_ID),
new MockTemplateResource(_WRONG_ERROR_TEMPLATE_ID), null,
_velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
try {
template.processTemplate(unsyncStringWriter);
Assert.fail();
}
catch (TemplateException te) {
String message = te.getMessage();
Assert.assertTrue(message.contains(_WRONG_ERROR_TEMPLATE_ID));
}
}
@Test
public void testProcessTemplate7() throws Exception {
Template template = new VelocityTemplate(
new MockTemplateResource(_WRONG_TEMPLATE_ID),
new StringTemplateResource(
_WRONG_ERROR_TEMPLATE_ID, _TEST_TEMPLATE_CONTENT),
null, _velocityEngine, _templateContextHelper, 60, false);
template.put(_TEST_KEY, _TEST_VALUE);
UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
template.processTemplate(unsyncStringWriter);
String result = unsyncStringWriter.toString();
Assert.assertEquals(_TEST_VALUE, result);
}
@Test
public void testProcessTemplate8() throws Exception {
Map<String, Object> context = new HashMap<>();
context.put(_TEST_KEY, _TEST_VALUE);
Template template = new VelocityTemplate(
new MockTemplateResource(_TEMPLATE_FILE_NAME), null, context,
_velocityEngine, _templateContextHelper, 60, false);
UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
template.processTemplate(unsyncStringWriter);
String result = unsyncStringWriter.toString();
Assert.assertEquals(_TEST_VALUE, result);
}
private static final String _TEMPLATE_FILE_NAME = "test.vm";
private static final String _TEST_KEY = "TEST_KEY";
private static final String _TEST_TEMPLATE_CONTENT = "$" + _TEST_KEY;
private static final String _TEST_VALUE = "TEST_VALUE";
private static final String _WRONG_ERROR_TEMPLATE_ID =
"WRONG_ERROR_TEMPLATE_ID";
private static final String _WRONG_TEMPLATE_ID = "WRONG_TEMPLATE_ID";
private static final Set<ServiceRegistration<?>> _serviceRegistrations =
new ConcurrentHashSet<>();
private static MockTemplateResourceLoader _templateResourceLoader;
private TemplateContextHelper _templateContextHelper;
private VelocityEngine _velocityEngine;
private static class MockTemplateContextHelper
extends TemplateContextHelper {
@Override
public Map<String, Object> getHelperUtilities(
ClassLoader classLoader, boolean restricted) {
return Collections.emptyMap();
}
@Override
public Set<String> getRestrictedVariables() {
return Collections.emptySet();
}
@Override
public void prepare(
Map<String, Object> contextObjects, HttpServletRequest request) {
String testValue = (String)contextObjects.get(_TEST_KEY);
contextObjects.put(testValue, testValue);
}
}
private static class MockTemplateResource implements TemplateResource {
/**
* The empty constructor is required by {@link java.io.Externalizable}.
* Do not use this for any other purpose.
*/
@SuppressWarnings("unused")
public MockTemplateResource() {
}
public MockTemplateResource(String templateId) {
_templateId = templateId;
}
@Override
public long getLastModified() {
return _lastModified;
}
@Override
public Reader getReader() {
if (_templateId.equals(_TEMPLATE_FILE_NAME)) {
return new StringReader(_TEST_TEMPLATE_CONTENT);
}
throw new ParseErrorException(
"Unable to get reader for template source " + _templateId);
}
@Override
public String getTemplateId() {
return _templateId;
}
@Override
public void readExternal(ObjectInput objectInput) throws IOException {
_lastModified = objectInput.readLong();
_templateId = objectInput.readUTF();
}
@Override
public void writeExternal(ObjectOutput objectOutput)
throws IOException {
objectOutput.writeLong(_lastModified);
objectOutput.writeUTF(_templateId);
}
private long _lastModified = System.currentTimeMillis();
private String _templateId;
}
private static class MockTemplateResourceLoader
extends VelocityTemplateResourceLoader {
@Override
protected void activate(Map<String, Object> properties) {
Registry registry = RegistryUtil.getRegistry();
setMultiVMPool(registry.getService(MultiVMPool.class));
setSingleVMPool(registry.getService(SingleVMPool.class));
super.activate(properties);
}
}
}