001
014
015 package com.liferay.portal.freemarker;
016
017 import com.liferay.portal.kernel.cache.PortalCache;
018 import com.liferay.portal.kernel.freemarker.FreeMarkerContext;
019 import com.liferay.portal.kernel.freemarker.FreeMarkerEngine;
020 import com.liferay.portal.kernel.freemarker.FreeMarkerVariablesUtil;
021 import com.liferay.portal.kernel.log.Log;
022 import com.liferay.portal.kernel.log.LogFactoryUtil;
023 import com.liferay.portal.kernel.util.StringPool;
024 import com.liferay.portal.kernel.util.Validator;
025 import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
026 import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
027 import com.liferay.portal.security.pacl.PACLPolicy;
028 import com.liferay.portal.security.pacl.PACLPolicyManager;
029 import com.liferay.portal.util.PropsValues;
030
031 import freemarker.cache.ClassTemplateLoader;
032 import freemarker.cache.MultiTemplateLoader;
033 import freemarker.cache.TemplateCache;
034 import freemarker.cache.TemplateLoader;
035
036 import freemarker.template.Configuration;
037 import freemarker.template.Template;
038
039 import java.io.IOException;
040 import java.io.Writer;
041
042 import java.lang.reflect.Constructor;
043
044 import java.util.Locale;
045 import java.util.Map;
046 import java.util.concurrent.ConcurrentHashMap;
047
048
052 public class FreeMarkerEngineImpl implements FreeMarkerEngine {
053
054 public void clearClassLoader(ClassLoader classLoader) {
055 _classLoaderFreeMarkerContexts.remove(classLoader);
056 }
057
058 public void flushTemplate(String freeMarkerTemplateId) {
059 if (_configuration == null) {
060 return;
061 }
062
063 if (_stringTemplateLoader != null) {
064 _stringTemplateLoader.removeTemplate(freeMarkerTemplateId);
065 }
066
067 PortalCache portalCache = LiferayCacheStorage.getPortalCache();
068
069 portalCache.remove(_getResourceCacheKey(freeMarkerTemplateId));
070 }
071
072 public FreeMarkerContext getWrappedClassLoaderToolsContext() {
073
074
075
076
077 ClassLoader contextClassLoader =
078 PACLClassLoaderUtil.getContextClassLoader();
079
080 PACLPolicy threadLocalPACLPolicy =
081 PortalSecurityManagerThreadLocal.getPACLPolicy();
082
083 PACLPolicy contextClassLoaderPACLPolicy =
084 PACLPolicyManager.getPACLPolicy(contextClassLoader);
085
086 try {
087 PortalSecurityManagerThreadLocal.setPACLPolicy(
088 contextClassLoaderPACLPolicy);
089
090 FreeMarkerContextImpl classLoaderContext =
091 _classLoaderFreeMarkerContexts.get(contextClassLoader);
092
093 if (classLoaderContext == null) {
094 classLoaderContext = new FreeMarkerContextImpl();
095
096 FreeMarkerVariablesUtil.insertHelperUtilities(
097 classLoaderContext, null);
098
099 _classLoaderFreeMarkerContexts.put(
100 contextClassLoader, classLoaderContext);
101 }
102
103 return new PACLFreeMarkerContextImpl(
104 classLoaderContext.getWrappedContext(),
105 contextClassLoaderPACLPolicy);
106 }
107 finally {
108 PortalSecurityManagerThreadLocal.setPACLPolicy(
109 threadLocalPACLPolicy);
110 }
111 }
112
113 public FreeMarkerContext getWrappedRestrictedToolsContext() {
114 return new FreeMarkerContextImpl(
115 _restrictedToolsContext.getWrappedContext());
116 }
117
118 public FreeMarkerContext getWrappedStandardToolsContext() {
119 return new FreeMarkerContextImpl(
120 _standardToolsContext.getWrappedContext());
121 }
122
123 public void init() throws Exception {
124 if (_configuration != null) {
125 return;
126 }
127
128 LiferayTemplateLoader liferayTemplateLoader =
129 new LiferayTemplateLoader();
130
131 liferayTemplateLoader.setTemplateLoaders(
132 PropsValues.FREEMARKER_ENGINE_TEMPLATE_LOADERS);
133
134 _stringTemplateLoader = new StringTemplateLoader();
135
136 MultiTemplateLoader multiTemplateLoader =
137 new MultiTemplateLoader(
138 new TemplateLoader[] {
139 new ClassTemplateLoader(getClass(), StringPool.SLASH),
140 _stringTemplateLoader, liferayTemplateLoader
141 });
142
143 _configuration = new Configuration();
144
145 _configuration.setDefaultEncoding(StringPool.UTF8);
146 _configuration.setLocalizedLookup(
147 PropsValues.FREEMARKER_ENGINE_LOCALIZED_LOOKUP);
148 _configuration.setNewBuiltinClassResolver(
149 new LiferayTemplateClassResolver());
150 _configuration.setObjectWrapper(new LiferayObjectWrapper());
151 _configuration.setSetting(
152 "auto_import", PropsValues.FREEMARKER_ENGINE_MACRO_LIBRARY);
153 _configuration.setSetting(
154 "cache_storage", PropsValues.FREEMARKER_ENGINE_CACHE_STORAGE);
155 _configuration.setSetting(
156 "template_exception_handler",
157 PropsValues.FREEMARKER_ENGINE_TEMPLATE_EXCEPTION_HANDLER);
158 _configuration.setTemplateLoader(multiTemplateLoader);
159 _configuration.setTemplateUpdateDelay(
160 PropsValues.FREEMARKER_ENGINE_MODIFICATION_CHECK_INTERVAL);
161
162 _encoding = _configuration.getEncoding(_configuration.getLocale());
163 _locale = _configuration.getLocale();
164
165 _restrictedToolsContext = new FreeMarkerContextImpl();
166
167 FreeMarkerVariablesUtil.insertHelperUtilities(
168 _restrictedToolsContext,
169 PropsValues.JOURNAL_TEMPLATE_FREEMARKER_RESTRICTED_VARIABLES);
170
171 _standardToolsContext = new FreeMarkerContextImpl();
172
173 FreeMarkerVariablesUtil.insertHelperUtilities(
174 _standardToolsContext, null);
175
176 ClassLoader classLoader = TemplateCache.class.getClassLoader();
177
178 Class<?> templateKeyClass = classLoader.loadClass(
179 TemplateCache.class.getName().concat("$TemplateKey"));
180
181 _templateKeyConstructor = templateKeyClass.getDeclaredConstructor(
182 String.class, Locale.class, String.class, boolean.class);
183
184 _templateKeyConstructor.setAccessible(true);
185 }
186
187 public boolean mergeTemplate(
188 String freeMarkerTemplateId, FreeMarkerContext freeMarkerContext,
189 Writer writer)
190 throws Exception {
191
192 return mergeTemplate(
193 freeMarkerTemplateId, null, freeMarkerContext, writer);
194 }
195
196 public boolean mergeTemplate(
197 String freeMarkerTemplateId, String freemarkerTemplateContent,
198 FreeMarkerContext freeMarkerContext, Writer writer)
199 throws Exception {
200
201 if (Validator.isNotNull(freemarkerTemplateContent)) {
202 PortalCache portalCache = LiferayCacheStorage.getPortalCache();
203
204 portalCache.remove(_getResourceCacheKey(freeMarkerTemplateId));
205
206 _stringTemplateLoader.putTemplate(
207 freeMarkerTemplateId, freemarkerTemplateContent);
208
209 if (_log.isDebugEnabled()) {
210 _log.debug(
211 "Added " + freeMarkerTemplateId +
212 " to the string based FreeMarker template repository");
213 }
214 }
215
216 FreeMarkerContextImpl freeMarkerContextImpl =
217 (FreeMarkerContextImpl)freeMarkerContext;
218
219 PACLPolicy threadLocalPACLPolicy =
220 PortalSecurityManagerThreadLocal.getPACLPolicy();
221
222 try {
223 if (freeMarkerContextImpl instanceof PACLFreeMarkerContextImpl) {
224 PACLFreeMarkerContextImpl paclContextImpl =
225 (PACLFreeMarkerContextImpl)freeMarkerContextImpl;
226
227 PortalSecurityManagerThreadLocal.setPACLPolicy(
228 paclContextImpl.getPaclPolicy());
229 }
230
231 Template template = _configuration.getTemplate(
232 freeMarkerTemplateId, StringPool.UTF8);
233
234 template.process(freeMarkerContextImpl.getWrappedContext(), writer);
235 }
236 finally {
237 if (freeMarkerContextImpl instanceof PACLFreeMarkerContextImpl) {
238 PortalSecurityManagerThreadLocal.setPACLPolicy(
239 threadLocalPACLPolicy);
240 }
241 }
242
243 return true;
244 }
245
246 public boolean resourceExists(String resource) {
247 try {
248 Template template = _configuration.getTemplate(resource);
249
250 if (template != null) {
251 return true;
252 }
253 else {
254 return false;
255 }
256 }
257 catch (IOException ioe) {
258 if (_log.isWarnEnabled()) {
259 _log.warn(ioe, ioe);
260 }
261
262 return false;
263 }
264 }
265
266 private String _getResourceCacheKey(String freeMarkerTemplateId) {
267 try {
268 Object object = _templateKeyConstructor.newInstance(
269 freeMarkerTemplateId, _locale, _encoding, Boolean.TRUE);
270
271 return object.toString();
272 }
273 catch (Exception e) {
274 throw new RuntimeException(
275 "Failed to build FreeMarker internal resource cache key for " +
276 "template id " + freeMarkerTemplateId, e);
277 }
278 }
279
280 private static Log _log = LogFactoryUtil.getLog(FreeMarkerEngineImpl.class);
281
282 private Map<ClassLoader, FreeMarkerContextImpl>
283 _classLoaderFreeMarkerContexts =
284 new ConcurrentHashMap<ClassLoader, FreeMarkerContextImpl>();
285 private Configuration _configuration;
286 private String _encoding;
287 private Locale _locale;
288 private FreeMarkerContextImpl _restrictedToolsContext;
289 private FreeMarkerContextImpl _standardToolsContext;
290 private StringTemplateLoader _stringTemplateLoader;
291 private Constructor<?> _templateKeyConstructor;
292
293 }