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.process;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.util.CharPool;
021    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
022    import com.liferay.portal.kernel.util.ServerDetector;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.util.URLCodec;
027    
028    import java.io.File;
029    
030    import java.lang.reflect.Method;
031    
032    import java.net.MalformedURLException;
033    import java.net.URI;
034    import java.net.URL;
035    import java.net.URLClassLoader;
036    import java.net.URLConnection;
037    
038    import java.util.Arrays;
039    import java.util.LinkedHashSet;
040    import java.util.Set;
041    
042    import javax.servlet.ServletContext;
043    import javax.servlet.ServletException;
044    
045    /**
046     * @author Shuyang Zhou
047     */
048    public class ClassPathUtil {
049    
050            public static Set<URL> getClassPathURLs(ClassLoader classLoader) {
051                    Set<URL> urls = new LinkedHashSet<URL>();
052    
053                    while (classLoader != null) {
054                            if (classLoader instanceof URLClassLoader) {
055                                    URLClassLoader urlClassLoader = (URLClassLoader)classLoader;
056    
057                                    urls.addAll(Arrays.asList(urlClassLoader.getURLs()));
058                            }
059    
060                            classLoader = classLoader.getParent();
061                    }
062    
063                    return urls;
064            }
065    
066            public static URL[] getClassPathURLs(String classPath)
067                    throws MalformedURLException {
068    
069                    String[] paths = StringUtil.split(classPath, File.pathSeparatorChar);
070    
071                    Set<URL> urls = new LinkedHashSet<URL>();
072    
073                    for (String path : paths) {
074                            File file = new File(path);
075    
076                            URI uri = file.toURI();
077    
078                            urls.add(uri.toURL());
079                    }
080    
081                    return urls.toArray(new URL[urls.size()]);
082            }
083    
084            public static String getGlobalClassPath() {
085                    return _globalClassPath;
086            }
087    
088            public static String getJVMClassPath(boolean includeBootClassPath) {
089                    String jvmClassPath = System.getProperty("java.class.path");
090    
091                    if (includeBootClassPath) {
092                            String bootClassPath = System.getProperty("sun.boot.class.path");
093    
094                            jvmClassPath = jvmClassPath.concat(File.pathSeparator).concat(
095                                    bootClassPath);
096                    }
097    
098                    return jvmClassPath;
099            }
100    
101            public static String getPortalClassPath() {
102                    return _portalClassPath;
103            }
104    
105            public static void initializeClassPaths(ServletContext servletContext) {
106                    ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
107    
108                    if (classLoader == null) {
109                            _log.error("Portal ClassLoader is null");
110    
111                            return;
112                    }
113    
114                    StringBundler sb = new StringBundler(8);
115    
116                    String appServerGlobalClassPath = _buildClassPath(
117                            classLoader, ServletException.class.getName());
118    
119                    sb.append(appServerGlobalClassPath);
120                    sb.append(File.pathSeparator);
121    
122                    String portalGlobalClassPath = _buildClassPath(
123                            classLoader, PortalException.class.getName());
124    
125                    sb.append(portalGlobalClassPath);
126    
127                    _globalClassPath = sb.toString();
128    
129                    sb.append(File.pathSeparator);
130                    sb.append(
131                            _buildClassPath(
132                                    classLoader, "com.liferay.portal.servlet.MainServlet"));
133                    sb.append(File.pathSeparator);
134                    sb.append(servletContext.getRealPath(""));
135                    sb.append("/WEB-INF/classes");
136    
137                    _portalClassPath = sb.toString();
138            }
139    
140            private static String _buildClassPath(
141                    ClassLoader classloader, String className) {
142    
143                    String pathOfClass = StringUtil.replace(
144                            className, CharPool.PERIOD, CharPool.SLASH);
145    
146                    pathOfClass = pathOfClass.concat(".class");
147    
148                    URL url = classloader.getResource(pathOfClass);
149    
150                    if (_log.isDebugEnabled()) {
151                            _log.debug("Build class path from " + url);
152                    }
153    
154                    String protocol = url.getProtocol();
155    
156                    if (protocol.equals("bundle") || protocol.equals("bundleresource")) {
157                            try {
158                                    URLConnection urlConnection = url.openConnection();
159    
160                                    Class<?> clazz = urlConnection.getClass();
161    
162                                    Method getLocalURLMethod = clazz.getDeclaredMethod(
163                                            "getLocalURL");
164    
165                                    getLocalURLMethod.setAccessible(true);
166    
167                                    url = (URL)getLocalURLMethod.invoke(urlConnection);
168                            }
169                            catch (Exception e) {
170                                    _log.error("Unable to resolve local URL from bundle", e);
171    
172                                    return StringPool.BLANK;
173                            }
174                    }
175    
176                    String path = URLCodec.decodeURL(url.getPath());
177    
178                    if (_log.isDebugEnabled()) {
179                            _log.debug("Path " + path);
180                    }
181    
182                    path = StringUtil.replace(path, CharPool.BACK_SLASH, CharPool.SLASH);
183    
184                    if (_log.isDebugEnabled()) {
185                            _log.debug("Decoded path " + path);
186                    }
187    
188                    if (ServerDetector.isWebLogic() && protocol.equals("zip")) {
189                            path = "file:".concat(path);
190                    }
191    
192                    if (ServerDetector.isJBoss() &&
193                            (protocol.equals("vfs") || protocol.equals("vfsfile"))) {
194    
195                            int pos = path.indexOf(".jar/");
196    
197                            if (pos != -1) {
198                                    String jarFilePath = path.substring(0, pos + 4);
199    
200                                    File jarFile = new File(jarFilePath);
201    
202                                    if (jarFile.isFile()) {
203                                            path = jarFilePath + '!' + path.substring(pos + 4);
204                                    }
205                            }
206    
207                            path = "file:".concat(path);
208                    }
209    
210                    File dir = null;
211    
212                    int pos = -1;
213    
214                    if (!path.startsWith("file:") ||
215                            ((pos = path.indexOf(CharPool.EXCLAMATION)) == -1)) {
216    
217                            if (!path.endsWith(pathOfClass)) {
218                                    _log.error(
219                                            "Class " + className + " is not loaded from a JAR file");
220    
221                                    return StringPool.BLANK;
222                            }
223    
224                            String classesDirName = path.substring(
225                                    0, path.length() - pathOfClass.length());
226    
227                            if (!classesDirName.endsWith("/WEB-INF/classes/")) {
228                                    _log.error(
229                                            "Class " + className + " is not loaded from a standard " +
230                                                    "location (/WEB-INF/classes)");
231    
232                                    return StringPool.BLANK;
233                            }
234    
235                            String libDirName = classesDirName.substring(
236                                    0, classesDirName.length() - "classes/".length());
237    
238                            libDirName += "/lib";
239    
240                            dir = new File(libDirName);
241                    }
242                    else {
243                            pos = path.lastIndexOf(CharPool.SLASH, pos);
244    
245                            dir = new File(path.substring("file:".length(), pos));
246                    }
247    
248                    if (!dir.isDirectory()) {
249                            _log.error(dir.toString() + " is not a directory");
250    
251                            return StringPool.BLANK;
252                    }
253    
254                    File[] files = dir.listFiles();
255    
256                    Arrays.sort(files);
257    
258                    StringBundler sb = new StringBundler(files.length * 2);
259    
260                    for (File file : files) {
261                            sb.append(file.getAbsolutePath());
262                            sb.append(File.pathSeparator);
263                    }
264    
265                    sb.setIndex(sb.index() - 1);
266    
267                    return sb.toString();
268            }
269    
270            private static Log _log = LogFactoryUtil.getLog(ClassPathUtil.class);
271    
272            private static String _globalClassPath;
273            private static String _portalClassPath;
274    
275    }