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 */ 020package org.sonar.batch.bootstrapper; 021 022import java.io.IOException; 023import java.net.URL; 024import java.net.URLClassLoader; 025import java.util.Enumeration; 026 027/** 028 * Special {@link URLClassLoader} to execute Sonar, which restricts loading from parent. 029 */ 030public class BootstrapClassLoader extends URLClassLoader { 031 032 private String[] unmaskedPackages; 033 034 public BootstrapClassLoader(ClassLoader parent, String... unmaskedPackages) { 035 super(new URL[0], parent); 036 this.unmaskedPackages = unmaskedPackages; 037 } 038 039 /** 040 * {@inheritDoc} Visibility of a method has been relaxed to public. 041 */ 042 @Override 043 public void addURL(URL url) { 044 super.addURL(url); 045 } 046 047 /** 048 * {@inheritDoc} Visibility of a method has been relaxed to public. 049 */ 050 @Override 051 public Class<?> findClass(String name) throws ClassNotFoundException { 052 return super.findClass(name); 053 } 054 055 /** 056 * @return true, if class can be loaded from parent ClassLoader 057 */ 058 boolean canLoadFromParent(String name) { 059 for (String pkg : unmaskedPackages) { 060 if (name.startsWith(pkg + ".")) { 061 return true; 062 } 063 } 064 return false; 065 } 066 067 /** 068 * Same behavior as in {@link URLClassLoader#loadClass(String, boolean)}, except loading from parent. 069 */ 070 @Override 071 protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 072 // First, check if the class has already been loaded 073 Class<?> c = findLoadedClass(name); 074 if (c == null) { 075 try { 076 // Load from parent 077 if ((getParent() != null) && canLoadFromParent(name)) { 078 c = getParent().loadClass(name); 079 } else { 080 // Load from system 081 c = getSystemClassLoader().loadClass(name); 082 } 083 } catch (ClassNotFoundException e) { 084 // If still not found, then invoke findClass in order 085 // to find the class. 086 c = findClass(name); 087 } 088 } 089 if (resolve) { 090 resolveClass(c); 091 } 092 return c; 093 } 094 095 /** 096 * Unlike {@link URLClassLoader#getResource(String)} don't return resource from parent. 097 * See http://jira.codehaus.org/browse/SONAR-2276 098 */ 099 @Override 100 public URL getResource(String name) { 101 return findResource(name); 102 } 103 104 /** 105 * Unlike {@link URLClassLoader#getResources(String)} don't return resources from parent. 106 * See http://jira.codehaus.org/browse/SONAR-2276 107 */ 108 @Override 109 public Enumeration<URL> getResources(String name) throws IOException { 110 return findResources(name); 111 } 112 113}