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.template.Template;
018    import com.liferay.portal.kernel.template.TemplateContextType;
019    import com.liferay.portal.kernel.template.TemplateException;
020    import com.liferay.portal.kernel.template.TemplateManager;
021    import com.liferay.portal.kernel.template.TemplateResource;
022    import com.liferay.portal.kernel.util.PropsKeys;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
025    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
026    import com.liferay.portal.security.pacl.PACLPolicy;
027    import com.liferay.portal.security.pacl.PACLPolicyManager;
028    import com.liferay.portal.template.RestrictedTemplate;
029    import com.liferay.portal.template.TemplateContextHelper;
030    import com.liferay.portal.util.PropsUtil;
031    import com.liferay.portal.util.PropsValues;
032    
033    import java.util.Map;
034    import java.util.concurrent.ConcurrentHashMap;
035    
036    import org.apache.commons.collections.ExtendedProperties;
037    import org.apache.velocity.VelocityContext;
038    import org.apache.velocity.app.VelocityEngine;
039    import org.apache.velocity.runtime.RuntimeConstants;
040    import org.apache.velocity.util.introspection.SecureUberspector;
041    
042    /**
043     * @author Raymond Augé
044     */
045    public class VelocityManager implements TemplateManager {
046    
047            public void destroy() {
048                    if (_velocityEngine == null) {
049                            return;
050                    }
051    
052                    _classLoaderVelocityContexts.clear();
053    
054                    _classLoaderVelocityContexts = null;
055                    _restrictedVelocityContext = null;
056                    _standardVelocityContext = null;
057                    _velocityEngine = null;
058                    _templateContextHelper = null;
059            }
060    
061            public void destroy(ClassLoader classLoader) {
062                    _classLoaderVelocityContexts.remove(classLoader);
063            }
064    
065            public String getName() {
066                    return VELOCITY;
067            }
068    
069            public Template getTemplate(
070                    TemplateResource templateResource,
071                    TemplateContextType templateContextType) {
072    
073                    return getTemplate(templateResource, null, templateContextType);
074            }
075    
076            public Template getTemplate(
077                    TemplateResource templateResource,
078                    TemplateResource errorTemplateResource,
079                    TemplateContextType templateContextType) {
080    
081                    if (templateContextType.equals(TemplateContextType.CLASS_LOADER)) {
082    
083                            // This template will have all of its utilities initialized within
084                            // the class loader of the current thread
085    
086                            ClassLoader contextClassLoader =
087                                    PACLClassLoaderUtil.getContextClassLoader();
088    
089                            PACLPolicy threadLocalPACLPolicy =
090                                    PortalSecurityManagerThreadLocal.getPACLPolicy();
091    
092                            PACLPolicy contextClassLoaderPACLPolicy =
093                                    PACLPolicyManager.getPACLPolicy(contextClassLoader);
094    
095                            try {
096                                    PortalSecurityManagerThreadLocal.setPACLPolicy(
097                                            contextClassLoaderPACLPolicy);
098    
099                                    VelocityContext velocityContext =
100                                            _classLoaderVelocityContexts.get(contextClassLoader);
101    
102                                    if (velocityContext == null) {
103                                            velocityContext = new VelocityContext();
104    
105                                            Map<String, Object> helperUtilities =
106                                                    _templateContextHelper.getHelperUtilities();
107    
108                                            for (Map.Entry<String, Object> entry :
109                                                            helperUtilities.entrySet()) {
110    
111                                                    velocityContext.put(entry.getKey(), entry.getValue());
112                                            }
113    
114                                            _classLoaderVelocityContexts.put(
115                                                    contextClassLoader, velocityContext);
116                                    }
117    
118                                    return new PACLVelocityTemplate(
119                                            templateResource, errorTemplateResource, velocityContext,
120                                            _velocityEngine, _templateContextHelper,
121                                            contextClassLoaderPACLPolicy);
122                            }
123                            finally {
124                                    PortalSecurityManagerThreadLocal.setPACLPolicy(
125                                            threadLocalPACLPolicy);
126                            }
127                    }
128                    else if (templateContextType.equals(TemplateContextType.EMPTY)) {
129                            return new VelocityTemplate(
130                                    templateResource, errorTemplateResource, null, _velocityEngine,
131                                    _templateContextHelper);
132                    }
133                    else if (templateContextType.equals(TemplateContextType.RESTRICTED)) {
134                            return new RestrictedTemplate(
135                                    new VelocityTemplate(
136                                            templateResource, errorTemplateResource,
137                                            _restrictedVelocityContext, _velocityEngine,
138                                            _templateContextHelper),
139                                    _templateContextHelper.getRestrictedVariables());
140                    }
141                    else if (templateContextType.equals(TemplateContextType.STANDARD)) {
142                            return new VelocityTemplate(
143                                    templateResource, errorTemplateResource,
144                                    _standardVelocityContext, _velocityEngine,
145                                    _templateContextHelper);
146                    }
147    
148                    return null;
149            }
150    
151            public void init() throws TemplateException {
152                    if (_velocityEngine != null) {
153                            return;
154                    }
155    
156                    _velocityEngine = new VelocityEngine();
157    
158                    ExtendedProperties extendedProperties = new FastExtendedProperties();
159    
160                    extendedProperties.setProperty(
161                            VelocityEngine.EVENTHANDLER_METHODEXCEPTION,
162                            LiferayMethodExceptionEventHandler.class.getName());
163    
164                    extendedProperties.setProperty(
165                            RuntimeConstants.INTROSPECTOR_RESTRICT_CLASSES,
166                            StringUtil.merge(PropsValues.VELOCITY_ENGINE_RESTRICTED_CLASSES));
167    
168                    extendedProperties.setProperty(
169                            RuntimeConstants.INTROSPECTOR_RESTRICT_PACKAGES,
170                            StringUtil.merge(PropsValues.VELOCITY_ENGINE_RESTRICTED_PACKAGES));
171    
172                    extendedProperties.setProperty(
173                            VelocityEngine.RESOURCE_LOADER, "liferay");
174    
175                    boolean cacheEnabled = false;
176    
177                    if (PropsValues.VELOCITY_ENGINE_RESOURCE_MODIFICATION_CHECK_INTERVAL !=
178                                    0) {
179    
180                            cacheEnabled = true;
181                    }
182    
183                    extendedProperties.setProperty(
184                            "liferay." + VelocityEngine.RESOURCE_LOADER + ".cache",
185                            String.valueOf(cacheEnabled));
186    
187                    extendedProperties.setProperty(
188                            "liferay." + VelocityEngine.RESOURCE_LOADER + ".class",
189                            LiferayResourceLoader.class.getName());
190    
191                    extendedProperties.setProperty(
192                            VelocityEngine.RESOURCE_MANAGER_CLASS,
193                            LiferayResourceManager.class.getName());
194    
195                    extendedProperties.setProperty(
196                            VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS,
197                            PropsUtil.get(PropsKeys.VELOCITY_ENGINE_LOGGER));
198    
199                    extendedProperties.setProperty(
200                            VelocityEngine.RUNTIME_LOG_LOGSYSTEM + ".log4j.category",
201                            PropsUtil.get(PropsKeys.VELOCITY_ENGINE_LOGGER_CATEGORY));
202    
203                    extendedProperties.setProperty(
204                            RuntimeConstants.UBERSPECT_CLASSNAME,
205                            SecureUberspector.class.getName());
206    
207                    extendedProperties.setProperty(
208                            VelocityEngine.VM_LIBRARY,
209                            PropsUtil.get(PropsKeys.VELOCITY_ENGINE_VELOCIMACRO_LIBRARY));
210    
211                    extendedProperties.setProperty(
212                            VelocityEngine.VM_LIBRARY_AUTORELOAD, String.valueOf(cacheEnabled));
213    
214                    extendedProperties.setProperty(
215                            VelocityEngine.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL,
216                            String.valueOf(cacheEnabled));
217    
218                    _velocityEngine.setExtendedProperties(extendedProperties);
219    
220                    try {
221                            _velocityEngine.init();
222                    }
223                    catch (Exception e) {
224                            throw new TemplateException(e);
225                    }
226    
227                    _restrictedVelocityContext = new VelocityContext();
228    
229                    Map<String, Object> helperUtilities =
230                            _templateContextHelper.getRestrictedHelperUtilities();
231    
232                    for (Map.Entry<String, Object> entry : helperUtilities.entrySet()) {
233                            _restrictedVelocityContext.put(entry.getKey(), entry.getValue());
234                    }
235    
236                    _standardVelocityContext = new VelocityContext();
237    
238                    helperUtilities = _templateContextHelper.getHelperUtilities();
239    
240                    for (Map.Entry<String, Object> entry : helperUtilities.entrySet()) {
241                            _standardVelocityContext.put(entry.getKey(), entry.getValue());
242                    }
243            }
244    
245            public void setTemplateContextHelper(
246                    TemplateContextHelper templateContextHelper) {
247    
248                    _templateContextHelper = templateContextHelper;
249            }
250    
251            private Map<ClassLoader, VelocityContext> _classLoaderVelocityContexts =
252                    new ConcurrentHashMap<ClassLoader, VelocityContext>();
253            private VelocityContext _restrictedVelocityContext;
254            private VelocityContext _standardVelocityContext;
255            private TemplateContextHelper _templateContextHelper;
256            private VelocityEngine _velocityEngine;
257    
258    }