001    /**
002     * Copyright (c) 2000-2012 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.kernel.servlet;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.GetterUtil;
020    import com.liferay.portal.kernel.util.PropsKeys;
021    import com.liferay.portal.kernel.util.PropsUtil;
022    import com.liferay.portal.kernel.util.ReflectionUtil;
023    import com.liferay.portal.kernel.util.StringPool;
024    
025    import java.io.File;
026    
027    import java.lang.reflect.Method;
028    
029    import java.util.Collection;
030    import java.util.List;
031    import java.util.Map;
032    import java.util.concurrent.ConcurrentHashMap;
033    
034    import javax.servlet.Servlet;
035    import javax.servlet.ServletConfig;
036    import javax.servlet.ServletContext;
037    
038    /**
039     * @author Shuyang Zhou
040     */
041    public class DirectServletRegistry {
042    
043            public static void clearServlets() {
044                    _instance._clearServlets();
045            }
046    
047            public static Servlet getServlet(String path) {
048                    return _instance._getServlet(path);
049            }
050    
051            public static void putServlet(String path, Servlet servlet) {
052                    _instance._putServlet(path, servlet);
053            }
054    
055            private DirectServletRegistry() {
056            }
057    
058            private void _clearServlets() {
059                    _servletInfos.clear();
060            }
061    
062            private long _getFileLastModified(String path, Servlet servlet) {
063                    ServletConfig servletConfig = servlet.getServletConfig();
064    
065                    ServletContext servletContext = servletConfig.getServletContext();
066    
067                    String rootPath = servletContext.getRealPath(StringPool.BLANK);
068    
069                    File file = new File(rootPath, path);
070    
071                    return file.lastModified();
072            }
073    
074            private Servlet _getServlet(String path) {
075                    ServletInfo servletInfo = _servletInfos.get(path);
076    
077                    if (servletInfo == null) {
078                            return null;
079                    }
080    
081                    Servlet servlet = servletInfo.getServlet();
082    
083                    if (_DIRECT_SERVLET_CONTEXT_RELOAD) {
084                            long lastModified = _getFileLastModified(path, servlet);
085    
086                            if ((lastModified == 0) ||
087                                    (lastModified != servletInfo.getLastModified())) {
088    
089                                    _servletInfos.remove(path);
090    
091                                    servlet = null;
092    
093                                    if (_log.isDebugEnabled()) {
094                                            _log.debug("Reload " + path);
095                                    }
096                            }
097                            else {
098                                    servlet = _reloadDependents(path, servlet, servletInfo);
099                            }
100                    }
101    
102                    return servlet;
103            }
104    
105            private void _putServlet(String path, Servlet servlet) {
106                    if (_servletInfos.containsKey(path)) {
107                            return;
108                    }
109    
110                    long lastModified = 1;
111    
112                    if (_DIRECT_SERVLET_CONTEXT_RELOAD) {
113                            lastModified = _getFileLastModified(path, servlet);
114                    }
115    
116                    if (lastModified > 0) {
117                            ServletInfo servletInfo = new ServletInfo();
118    
119                            servletInfo.setLastModified(lastModified);
120                            servletInfo.setServlet(servlet);
121    
122                            _servletInfos.put(path, servletInfo);
123                    }
124            }
125    
126            private Servlet _reloadDependents(
127                    String path, Servlet servlet, ServletInfo servletInfo) {
128    
129                    try {
130                            if (!_reloadDependents) {
131                                    return servlet;
132                            }
133    
134                            Method method = ReflectionUtil.getDeclaredMethod(
135                                    servlet.getClass(), "getDependants");
136    
137                            Collection<String> dependants = null;
138    
139                            String jasperVersion = JasperVersionDetector.getJasperVersion();
140    
141                            if (jasperVersion.contains("7.0")) {
142                                    Map<String, ?> dependantsMap = (Map<String, ?>)method.invoke(
143                                            servlet);
144    
145                                    if (dependantsMap != null) {
146                                            dependants = dependantsMap.keySet();
147                                    }
148                            }
149                            else {
150                                    dependants = (List<String>)method.invoke(servlet);
151                            }
152    
153                            if (dependants == null) {
154                                    return servlet;
155                            }
156    
157                            boolean reloadServlet = false;
158    
159                            for (String dependant : dependants) {
160                                    long lastModified = _getFileLastModified(dependant, servlet);
161    
162                                    Long previousLastModified = _dependantTimestamps.get(dependant);
163    
164                                    if (previousLastModified == null) {
165                                            previousLastModified = lastModified;
166                                    }
167    
168                                    if ((lastModified == 0) ||
169                                            (lastModified != previousLastModified.longValue())) {
170    
171                                            reloadServlet = true;
172    
173                                            _dependantTimestamps.put(dependant, lastModified);
174    
175                                            if (_log.isDebugEnabled()) {
176                                                    _log.debug("Reload dependent " + dependant);
177                                            }
178                                    }
179                            }
180    
181                            if (reloadServlet) {
182                                    _servletInfos.remove(path);
183    
184                                    servlet = null;
185                            }
186                    }
187                    catch (NoSuchMethodException nsme) {
188                            if (_log.isWarnEnabled()) {
189                                    _log.warn(
190                                            "Reloading of dependant JSP is disabled because your " +
191                                                    "Servlet container is not a variant of Jasper");
192                            }
193    
194                            _reloadDependents = false;
195                    }
196                    catch (Exception e) {
197                            _log.error(e, e);
198                    }
199    
200                    return servlet;
201            }
202    
203            private static final boolean _DIRECT_SERVLET_CONTEXT_RELOAD =
204                    GetterUtil.getBoolean(
205                            PropsUtil.get(PropsKeys.DIRECT_SERVLET_CONTEXT_RELOAD));
206    
207            private static Log _log = LogFactoryUtil.getLog(
208                    DirectServletRegistry.class);
209    
210            private static DirectServletRegistry _instance =
211                    new DirectServletRegistry();
212    
213            private static boolean _reloadDependents = true;
214    
215            private Map<String, Long> _dependantTimestamps =
216                    new ConcurrentHashMap<String, Long>();
217            private Map<String, ServletInfo> _servletInfos =
218                    new ConcurrentHashMap<String, ServletInfo>();
219    
220            private class ServletInfo {
221    
222                    public long getLastModified() {
223                            return _lastModified;
224                    }
225    
226                    public Servlet getServlet() {
227                            return _servlet;
228                    }
229    
230                    public void setLastModified(long lastModified) {
231                            _lastModified = lastModified;
232                    }
233    
234                    public void setServlet(Servlet servlet) {
235                            _servlet = servlet;
236                    }
237    
238                    private long _lastModified;
239                    private Servlet _servlet;
240    
241            }
242    
243    }