1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.kernel.servlet;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.util.FileUtil;
28  import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
29  import com.liferay.portal.kernel.util.ServerDetector;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.util.StringUtil;
32  
33  import java.io.File;
34  import java.io.IOException;
35  
36  import java.util.HashSet;
37  import java.util.Set;
38  import java.util.jar.JarEntry;
39  import java.util.jar.JarInputStream;
40  
41  import javax.servlet.ServletContext;
42  
43  /**
44   * <a href="ServletContextUtil.java.html"><b><i>View Source</i></b></a>
45   *
46   * @author Brian Wing Shun Chan
47   */
48  public class ServletContextUtil {
49  
50      public static final String LOG_INFO_PREFIX =
51          "Please configure Tomcat to unpack WARs to enable ";
52  
53      public static final String LOG_INFO_LAST_MODIFIED =
54          LOG_INFO_PREFIX + "retrieval of the most recent last modified date " +
55              "of a WAR for best performance";
56  
57      public static final String LOG_INFO_SPRITES =
58          LOG_INFO_PREFIX + "enable sprites for best performance";
59  
60      public static Set<String> getClassNames(ServletContext servletContext)
61          throws IOException {
62  
63          Set<String> classNames = new HashSet<String>();
64  
65          _getClassNames(servletContext, "/WEB-INF/classes", classNames);
66          _getClassNames(servletContext, "/WEB-INF/lib", classNames);
67  
68          return classNames;
69      }
70  
71      public static long getLastModified(ServletContext servletContext) {
72          return getLastModified(servletContext, StringPool.SLASH);
73      }
74  
75      public static long getLastModified(
76          ServletContext servletContext, String resourcePath) {
77  
78          return getLastModified(servletContext, resourcePath, false);
79      }
80  
81      public static long getLastModified(
82          ServletContext servletContext, String resourcePath, boolean cache) {
83  
84          if (cache) {
85              Long lastModified = (Long)servletContext.getAttribute(
86                  ServletContextUtil.class.getName() + StringPool.PERIOD +
87                      resourcePath);
88  
89              if (lastModified != null) {
90                  return lastModified.longValue();
91              }
92          }
93  
94          long lastModified = 0;
95  
96          Set<String> resourcePaths = servletContext.getResourcePaths(
97              resourcePath);
98  
99          if (resourcePaths != null) {
100             for (String curResourcePath : resourcePaths) {
101                 if (curResourcePath.endsWith(StringPool.SLASH)) {
102                     long curLastModified = getLastModified(
103                         servletContext, curResourcePath);
104 
105                     if (curLastModified > lastModified) {
106                         lastModified = curLastModified;
107                     }
108                 }
109                 else {
110                     String realPath = getRealPath(
111                         servletContext, curResourcePath);
112 
113                     if (realPath == null) {
114                         if (ServerDetector.isTomcat()) {
115                             if (_log.isInfoEnabled()) {
116                                 _log.info(LOG_INFO_LAST_MODIFIED);
117                             }
118                         }
119                         else {
120                             _log.error(
121                                 "Real path for " + curResourcePath +
122                                     " is null");
123                         }
124 
125                         continue;
126                     }
127 
128                     File file = new File(realPath);
129 
130                     if (file.lastModified() > lastModified) {
131                         lastModified = file.lastModified();
132                     }
133                 }
134             }
135         }
136 
137         if (cache) {
138             servletContext.setAttribute(
139                 ServletContextUtil.class.getName() + StringPool.PERIOD +
140                     resourcePath,
141                 new Long(lastModified));
142         }
143 
144         return lastModified;
145     }
146 
147     public static String getRealPath(
148         ServletContext servletContext, String path) {
149 
150         String realPath = servletContext.getRealPath(path);
151 
152         if ((realPath == null) && ServerDetector.isWebLogic()) {
153             String rootDir = getRootDir(servletContext);
154 
155             if (path.startsWith(StringPool.SLASH)) {
156                 realPath = rootDir + path.substring(1);
157             }
158             else {
159                 realPath = rootDir + path;
160             }
161 
162             if (!FileUtil.exists(realPath)) {
163                 realPath = null;
164             }
165         }
166 
167         return realPath;
168     }
169 
170     protected static String getRootDir(ServletContext servletContext) {
171         String key = ServletContextUtil.class.getName() + ".rootDir";
172 
173         String rootDir = (String)servletContext.getAttribute(key);
174 
175         if (rootDir == null) {
176             ClassLoader classLoader = (ClassLoader)servletContext.getAttribute(
177                 PortletServlet.PORTLET_CLASS_LOADER);
178 
179             if (classLoader == null) {
180                 classLoader = PortalClassLoaderUtil.getClassLoader();
181             }
182 
183             rootDir = WebDirDetector.getRootDir(classLoader);
184 
185             servletContext.setAttribute(key, rootDir);
186         }
187 
188         return rootDir;
189     }
190 
191     private static String _getClassName(String path) {
192         return _getClassName(null, path);
193     }
194 
195     private static String _getClassName(String rootResourcePath, String path) {
196         String className = path.substring(
197             0, path.length() - _EXT_CLASS.length());
198 
199         if (rootResourcePath != null) {
200             className = className.substring(rootResourcePath.length() + 1);
201         }
202 
203         className = StringUtil.replace(
204             className, StringPool.SLASH, StringPool.PERIOD);
205 
206         return className;
207     }
208 
209     private static void _getClassNames(
210             ServletContext servletContext, String rootResourcePath,
211             Set<String> classNames)
212         throws IOException {
213 
214         _getClassNames(
215             servletContext, rootResourcePath,
216             servletContext.getResourcePaths(rootResourcePath), classNames);
217     }
218 
219     private static void _getClassNames(
220             ServletContext servletContext, String rootResourcePath,
221             Set<String> resourcePaths, Set<String> classNames)
222         throws IOException {
223 
224         if (resourcePaths == null) {
225             return;
226         }
227 
228         for (String resourcePath : resourcePaths) {
229             if (resourcePath.endsWith(_EXT_CLASS)) {
230                 String className = _getClassName(
231                     rootResourcePath, resourcePath);
232 
233                 classNames.add(className);
234             }
235             else if (resourcePath.endsWith(_EXT_JAR)) {
236                 JarInputStream jarFile = new JarInputStream(
237                     servletContext.getResourceAsStream(resourcePath));
238 
239                 while (true) {
240                     JarEntry jarEntry = jarFile.getNextJarEntry();
241 
242                     if (jarEntry == null) {
243                         break;
244                     }
245 
246                     String jarEntryName = jarEntry.getName();
247 
248                     if (jarEntryName.endsWith(_EXT_CLASS)) {
249                         String className = _getClassName(jarEntryName);
250 
251                         classNames.add(className);
252                     }
253                 }
254 
255             }
256             else if (resourcePath.endsWith(StringPool.SLASH)) {
257                 _getClassNames(
258                     servletContext, rootResourcePath,
259                     servletContext.getResourcePaths(resourcePath), classNames);
260             }
261         }
262     }
263 
264     private static final String _EXT_CLASS = ".class";
265 
266     private static final String _EXT_JAR = ".jar";
267 
268     private static Log _log = LogFactoryUtil.getLog(ServletContextUtil.class);
269 
270 }