1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.kernel.servlet;
16  
17  import com.liferay.portal.kernel.log.Log;
18  import com.liferay.portal.kernel.log.LogFactoryUtil;
19  import com.liferay.portal.kernel.util.FileUtil;
20  import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
21  import com.liferay.portal.kernel.util.ServerDetector;
22  import com.liferay.portal.kernel.util.StringPool;
23  import com.liferay.portal.kernel.util.StringUtil;
24  
25  import java.io.File;
26  import java.io.IOException;
27  
28  import java.util.HashSet;
29  import java.util.Set;
30  import java.util.jar.JarEntry;
31  import java.util.jar.JarInputStream;
32  
33  import javax.servlet.ServletContext;
34  
35  /**
36   * <a href="ServletContextUtil.java.html"><b><i>View Source</i></b></a>
37   *
38   * @author Brian Wing Shun Chan
39   */
40  public class ServletContextUtil {
41  
42      public static final String LOG_INFO_PREFIX =
43          "Please configure Tomcat to unpack WARs to enable ";
44  
45      public static final String LOG_INFO_LAST_MODIFIED =
46          LOG_INFO_PREFIX + "retrieval of the most recent last modified date " +
47              "of a WAR for best performance";
48  
49      public static final String LOG_INFO_SPRITES =
50          LOG_INFO_PREFIX + "enable sprites for best performance";
51  
52      public static Set<String> getClassNames(ServletContext servletContext)
53          throws IOException {
54  
55          Set<String> classNames = new HashSet<String>();
56  
57          _getClassNames(servletContext, "/WEB-INF/classes", classNames);
58          _getClassNames(servletContext, "/WEB-INF/lib", classNames);
59  
60          return classNames;
61      }
62  
63      public static long getLastModified(ServletContext servletContext) {
64          return getLastModified(servletContext, StringPool.SLASH);
65      }
66  
67      public static long getLastModified(
68          ServletContext servletContext, String resourcePath) {
69  
70          return getLastModified(servletContext, resourcePath, false);
71      }
72  
73      public static long getLastModified(
74          ServletContext servletContext, String resourcePath, boolean cache) {
75  
76          if (cache) {
77              Long lastModified = (Long)servletContext.getAttribute(
78                  ServletContextUtil.class.getName() + StringPool.PERIOD +
79                      resourcePath);
80  
81              if (lastModified != null) {
82                  return lastModified.longValue();
83              }
84          }
85  
86          long lastModified = 0;
87  
88          Set<String> resourcePaths = servletContext.getResourcePaths(
89              resourcePath);
90  
91          if (resourcePaths != null) {
92              for (String curResourcePath : resourcePaths) {
93                  if (curResourcePath.endsWith(StringPool.SLASH)) {
94                      long curLastModified = getLastModified(
95                          servletContext, curResourcePath);
96  
97                      if (curLastModified > lastModified) {
98                          lastModified = curLastModified;
99                      }
100                 }
101                 else {
102                     String realPath = getRealPath(
103                         servletContext, curResourcePath);
104 
105                     if (realPath == null) {
106                         if (ServerDetector.isTomcat()) {
107                             if (_log.isInfoEnabled()) {
108                                 _log.info(LOG_INFO_LAST_MODIFIED);
109                             }
110                         }
111                         else {
112                             _log.error(
113                                 "Real path for " + curResourcePath +
114                                     " is null");
115                         }
116 
117                         continue;
118                     }
119 
120                     File file = new File(realPath);
121 
122                     if (file.lastModified() > lastModified) {
123                         lastModified = file.lastModified();
124                     }
125                 }
126             }
127         }
128 
129         if (cache) {
130             servletContext.setAttribute(
131                 ServletContextUtil.class.getName() + StringPool.PERIOD +
132                     resourcePath,
133                 new Long(lastModified));
134         }
135 
136         return lastModified;
137     }
138 
139     public static String getRealPath(
140         ServletContext servletContext, String path) {
141 
142         String realPath = servletContext.getRealPath(path);
143 
144         if ((realPath == null) && ServerDetector.isWebLogic()) {
145             String rootDir = getRootDir(servletContext);
146 
147             if (path.startsWith(StringPool.SLASH)) {
148                 realPath = rootDir + path.substring(1);
149             }
150             else {
151                 realPath = rootDir + path;
152             }
153 
154             if (!FileUtil.exists(realPath)) {
155                 realPath = null;
156             }
157         }
158 
159         return realPath;
160     }
161 
162     protected static String getRootDir(ServletContext servletContext) {
163         String key = ServletContextUtil.class.getName() + ".rootDir";
164 
165         String rootDir = (String)servletContext.getAttribute(key);
166 
167         if (rootDir == null) {
168             ClassLoader classLoader = (ClassLoader)servletContext.getAttribute(
169                 PortletServlet.PORTLET_CLASS_LOADER);
170 
171             if (classLoader == null) {
172                 classLoader = PortalClassLoaderUtil.getClassLoader();
173             }
174 
175             rootDir = WebDirDetector.getRootDir(classLoader);
176 
177             servletContext.setAttribute(key, rootDir);
178         }
179 
180         return rootDir;
181     }
182 
183     private static String _getClassName(String path) {
184         return _getClassName(null, path);
185     }
186 
187     private static String _getClassName(String rootResourcePath, String path) {
188         String className = path.substring(
189             0, path.length() - _EXT_CLASS.length());
190 
191         if (rootResourcePath != null) {
192             className = className.substring(rootResourcePath.length() + 1);
193         }
194 
195         className = StringUtil.replace(
196             className, StringPool.SLASH, StringPool.PERIOD);
197 
198         return className;
199     }
200 
201     private static void _getClassNames(
202             ServletContext servletContext, String rootResourcePath,
203             Set<String> classNames)
204         throws IOException {
205 
206         _getClassNames(
207             servletContext, rootResourcePath,
208             servletContext.getResourcePaths(rootResourcePath), classNames);
209     }
210 
211     private static void _getClassNames(
212             ServletContext servletContext, String rootResourcePath,
213             Set<String> resourcePaths, Set<String> classNames)
214         throws IOException {
215 
216         if (resourcePaths == null) {
217             return;
218         }
219 
220         for (String resourcePath : resourcePaths) {
221             if (resourcePath.endsWith(_EXT_CLASS)) {
222                 String className = _getClassName(
223                     rootResourcePath, resourcePath);
224 
225                 classNames.add(className);
226             }
227             else if (resourcePath.endsWith(_EXT_JAR)) {
228                 JarInputStream jarFile = new JarInputStream(
229                     servletContext.getResourceAsStream(resourcePath));
230 
231                 while (true) {
232                     JarEntry jarEntry = jarFile.getNextJarEntry();
233 
234                     if (jarEntry == null) {
235                         break;
236                     }
237 
238                     String jarEntryName = jarEntry.getName();
239 
240                     if (jarEntryName.endsWith(_EXT_CLASS)) {
241                         String className = _getClassName(jarEntryName);
242 
243                         classNames.add(className);
244                     }
245                 }
246 
247             }
248             else if (resourcePath.endsWith(StringPool.SLASH)) {
249                 _getClassNames(
250                     servletContext, rootResourcePath,
251                     servletContext.getResourcePaths(resourcePath), classNames);
252             }
253         }
254     }
255 
256     private static final String _EXT_CLASS = ".class";
257 
258     private static final String _EXT_JAR = ".jar";
259 
260     private static Log _log = LogFactoryUtil.getLog(ServletContextUtil.class);
261 
262 }