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