/** * 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.osgi.util.StringPlus; import com.liferay.portal.kernel.cache.PortalCache; import com.liferay.portal.kernel.cache.SingleVMPoolUtil; import com.liferay.portal.kernel.template.TemplateConstants; import com.liferay.portal.kernel.template.TemplateResource; import com.liferay.portal.kernel.template.TemplateResourceLoader; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.ReflectionUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.template.TemplateResourceThreadLocal; import java.io.IOException; import java.io.Reader; import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.List; import org.apache.commons.collections.ExtendedProperties; import org.apache.velocity.Template; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.exception.ParseErrorException; import org.apache.velocity.exception.ResourceNotFoundException; import org.apache.velocity.runtime.RuntimeInstance; import org.apache.velocity.runtime.RuntimeServices; import org.apache.velocity.runtime.resource.Resource; import org.apache.velocity.runtime.resource.ResourceManager; import org.apache.velocity.runtime.resource.ResourceManagerImpl; /** * @author Brian Wing Shun Chan * @author Shuyang Zhou */ public class LiferayResourceManager extends ResourceManagerImpl { public LiferayResourceManager() { String portalCacheName = TemplateResource.class.getName(); portalCacheName = portalCacheName.concat(StringPool.POUND).concat( TemplateConstants.LANG_TYPE_VM); _portalCache = SingleVMPoolUtil.getPortalCache(portalCacheName); } @Override public String getLoaderNameForResource(String source) { // Velocity's default implementation makes its cache useless because // getResourceStream is called to test the availability of a template if ((globalCache.get(ResourceManager.RESOURCE_CONTENT + source) != null) || (globalCache.get(ResourceManager.RESOURCE_TEMPLATE + source) != null)) { return LiferayResourceLoader.class.getName(); } else { return super.getLoaderNameForResource(source); } } @Override public Resource getResource( final String resourceName, final int resourceType, final String encoding) throws Exception, ParseErrorException, ResourceNotFoundException { for (String macroTemplateId : _macroTemplateIds) { if (resourceName.equals(macroTemplateId)) { // This resource is provided by the portal, so invoke it from an // access controller try { return AccessController.doPrivileged( new ResourcePrivilegedExceptionAction( resourceName, resourceType, encoding)); } catch (PrivilegedActionException pae) { throw pae.getException(); } } } return _getResource(resourceName, resourceType, encoding); } @Override public synchronized void initialize(RuntimeServices runtimeServices) throws Exception { ExtendedProperties extendedProperties = runtimeServices.getConfiguration(); Field field = ReflectionUtil.getDeclaredField( RuntimeInstance.class, "configuration"); field.set( runtimeServices, new FastExtendedProperties(extendedProperties)); _macroTemplateIds = StringPlus.asList( extendedProperties.get(VelocityEngine.VM_LIBRARY)); _resourceModificationCheckInterval = GetterUtil.getInteger( extendedProperties.get( "liferay." + VelocityEngine.RESOURCE_LOADER + ".resourceModificationCheckInterval"), 60); _templateResourceLoader = (TemplateResourceLoader)extendedProperties.get( VelocityTemplateResourceLoader.class.getName()); super.initialize(runtimeServices); } private Template _createTemplate(TemplateResource templateResource) throws IOException { Template template = new LiferayTemplate(templateResource); template.setEncoding(TemplateConstants.DEFAUT_ENCODING); template.setName(templateResource.getTemplateId()); template.setResourceLoader(new LiferayResourceLoader()); template.setRuntimeServices(rsvc); template.process(); return template; } private Resource _getResource( final String resourceName, final int resourceType, final String encoding) throws Exception, ParseErrorException, ResourceNotFoundException { if (resourceType != ResourceManager.RESOURCE_TEMPLATE) { return super.getResource(resourceName, resourceType, encoding); } TemplateResource templateResource = null; if (resourceName.startsWith( TemplateConstants.TEMPLATE_RESOURCE_UUID_PREFIX)) { templateResource = TemplateResourceThreadLocal.getTemplateResource( TemplateConstants.LANG_TYPE_VM); } else { templateResource = _templateResourceLoader.getTemplateResource( resourceName); } if (templateResource == null) { throw new ResourceNotFoundException( "Unable to find Velocity template with ID " + resourceName); } Object object = _portalCache.get(templateResource); if ((object != null) && (object instanceof Template)) { return (Template)object; } Template template = _createTemplate(templateResource); if (_resourceModificationCheckInterval != 0) { _portalCache.put(templateResource, template); } return template; } private List<String> _macroTemplateIds; private final PortalCache<TemplateResource, Object> _portalCache; private int _resourceModificationCheckInterval = 60; private TemplateResourceLoader _templateResourceLoader; private static class LiferayTemplate extends Template { public LiferayTemplate(TemplateResource templateResource) { _templateResource = templateResource; } @Override public boolean process() throws IOException, ParseErrorException { data = null; try (Reader reader = _templateResource.getReader()) { data = rsvc.parse(reader, name); initDocument(); return true; } catch (Exception e) { throw new ParseErrorException( "Unable to parse Velocity template"); } } private final TemplateResource _templateResource; } private class ResourcePrivilegedExceptionAction implements PrivilegedExceptionAction<Resource> { public ResourcePrivilegedExceptionAction( String resourceName, int resourceType, String encoding) { _resourceName = resourceName; _resourceType = resourceType; _encoding = encoding; } @Override public Resource run() throws Exception { return _getResource(_resourceName, _resourceType, _encoding); } private final String _encoding; private final String _resourceName; private final int _resourceType; } }