001    /**
002     * Copyright (c) 2000-2012 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.CharPool;
020    import com.liferay.portal.kernel.util.StringPool;
021    import com.liferay.portal.kernel.util.StringUtil;
022    
023    import java.io.IOException;
024    
025    import java.net.MalformedURLException;
026    import java.net.URI;
027    import java.net.URISyntaxException;
028    import java.net.URL;
029    import java.net.URLConnection;
030    
031    import java.util.HashSet;
032    import java.util.Set;
033    import java.util.jar.JarEntry;
034    import java.util.jar.JarInputStream;
035    
036    import javax.servlet.ServletContext;
037    
038    /**
039     * @author Brian Wing Shun Chan
040     * @author Raymond Augé
041     */
042    public class ServletContextUtil {
043    
044            public static final String PATH_WEB_XML = "/WEB-INF/web.xml";
045    
046            public static final String URI_ATTRIBUTE =
047                    ServletContextUtil.class.getName().concat(".rootURI");
048    
049            public static Set<String> getClassNames(ServletContext servletContext)
050                    throws IOException {
051    
052                    Set<String> classNames = new HashSet<String>();
053    
054                    _getClassNames(servletContext, "/WEB-INF/classes", classNames);
055                    _getClassNames(servletContext, "/WEB-INF/lib", classNames);
056    
057                    return classNames;
058            }
059    
060            public static long getLastModified(ServletContext servletContext) {
061                    return getLastModified(servletContext, StringPool.SLASH);
062            }
063    
064            public static long getLastModified(
065                    ServletContext servletContext, String resourcePath) {
066    
067                    return getLastModified(servletContext, resourcePath, false);
068            }
069    
070            public static long getLastModified(
071                    ServletContext servletContext, String resourcePath, boolean cache) {
072    
073                    if (cache) {
074                            Long lastModified = (Long)servletContext.getAttribute(
075                                    ServletContextUtil.class.getName() + StringPool.PERIOD +
076                                            resourcePath);
077    
078                            if (lastModified != null) {
079                                    return lastModified.longValue();
080                            }
081                    }
082    
083                    long lastModified = 0;
084    
085                    Set<String> resourcePaths = null;
086    
087                    if (resourcePath.endsWith(StringPool.SLASH)) {
088                            resourcePaths = servletContext.getResourcePaths(resourcePath);
089                    }
090                    else {
091                            resourcePaths = new HashSet<String>();
092    
093                            resourcePaths.add(resourcePath);
094                    }
095    
096                    if ((resourcePaths == null) || resourcePaths.isEmpty()) {
097                            if (cache) {
098                                    servletContext.setAttribute(
099                                            ServletContextUtil.class.getName() + StringPool.PERIOD +
100                                                    resourcePath,
101                                            new Long(lastModified));
102                            }
103    
104                            return lastModified;
105                    }
106    
107                    for (String curResourcePath : resourcePaths) {
108                            if (curResourcePath.endsWith(StringPool.SLASH)) {
109                                    long curLastModified = getLastModified(
110                                            servletContext, curResourcePath);
111    
112                                    if (curLastModified > lastModified) {
113                                            lastModified = curLastModified;
114                                    }
115                            }
116                            else {
117                                    try {
118                                            URL resourceURL = servletContext.getResource(
119                                                    curResourcePath);
120    
121                                            if (resourceURL == null) {
122                                                    _log.error(
123                                                            "Resource url for " + curResourcePath + " is null");
124    
125                                                    continue;
126                                            }
127    
128                                            URLConnection urlConnection = resourceURL.openConnection();
129    
130                                            if (urlConnection.getLastModified() > lastModified) {
131                                                    lastModified = urlConnection.getLastModified();
132                                            }
133                                    }
134                                    catch (IOException ioe) {
135                                            _log.error(ioe, ioe);
136                                    }
137                            }
138                    }
139    
140                    if (cache) {
141                            servletContext.setAttribute(
142                                    ServletContextUtil.class.getName() + StringPool.PERIOD +
143                                            resourcePath,
144                                    new Long(lastModified));
145                    }
146    
147                    return lastModified;
148            }
149    
150            public static String getRootPath(ServletContext servletContext)
151                    throws MalformedURLException {
152    
153                    URI rootURI = getRootURI(servletContext);
154    
155                    return rootURI.toString();
156            }
157    
158            public static URI getRootURI(ServletContext servletContext)
159                    throws MalformedURLException {
160    
161                    URI rootURI = (URI)servletContext.getAttribute(URI_ATTRIBUTE);
162    
163                    if (rootURI != null) {
164                            return rootURI;
165                    }
166    
167                    try {
168                            URL rootURL = servletContext.getResource(PATH_WEB_XML);
169    
170                            String path = rootURL.getPath();
171    
172                            int index = path.indexOf(PATH_WEB_XML);
173    
174                            if (index < 0) {
175                                    throw new MalformedURLException("Invalid URL " + rootURL);
176                            }
177    
178                            if (index == 0) {
179                                    path = StringPool.SLASH;
180                            }
181                            else {
182                                    path = path.substring(0, index);
183                            }
184    
185                            rootURI = new URI(rootURL.getProtocol(), path, null);
186    
187                            servletContext.setAttribute(URI_ATTRIBUTE, rootURI);
188                    }
189                    catch (URISyntaxException urise) {
190                            throw new MalformedURLException(urise.getMessage());
191                    }
192    
193                    return rootURI;
194            }
195    
196            private static String _getClassName(String path) {
197                    return _getClassName(null, path);
198            }
199    
200            private static String _getClassName(String rootResourcePath, String path) {
201                    String className = path.substring(
202                            0, path.length() - _EXT_CLASS.length());
203    
204                    if (rootResourcePath != null) {
205                            className = className.substring(rootResourcePath.length() + 1);
206                    }
207    
208                    className = StringUtil.replace(
209                            className, CharPool.SLASH, CharPool.PERIOD);
210    
211                    return className;
212            }
213    
214            private static void _getClassNames(
215                            ServletContext servletContext, String rootResourcePath,
216                            Set<String> classNames)
217                    throws IOException {
218    
219                    _getClassNames(
220                            servletContext, rootResourcePath,
221                            servletContext.getResourcePaths(rootResourcePath), classNames);
222            }
223    
224            private static void _getClassNames(
225                            ServletContext servletContext, String rootResourcePath,
226                            Set<String> resourcePaths, Set<String> classNames)
227                    throws IOException {
228    
229                    if (resourcePaths == null) {
230                            return;
231                    }
232    
233                    for (String resourcePath : resourcePaths) {
234                            if (resourcePath.endsWith(_EXT_CLASS)) {
235                                    String className = _getClassName(
236                                            rootResourcePath, resourcePath);
237    
238                                    classNames.add(className);
239                            }
240                            else if (resourcePath.endsWith(_EXT_JAR)) {
241                                    JarInputStream jarFile = new JarInputStream(
242                                            servletContext.getResourceAsStream(resourcePath));
243    
244                                    while (true) {
245                                            JarEntry jarEntry = jarFile.getNextJarEntry();
246    
247                                            if (jarEntry == null) {
248                                                    break;
249                                            }
250    
251                                            String jarEntryName = jarEntry.getName();
252    
253                                            if (jarEntryName.endsWith(_EXT_CLASS)) {
254                                                    String className = _getClassName(jarEntryName);
255    
256                                                    classNames.add(className);
257                                            }
258                                    }
259    
260                                    jarFile.close();
261    
262                            }
263                            else if (resourcePath.endsWith(StringPool.SLASH)) {
264                                    _getClassNames(
265                                            servletContext, rootResourcePath,
266                                            servletContext.getResourcePaths(resourcePath), classNames);
267                            }
268                    }
269            }
270    
271            private static final String _EXT_CLASS = ".class";
272    
273            private static final String _EXT_JAR = ".jar";
274    
275            private static Log _log = LogFactoryUtil.getLog(ServletContextUtil.class);
276    
277    }