001    /**
002     * Copyright (c) 2000-2013 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.cache.PortalCache;
018    import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
019    import com.liferay.portal.kernel.template.TemplateConstants;
020    import com.liferay.portal.kernel.template.TemplateResource;
021    import com.liferay.portal.kernel.template.TemplateResourceLoaderUtil;
022    import com.liferay.portal.kernel.util.PropsKeys;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.template.TemplateResourceThreadLocal;
025    import com.liferay.portal.util.PropsUtil;
026    import com.liferay.portal.util.PropsValues;
027    
028    import freemarker.cache.TemplateCache;
029    
030    import freemarker.template.Configuration;
031    import freemarker.template.Template;
032    
033    import java.io.IOException;
034    
035    import java.security.AccessController;
036    import java.security.PrivilegedActionException;
037    import java.security.PrivilegedExceptionAction;
038    
039    import java.util.Locale;
040    
041    /**
042     * @author Tina Tian
043     */
044    public class LiferayTemplateCache extends TemplateCache {
045    
046            public LiferayTemplateCache(Configuration configuration) {
047                    _configuration = configuration;
048    
049                    String cacheName = TemplateResource.class.getName();
050    
051                    cacheName = cacheName.concat(StringPool.POUND).concat(
052                            TemplateConstants.LANG_TYPE_FTL);
053    
054                    _portalCache = SingleVMPoolUtil.getCache(cacheName);
055            }
056    
057            @Override
058            public Template getTemplate(
059                            String templateId, Locale locale, String encoding, boolean parse)
060                    throws IOException {
061    
062                    String[] macroTemplateIds = PropsUtil.getArray(
063                            PropsKeys.FREEMARKER_ENGINE_MACRO_LIBRARY);
064    
065                    for (String macroTemplateId : macroTemplateIds) {
066                            int pos = macroTemplateId.indexOf(" as ");
067    
068                            if (pos != -1) {
069                                    macroTemplateId = macroTemplateId.substring(0, pos);
070                            }
071    
072                            if (templateId.equals(macroTemplateId)) {
073    
074                                    // This template is provided by the portal, so invoke it from an
075                                    // access controller
076    
077                                    try {
078                                            return AccessController.doPrivileged(
079                                                    new TemplatePrivilegedExceptionAction(
080                                                            macroTemplateId, locale, encoding, parse));
081                                    }
082                                    catch (PrivilegedActionException pae) {
083                                            throw (IOException)pae.getException();
084                                    }
085                            }
086                    }
087    
088                    return doGetTemplate(templateId, locale, encoding, parse);
089            }
090    
091            private Template doGetTemplate(
092                            String templateId, Locale locale, String encoding, boolean parse)
093                    throws IOException {
094    
095                    if (templateId == null) {
096                            throw new IllegalArgumentException("Argument \"name\" is null");
097                    }
098    
099                    if (locale == null) {
100                            throw new IllegalArgumentException("Argument \"locale\" is null");
101                    }
102    
103                    if (encoding == null) {
104                            throw new IllegalArgumentException("Argument \"encoding\" is null");
105                    }
106    
107                    TemplateResource templateResource = null;
108    
109                    if (templateId.startsWith(
110                                    TemplateConstants.TEMPLATE_RESOURCE_UUID_PREFIX)) {
111    
112                            templateResource = TemplateResourceThreadLocal.getTemplateResource(
113                                    TemplateConstants.LANG_TYPE_FTL);
114                    }
115                    else {
116                            try {
117                                    templateResource =
118                                            TemplateResourceLoaderUtil.getTemplateResource(
119                                                    TemplateConstants.LANG_TYPE_FTL, templateId);
120                            }
121                            catch (Exception e) {
122                                    templateResource = null;
123                            }
124                    }
125    
126                    if (templateResource == null) {
127                            throw new IOException(
128                                    "Unable to find FreeMarker template with ID " + templateId);
129                    }
130    
131                    Object object = _portalCache.get(templateResource);
132    
133                    if ((object != null) && (object instanceof Template)) {
134                            return (Template)object;
135                    }
136    
137                    Template template = new Template(
138                            templateResource.getTemplateId(), templateResource.getReader(),
139                            _configuration, TemplateConstants.DEFAUT_ENCODING);
140    
141                    if (PropsValues.
142                                    FREEMARKER_ENGINE_RESOURCE_MODIFICATION_CHECK_INTERVAL != 0) {
143    
144                            _portalCache.put(templateResource, template);
145                    }
146    
147                    return template;
148            }
149    
150            private Configuration _configuration;
151            private PortalCache<TemplateResource, Object> _portalCache;
152    
153            private class TemplatePrivilegedExceptionAction
154                    implements PrivilegedExceptionAction<Template> {
155    
156                    public TemplatePrivilegedExceptionAction(
157                            String templateId, Locale locale, String encoding, boolean parse) {
158    
159                            _templateId = templateId;
160                            _locale = locale;
161                            _encoding = encoding;
162                            _parse = parse;
163                    }
164    
165                    @Override
166                    public Template run() throws Exception {
167                            return doGetTemplate(_templateId, _locale, _encoding, _parse);
168                    }
169    
170                    private String _encoding;
171                    private Locale _locale;
172                    private boolean _parse;
173                    private String _templateId;
174    
175            }
176    
177    }