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.freemarker;
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.ReflectionUtil;
023    import com.liferay.portal.kernel.util.StringPool;
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.PropsValues;
031    
032    import freemarker.cache.TemplateCache;
033    
034    import freemarker.template.Configuration;
035    
036    import java.lang.reflect.Field;
037    
038    import java.util.Map;
039    import java.util.concurrent.ConcurrentHashMap;
040    
041    /**
042     * @author Mika Koivisto
043     * @author Tina Tina
044     */
045    public class FreeMarkerManager implements TemplateManager {
046    
047            public void destroy() {
048                    if (_configuration == null) {
049                            return;
050                    }
051    
052                    _classLoaderHelperUtilities.clear();
053    
054                    _classLoaderHelperUtilities = null;
055    
056                    _configuration.clearEncodingMap();
057                    _configuration.clearSharedVariables();
058                    _configuration.clearTemplateCache();
059    
060                    _configuration = null;
061    
062                    _restrictedHelperUtilities.clear();
063    
064                    _restrictedHelperUtilities = null;
065    
066                    _standardHelperUtilities.clear();
067    
068                    _standardHelperUtilities = null;
069    
070                    _templateContextHelper = null;
071            }
072    
073            public void destroy(ClassLoader classLoader) {
074                    _classLoaderHelperUtilities.remove(classLoader);
075            }
076    
077            public String getName() {
078                    return FREEMARKER;
079            }
080    
081            public Template getTemplate(
082                    TemplateResource templateResource,
083                    TemplateContextType templateContextType) {
084    
085                    return getTemplate(templateResource, null, templateContextType);
086            }
087    
088            public Template getTemplate(
089                    TemplateResource templateResource,
090                    TemplateResource errorTemplateResource,
091                    TemplateContextType templateContextType) {
092    
093                    if (templateContextType.equals(TemplateContextType.CLASS_LOADER)) {
094    
095                            // This template will have all of its utilities initialized within
096                            // the class loader of the current thread
097    
098                            ClassLoader contextClassLoader =
099                                    PACLClassLoaderUtil.getContextClassLoader();
100    
101                            PACLPolicy threadLocalPACLPolicy =
102                                    PortalSecurityManagerThreadLocal.getPACLPolicy();
103    
104                            PACLPolicy contextClassLoaderPACLPolicy =
105                                    PACLPolicyManager.getPACLPolicy(contextClassLoader);
106    
107                            try {
108                                    PortalSecurityManagerThreadLocal.setPACLPolicy(
109                                            contextClassLoaderPACLPolicy);
110    
111                                    Map<String, Object> helperUtilities =
112                                            _classLoaderHelperUtilities.get(contextClassLoader);
113    
114                                    if (helperUtilities == null) {
115                                            helperUtilities =
116                                                    _templateContextHelper.getHelperUtilities();
117    
118                                            _classLoaderHelperUtilities.put(
119                                                    contextClassLoader, helperUtilities);
120                                    }
121    
122                                    return new PACLFreeMarkerTemplate(
123                                            templateResource, errorTemplateResource, helperUtilities,
124                                            _configuration, _templateContextHelper,
125                                            contextClassLoaderPACLPolicy);
126                            }
127                            finally {
128                                    PortalSecurityManagerThreadLocal.setPACLPolicy(
129                                            threadLocalPACLPolicy);
130                            }
131                    }
132                    else if (templateContextType.equals(TemplateContextType.EMPTY)) {
133                            return new FreeMarkerTemplate(
134                                    templateResource, errorTemplateResource, null, _configuration,
135                                    _templateContextHelper);
136                    }
137                    else if (templateContextType.equals(TemplateContextType.RESTRICTED)) {
138                            return new RestrictedTemplate(
139                                    new FreeMarkerTemplate(
140                                            templateResource, errorTemplateResource,
141                                            _restrictedHelperUtilities, _configuration,
142                                            _templateContextHelper),
143                                    _templateContextHelper.getRestrictedVariables());
144                    }
145                    else if (templateContextType.equals(TemplateContextType.STANDARD)) {
146                            return new FreeMarkerTemplate(
147                                    templateResource, errorTemplateResource,
148                                    _standardHelperUtilities, _configuration,
149                                    _templateContextHelper);
150                    }
151    
152                    return null;
153            }
154    
155            public void init() throws TemplateException {
156                    if (_configuration != null) {
157                            return;
158                    }
159    
160                    _configuration = new Configuration();
161    
162                    try {
163                            Field field = ReflectionUtil.getDeclaredField(
164                                    Configuration.class, "cache");
165    
166                            TemplateCache templateCache = new LiferayTemplateCache(
167                                    _configuration);
168    
169                            field.set(_configuration, templateCache);
170                    }
171                    catch (Exception e) {
172                            throw new TemplateException(
173                                    "Unable to Initialize Freemarker manager");
174                    }
175    
176                    _configuration.setDefaultEncoding(StringPool.UTF8);
177                    _configuration.setLocalizedLookup(
178                            PropsValues.FREEMARKER_ENGINE_LOCALIZED_LOOKUP);
179                    _configuration.setNewBuiltinClassResolver(
180                            new LiferayTemplateClassResolver());
181                    _configuration.setObjectWrapper(new LiferayObjectWrapper());
182    
183                    try {
184                            _configuration.setSetting(
185                                    "auto_import", PropsValues.FREEMARKER_ENGINE_MACRO_LIBRARY);
186                            _configuration.setSetting(
187                                    "template_exception_handler",
188                                    PropsValues.FREEMARKER_ENGINE_TEMPLATE_EXCEPTION_HANDLER);
189                    }
190                    catch (Exception e) {
191                            throw new TemplateException("Unable to init freemarker manager", e);
192                    }
193    
194                    _standardHelperUtilities = _templateContextHelper.getHelperUtilities();
195                    _restrictedHelperUtilities =
196                            _templateContextHelper.getRestrictedHelperUtilities();
197            }
198    
199            public void setTemplateContextHelper(
200                    TemplateContextHelper templateContextHelper) {
201    
202                    _templateContextHelper = templateContextHelper;
203            }
204    
205            private Map<ClassLoader, Map<String, Object>> _classLoaderHelperUtilities =
206                    new ConcurrentHashMap<ClassLoader, Map<String, Object>>();
207            private Configuration _configuration;
208            private Map<String, Object> _restrictedHelperUtilities;
209            private Map<String, Object> _standardHelperUtilities;
210            private TemplateContextHelper _templateContextHelper;
211    
212    }