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