001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.xbean.finder; 018 019import org.apache.xbean.finder.util.Files; 020 021import java.io.File; 022import java.io.IOException; 023import java.net.MalformedURLException; 024import java.net.URL; 025import java.net.URLClassLoader; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.HashSet; 030import java.util.Set; 031 032public final class ClassLoaders { 033 private static final boolean DONT_USE_GET_URLS = Boolean.getBoolean("xbean.finder.use.get-resources"); 034 private static final ClassLoader SYSTEM = ClassLoader.getSystemClassLoader(); 035 036 private static final boolean UNIX = !System.getProperty("os.name").toLowerCase().contains("win"); 037 038 public static Set<URL> findUrls(final ClassLoader classLoader) throws IOException { 039 if (classLoader == null || (SYSTEM.getParent() != null && classLoader == SYSTEM.getParent())) { 040 return Collections.emptySet(); 041 } 042 043 final Set<URL> urls = new HashSet<URL>(); 044 045 if (URLClassLoader.class.isInstance(classLoader) && !DONT_USE_GET_URLS) { 046 if (!isSurefire(classLoader)) { 047 for (final Collection<URL> item : Arrays.asList( 048 Arrays.asList(URLClassLoader.class.cast(classLoader).getURLs()), findUrls(classLoader.getParent()))) { 049 for (final URL url : item) { 050 addIfNotSo(urls, url); 051 } 052 } 053 } else { // http://jira.codehaus.org/browse/SUREFIRE-928 - we could reuse findUrlFromResources but this seems faster 054 urls.addAll(fromClassPath()); 055 } 056 } 057 058 // DONT_USE_GET_URLS ||?java -jar xxx.jar and use MANIFEST.MF Class-Path? 059 // here perf is not an issue since we would either miss all the classpath or we have a single jar 060 if (urls.size() <= 1) { 061 final Set<URL> urlFromResources = findUrlFromResources(classLoader); 062 if (!urls.isEmpty()) { 063 final URL theUrl = urls.iterator().next(); 064 if ("file".equals(theUrl.getProtocol())) { // theUrl can be file:xxxx but it is the same entry actually 065 urlFromResources.remove(new URL("jar:" + theUrl.toExternalForm() + "!/")); 066 } 067 } 068 urls.addAll(urlFromResources); 069 } 070 071 return urls; 072 } 073 074 private static void addIfNotSo(final Set<URL> urls, final URL url) { 075 if (UNIX && isNative(url)) { 076 return; 077 } 078 079 urls.add(url); 080 } 081 082 public static boolean isNative(final URL url) { 083 final File file = Files.toFile(url); 084 if (file != null) { 085 final String name = file.getName(); 086 if (!name.endsWith(".jar") && !file.isDirectory() 087 && name.contains(".so") && file.getAbsolutePath().startsWith("/usr/lib")) { 088 return true; 089 } 090 } 091 return false; 092 } 093 094 095 private static boolean isSurefire(ClassLoader classLoader) { 096 return System.getProperty("surefire.real.class.path") != null && classLoader == SYSTEM; 097 } 098 099 private static Collection<URL> fromClassPath() { 100 final String[] cp = System.getProperty("java.class.path").split(System.getProperty("path.separator", ":")); 101 final Set<URL> urls = new HashSet<URL>(); 102 for (final String path : cp) { 103 try { 104 urls.add(new File(path).toURI().toURL()); // don't build the url in plain String since it is not portable 105 } catch (final MalformedURLException e) { 106 // ignore 107 } 108 } 109 return urls; 110 } 111 112 public static Set<URL> findUrlFromResources(final ClassLoader classLoader) throws IOException { 113 final Set<URL> set = new HashSet<URL>(); 114 for (final URL url : Collections.list(classLoader.getResources("META-INF"))) { 115 final String externalForm = url.toExternalForm(); 116 set.add(new URL(externalForm.substring(0, externalForm.lastIndexOf("META-INF")))); 117 } 118 set.addAll(Collections.list(classLoader.getResources(""))); 119 return set; 120 } 121 122 private ClassLoaders() { 123 // no-op 124 } 125}