001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.velocity;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.PropsKeys;
020    import com.liferay.portal.kernel.util.StringPool;
021    import com.liferay.portal.kernel.util.StringUtil;
022    import com.liferay.portal.kernel.util.Validator;
023    import com.liferay.portal.kernel.velocity.VelocityContext;
024    import com.liferay.portal.kernel.velocity.VelocityEngine;
025    import com.liferay.portal.kernel.velocity.VelocityVariablesUtil;
026    import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
027    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
028    import com.liferay.portal.security.pacl.PACLPolicy;
029    import com.liferay.portal.security.pacl.PACLPolicyManager;
030    import com.liferay.portal.util.PropsUtil;
031    import com.liferay.portal.util.PropsValues;
032    
033    import java.io.Writer;
034    
035    import java.util.Map;
036    import java.util.concurrent.ConcurrentHashMap;
037    
038    import org.apache.commons.collections.ExtendedProperties;
039    import org.apache.velocity.runtime.RuntimeConstants;
040    import org.apache.velocity.runtime.resource.ResourceManager;
041    import org.apache.velocity.runtime.resource.loader.StringResourceLoader;
042    import org.apache.velocity.runtime.resource.util.StringResourceRepository;
043    
044    /**
045     * @author Raymond Augé
046     */
047    public class VelocityEngineImpl implements VelocityEngine {
048    
049            public VelocityEngineImpl() {
050            }
051    
052            public void clearClassLoader(ClassLoader classLoader) {
053                    _classLoaderVelocityContexts.remove(classLoader);
054            }
055    
056            public void flushTemplate(String velocityTemplateId) {
057                    StringResourceRepository stringResourceRepository =
058                            StringResourceLoader.getRepository();
059    
060                    if (stringResourceRepository != null) {
061                            stringResourceRepository.removeStringResource(velocityTemplateId);
062                    }
063    
064                    LiferayResourceCacheUtil.remove(
065                            _getResourceCacheKey(velocityTemplateId));
066            }
067    
068            public VelocityContext getEmptyContext() {
069                    return new VelocityContextImpl();
070            }
071    
072            public VelocityContext getRestrictedToolsContext() {
073                    return _restrictedToolsContext;
074            }
075    
076            public VelocityContext getStandardToolsContext() {
077                    return _standardToolsContext;
078            }
079    
080            public VelocityContext getWrappedClassLoaderToolsContext() {
081    
082                    // This context will have all of its utilities initialized within the
083                    // class loader of the current thread
084    
085                    ClassLoader contextClassLoader =
086                            PACLClassLoaderUtil.getContextClassLoader();
087    
088                    PACLPolicy threadLocalPACLPolicy =
089                            PortalSecurityManagerThreadLocal.getPACLPolicy();
090    
091                    PACLPolicy contextClassLoaderPACLPolicy =
092                            PACLPolicyManager.getPACLPolicy(contextClassLoader);
093    
094                    try {
095                            PortalSecurityManagerThreadLocal.setPACLPolicy(
096                                    contextClassLoaderPACLPolicy);
097    
098                            VelocityContextImpl velocityContextImpl =
099                                    _classLoaderVelocityContexts.get(contextClassLoader);
100    
101                            if (velocityContextImpl == null) {
102                                    velocityContextImpl = new VelocityContextImpl();
103    
104                                    VelocityVariablesUtil.insertHelperUtilities(
105                                            velocityContextImpl, null);
106    
107                                    _classLoaderVelocityContexts.put(
108                                            contextClassLoader, velocityContextImpl);
109                            }
110    
111                            return new PACLVelocityContextImpl(
112                                    velocityContextImpl.getWrappedVelocityContext(),
113                                    contextClassLoaderPACLPolicy);
114                    }
115                    finally {
116                            PortalSecurityManagerThreadLocal.setPACLPolicy(
117                                    threadLocalPACLPolicy);
118                    }
119            }
120    
121            public VelocityContext getWrappedRestrictedToolsContext() {
122                    return new VelocityContextImpl(
123                            _restrictedToolsContext.getWrappedVelocityContext());
124            }
125    
126            public VelocityContext getWrappedStandardToolsContext() {
127                    return new VelocityContextImpl(
128                            _standardToolsContext.getWrappedVelocityContext());
129            }
130    
131            public void init() throws Exception {
132                    if (_velocityEngine != null) {
133                            return;
134                    }
135    
136                    _velocityEngine = new org.apache.velocity.app.VelocityEngine();
137    
138                    LiferayResourceLoader.setVelocityResourceListeners(
139                            PropsValues.VELOCITY_ENGINE_RESOURCE_LISTENERS);
140    
141                    ExtendedProperties extendedProperties = new FastExtendedProperties();
142    
143                    extendedProperties.setProperty(
144                            org.apache.velocity.app.VelocityEngine.EVENTHANDLER_METHODEXCEPTION,
145                            LiferayMethodExceptionEventHandler.class.getName());
146    
147                    extendedProperties.setProperty(
148                            RuntimeConstants.INTROSPECTOR_RESTRICT_CLASSES,
149                            StringUtil.merge(PropsValues.VELOCITY_ENGINE_RESTRICTED_CLASSES));
150    
151                    extendedProperties.setProperty(
152                            RuntimeConstants.INTROSPECTOR_RESTRICT_PACKAGES,
153                            StringUtil.merge(PropsValues.VELOCITY_ENGINE_RESTRICTED_PACKAGES));
154    
155                    extendedProperties.setProperty(_RESOURCE_LOADER, "string,servlet");
156    
157                    extendedProperties.setProperty(
158                            "string." + _RESOURCE_LOADER + ".cache",
159                            String.valueOf(
160                                    PropsValues.VELOCITY_ENGINE_RESOURCE_MANAGER_CACHE_ENABLED));
161    
162                    extendedProperties.setProperty(
163                            "string." + _RESOURCE_LOADER + ".class",
164                            StringResourceLoader.class.getName());
165    
166                    extendedProperties.setProperty(
167                            "string." + _RESOURCE_LOADER + ".repository.class",
168                            StringResourceRepositoryImpl.class.getName());
169    
170                    extendedProperties.setProperty(
171                            "servlet." + _RESOURCE_LOADER + ".cache",
172                            String.valueOf(
173                                    PropsValues.VELOCITY_ENGINE_RESOURCE_MANAGER_CACHE_ENABLED));
174    
175                    extendedProperties.setProperty(
176                            "servlet." + _RESOURCE_LOADER + ".class",
177                            LiferayResourceLoader.class.getName());
178    
179                    extendedProperties.setProperty(
180                            org.apache.velocity.app.VelocityEngine.RESOURCE_MANAGER_CLASS,
181                            PropsUtil.get(PropsKeys.VELOCITY_ENGINE_RESOURCE_MANAGER));
182    
183                    extendedProperties.setProperty(
184                            org.apache.velocity.app.VelocityEngine.RESOURCE_MANAGER_CACHE_CLASS,
185                            PropsUtil.get(PropsKeys.VELOCITY_ENGINE_RESOURCE_MANAGER_CACHE));
186    
187                    extendedProperties.setProperty(
188                            org.apache.velocity.app.VelocityEngine.VM_LIBRARY,
189                            PropsUtil.get(PropsKeys.VELOCITY_ENGINE_VELOCIMACRO_LIBRARY));
190    
191                    extendedProperties.setProperty(
192                            org.apache.velocity.app.VelocityEngine.VM_LIBRARY_AUTORELOAD,
193                            String.valueOf(
194                                    !PropsValues.VELOCITY_ENGINE_RESOURCE_MANAGER_CACHE_ENABLED));
195    
196                    extendedProperties.setProperty(
197                            org.apache.velocity.app.VelocityEngine.
198                                    VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL,
199                            String.valueOf(
200                                    !PropsValues.VELOCITY_ENGINE_RESOURCE_MANAGER_CACHE_ENABLED));
201    
202                    extendedProperties.setProperty(
203                            org.apache.velocity.app.VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS,
204                            PropsUtil.get(PropsKeys.VELOCITY_ENGINE_LOGGER));
205    
206                    extendedProperties.setProperty(
207                            org.apache.velocity.app.VelocityEngine.RUNTIME_LOG_LOGSYSTEM +
208                                    ".log4j.category",
209                            PropsUtil.get(PropsKeys.VELOCITY_ENGINE_LOGGER_CATEGORY));
210    
211                    _velocityEngine.setExtendedProperties(extendedProperties);
212    
213                    _velocityEngine.init();
214    
215                    _restrictedToolsContext = new VelocityContextImpl();
216    
217                    VelocityVariablesUtil.insertHelperUtilities(
218                            _restrictedToolsContext,
219                            PropsValues.JOURNAL_TEMPLATE_VELOCITY_RESTRICTED_VARIABLES);
220    
221                    _standardToolsContext = new VelocityContextImpl();
222    
223                    VelocityVariablesUtil.insertHelperUtilities(
224                            _standardToolsContext, null);
225            }
226    
227            public boolean mergeTemplate(
228                            String velocityTemplateId, String velocityTemplateContent,
229                            VelocityContext velocityContext, Writer writer)
230                    throws Exception {
231    
232                    if (Validator.isNotNull(velocityTemplateContent)) {
233                            LiferayResourceCacheUtil.remove(
234                                    _getResourceCacheKey(velocityTemplateId));
235    
236                            StringResourceRepository stringResourceRepository =
237                                    StringResourceLoader.getRepository();
238    
239                            stringResourceRepository.putStringResource(
240                                    velocityTemplateId, velocityTemplateContent);
241    
242                            if (_log.isDebugEnabled()) {
243                                    _log.debug(
244                                            "Added " + velocityTemplateId +
245                                                    " to the Velocity template repository");
246                            }
247                    }
248    
249                    VelocityContextImpl velocityContextImpl =
250                            (VelocityContextImpl)velocityContext;
251    
252                    PACLPolicy threadLocalPACLPolicy =
253                            PortalSecurityManagerThreadLocal.getPACLPolicy();
254    
255                    try {
256                            if (velocityContextImpl instanceof PACLVelocityContextImpl) {
257                                    PACLVelocityContextImpl paclContextImpl =
258                                            (PACLVelocityContextImpl)velocityContextImpl;
259    
260                                    PortalSecurityManagerThreadLocal.setPACLPolicy(
261                                            paclContextImpl.getPaclPolicy());
262                            }
263    
264                            return _velocityEngine.mergeTemplate(
265                                    velocityTemplateId, StringPool.UTF8,
266                                    velocityContextImpl.getWrappedVelocityContext(), writer);
267                    }
268                    finally {
269                            if (velocityContextImpl instanceof PACLVelocityContextImpl) {
270                                    PortalSecurityManagerThreadLocal.setPACLPolicy(
271                                            threadLocalPACLPolicy);
272                            }
273                    }
274            }
275    
276            public boolean mergeTemplate(
277                            String velocityTemplateId, VelocityContext velocityContext,
278                            Writer writer)
279                    throws Exception {
280    
281                    return mergeTemplate(velocityTemplateId, null, velocityContext, writer);
282            }
283    
284            public boolean resourceExists(String resource) {
285                    return _velocityEngine.resourceExists(resource);
286            }
287    
288            private String _getResourceCacheKey(String velocityTemplateId) {
289                    return _RESOURCE_TEMPLATE_NAME_SPACE.concat(velocityTemplateId);
290            }
291    
292            private static final String _RESOURCE_LOADER =
293                    org.apache.velocity.app.VelocityEngine.RESOURCE_LOADER;
294    
295            private static final String _RESOURCE_TEMPLATE_NAME_SPACE = String.valueOf(
296                    ResourceManager.RESOURCE_TEMPLATE);
297    
298            private static Log _log = LogFactoryUtil.getLog(VelocityEngineImpl.class);
299    
300            private Map<ClassLoader, VelocityContextImpl> _classLoaderVelocityContexts =
301                    new ConcurrentHashMap<ClassLoader, VelocityContextImpl>();
302            private VelocityContextImpl _restrictedToolsContext;
303            private VelocityContextImpl _standardToolsContext;
304            private org.apache.velocity.app.VelocityEngine _velocityEngine;
305    
306    }