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.kernel.cache.MultiVMPool;
018    import com.liferay.portal.kernel.cache.PortalCache;
019    import com.liferay.portal.kernel.cache.PortalCacheListener;
020    import com.liferay.portal.kernel.cache.PortalCacheListenerScope;
021    import com.liferay.portal.kernel.cache.SingleVMPool;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
025    import com.liferay.portal.kernel.template.ClassLoaderTemplateResource;
026    import com.liferay.portal.kernel.template.TemplateConstants;
027    import com.liferay.portal.kernel.template.TemplateException;
028    import com.liferay.portal.kernel.template.TemplateResource;
029    import com.liferay.portal.kernel.template.TemplateResourceLoader;
030    import com.liferay.portal.kernel.template.URLTemplateResource;
031    import com.liferay.portal.kernel.util.InstanceFactory;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.Validator;
034    
035    import java.io.IOException;
036    import java.io.ObjectInput;
037    import java.io.ObjectOutput;
038    import java.io.Reader;
039    
040    import java.util.HashSet;
041    import java.util.Set;
042    
043    /**
044     * @author Tina Tian
045     */
046    @DoPrivileged
047    public class DefaultTemplateResourceLoader implements TemplateResourceLoader {
048    
049            public DefaultTemplateResourceLoader(
050                    String name, String[] templateResourceParserClassNames,
051                    long modificationCheckInterval, MultiVMPool multiVMPool,
052                    SingleVMPool singleVMPool) {
053    
054                    if (Validator.isNull(name)) {
055                            throw new IllegalArgumentException(
056                                    "Template resource loader name is null");
057                    }
058    
059                    if (templateResourceParserClassNames == null) {
060                            throw new IllegalArgumentException(
061                                    "Template resource parser class names is null");
062                    }
063    
064                    _name = name;
065    
066                    for (String templateResourceParserClassName :
067                                    templateResourceParserClassNames) {
068    
069                            try {
070                                    TemplateResourceParser templateResourceParser =
071                                            (TemplateResourceParser)InstanceFactory.newInstance(
072                                                    templateResourceParserClassName);
073    
074                                    _templateResourceParsers.add(templateResourceParser);
075                            }
076                            catch (Exception e) {
077                                    _log.error(e, e);
078                            }
079                    }
080    
081                    _modificationCheckInterval = modificationCheckInterval;
082    
083                    _multiVMPool = multiVMPool;
084    
085                    String portalCacheName = TemplateResourceLoader.class.getName();
086    
087                    portalCacheName = portalCacheName.concat(
088                            StringPool.PERIOD).concat(name);
089    
090                    _multiVMPortalCache =
091                            (PortalCache<String, TemplateResource>)_multiVMPool.getPortalCache(
092                                    portalCacheName);
093    
094                    PortalCacheListener<String, TemplateResource> cacheListener =
095                            new TemplateResourcePortalCacheListener(name);
096    
097                    _multiVMPortalCache.registerPortalCacheListener(
098                            cacheListener, PortalCacheListenerScope.ALL);
099    
100                    _singleVMPool = singleVMPool;
101    
102                    _singleVMPortalCache =
103                            (PortalCache<String, TemplateResource>)_singleVMPool.getPortalCache(
104                                    portalCacheName);
105    
106                    _singleVMPortalCache.registerPortalCacheListener(
107                            cacheListener, PortalCacheListenerScope.ALL);
108            }
109    
110            @Override
111            public void clearCache() {
112                    _multiVMPortalCache.removeAll();
113                    _singleVMPortalCache.removeAll();
114            }
115    
116            @Override
117            public void clearCache(String templateId) {
118                    _multiVMPortalCache.remove(templateId);
119                    _singleVMPortalCache.remove(templateId);
120            }
121    
122            @Override
123            public void destroy() {
124                    _multiVMPool.removePortalCache(
125                            _multiVMPortalCache.getPortalCacheName());
126                    _singleVMPool.removePortalCache(
127                            _singleVMPortalCache.getPortalCacheName());
128    
129                    _templateResourceParsers.clear();
130            }
131    
132            @Override
133            public String getName() {
134                    return _name;
135            }
136    
137            @Override
138            public TemplateResource getTemplateResource(String templateId) {
139                    if (_modificationCheckInterval == 0) {
140                            return _loadFromParser(templateId);
141                    }
142    
143                    TemplateResource templateResource = _loadFromCache(templateId);
144    
145                    if (templateResource != null) {
146                            if (templateResource instanceof NullHolderTemplateResource) {
147                                    return null;
148                            }
149    
150                            return templateResource;
151                    }
152    
153                    templateResource = _loadFromParser(templateId);
154    
155                    _updateCache(templateId, templateResource);
156    
157                    return templateResource;
158            }
159    
160            @Override
161            public boolean hasTemplateResource(String templateId) {
162                    TemplateResource templateResource = getTemplateResource(templateId);
163    
164                    if (templateResource != null) {
165                            return true;
166                    }
167    
168                    return false;
169            }
170    
171            private TemplateResource _getTemplateResource() {
172                    TemplateResource templateResource =
173                            TemplateResourceThreadLocal.getTemplateResource(_name);
174    
175                    if (templateResource instanceof CacheTemplateResource) {
176                            CacheTemplateResource cacheTemplateResource =
177                                    (CacheTemplateResource)templateResource;
178    
179                            return cacheTemplateResource.getInnerTemplateResource();
180                    }
181    
182                    return templateResource;
183            }
184    
185            private Set<TemplateResourceParser> _getTemplateResourceParsers() {
186                    TemplateResource templateResource = _getTemplateResource();
187    
188                    if ((templateResource != null) &&
189                            (templateResource instanceof ClassLoaderTemplateResource)) {
190    
191                            ClassLoaderTemplateResource classLoaderTemplateResource =
192                                    (ClassLoaderTemplateResource)templateResource;
193    
194                            ClassLoaderResourceParser classLoaderResourceParser =
195                                    new ClassLoaderResourceParser(
196                                            classLoaderTemplateResource.getClassLoader());
197    
198                            Set<TemplateResourceParser> templateResourceParsers = new HashSet<>(
199                                    _templateResourceParsers);
200    
201                            templateResourceParsers.add(classLoaderResourceParser);
202    
203                            return templateResourceParsers;
204                    }
205    
206                    return _templateResourceParsers;
207            }
208    
209            private TemplateResource _loadFromCache(
210                    PortalCache<String, TemplateResource> portalCache, String templateId) {
211    
212                    Object object = portalCache.get(templateId);
213    
214                    if (object == null) {
215                            return null;
216                    }
217    
218                    if (!(object instanceof TemplateResource)) {
219                            portalCache.remove(templateId);
220    
221                            if (_log.isWarnEnabled()) {
222                                    _log.warn(
223                                            "Remove template " + templateId +
224                                                    " because it is not a template resource");
225                            }
226    
227                            return null;
228                    }
229    
230                    TemplateResource templateResource = (TemplateResource)object;
231    
232                    if (_modificationCheckInterval > 0) {
233                            long expireTime =
234                                    templateResource.getLastModified() + _modificationCheckInterval;
235    
236                            if (System.currentTimeMillis() > expireTime) {
237                                    portalCache.remove(templateId);
238    
239                                    templateResource = _nullHolderTemplateResource;
240    
241                                    if (_log.isDebugEnabled()) {
242                                            _log.debug(
243                                                    "Remove expired template resource " + templateId);
244                                    }
245                            }
246                    }
247    
248                    return templateResource;
249            }
250    
251            private TemplateResource _loadFromCache(String templateId) {
252                    TemplateResource templateResource = _loadFromCache(
253                            _singleVMPortalCache, templateId);
254    
255                    if (templateResource != null) {
256                            if (templateResource == _nullHolderTemplateResource) {
257                                    return null;
258                            }
259    
260                            return templateResource;
261                    }
262    
263                    templateResource = _loadFromCache(_multiVMPortalCache, templateId);
264    
265                    if ((templateResource == null) ||
266                            (templateResource == _nullHolderTemplateResource)) {
267    
268                            return null;
269                    }
270    
271                    return templateResource;
272            }
273    
274            private TemplateResource _loadFromParser(String templateId) {
275                    Set<TemplateResourceParser> templateResourceParsers =
276                            _getTemplateResourceParsers();
277    
278                    for (TemplateResourceParser templateResourceParser :
279                                    templateResourceParsers) {
280    
281                            try {
282                                    TemplateResource templateResource =
283                                            templateResourceParser.getTemplateResource(templateId);
284    
285                                    if (templateResource != null) {
286                                            if ((_modificationCheckInterval != 0) &&
287                                                    !_name.equals(TemplateConstants.LANG_TYPE_VM)) {
288    
289                                                    templateResource = new CacheTemplateResource(
290                                                            templateResource);
291                                            }
292    
293                                            return templateResource;
294                                    }
295                            }
296                            catch (TemplateException te) {
297                                    if (_log.isWarnEnabled()) {
298                                            _log.warn(
299                                                    "Unable to parse template " + templateId +
300                                                            " with parser " + templateResourceParser,
301                                                    te);
302                                    }
303                            }
304                    }
305    
306                    return null;
307            }
308    
309            private void _updateCache(
310                    String templateId, TemplateResource templateResource) {
311    
312                    if (!(templateResource instanceof CacheTemplateResource)) {
313                            return;
314                    }
315    
316                    if (templateResource == null) {
317                            _singleVMPortalCache.put(
318                                    templateId, new NullHolderTemplateResource());
319    
320                            return;
321                    }
322    
323                    CacheTemplateResource cacheTemplateResource =
324                            (CacheTemplateResource)templateResource;
325    
326                    TemplateResource innerTemplateResource =
327                            cacheTemplateResource.getInnerTemplateResource();
328    
329                    if (innerTemplateResource instanceof URLTemplateResource) {
330                            _singleVMPortalCache.put(templateId, templateResource);
331    
332                            return;
333                    }
334    
335                    _multiVMPortalCache.put(templateId, templateResource);
336            }
337    
338            private static final Log _log = LogFactoryUtil.getLog(
339                    DefaultTemplateResourceLoader.class);
340    
341            private static final NullHolderTemplateResource
342                    _nullHolderTemplateResource = new NullHolderTemplateResource();
343    
344            private long _modificationCheckInterval;
345            private final MultiVMPool _multiVMPool;
346            private final PortalCache<String, TemplateResource> _multiVMPortalCache;
347            private final String _name;
348            private final SingleVMPool _singleVMPool;
349            private final PortalCache<String, TemplateResource> _singleVMPortalCache;
350            private final Set<TemplateResourceParser> _templateResourceParsers =
351                    new HashSet<>();
352    
353            private static class NullHolderTemplateResource
354                    implements TemplateResource {
355    
356                    /**
357                     * The empty constructor is required by {@link java.io.Externalizable}.
358                     * Do not use this for any other purpose.
359                     */
360                    public NullHolderTemplateResource() {
361                    }
362    
363                    @Override
364                    public long getLastModified() {
365                            return _lastModified;
366                    }
367    
368                    @Override
369                    public Reader getReader() {
370                            return null;
371                    }
372    
373                    @Override
374                    public String getTemplateId() {
375                            return null;
376                    }
377    
378                    @Override
379                    public void readExternal(ObjectInput objectInput) throws IOException {
380                            _lastModified = objectInput.readLong();
381                    }
382    
383                    @Override
384                    public void writeExternal(ObjectOutput objectOutput)
385                            throws IOException {
386    
387                            objectOutput.writeLong(_lastModified);
388                    }
389    
390                    private long _lastModified = System.currentTimeMillis();
391    
392            }
393    
394    }