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.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.CharPool;
020    import com.liferay.portal.kernel.util.FileUtil;
021    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
022    import com.liferay.portal.kernel.util.ServerDetector;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.StringUtil;
025    
026    import java.io.File;
027    import java.io.IOException;
028    
029    import java.util.HashSet;
030    import java.util.Set;
031    import java.util.jar.JarEntry;
032    import java.util.jar.JarInputStream;
033    
034    import javax.servlet.ServletContext;
035    
036    /**
037     * @author Brian Wing Shun Chan
038     */
039    public class ServletContextUtil {
040    
041            public static final String LOG_INFO_LAST_MODIFIED =
042                    ServletContextUtil.LOG_INFO_PREFIX + "retrieval of the most recent " +
043                            "last modified date of a WAR for best performance";
044    
045            public static final String LOG_INFO_PREFIX =
046                    "Please configure Tomcat to unpack WARs to enable ";
047    
048            public static final String LOG_INFO_SPRITES =
049                    LOG_INFO_PREFIX + "enable sprites for best performance";
050    
051            public static Set<String> getClassNames(ServletContext servletContext)
052                    throws IOException {
053    
054                    Set<String> classNames = new HashSet<String>();
055    
056                    _getClassNames(servletContext, "/WEB-INF/classes", classNames);
057                    _getClassNames(servletContext, "/WEB-INF/lib", classNames);
058    
059                    return classNames;
060            }
061    
062            public static long getLastModified(ServletContext servletContext) {
063                    return getLastModified(servletContext, StringPool.SLASH);
064            }
065    
066            public static long getLastModified(
067                    ServletContext servletContext, String resourcePath) {
068    
069                    return getLastModified(servletContext, resourcePath, false);
070            }
071    
072            public static long getLastModified(
073                    ServletContext servletContext, String resourcePath, boolean cache) {
074    
075                    if (cache) {
076                            Long lastModified = (Long)servletContext.getAttribute(
077                                    ServletContextUtil.class.getName() + StringPool.PERIOD +
078                                            resourcePath);
079    
080                            if (lastModified != null) {
081                                    return lastModified.longValue();
082                            }
083                    }
084    
085                    long lastModified = 0;
086    
087                    Set<String> resourcePaths = servletContext.getResourcePaths(
088                            resourcePath);
089    
090                    if (resourcePaths != null) {
091                            for (String curResourcePath : resourcePaths) {
092                                    if (curResourcePath.endsWith(StringPool.SLASH)) {
093                                            long curLastModified = getLastModified(
094                                                    servletContext, curResourcePath);
095    
096                                            if (curLastModified > lastModified) {
097                                                    lastModified = curLastModified;
098                                            }
099                                    }
100                                    else {
101                                            String realPath = getRealPath(
102                                                    servletContext, curResourcePath);
103    
104                                            if (realPath == null) {
105                                                    if (ServerDetector.isTomcat()) {
106                                                            if (_log.isInfoEnabled()) {
107                                                                    _log.info(LOG_INFO_LAST_MODIFIED);
108                                                            }
109                                                    }
110                                                    else {
111                                                            _log.error(
112                                                                    "Real path for " + curResourcePath +
113                                                                            " is null");
114                                                    }
115    
116                                                    continue;
117                                            }
118    
119                                            File file = new File(realPath);
120    
121                                            if (file.lastModified() > lastModified) {
122                                                    lastModified = file.lastModified();
123                                            }
124                                    }
125                            }
126                    }
127    
128                    if (cache) {
129                            servletContext.setAttribute(
130                                    ServletContextUtil.class.getName() + StringPool.PERIOD +
131                                            resourcePath,
132                                    new Long(lastModified));
133                    }
134    
135                    return lastModified;
136            }
137    
138            public static String getRealPath(
139                    ServletContext servletContext, String path) {
140    
141                    String realPath = servletContext.getRealPath(path);
142    
143                    if ((realPath == null) && ServerDetector.isWebLogic()) {
144                            String rootDir = getRootDir(servletContext);
145    
146                            if (path.startsWith(StringPool.SLASH)) {
147                                    realPath = rootDir + path.substring(1);
148                            }
149                            else {
150                                    realPath = rootDir + path;
151                            }
152    
153                            if (!FileUtil.exists(realPath)) {
154                                    realPath = null;
155                            }
156                    }
157    
158                    return realPath;
159            }
160    
161            protected static String getRootDir(ServletContext servletContext) {
162                    String key = ServletContextUtil.class.getName() + ".rootDir";
163    
164                    String rootDir = (String)servletContext.getAttribute(key);
165    
166                    if (rootDir == null) {
167                            ClassLoader classLoader = (ClassLoader)servletContext.getAttribute(
168                                    PluginContextListener.PLUGIN_CLASS_LOADER);
169    
170                            if (classLoader == null) {
171                                    classLoader = PortalClassLoaderUtil.getClassLoader();
172                            }
173    
174                            rootDir = WebDirDetector.getRootDir(classLoader);
175    
176                            servletContext.setAttribute(key, rootDir);
177                    }
178    
179                    return rootDir;
180            }
181    
182            private static String _getClassName(String path) {
183                    return _getClassName(null, path);
184            }
185    
186            private static String _getClassName(String rootResourcePath, String path) {
187                    String className = path.substring(
188                            0, path.length() - _EXT_CLASS.length());
189    
190                    if (rootResourcePath != null) {
191                            className = className.substring(rootResourcePath.length() + 1);
192                    }
193    
194                    className = StringUtil.replace(
195                            className, CharPool.SLASH, CharPool.PERIOD);
196    
197                    return className;
198            }
199    
200            private static void _getClassNames(
201                            ServletContext servletContext, String rootResourcePath,
202                            Set<String> classNames)
203                    throws IOException {
204    
205                    _getClassNames(
206                            servletContext, rootResourcePath,
207                            servletContext.getResourcePaths(rootResourcePath), classNames);
208            }
209    
210            private static void _getClassNames(
211                            ServletContext servletContext, String rootResourcePath,
212                            Set<String> resourcePaths, Set<String> classNames)
213                    throws IOException {
214    
215                    if (resourcePaths == null) {
216                            return;
217                    }
218    
219                    for (String resourcePath : resourcePaths) {
220                            if (resourcePath.endsWith(_EXT_CLASS)) {
221                                    String className = _getClassName(
222                                            rootResourcePath, resourcePath);
223    
224                                    classNames.add(className);
225                            }
226                            else if (resourcePath.endsWith(_EXT_JAR)) {
227                                    JarInputStream jarFile = new JarInputStream(
228                                            servletContext.getResourceAsStream(resourcePath));
229    
230                                    while (true) {
231                                            JarEntry jarEntry = jarFile.getNextJarEntry();
232    
233                                            if (jarEntry == null) {
234                                                    break;
235                                            }
236    
237                                            String jarEntryName = jarEntry.getName();
238    
239                                            if (jarEntryName.endsWith(_EXT_CLASS)) {
240                                                    String className = _getClassName(jarEntryName);
241    
242                                                    classNames.add(className);
243                                            }
244                                    }
245    
246                                    jarFile.close();
247    
248                            }
249                            else if (resourcePath.endsWith(StringPool.SLASH)) {
250                                    _getClassNames(
251                                            servletContext, rootResourcePath,
252                                            servletContext.getResourcePaths(resourcePath), classNames);
253                            }
254                    }
255            }
256    
257            private static final String _EXT_CLASS = ".class";
258    
259            private static final String _EXT_JAR = ".jar";
260    
261            private static Log _log = LogFactoryUtil.getLog(ServletContextUtil.class);
262    
263    }