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