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