001    /**
002     * Copyright (c) 2000-present 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.template;
016    
017    import com.liferay.portal.deploy.sandbox.SandboxHandler;
018    import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
019    import com.liferay.portal.kernel.cache.PortalCache;
020    import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
021    import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
022    import com.liferay.portal.kernel.template.StringTemplateResource;
023    import com.liferay.portal.kernel.template.Template;
024    import com.liferay.portal.kernel.template.TemplateConstants;
025    import com.liferay.portal.kernel.template.TemplateException;
026    import com.liferay.portal.kernel.template.TemplateResource;
027    import com.liferay.portal.kernel.template.TemplateResourceLoader;
028    import com.liferay.portal.kernel.template.URLTemplateResource;
029    import com.liferay.portal.kernel.util.StringBundler;
030    import com.liferay.portal.kernel.util.StringPool;
031    
032    import java.io.Serializable;
033    import java.io.Writer;
034    
035    import java.util.Collection;
036    import java.util.HashMap;
037    import java.util.Map;
038    import java.util.Set;
039    
040    import javax.servlet.http.HttpServletRequest;
041    
042    /**
043     * @author Tina Tian
044     */
045    public abstract class AbstractTemplate implements Template {
046    
047            public AbstractTemplate(
048                    TemplateResource templateResource,
049                    TemplateResource errorTemplateResource, Map<String, Object> context,
050                    TemplateContextHelper templateContextHelper, String templateManagerName,
051                    long interval) {
052    
053                    if (templateResource == null) {
054                            throw new IllegalArgumentException("Template resource is null");
055                    }
056    
057                    if (templateContextHelper == null) {
058                            throw new IllegalArgumentException(
059                                    "Template context helper is null");
060                    }
061    
062                    if (templateManagerName == null) {
063                            throw new IllegalArgumentException("Template manager name is null");
064                    }
065    
066                    this.templateResource = templateResource;
067                    this.errorTemplateResource = errorTemplateResource;
068    
069                    this.context = new HashMap<>();
070    
071                    if (context != null) {
072                            for (Map.Entry<String, Object> entry : context.entrySet()) {
073                                    put(entry.getKey(), entry.getValue());
074                            }
075                    }
076    
077                    _templateContextHelper = templateContextHelper;
078    
079                    if (interval != 0) {
080                            _cacheTemplateResource(templateManagerName);
081                    }
082            }
083    
084            @Override
085            public void clear() {
086                    context.clear();
087            }
088    
089            @Override
090            public boolean containsKey(Object key) {
091                    return context.containsKey(key);
092            }
093    
094            @Override
095            public boolean containsValue(Object value) {
096                    return context.containsValue(value);
097            }
098    
099            @Override
100            public void doProcessTemplate(Writer writer) throws Exception {
101                    UnsyncStringWriter unsyncStringWriter = new UnsyncStringWriter();
102    
103                    put(TemplateConstants.WRITER, unsyncStringWriter);
104    
105                    processTemplate(templateResource, unsyncStringWriter);
106    
107                    StringBundler sb = unsyncStringWriter.getStringBundler();
108    
109                    sb.writeTo(writer);
110            }
111    
112            @Override
113            public Set<Entry<String, Object>> entrySet() {
114                    return context.entrySet();
115            }
116    
117            @Override
118            public Object get(Object key) {
119                    if (key == null) {
120                            return null;
121                    }
122    
123                    return context.get(key);
124            }
125    
126            @Override
127            public Object get(String key) {
128                    if (key == null) {
129                            return null;
130                    }
131    
132                    return context.get(key);
133            }
134    
135            @Override
136            public String[] getKeys() {
137                    Set<String> keys = context.keySet();
138    
139                    return keys.toArray(new String[keys.size()]);
140            }
141    
142            @Override
143            public boolean isEmpty() {
144                    return context.isEmpty();
145            }
146    
147            @Override
148            public Set<String> keySet() {
149                    return context.keySet();
150            }
151    
152            @Override
153            public void prepare(HttpServletRequest request) {
154                    _templateContextHelper.prepare(this, request);
155            }
156    
157            @Override
158            public void processTemplate(Writer writer) throws TemplateException {
159                    if (errorTemplateResource == null) {
160                            try {
161                                    processTemplate(templateResource, writer);
162    
163                                    return;
164                            }
165                            catch (Exception e) {
166                                    throw new TemplateException(
167                                            "Unable to process template " +
168                                                    templateResource.getTemplateId(),
169                                            e);
170                            }
171                    }
172    
173                    Writer oldWriter = (Writer)get(TemplateConstants.WRITER);
174    
175                    try {
176                            doProcessTemplate(writer);
177                    }
178                    catch (Exception e) {
179                            put(TemplateConstants.WRITER, writer);
180    
181                            handleException(e, writer);
182                    }
183                    finally {
184                            put(TemplateConstants.WRITER, oldWriter);
185                    }
186            }
187    
188            @Override
189            public Object put(String key, Object value) {
190                    if ((key == null) || (value == null)) {
191                            return null;
192                    }
193    
194                    return context.put(key, value);
195            }
196    
197            @Override
198            public void putAll(Map<? extends String, ? extends Object> map) {
199                    context.putAll(map);
200            }
201    
202            @Override
203            public Object remove(Object key) {
204                    return context.remove(key);
205            }
206    
207            @Override
208            public int size() {
209                    return context.size();
210            }
211    
212            @Override
213            public Collection<Object> values() {
214                    return context.values();
215            }
216    
217            protected String getTemplateResourceUUID(
218                    TemplateResource templateResource) {
219    
220                    return TemplateConstants.TEMPLATE_RESOURCE_UUID_PREFIX.concat(
221                            StringPool.POUND).concat(templateResource.getTemplateId());
222            }
223    
224            protected abstract void handleException(Exception exception, Writer writer)
225                    throws TemplateException;
226    
227            protected abstract void processTemplate(
228                            TemplateResource templateResource, Writer writer)
229                    throws Exception;
230    
231            protected Map<String, Object> context;
232            protected TemplateResource errorTemplateResource;
233            protected TemplateResource templateResource;
234    
235            private void _cacheTemplateResource(String templateManagerName) {
236                    String templateId = templateResource.getTemplateId();
237    
238                    if (templateManagerName.equals(TemplateConstants.LANG_TYPE_VM) &&
239                            templateId.contains(SandboxHandler.SANDBOX_MARKER)) {
240    
241                            return;
242                    }
243    
244                    if (!(templateResource instanceof CacheTemplateResource) &&
245                            !(templateResource instanceof StringTemplateResource)) {
246    
247                            templateResource = new CacheTemplateResource(templateResource);
248                    }
249    
250                    String portalCacheName = TemplateResourceLoader.class.getName();
251    
252                    portalCacheName = portalCacheName.concat(StringPool.PERIOD).concat(
253                            templateManagerName);
254    
255                    PortalCache<String, Serializable> portalCache = _getPortalCache(
256                            templateResource, portalCacheName);
257    
258                    Object object = portalCache.get(templateResource.getTemplateId());
259    
260                    if ((object == null) || !templateResource.equals(object)) {
261                            portalCache.put(templateResource.getTemplateId(), templateResource);
262                    }
263    
264                    if (errorTemplateResource == null) {
265                            return;
266                    }
267    
268                    String errorTemplateId = errorTemplateResource.getTemplateId();
269    
270                    if (templateManagerName.equals(TemplateConstants.LANG_TYPE_VM) &&
271                            errorTemplateId.contains(SandboxHandler.SANDBOX_MARKER)) {
272    
273                            return;
274                    }
275    
276                    if (!(errorTemplateResource instanceof CacheTemplateResource) &&
277                            !(errorTemplateResource instanceof StringTemplateResource)) {
278    
279                            errorTemplateResource = new CacheTemplateResource(
280                                    errorTemplateResource);
281                    }
282    
283                    portalCache = _getPortalCache(errorTemplateResource, portalCacheName);
284    
285                    object = portalCache.get(errorTemplateResource.getTemplateId());
286    
287                    if ((object == null) || !errorTemplateResource.equals(object)) {
288                            portalCache.put(
289                                    errorTemplateResource.getTemplateId(), errorTemplateResource);
290                    }
291            }
292    
293            private PortalCache<String, Serializable> _getPortalCache(
294                    TemplateResource templateResource, String portalCacheName) {
295    
296                    if (!(templateResource instanceof CacheTemplateResource)) {
297                            return MultiVMPoolUtil.getCache(portalCacheName);
298                    }
299    
300                    CacheTemplateResource cacheTemplateResource =
301                            (CacheTemplateResource)templateResource;
302    
303                    TemplateResource innerTemplateResource =
304                            cacheTemplateResource.getInnerTemplateResource();
305    
306                    if (innerTemplateResource instanceof URLTemplateResource) {
307                            return SingleVMPoolUtil.getCache(portalCacheName);
308                    }
309    
310                    return MultiVMPoolUtil.getCache(portalCacheName);
311            }
312    
313            private final TemplateContextHelper _templateContextHelper;
314    
315    }