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.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.TemplateConstants;
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.util.InstanceFactory;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.Validator;
032    
033    import java.io.IOException;
034    import java.io.ObjectInput;
035    import java.io.ObjectOutput;
036    import java.io.Reader;
037    
038    import java.util.HashSet;
039    import java.util.Set;
040    
041    /**
042     * @author Tina Tian
043     */
044    @DoPrivileged
045    public class DefaultTemplateResourceLoader implements TemplateResourceLoader {
046    
047            public DefaultTemplateResourceLoader(
048                    String name, String[] templateResourceParserClassNames,
049                    long modificationCheckInterval) {
050    
051                    if (Validator.isNull(name)) {
052                            throw new IllegalArgumentException(
053                                    "Template resource loader name is null");
054                    }
055    
056                    if (templateResourceParserClassNames == null) {
057                            throw new IllegalArgumentException(
058                                    "Template resource parser class names is null");
059                    }
060    
061                    _name = name;
062    
063                    for (String templateResourceParserClassName :
064                                    templateResourceParserClassNames) {
065    
066                            try {
067                                    TemplateResourceParser templateResourceParser =
068                                            (TemplateResourceParser)InstanceFactory.newInstance(
069                                                    templateResourceParserClassName);
070    
071                                    _templateResourceParsers.add(templateResourceParser);
072                            }
073                            catch (Exception e) {
074                                    _log.error(e, e);
075                            }
076                    }
077    
078                    _modificationCheckInterval = modificationCheckInterval;
079    
080                    String cacheName = TemplateResourceLoader.class.getName();
081    
082                    cacheName = cacheName.concat(StringPool.PERIOD).concat(name);
083    
084                    _portalCache = MultiVMPoolUtil.getCache(cacheName);
085    
086                    CacheListener<String, TemplateResource> cacheListener =
087                            new TemplateResourceCacheListener(name);
088    
089                    _portalCache.registerCacheListener(
090                            cacheListener, CacheListenerScope.ALL);
091            }
092    
093            @Override
094            public void clearCache() {
095                    _portalCache.removeAll();
096            }
097    
098            @Override
099            public void clearCache(String templateId) {
100                    _portalCache.remove(templateId);
101            }
102    
103            @Override
104            public void destroy() {
105                    _portalCache.destroy();
106    
107                    _templateResourceParsers.clear();
108            }
109    
110            @Override
111            public String getName() {
112                    return _name;
113            }
114    
115            @Override
116            public TemplateResource getTemplateResource(String templateId) {
117                    TemplateResource templateResource = _loadFromCache(templateId);
118    
119                    if (templateResource != null) {
120                            if (templateResource instanceof NullHolderTemplateResource) {
121                                    return null;
122                            }
123    
124                            return templateResource;
125                    }
126    
127                    templateResource = _loadFromParser(templateId);
128    
129                    if (_modificationCheckInterval != 0) {
130                            if (templateResource == null) {
131                                    _portalCache.put(templateId, new NullHolderTemplateResource());
132                            }
133                            else {
134                                    _portalCache.put(templateId, templateResource);
135                            }
136                    }
137    
138                    return templateResource;
139            }
140    
141            @Override
142            public boolean hasTemplateResource(String templateId) {
143                    TemplateResource templateResource = getTemplateResource(templateId);
144    
145                    if (templateResource != null) {
146                            return true;
147                    }
148    
149                    return false;
150            }
151    
152            private TemplateResource _loadFromCache(String templateId) {
153                    if (_modificationCheckInterval == 0) {
154                            return null;
155                    }
156    
157                    Object object = _portalCache.get(templateId);
158    
159                    if (object == null) {
160                            return null;
161                    }
162    
163                    if (!(object instanceof TemplateResource)) {
164                            _portalCache.remove(templateId);
165    
166                            if (_log.isWarnEnabled()) {
167                                    _log.warn(
168                                            "Remove template " + templateId +
169                                                    " because it is not a template resource");
170                            }
171    
172                            return null;
173                    }
174    
175                    TemplateResource templateResource = (TemplateResource)object;
176    
177                    if (_modificationCheckInterval > 0) {
178                            long expireTime =
179                                    templateResource.getLastModified() + _modificationCheckInterval;
180    
181                            if (System.currentTimeMillis() > expireTime) {
182                                    _portalCache.remove(templateId);
183    
184                                    templateResource = null;
185    
186                                    if (_log.isDebugEnabled()) {
187                                            _log.debug(
188                                                    "Remove expired template resource " + templateId);
189                                    }
190                            }
191                    }
192    
193                    return templateResource;
194            }
195    
196            private TemplateResource _loadFromParser(String templateId) {
197                    for (TemplateResourceParser templateResourceParser :
198                                    _templateResourceParsers) {
199    
200                            try {
201                                    TemplateResource templateResource =
202                                            templateResourceParser.getTemplateResource(templateId);
203    
204                                    if (templateResource != null) {
205                                            if ((_modificationCheckInterval != 0) &&
206                                                    (!_name.equals(TemplateConstants.LANG_TYPE_VM) ||
207                                                     !templateId.contains(
208                                                             SandboxHandler.SANDBOX_MARKER))) {
209    
210                                                    templateResource = new CacheTemplateResource(
211                                                            templateResource);
212                                            }
213    
214                                            return templateResource;
215                                    }
216                            }
217                            catch (TemplateException te) {
218                                    _log.warn(
219                                            "Unable to parse template " + templateId + " with parser " +
220                                                    templateResourceParser,
221                                            te);
222                            }
223                    }
224    
225                    return null;
226            }
227    
228            private static Log _log = LogFactoryUtil.getLog(
229                    DefaultTemplateResourceLoader.class);
230    
231            private long _modificationCheckInterval;
232            private String _name;
233            private PortalCache<String, TemplateResource> _portalCache;
234            private Set<TemplateResourceParser> _templateResourceParsers =
235                    new HashSet<TemplateResourceParser>();
236    
237            private static class NullHolderTemplateResource
238                    implements TemplateResource {
239    
240                    /**
241                     * The empty constructor is required by {@link java.io.Externalizable}.
242                     * Do not use this for any other purpose.
243                     */
244                    public NullHolderTemplateResource() {
245                    }
246    
247                    @Override
248                    public long getLastModified() {
249                            return _lastModified;
250                    }
251    
252                    @Override
253                    public Reader getReader() {
254                            return null;
255                    }
256    
257                    @Override
258                    public String getTemplateId() {
259                            return null;
260                    }
261    
262                    @Override
263                    public void readExternal(ObjectInput objectInput) throws IOException {
264                            _lastModified = objectInput.readLong();
265                    }
266    
267                    @Override
268                    public void writeExternal(ObjectOutput objectOutput)
269                            throws IOException {
270    
271                            objectOutput.writeLong(_lastModified);
272                    }
273    
274                    private long _lastModified = System.currentTimeMillis();
275    
276            }
277    
278    }