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.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 path) {
066    
067                    return getLastModified(servletContext, path, false);
068            }
069    
070            public static long getLastModified(
071                    ServletContext servletContext, String path, boolean cache) {
072    
073                    if (cache) {
074                            Long lastModified = (Long)servletContext.getAttribute(
075                                    ServletContextUtil.class.getName() + StringPool.PERIOD +
076                                            path);
077    
078                            if (lastModified != null) {
079                                    return lastModified.longValue();
080                            }
081                    }
082    
083                    long lastModified = 0;
084    
085                    Set<String> paths = null;
086    
087                    if (path.endsWith(StringPool.SLASH)) {
088                            paths = servletContext.getResourcePaths(path);
089                    }
090                    else {
091                            paths = new HashSet<String>();
092    
093                            paths.add(path);
094                    }
095    
096                    if ((paths == null) || paths.isEmpty()) {
097                            if (cache) {
098                                    servletContext.setAttribute(
099                                            ServletContextUtil.class.getName() + StringPool.PERIOD +
100                                                    path,
101                                            new Long(lastModified));
102                            }
103    
104                            return lastModified;
105                    }
106    
107                    for (String curPath : paths) {
108                            if (curPath.endsWith(StringPool.SLASH)) {
109                                    long curLastModified = getLastModified(servletContext, curPath);
110    
111                                    if (curLastModified > lastModified) {
112                                            lastModified = curLastModified;
113                                    }
114                            }
115                            else {
116                                    try {
117                                            URL url = servletContext.getResource(curPath);
118    
119                                            if (url == null) {
120                                                    _log.error("Resource URL for " + curPath + " is null");
121    
122                                                    continue;
123                                            }
124    
125                                            URLConnection urlConnection = url.openConnection();
126    
127                                            if (urlConnection.getLastModified() > lastModified) {
128                                                    lastModified = urlConnection.getLastModified();
129                                            }
130                                    }
131                                    catch (IOException ioe) {
132                                            _log.error(ioe, ioe);
133                                    }
134                            }
135                    }
136    
137                    if (cache) {
138                            servletContext.setAttribute(
139                                    ServletContextUtil.class.getName() + StringPool.PERIOD +
140                                            path,
141                                    new Long(lastModified));
142                    }
143    
144                    return lastModified;
145            }
146    
147            public static String getResourcePath(URL url) throws URISyntaxException {
148                    URI uri = getResourceURI(url);
149    
150                    return uri.toString();
151            }
152    
153            public static URI getResourceURI(URL url) throws URISyntaxException {
154                    return _getResourceURI(url, url.getPath());
155            }
156    
157            public static String getRootPath(ServletContext servletContext)
158                    throws MalformedURLException {
159    
160                    URI rootURI = getRootURI(servletContext);
161    
162                    return rootURI.toString();
163            }
164    
165            public static URI getRootURI(ServletContext servletContext)
166                    throws MalformedURLException {
167    
168                    URI rootURI = (URI)servletContext.getAttribute(URI_ATTRIBUTE);
169    
170                    if (rootURI != null) {
171                            return rootURI;
172                    }
173    
174                    try {
175                            URL rootURL = servletContext.getResource(PATH_WEB_XML);
176    
177                            String path = rootURL.getPath();
178    
179                            int index = path.indexOf(PATH_WEB_XML);
180    
181                            if (index < 0) {
182                                    throw new MalformedURLException("Invalid URL " + rootURL);
183                            }
184    
185                            if (index == 0) {
186                                    path = StringPool.SLASH;
187                            }
188                            else {
189                                    path = path.substring(0, index);
190                            }
191    
192                            rootURI = _getResourceURI(rootURL, path);
193    
194                            servletContext.setAttribute(URI_ATTRIBUTE, rootURI);
195                    }
196                    catch (URISyntaxException urise) {
197                            throw new MalformedURLException(urise.getMessage());
198                    }
199    
200                    return rootURI;
201            }
202    
203            private static String _getClassName(String path) {
204                    return _getClassName(null, path);
205            }
206    
207            private static String _getClassName(String rootPath, String path) {
208                    String className = path.substring(
209                            0, path.length() - _EXT_CLASS.length());
210    
211                    if (rootPath != null) {
212                            className = className.substring(rootPath.length() + 1);
213                    }
214    
215                    className = StringUtil.replace(
216                            className, CharPool.SLASH, CharPool.PERIOD);
217    
218                    return className;
219            }
220    
221            private static void _getClassNames(
222                            ServletContext servletContext, String rootPath,
223                            Set<String> classNames)
224                    throws IOException {
225    
226                    _getClassNames(
227                            servletContext, rootPath, servletContext.getResourcePaths(rootPath),
228                            classNames);
229            }
230    
231            private static void _getClassNames(
232                            ServletContext servletContext, String rootPath, Set<String> paths,
233                            Set<String> classNames)
234                    throws IOException {
235    
236                    if (paths == null) {
237                            return;
238                    }
239    
240                    for (String path : paths) {
241                            if (path.endsWith(_EXT_CLASS)) {
242                                    String className = _getClassName(rootPath, path);
243    
244                                    classNames.add(className);
245                            }
246                            else if (path.endsWith(_EXT_JAR)) {
247                                    JarInputStream jarFile = new JarInputStream(
248                                            servletContext.getResourceAsStream(path));
249    
250                                    while (true) {
251                                            JarEntry jarEntry = jarFile.getNextJarEntry();
252    
253                                            if (jarEntry == null) {
254                                                    break;
255                                            }
256    
257                                            String jarEntryName = jarEntry.getName();
258    
259                                            if (jarEntryName.endsWith(_EXT_CLASS)) {
260                                                    String className = _getClassName(jarEntryName);
261    
262                                                    classNames.add(className);
263                                            }
264                                    }
265    
266                                    jarFile.close();
267    
268                            }
269                            else if (path.endsWith(StringPool.SLASH)) {
270                                    _getClassNames(
271                                            servletContext, rootPath,
272                                            servletContext.getResourcePaths(path), classNames);
273                            }
274                    }
275            }
276    
277            private static URI _getResourceURI(URL url, String path)
278                    throws URISyntaxException {
279    
280                    return new URI(url.getProtocol(), path, null);
281            }
282    
283            private static final String _EXT_CLASS = ".class";
284    
285            private static final String _EXT_JAR = ".jar";
286    
287            private static Log _log = LogFactoryUtil.getLog(ServletContextUtil.class);
288    
289    }