/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.process;
import aQute.bnd.annotation.ProviderType;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.process.ProcessConfig.Builder;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.ClassLoaderUtil;
import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
import com.liferay.portal.kernel.util.ServerDetector;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.URLCodec;
import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
/**
* @author Shuyang Zhou
*/
@ProviderType
public class ClassPathUtil {
public static String buildClassPath(Class<?>... classes) {
if (ArrayUtil.isEmpty(classes)) {
return StringPool.BLANK;
}
StringBundler sb = new StringBundler(classes.length * 2);
for (Class<?> clazz : classes) {
sb.append(_buildClassPath(clazz.getClassLoader(), clazz.getName()));
sb.append(File.pathSeparator);
}
sb.setIndex(sb.index() - 1);
return sb.toString();
}
public static Set<URL> getClassPathURLs(ClassLoader classLoader) {
Set<URL> urls = new LinkedHashSet<>();
while (classLoader != null) {
if (classLoader instanceof URLClassLoader) {
URLClassLoader urlClassLoader = (URLClassLoader)classLoader;
Collections.addAll(urls, urlClassLoader.getURLs());
}
classLoader = classLoader.getParent();
}
return urls;
}
public static URL[] getClassPathURLs(String classPath)
throws MalformedURLException {
String[] paths = StringUtil.split(classPath, File.pathSeparatorChar);
Set<URL> urls = new LinkedHashSet<>();
for (String path : paths) {
File file = new File(path);
URI uri = file.toURI();
urls.add(uri.toURL());
}
return urls.toArray(new URL[urls.size()]);
}
public static String getGlobalClassPath() {
return _globalClassPath;
}
public static String getJVMClassPath(boolean includeBootClassPath) {
String jvmClassPath = System.getProperty("java.class.path");
if (includeBootClassPath) {
String bootClassPath = System.getProperty("sun.boot.class.path");
jvmClassPath = jvmClassPath.concat(File.pathSeparator).concat(
bootClassPath);
}
return jvmClassPath;
}
public static String getPortalClassPath() {
return _portalClassPath;
}
public static ProcessConfig getPortalProcessConfig() {
return _portalProcessConfig;
}
public static void initializeClassPaths(ServletContext servletContext) {
ClassLoader classLoader = PortalClassLoaderUtil.getClassLoader();
if (classLoader == null) {
classLoader = ClassLoaderUtil.getContextClassLoader();
}
StringBundler sb = new StringBundler(8);
String appServerGlobalClassPath = _buildClassPath(
classLoader, ServletException.class.getName());
sb.append(appServerGlobalClassPath);
sb.append(File.pathSeparator);
String portalGlobalClassPath = _buildClassPath(
classLoader, PortalException.class.getName());
sb.append(portalGlobalClassPath);
_globalClassPath = sb.toString();
sb.append(File.pathSeparator);
sb.append(
_buildClassPath(
classLoader, "com.liferay.portal.servlet.MainServlet"));
if (servletContext != null) {
sb.append(File.pathSeparator);
sb.append(servletContext.getRealPath(""));
sb.append("/WEB-INF/classes");
}
_portalClassPath = sb.toString();
Builder builder = new Builder();
builder.setArguments(Arrays.asList("-Djava.awt.headless=true"));
builder.setBootstrapClassPath(_globalClassPath);
builder.setReactClassLoader(classLoader);
builder.setRuntimeClassPath(_portalClassPath);
_portalProcessConfig = builder.build();
}
private static String _buildClassPath(
ClassLoader classloader, String className) {
String pathOfClass = StringUtil.replace(
className, CharPool.PERIOD, CharPool.SLASH);
pathOfClass = pathOfClass.concat(".class");
URL url = classloader.getResource(pathOfClass);
if (_log.isDebugEnabled()) {
_log.debug("Build class path from " + url);
}
String protocol = url.getProtocol();
if (protocol.equals("bundle") || protocol.equals("bundleresource")) {
try {
URLConnection urlConnection = url.openConnection();
Class<?> clazz = urlConnection.getClass();
Method getLocalURLMethod = clazz.getDeclaredMethod(
"getLocalURL");
getLocalURLMethod.setAccessible(true);
url = (URL)getLocalURLMethod.invoke(urlConnection);
}
catch (Exception e) {
_log.error("Unable to resolve local URL from bundle", e);
return StringPool.BLANK;
}
}
String path = URLCodec.decodeURL(url.getPath());
if (_log.isDebugEnabled()) {
_log.debug("Path " + path);
}
path = StringUtil.replace(path, CharPool.BACK_SLASH, CharPool.SLASH);
if (_log.isDebugEnabled()) {
_log.debug("Decoded path " + path);
}
if (ServerDetector.isWebLogic() && protocol.equals("zip")) {
path = "file:".concat(path);
}
if ((ServerDetector.isJBoss() || ServerDetector.isWildfly()) &&
(protocol.equals("vfs") || protocol.equals("vfsfile") ||
protocol.equals("vfszip"))) {
int pos = path.indexOf(".jar/");
if (pos != -1) {
String jarFilePath = path.substring(0, pos + 4);
File jarFile = new File(jarFilePath);
if (jarFile.isFile()) {
path = jarFilePath + '!' + path.substring(pos + 4);
}
}
path = "file:".concat(path);
}
File dir = null;
int pos = -1;
if (!path.startsWith("file:") ||
((pos = path.indexOf(CharPool.EXCLAMATION)) == -1)) {
if (!path.endsWith(pathOfClass)) {
_log.error(
"Class " + className + " is not loaded from a JAR file");
return StringPool.BLANK;
}
String classesDirName = path.substring(
0, path.length() - pathOfClass.length());
if (!classesDirName.endsWith("/WEB-INF/classes/")) {
_log.error(
"Class " + className + " is not loaded from a standard " +
"location (/WEB-INF/classes)");
return StringPool.BLANK;
}
String libDirName = classesDirName.substring(
0, classesDirName.length() - "classes/".length());
libDirName += "/lib";
dir = new File(libDirName);
}
else {
pos = path.lastIndexOf(CharPool.SLASH, pos);
dir = new File(path.substring("file:".length(), pos));
}
if (!dir.isDirectory()) {
_log.error(dir.toString() + " is not a directory");
return StringPool.BLANK;
}
File[] files = dir.listFiles(
new FileFilter() {
@Override
public boolean accept(File file) {
if (file.isDirectory()) {
return false;
}
String name = file.getName();
if (name.equals("bundleFile") || name.endsWith(".jar")) {
return true;
}
return false;
}
});
if (files == null) {
return StringPool.BLANK;
}
Arrays.sort(files);
StringBundler sb = new StringBundler(files.length * 2);
for (File file : files) {
sb.append(file.getAbsolutePath());
sb.append(File.pathSeparator);
}
sb.setIndex(sb.index() - 1);
return sb.toString();
}
private static final Log _log = LogFactoryUtil.getLog(ClassPathUtil.class);
private static String _globalClassPath;
private static String _portalClassPath;
private static ProcessConfig _portalProcessConfig;
}