001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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    
097            @Override
098            public void clearCache() {
099                    _multiVMPortalCache.removeAll();
100                    _singleVMPortalCache.removeAll();
101            }
102    
103            @Override
104            public void clearCache(String templateId) {
105                    _multiVMPortalCache.remove(templateId);
106                    _singleVMPortalCache.remove(templateId);
107            }
108    
109            @Override
110            public void destroy() {
111                    _multiVMPortalCache.destroy();
112                    _singleVMPortalCache.destroy();
113    
114                    _templateResourceParsers.clear();
115            }
116    
117            @Override
118            public String getName() {
119                    return _name;
120            }
121    
122            @Override
123            public TemplateResource getTemplateResource(String templateId) {
124                    if (_modificationCheckInterval == 0) {
125                            return _loadFromParser(templateId);
126                    }
127    
128                    TemplateResource templateResource = _loadFromCache(templateId);
129    
130                    if (templateResource != null) {
131                            if (templateResource instanceof NullHolderTemplateResource) {
132                                    return null;
133                            }
134    
135                            return templateResource;
136                    }
137    
138                    templateResource = _loadFromParser(templateId);
139    
140                    _updateCache(templateId, templateResource);
141    
142                    return templateResource;
143            }
144    
145            @Override
146            public boolean hasTemplateResource(String templateId) {
147                    TemplateResource templateResource = getTemplateResource(templateId);
148    
149                    if (templateResource != null) {
150                            return true;
151                    }
152    
153                    return false;
154            }
155    
156            private TemplateResource _loadFromCache(
157                    PortalCache<String, TemplateResource> portalCache, String templateId) {
158    
159                    Object object = portalCache.get(templateId);
160    
161                    if (object == null) {
162                            return null;
163                    }
164    
165                    if (!(object instanceof TemplateResource)) {
166                            portalCache.remove(templateId);
167    
168                            if (_log.isWarnEnabled()) {
169                                    _log.warn(
170                                            "Remove template " + templateId +
171                                                    " because it is not a template resource");
172                            }
173    
174                            return null;
175                    }
176    
177                    TemplateResource templateResource = (TemplateResource)object;
178    
179                    if (_modificationCheckInterval > 0) {
180                            long expireTime =
181                                    templateResource.getLastModified() + _modificationCheckInterval;
182    
183                            if (System.currentTimeMillis() > expireTime) {
184                                    portalCache.remove(templateId);
185    
186                                    templateResource = _nullHolderTemplateResource;
187    
188                                    if (_log.isDebugEnabled()) {
189                                            _log.debug(
190                                                    "Remove expired template resource " + templateId);
191                                    }
192                            }
193                    }
194    
195                    return templateResource;
196            }
197    
198            private TemplateResource _loadFromCache(String templateId) {
199                    TemplateResource templateResource = _loadFromCache(
200                            _singleVMPortalCache, templateId);
201    
202                    if (templateResource != null) {
203                            if (templateResource == _nullHolderTemplateResource) {
204                                    return null;
205                            }
206    
207                            return templateResource;
208                    }
209    
210                    templateResource = _loadFromCache(_multiVMPortalCache, templateId);
211    
212                    if ((templateResource == null) ||
213                            (templateResource == _nullHolderTemplateResource)) {
214    
215                            return null;
216                    }
217    
218                    return templateResource;
219            }
220    
221            private TemplateResource _loadFromParser(String templateId) {
222                    for (TemplateResourceParser templateResourceParser :
223                                    _templateResourceParsers) {
224    
225                            try {
226                                    TemplateResource templateResource =
227                                            templateResourceParser.getTemplateResource(templateId);
228    
229                                    if (templateResource != null) {
230                                            if ((_modificationCheckInterval != 0) &&
231                                                    (!_name.equals(TemplateConstants.LANG_TYPE_VM) ||
232                                                     !templateId.contains(
233                                                             SandboxHandler.SANDBOX_MARKER))) {
234    
235                                                    templateResource = new CacheTemplateResource(
236                                                            templateResource);
237                                            }
238    
239                                            return templateResource;
240                                    }
241                            }
242                            catch (TemplateException te) {
243                                    if (_log.isWarnEnabled()) {
244                                            _log.warn(
245                                                    "Unable to parse template " + templateId +
246                                                            " with parser " + templateResourceParser,
247                                                    te);
248                                    }
249                            }
250                    }
251    
252                    return null;
253            }
254    
255            private void _updateCache(
256                    String templateId, TemplateResource templateResource) {
257    
258                    if (templateResource == null) {
259                            _singleVMPortalCache.put(
260                                    templateId, new NullHolderTemplateResource());
261    
262                            return;
263                    }
264    
265                    CacheTemplateResource cacheTemplateResource =
266                            (CacheTemplateResource)templateResource;
267    
268                    TemplateResource innerTemplateResource =
269                            cacheTemplateResource.getInnerTemplateResource();
270    
271                    if (innerTemplateResource instanceof URLTemplateResource) {
272                            _singleVMPortalCache.put(templateId, templateResource);
273    
274                            return;
275                    }
276    
277                    _multiVMPortalCache.put(templateId, templateResource);
278            }
279    
280            private static Log _log = LogFactoryUtil.getLog(
281                    DefaultTemplateResourceLoader.class);
282    
283            private static NullHolderTemplateResource _nullHolderTemplateResource =
284                    new NullHolderTemplateResource();
285    
286            private long _modificationCheckInterval;
287            private PortalCache<String, TemplateResource> _multiVMPortalCache;
288            private String _name;
289            private PortalCache<String, TemplateResource> _singleVMPortalCache;
290            private Set<TemplateResourceParser> _templateResourceParsers =
291                    new HashSet<TemplateResourceParser>();
292    
293            private static class NullHolderTemplateResource
294                    implements TemplateResource {
295    
296                    /**
297                     * The empty constructor is required by {@link java.io.Externalizable}.
298                     * Do not use this for any other purpose.
299                     */
300                    public NullHolderTemplateResource() {
301                    }
302    
303                    @Override
304                    public long getLastModified() {
305                            return _lastModified;
306                    }
307    
308                    @Override
309                    public Reader getReader() {
310                            return null;
311                    }
312    
313                    @Override
314                    public String getTemplateId() {
315                            return null;
316                    }
317    
318                    @Override
319                    public void readExternal(ObjectInput objectInput) throws IOException {
320                            _lastModified = objectInput.readLong();
321                    }
322    
323                    @Override
324                    public void writeExternal(ObjectOutput objectOutput)
325                            throws IOException {
326    
327                            objectOutput.writeLong(_lastModified);
328                    }
329    
330                    private long _lastModified = System.currentTimeMillis();
331    
332            }
333    
334    }