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