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.template;
016    
017    import com.liferay.portal.deploy.sandbox.SandboxHandler;
018    import com.liferay.portal.kernel.cache.CacheListener;
019    import com.liferay.portal.kernel.cache.CacheListenerScope;
020    import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
021    import com.liferay.portal.kernel.cache.PortalCache;
022    import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
023    import com.liferay.portal.kernel.log.Log;
024    import com.liferay.portal.kernel.log.LogFactoryUtil;
025    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
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) {
052    
053                    if (Validator.isNull(name)) {
054                            throw new IllegalArgumentException(
055                                    "Template resource loader name is null");
056                    }
057    
058                    if (templateResourceParserClassNames == null) {
059                            throw new IllegalArgumentException(
060                                    "Template resource parser class names is null");
061                    }
062    
063                    _name = name;
064    
065                    for (String templateResourceParserClassName :
066                                    templateResourceParserClassNames) {
067    
068                            try {
069                                    TemplateResourceParser templateResourceParser =
070                                            (TemplateResourceParser)InstanceFactory.newInstance(
071                                                    templateResourceParserClassName);
072    
073                                    _templateResourceParsers.add(templateResourceParser);
074                            }
075                            catch (Exception e) {
076                                    _log.error(e, e);
077                            }
078                    }
079    
080                    _modificationCheckInterval = modificationCheckInterval;
081    
082                    String cacheName = TemplateResourceLoader.class.getName();
083    
084                    cacheName = cacheName.concat(StringPool.PERIOD).concat(name);
085    
086                    _multiVMPortalCache = MultiVMPoolUtil.getCache(cacheName);
087    
088                    CacheListener<String, TemplateResource> cacheListener =
089                            new TemplateResourceCacheListener(name);
090    
091                    _multiVMPortalCache.registerCacheListener(
092                            cacheListener, CacheListenerScope.ALL);
093    
094                    _singleVMPortalCache = SingleVMPoolUtil.getCache(cacheName);
095    
096                    _singleVMPortalCache.registerCacheListener(
097                            cacheListener, CacheListenerScope.ALL);
098            }
099    
100            @Override
101            public void clearCache() {
102                    _multiVMPortalCache.removeAll();
103                    _singleVMPortalCache.removeAll();
104            }
105    
106            @Override
107            public void clearCache(String templateId) {
108                    _multiVMPortalCache.remove(templateId);
109                    _singleVMPortalCache.remove(templateId);
110            }
111    
112            @Override
113            public void destroy() {
114                    _multiVMPortalCache.destroy();
115                    _singleVMPortalCache.destroy();
116    
117                    _templateResourceParsers.clear();
118            }
119    
120            @Override
121            public String getName() {
122                    return _name;
123            }
124    
125            @Override
126            public TemplateResource getTemplateResource(String templateId) {
127                    if (_modificationCheckInterval == 0) {
128                            return _loadFromParser(templateId);
129                    }
130    
131                    TemplateResource templateResource = _loadFromCache(templateId);
132    
133                    if (templateResource != null) {
134                            if (templateResource instanceof NullHolderTemplateResource) {
135                                    return null;
136                            }
137    
138                            return templateResource;
139                    }
140    
141                    templateResource = _loadFromParser(templateId);
142    
143                    _updateCache(templateId, templateResource);
144    
145                    return templateResource;
146            }
147    
148            @Override
149            public boolean hasTemplateResource(String templateId) {
150                    TemplateResource templateResource = getTemplateResource(templateId);
151    
152                    if (templateResource != null) {
153                            return true;
154                    }
155    
156                    return false;
157            }
158    
159            private TemplateResource _loadFromCache(
160                    PortalCache<String, TemplateResource> portalCache, String templateId) {
161    
162                    Object object = portalCache.get(templateId);
163    
164                    if (object == null) {
165                            return null;
166                    }
167    
168                    if (!(object instanceof TemplateResource)) {
169                            portalCache.remove(templateId);
170    
171                            if (_log.isWarnEnabled()) {
172                                    _log.warn(
173                                            "Remove template " + templateId +
174                                                    " because it is not a template resource");
175                            }
176    
177                            return null;
178                    }
179    
180                    TemplateResource templateResource = (TemplateResource)object;
181    
182                    if (_modificationCheckInterval > 0) {
183                            long expireTime =
184                                    templateResource.getLastModified() + _modificationCheckInterval;
185    
186                            if (System.currentTimeMillis() > expireTime) {
187                                    portalCache.remove(templateId);
188    
189                                    templateResource = _nullHolderTemplateResource;
190    
191                                    if (_log.isDebugEnabled()) {
192                                            _log.debug(
193                                                    "Remove expired template resource " + templateId);
194                                    }
195                            }
196                    }
197    
198                    return templateResource;
199            }
200    
201            private TemplateResource _loadFromCache(String templateId) {
202                    TemplateResource templateResource = _loadFromCache(
203                            _singleVMPortalCache, templateId);
204    
205                    if (templateResource != null) {
206                            if (templateResource == _nullHolderTemplateResource) {
207                                    return null;
208                            }
209    
210                            return templateResource;
211                    }
212    
213                    templateResource = _loadFromCache(_multiVMPortalCache, templateId);
214    
215                    if ((templateResource == null) ||
216                            (templateResource == _nullHolderTemplateResource)) {
217    
218                            return null;
219                    }
220    
221                    return templateResource;
222            }
223    
224            private TemplateResource _loadFromParser(String templateId) {
225                    for (TemplateResourceParser templateResourceParser :
226                                    _templateResourceParsers) {
227    
228                            try {
229                                    TemplateResource templateResource =
230                                            templateResourceParser.getTemplateResource(templateId);
231    
232                                    if (templateResource != null) {
233                                            if ((_modificationCheckInterval != 0) &&
234                                                    (!_name.equals(TemplateConstants.LANG_TYPE_VM) ||
235                                                     !templateId.contains(
236                                                             SandboxHandler.SANDBOX_MARKER))) {
237    
238                                                    templateResource = new CacheTemplateResource(
239                                                            templateResource);
240                                            }
241    
242                                            return templateResource;
243                                    }
244                            }
245                            catch (TemplateException te) {
246                                    if (_log.isWarnEnabled()) {
247                                            _log.warn(
248                                                    "Unable to parse template " + templateId +
249                                                            " with parser " + templateResourceParser,
250                                                    te);
251                                    }
252                            }
253                    }
254    
255                    return null;
256            }
257    
258            private void _updateCache(
259                    String templateId, TemplateResource templateResource) {
260    
261                    if (templateResource == null) {
262                            _singleVMPortalCache.put(
263                                    templateId, new NullHolderTemplateResource());
264    
265                            return;
266                    }
267    
268                    CacheTemplateResource cacheTemplateResource =
269                            (CacheTemplateResource)templateResource;
270    
271                    TemplateResource innerTemplateResource =
272                            cacheTemplateResource.getInnerTemplateResource();
273    
274                    if (innerTemplateResource instanceof URLTemplateResource) {
275                            _singleVMPortalCache.put(templateId, templateResource);
276    
277                            return;
278                    }
279    
280                    _multiVMPortalCache.put(templateId, templateResource);
281            }
282    
283            private static Log _log = LogFactoryUtil.getLog(
284                    DefaultTemplateResourceLoader.class);
285    
286            private static NullHolderTemplateResource _nullHolderTemplateResource =
287                    new NullHolderTemplateResource();
288    
289            private long _modificationCheckInterval;
290            private PortalCache<String, TemplateResource> _multiVMPortalCache;
291            private String _name;
292            private PortalCache<String, TemplateResource> _singleVMPortalCache;
293            private Set<TemplateResourceParser> _templateResourceParsers =
294                    new HashSet<TemplateResourceParser>();
295    
296            private static class NullHolderTemplateResource
297                    implements TemplateResource {
298    
299                    /**
300                     * The empty constructor is required by {@link java.io.Externalizable}.
301                     * Do not use this for any other purpose.
302                     */
303                    public NullHolderTemplateResource() {
304                    }
305    
306                    @Override
307                    public long getLastModified() {
308                            return _lastModified;
309                    }
310    
311                    @Override
312                    public Reader getReader() {
313                            return null;
314                    }
315    
316                    @Override
317                    public String getTemplateId() {
318                            return null;
319                    }
320    
321                    @Override
322                    public void readExternal(ObjectInput objectInput) throws IOException {
323                            _lastModified = objectInput.readLong();
324                    }
325    
326                    @Override
327                    public void writeExternal(ObjectOutput objectOutput)
328                            throws IOException {
329    
330                            objectOutput.writeLong(_lastModified);
331                    }
332    
333                    private long _lastModified = System.currentTimeMillis();
334    
335            }
336    
337    }