001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.velocity;
016    
017    import com.liferay.portal.kernel.cache.PortalCache;
018    import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
019    import com.liferay.portal.kernel.template.TemplateManager;
020    import com.liferay.portal.kernel.template.TemplateResource;
021    import com.liferay.portal.kernel.template.TemplateResourceLoaderUtil;
022    import com.liferay.portal.kernel.util.ReflectionUtil;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.template.TemplateResourceThreadLocal;
025    import com.liferay.portal.util.PropsValues;
026    
027    import java.io.IOException;
028    import java.io.Reader;
029    
030    import java.lang.reflect.Field;
031    
032    import org.apache.commons.collections.ExtendedProperties;
033    import org.apache.velocity.Template;
034    import org.apache.velocity.exception.ParseErrorException;
035    import org.apache.velocity.exception.ResourceNotFoundException;
036    import org.apache.velocity.runtime.RuntimeInstance;
037    import org.apache.velocity.runtime.RuntimeServices;
038    import org.apache.velocity.runtime.resource.Resource;
039    import org.apache.velocity.runtime.resource.ResourceManager;
040    import org.apache.velocity.runtime.resource.ResourceManagerImpl;
041    
042    /**
043     * @author Brian Wing Shun Chan
044     * @author Shuyang Zhou
045     */
046    public class LiferayResourceManager extends ResourceManagerImpl {
047    
048            public LiferayResourceManager() {
049                    String cacheName = TemplateResource.class.getName();
050    
051                    cacheName = cacheName.concat(StringPool.POUND).concat(
052                            TemplateManager.VELOCITY);
053    
054                    _portalCache = SingleVMPoolUtil.getCache(cacheName);
055            }
056    
057            @Override
058            public String getLoaderNameForResource(String source) {
059    
060                    // Velocity's default implementation makes its cache useless because
061                    // getResourceStream is called to test the availability of a template
062    
063                    if ((globalCache.get(ResourceManager.RESOURCE_CONTENT + source) !=
064                                    null) ||
065                            (globalCache.get(ResourceManager.RESOURCE_TEMPLATE + source) !=
066                                    null)) {
067    
068                            return LiferayResourceLoader.class.getName();
069                    }
070                    else {
071                            return super.getLoaderNameForResource(source);
072                    }
073            }
074    
075            @Override
076            public Resource getResource(
077                            final String resourceName, final int resourceType,
078                            final String encoding)
079                    throws Exception, ParseErrorException, ResourceNotFoundException {
080    
081                    if (resourceType != ResourceManager.RESOURCE_TEMPLATE) {
082                            return super.getResource(resourceName, resourceType, encoding);
083                    }
084    
085                    TemplateResource templateResource = null;
086    
087                    if (resourceName.startsWith(
088                                    TemplateResource.TEMPLATE_RESOURCE_UUID_PREFIX)) {
089    
090                            templateResource = TemplateResourceThreadLocal.getTemplateResource(
091                                    TemplateManager.VELOCITY);
092                    }
093                    else {
094                            templateResource = TemplateResourceLoaderUtil.getTemplateResource(
095                                    TemplateManager.VELOCITY, resourceName);
096                    }
097    
098                    if (templateResource == null) {
099                            throw new ResourceNotFoundException(
100                                    "Unable to find Velocity template with ID " + resourceName);
101                    }
102    
103                    Object object = _portalCache.get(templateResource);
104    
105                    if ((object != null) && (object instanceof Template)) {
106                            return (Template)object;
107                    }
108    
109                    Template template = _createTemplate(templateResource);
110    
111                    if (PropsValues.VELOCITY_ENGINE_RESOURCE_MODIFICATION_CHECK_INTERVAL !=
112                                    0) {
113    
114                            _portalCache.put(templateResource, template);
115                    }
116    
117                    return template;
118            }
119    
120            @Override
121            public synchronized void initialize(RuntimeServices runtimeServices)
122                    throws Exception {
123    
124                    ExtendedProperties extendedProperties =
125                            runtimeServices.getConfiguration();
126    
127                    Field field = ReflectionUtil.getDeclaredField(
128                            RuntimeInstance.class, "configuration");
129    
130                    field.set(
131                            runtimeServices, new FastExtendedProperties(extendedProperties));
132    
133                    super.initialize(runtimeServices);
134            }
135    
136            private Template _createTemplate(TemplateResource templateResource)
137                    throws IOException {
138    
139                    Template template = new LiferayTemplate(templateResource.getReader());
140    
141                    template.setEncoding(TemplateResource.DEFAUT_ENCODING);
142                    template.setName(templateResource.getTemplateId());
143                    template.setResourceLoader(new LiferayResourceLoader());
144                    template.setRuntimeServices(rsvc);
145    
146                    template.process();
147    
148                    return template;
149            }
150    
151            private PortalCache<TemplateResource, Object> _portalCache;
152    
153            private class LiferayTemplate extends Template {
154    
155                    public LiferayTemplate(Reader reader) {
156                            _reader = reader;
157                    }
158    
159                    @Override
160                    public boolean process() throws IOException, ParseErrorException {
161                            data = null;
162    
163                            try {
164                                    data = rsvc.parse(_reader, name);
165    
166                                    initDocument();
167    
168                                    return true;
169                            }
170                            catch (Exception e) {
171                                    throw new ParseErrorException(
172                                            "Unable to parse Velocity template");
173                            }
174                            finally {
175                                    if (_reader != null) {
176                                            _reader.close();
177                                    }
178                            }
179                    }
180    
181                    private Reader _reader;
182    
183            }
184    
185    }