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