001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.java.bytecode.loader; 021 022 import java.io.Closeable; 023 import java.io.File; 024 import java.io.IOException; 025 import java.net.URL; 026 import java.util.ArrayList; 027 import java.util.Collection; 028 import java.util.Enumeration; 029 import java.util.List; 030 031 import com.google.common.collect.Iterators; 032 033 /** 034 * Class loader, which is able to load classes from a list of JAR files and directories. 035 */ 036 public class SquidClassLoader extends ClassLoader implements Closeable { 037 038 private final List<Loader> loaders; 039 040 public SquidClassLoader(Collection<File> files) throws IOException { 041 super(null); 042 loaders = new ArrayList<Loader>(); 043 for (File file : files) { 044 if (file.exists()) { 045 if (file.isDirectory()) { 046 loaders.add(new FileSystemLoader(file)); 047 } else { 048 loaders.add(new JarLoader(file)); 049 } 050 } 051 } 052 } 053 054 @Override 055 protected Class<?> findClass(String name) throws ClassNotFoundException { 056 byte[] classBytes = loadClassBytes(name); 057 if (classBytes == null) { 058 throw new ClassNotFoundException(name); 059 } 060 // TODO Godin: definePackage ? 061 return defineClass(name, classBytes, 0, classBytes.length); 062 } 063 064 private byte[] loadClassBytes(String name) { 065 String resourceName = name.replace('.', '/') + ".class"; 066 for (Loader loader : loaders) { 067 byte[] classBytes = loader.loadBytes(resourceName); 068 if (classBytes != null) { 069 return classBytes; 070 } 071 } 072 return null; 073 } 074 075 @Override 076 public URL findResource(String name) { 077 for (Loader loader : loaders) { 078 URL url = loader.findResource(name); 079 if (url != null) { 080 return url; 081 } 082 } 083 return null; 084 } 085 086 @Override 087 protected Enumeration<URL> findResources(String name) throws IOException { 088 List<URL> result = new ArrayList<URL>(); 089 for (Loader loader : loaders) { 090 URL url = loader.findResource(name); 091 if (url != null) { 092 result.add(url); 093 } 094 } 095 return Iterators.asEnumeration(result.iterator()); 096 } 097 098 /** 099 * Closes this class loader, so that it can no longer be used to load new classes or resources. 100 * Any classes or resources that are already loaded, are still accessible. 101 * 102 * If class loader is already closed, then invoking this method has no effect. 103 */ 104 public void close() { 105 for (Loader loader : loaders) { 106 loader.close(); 107 } 108 } 109 110 }