package org.jetbrains.jps.runConf.java; import java.io.File; import java.net.URL; import java.util.LinkedHashSet; import java.util.Set; public class ClasspathUtil { private static final String FILE = "file"; private static final String JAR = "jar"; private static final String JAR_DELIMITER = "!"; private static final String PROTOCOL_DELIMITER = ":"; public static String composeClasspath(Class[] classes) { Set<String> cp = new LinkedHashSet<String>(); if (classes != null) { for (Class classFromLib : classes) { cp.add(getResourceRoot(classFromLib)); } } StringBuilder result = new StringBuilder(); for (String path : cp) { if (result.length() > 0) { result.append(File.pathSeparator); } result.append(path); } return result.toString(); } /** * Attempts to detect classpath entry which contains given resource */ private static String getResourceRoot(Class context, String path) { URL url = context.getResource(path); if (url == null) { url = ClassLoader.getSystemResource(path.substring(1)); } if (url == null) { return null; } return extractRoot(url, path); } /** * Attempts to extract classpath entry part from passed URL. */ private static String extractRoot(URL resourceURL, String resourcePath) { if (!(resourcePath.startsWith("/") || resourcePath.startsWith("\\"))) { //noinspection HardCodedStringLiteral System.err.println("precondition failed"); return null; } String protocol = resourceURL.getProtocol(); String resultPath = null; if (FILE.equals(protocol)) { String path = resourceURL.getFile(); String testPath = path.replace('\\', '/').toLowerCase(); String testResourcePath = resourcePath.replace('\\', '/').toLowerCase(); if (testPath.endsWith(testResourcePath)) { resultPath = path.substring(0, path.length() - resourcePath.length()); } } else if (JAR.equals(protocol)) { String fullPath = resourceURL.getFile(); int delimiter = fullPath.indexOf(JAR_DELIMITER); if (delimiter >= 0) { String archivePath = fullPath.substring(0, delimiter); if (archivePath.startsWith(FILE + PROTOCOL_DELIMITER)) { resultPath = archivePath.substring(FILE.length() + PROTOCOL_DELIMITER.length()); } } } if (resultPath != null && resultPath.endsWith(File.separator)) { resultPath = resultPath.substring(0, resultPath.length() - 1); } resultPath = replaceAll(resultPath, "%20", " "); resultPath = replaceAll(resultPath, "%23", "#"); // !Workaround for /D:/some/path/a.jar, which doesn't work if D is subst disk if (resultPath.startsWith("/") && resultPath.indexOf(":") == 2) { resultPath = resultPath.substring(1); } return resultPath; } private static String replaceAll(final String text, final String pattern, final String replacement) { if (pattern.length() == 0 || text.length() < pattern.length()) { return text; } final StringBuilder buf = new StringBuilder(text.length()); int currentTextIndex = 0; while (currentTextIndex < text.length()) { final int startOfPattern = text.indexOf(pattern, currentTextIndex); if (startOfPattern < 0) { if (currentTextIndex == 0) { // there are no patterns in the text at all return text; } buf.append(text.substring(currentTextIndex)); // append the rest of the text return buf.toString(); } buf.append(text.substring(currentTextIndex, startOfPattern)); buf.append(replacement); currentTextIndex = startOfPattern + pattern.length(); } return buf.toString(); } private static String getResourceRoot(final Class aClass) { return getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class"); } }