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