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   */
49  public class ServletContextUtil {
50  
51      public static final String LOG_INFO_PREFIX =
52          "Please configure Tomcat to unpack WARs to enable ";
53  
54      public static final String LOG_INFO_LAST_MODIFIED =
55          LOG_INFO_PREFIX + "retrieval of the most recent last modified date " +
56              "of a WAR for best performance";
57  
58      public static final String LOG_INFO_SPRITES =
59          LOG_INFO_PREFIX + "enable sprites for best performance";
60  
61      public static Set<String> getClassNames(ServletContext servletContext)
62          throws IOException {
63  
64          Set<String> classNames = new HashSet<String>();
65  
66          _getClassNames(servletContext, "/WEB-INF/classes", classNames);
67          _getClassNames(servletContext, "/WEB-INF/lib", classNames);
68  
69          return classNames;
70      }
71  
72      public static long getLastModified(ServletContext servletContext) {
73          return getLastModified(servletContext, StringPool.SLASH);
74      }
75  
76      public static long getLastModified(
77          ServletContext servletContext, String resourcePath) {
78  
79          return getLastModified(servletContext, resourcePath, false);
80      }
81  
82      public static long getLastModified(
83          ServletContext servletContext, String resourcePath, boolean cache) {
84  
85          if (cache) {
86              Long lastModified = (Long)servletContext.getAttribute(
87                  ServletContextUtil.class.getName() + StringPool.PERIOD +
88                      resourcePath);
89  
90              if (lastModified != null) {
91                  return lastModified.longValue();
92              }
93          }
94  
95          long lastModified = 0;
96  
97          Set<String> resourcePaths = servletContext.getResourcePaths(
98              resourcePath);
99  
100         if (resourcePaths != null) {
101             for (String curResourcePath : resourcePaths) {
102                 if (curResourcePath.endsWith(StringPool.SLASH)) {
103                     long curLastModified = getLastModified(
104                         servletContext, curResourcePath);
105 
106                     if (curLastModified > lastModified) {
107                         lastModified = curLastModified;
108                     }
109                 }
110                 else {
111                     String realPath = getRealPath(
112                         servletContext, curResourcePath);
113 
114                     if (realPath == null) {
115                         if (ServerDetector.isTomcat()) {
116                             if (_log.isInfoEnabled()) {
117                                 _log.info(LOG_INFO_LAST_MODIFIED);
118                             }
119                         }
120                         else {
121                             _log.error(
122                                 "Real path for " + curResourcePath +
123                                     " is null");
124                         }
125 
126                         continue;
127                     }
128 
129                     File file = new File(realPath);
130 
131                     if (file.lastModified() > lastModified) {
132                         lastModified = file.lastModified();
133                     }
134                 }
135             }
136         }
137 
138         if (cache) {
139             servletContext.setAttribute(
140                 ServletContextUtil.class.getName() + StringPool.PERIOD +
141                     resourcePath,
142                 new Long(lastModified));
143         }
144 
145         return lastModified;
146     }
147 
148     public static String getRealPath(
149         ServletContext servletContext, String path) {
150 
151         String realPath = servletContext.getRealPath(path);
152 
153         if ((realPath == null) && ServerDetector.isWebLogic()) {
154             String rootDir = getRootDir(servletContext);
155 
156             if (path.startsWith(StringPool.SLASH)) {
157                 realPath = rootDir + path.substring(1);
158             }
159             else {
160                 realPath = rootDir + path;
161             }
162 
163             if (!FileUtil.exists(realPath)) {
164                 realPath = null;
165             }
166         }
167 
168         return realPath;
169     }
170 
171     protected static String getRootDir(ServletContext servletContext) {
172         String key = ServletContextUtil.class.getName() + ".rootDir";
173 
174         String rootDir = (String)servletContext.getAttribute(key);
175 
176         if (rootDir == null) {
177             ClassLoader classLoader = (ClassLoader)servletContext.getAttribute(
178                 PortletServlet.PORTLET_CLASS_LOADER);
179 
180             if (classLoader == null) {
181                 classLoader = PortalClassLoaderUtil.getClassLoader();
182             }
183 
184             rootDir = WebDirDetector.getRootDir(classLoader);
185 
186             servletContext.setAttribute(key, rootDir);
187         }
188 
189         return rootDir;
190     }
191 
192     private static String _getClassName(String path) {
193         return _getClassName(null, path);
194     }
195 
196     private static String _getClassName(String rootResourcePath, String path) {
197         String className = path.substring(
198             0, path.length() - _EXT_CLASS.length());
199 
200         if (rootResourcePath != null) {
201             className = className.substring(rootResourcePath.length() + 1);
202         }
203 
204         className = StringUtil.replace(
205             className, StringPool.SLASH, StringPool.PERIOD);
206 
207         return className;
208     }
209 
210     private static void _getClassNames(
211             ServletContext servletContext, String rootResourcePath,
212             Set<String> classNames)
213         throws IOException {
214 
215         _getClassNames(
216             servletContext, rootResourcePath,
217             servletContext.getResourcePaths(rootResourcePath), classNames);
218     }
219 
220     private static void _getClassNames(
221             ServletContext servletContext, String rootResourcePath,
222             Set<String> resourcePaths, Set<String> classNames)
223         throws IOException {
224 
225         if (resourcePaths == null) {
226             return;
227         }
228 
229         for (String resourcePath : resourcePaths) {
230             if (resourcePath.endsWith(_EXT_CLASS)) {
231                 String className = _getClassName(
232                     rootResourcePath, resourcePath);
233 
234                 classNames.add(className);
235             }
236             else if (resourcePath.endsWith(_EXT_JAR)) {
237                 JarInputStream jarFile = new JarInputStream(
238                     servletContext.getResourceAsStream(resourcePath));
239 
240                 while (true) {
241                     JarEntry jarEntry = jarFile.getNextJarEntry();
242 
243                     if (jarEntry == null) {
244                         break;
245                     }
246 
247                     String jarEntryName = jarEntry.getName();
248 
249                     if (jarEntryName.endsWith(_EXT_CLASS)) {
250                         String className = _getClassName(jarEntryName);
251 
252                         classNames.add(className);
253                     }
254                 }
255 
256             }
257             else if (resourcePath.endsWith(StringPool.SLASH)) {
258                 _getClassNames(
259                     servletContext, rootResourcePath,
260                     servletContext.getResourcePaths(resourcePath), classNames);
261             }
262         }
263     }
264 
265     private static final String _EXT_CLASS = ".class";
266 
267     private static final String _EXT_JAR = ".jar";
268 
269     private static Log _log = LogFactoryUtil.getLog(ServletContextUtil.class);
270 
271 }