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            public void clearCache() {
094                    _portalCache.removeAll();
095            }
096    
097            public void clearCache(String templateId) {
098                    _portalCache.remove(templateId);
099            }
100    
101            public void destroy() {
102                    _portalCache.destroy();
103    
104                    _templateResourceParsers.clear();
105            }
106    
107            public String getName() {
108                    return _name;
109            }
110    
111            public TemplateResource getTemplateResource(String templateId) {
112                    TemplateResource templateResource = _loadFromCache(templateId);
113    
114                    if (templateResource != null) {
115                            if (templateResource instanceof NullHolderTemplateResource) {
116                                    return null;
117                            }
118    
119                            return templateResource;
120                    }
121    
122                    templateResource = _loadFromParser(templateId);
123    
124                    if (_modificationCheckInterval != 0) {
125                            if (templateResource == null) {
126                                    _portalCache.put(templateId, new NullHolderTemplateResource());
127                            }
128                            else {
129                                    _portalCache.put(templateId, templateResource);
130                            }
131                    }
132    
133                    return templateResource;
134            }
135    
136            public boolean hasTemplateResource(String templateId) {
137                    TemplateResource templateResource = getTemplateResource(templateId);
138    
139                    if (templateResource != null) {
140                            return true;
141                    }
142    
143                    return false;
144            }
145    
146            private TemplateResource _loadFromCache(String templateId) {
147                    if (_modificationCheckInterval == 0) {
148                            return null;
149                    }
150    
151                    Object object = _portalCache.get(templateId);
152    
153                    if (object == null) {
154                            return null;
155                    }
156    
157                    if (!(object instanceof TemplateResource)) {
158                            _portalCache.remove(templateId);
159    
160                            if (_log.isWarnEnabled()) {
161                                    _log.warn(
162                                            "Remove template " + templateId +
163                                                    " because it is not a template resource");
164                            }
165    
166                            return null;
167                    }
168    
169                    TemplateResource templateResource = (TemplateResource)object;
170    
171                    if (_modificationCheckInterval > 0) {
172                            long expireTime =
173                                    templateResource.getLastModified() + _modificationCheckInterval;
174    
175                            if (System.currentTimeMillis() > expireTime) {
176                                    _portalCache.remove(templateId);
177    
178                                    templateResource = null;
179    
180                                    if (_log.isDebugEnabled()) {
181                                            _log.debug(
182                                                    "Remove expired template resource " + templateId);
183                                    }
184                            }
185                    }
186    
187                    return templateResource;
188            }
189    
190            private TemplateResource _loadFromParser(String templateId) {
191                    for (TemplateResourceParser templateResourceParser :
192                                    _templateResourceParsers) {
193    
194                            try {
195                                    TemplateResource templateResource =
196                                            templateResourceParser.getTemplateResource(templateId);
197    
198                                    if (templateResource != null) {
199                                            if ((_modificationCheckInterval != 0) &&
200                                                    (!_name.equals(TemplateConstants.LANG_TYPE_VM) ||
201                                                     !templateId.contains(
202                                                             SandboxHandler.SANDBOX_MARKER))) {
203    
204                                                    templateResource = new CacheTemplateResource(
205                                                            templateResource);
206                                            }
207    
208                                            return templateResource;
209                                    }
210                            }
211                            catch (TemplateException te) {
212                                    _log.warn(
213                                            "Unable to parse template " + templateId + " with parser " +
214                                                    templateResourceParser,
215                                            te);
216                            }
217                    }
218    
219                    return null;
220            }
221    
222            private static Log _log = LogFactoryUtil.getLog(
223                    DefaultTemplateResourceLoader.class);
224    
225            private long _modificationCheckInterval;
226            private String _name;
227            private PortalCache<String, TemplateResource> _portalCache;
228            private Set<TemplateResourceParser> _templateResourceParsers =
229                    new HashSet<TemplateResourceParser>();
230    
231            private static class NullHolderTemplateResource
232                    implements TemplateResource {
233    
234                    /**
235                     * The empty constructor is required by {@link java.io.Externalizable}.
236                     * Do not use this for any other purpose.
237                     */
238                    public NullHolderTemplateResource() {
239                    }
240    
241                    public long getLastModified() {
242                            return _lastModified;
243                    }
244    
245                    public Reader getReader() {
246                            return null;
247                    }
248    
249                    public String getTemplateId() {
250                            return null;
251                    }
252    
253                    public void readExternal(ObjectInput objectInput) throws IOException {
254                            _lastModified = objectInput.readLong();
255                    }
256    
257                    public void writeExternal(ObjectOutput objectOutput)
258                            throws IOException {
259    
260                            objectOutput.writeLong(_lastModified);
261                    }
262    
263                    private long _lastModified = System.currentTimeMillis();
264    
265            }
266    
267    }