]> source.dussan.org Git - sonarqube.git/commitdiff
Revert "SONAR-21195 allow plugins loaded in different containers to access classLoade...
authorMatteo Mara <matteo.mara@sonarsource.com>
Fri, 22 Dec 2023 09:28:21 +0000 (10:28 +0100)
committersonartech <sonartech@sonarsource.com>
Fri, 22 Dec 2023 20:03:01 +0000 (20:03 +0000)
This reverts commit 9d91fc4c8fa35bc7fc985a71a2d38ef0759e50e3.

36 files changed:
build.gradle
sonar-core/build.gradle
sonar-core/src/main/java/org/sonar/classloader/ClassRealm.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/ClassloaderBuilder.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/ClassloaderRef.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/DefaultClassloaderRef.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/Mask.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/NullClassloaderRef.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/ParentFirstStrategy.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/SelfFirstStrategy.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/Strategy.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/StrategyContext.java [deleted file]
sonar-core/src/main/java/org/sonar/classloader/package-info.java [deleted file]
sonar-core/src/main/java/org/sonar/core/platform/PluginClassLoader.java
sonar-core/src/main/java/org/sonar/core/platform/PluginClassLoaderDef.java
sonar-core/src/main/java/org/sonar/core/platform/PluginClassloaderFactory.java
sonar-core/src/test/java/org/sonar/classloader/ClassloaderBuilderTest.java [deleted file]
sonar-core/src/test/java/org/sonar/classloader/MaskTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/platform/PluginClassloaderFactoryTest.java
sonar-core/tester/a.jar [deleted file]
sonar-core/tester/a/A.class [deleted file]
sonar-core/tester/a/A.java [deleted file]
sonar-core/tester/a/a.txt [deleted file]
sonar-core/tester/a_v2.jar [deleted file]
sonar-core/tester/a_v2/A.class [deleted file]
sonar-core/tester/a_v2/A.java [deleted file]
sonar-core/tester/a_v2/a.txt [deleted file]
sonar-core/tester/b.jar [deleted file]
sonar-core/tester/b/B.class [deleted file]
sonar-core/tester/b/B.java [deleted file]
sonar-core/tester/b/b.txt [deleted file]
sonar-core/tester/build.sh [deleted file]
sonar-core/tester/c.jar [deleted file]
sonar-core/tester/c/C.class [deleted file]
sonar-core/tester/c/C.java [deleted file]
sonar-core/tester/c/c.txt [deleted file]

index eac01d4dc97744537c714dcbb9a15b13e7884602..e1d932bc93932efe7e353c401f0521ad3519b98b 100644 (file)
@@ -376,6 +376,7 @@ subprojects {
       dependency('org.codehaus.sonar:sonar-channel:4.2') {
         exclude 'org.slf4j:slf4j-api'
       }
+      dependency 'org.codehaus.sonar:sonar-classloader:1.0'
       dependency 'com.fasterxml.staxmate:staxmate:2.4.1'
       dependencySet(group: 'org.eclipse.jetty', version: '9.4.6.v20170531') {
         entry 'jetty-proxy'
index 79045ab8c4664f0608283fb359cd0d84cf1d1bc5..0a7ac004a70fbd70fa0a9b926685edb3953c1cdf 100644 (file)
@@ -17,6 +17,7 @@ dependencies {
   api 'commons-lang:commons-lang'
   api 'javax.annotation:javax.annotation-api'
   api 'javax.inject:javax.inject'
+  api 'org.codehaus.sonar:sonar-classloader'
   api 'org.slf4j:slf4j-api'
   api 'org.sonarsource.api.plugin:sonar-plugin-api'
   api 'org.sonarsource.update-center:sonar-update-center-common'
diff --git a/sonar-core/src/main/java/org/sonar/classloader/ClassRealm.java b/sonar-core/src/main/java/org/sonar/classloader/ClassRealm.java
deleted file mode 100644 (file)
index f66def1..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.List;
-import javax.annotation.CheckForNull;
-
-class ClassRealm extends URLClassLoader implements StrategyContext {
-
-  private final String key;
-  private Mask mask = Mask.ALL;
-  private Mask exportMask = Mask.ALL;
-  private ClassloaderRef parentRef = NullClassloaderRef.INSTANCE;
-  private List<ClassloaderRef> siblingRefs = new ArrayList<>();
-  private Strategy strategy;
-
-  ClassRealm(String key, ClassLoader baseClassloader) {
-    super(new URL[0], baseClassloader);
-    this.key = key;
-  }
-
-  String getKey() {
-    return key;
-  }
-
-  ClassRealm setMask(Mask mask) {
-    this.mask = mask;
-    return this;
-  }
-
-  Mask getExportMask() {
-    return exportMask;
-  }
-
-  ClassRealm setExportMask(Mask exportMask) {
-    this.exportMask = exportMask;
-    return this;
-  }
-
-  ClassRealm setParent(ClassloaderRef parentRef) {
-    this.parentRef = parentRef;
-    return this;
-  }
-
-  ClassRealm addSibling(ClassloaderRef ref) {
-    this.siblingRefs.add(ref);
-    return this;
-  }
-
-  ClassRealm setStrategy(Strategy strategy) {
-    this.strategy = strategy;
-    return this;
-  }
-
-  ClassRealm addConstituent(URL url) {
-    super.addURL(url);
-    return this;
-  }
-
-  @Override
-  public Class<?> loadClass(String name) throws ClassNotFoundException {
-    return loadClass(name, false);
-  }
-
-  @Override
-  protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
-    if (mask.acceptClass(name)) {
-      try {
-        // first, try loading bootstrap classes
-        return super.loadClass(name, resolve);
-      } catch (ClassNotFoundException ignored) {
-        // next, try loading via siblings, self and parent as controlled by strategy
-        return strategy.loadClass(this, name);
-      }
-    }
-    throw new ClassNotFoundException(String.format("Class %s is not accepted in classloader %s", name, this));
-  }
-
-
-  @Override
-  protected Class<?> findClass(String name) throws ClassNotFoundException {
-    // not supposed to be used. Replaced by loadClassFromSelf(String)
-    throw new ClassNotFoundException(name);
-  }
-
-  @CheckForNull
-  @Override
-  public URL getResource(String name) {
-    if (mask.acceptResource(name)) {
-      return strategy.getResource(this, name);
-    }
-    return null;
-  }
-
-  @Override
-  public Enumeration<URL> getResources(String name) throws IOException {
-    // Important note: do not use java.util.Set as equals and hashCode methods of
-    // java.net.URL perform domain name resolution. This can result in a big performance hit.
-    List<URL> resources = new ArrayList<>();
-    if (mask.acceptResource(name)) {
-      strategy.getResources(this, name, resources);
-    }
-    return Collections.enumeration(resources);
-  }
-
-  @Override
-  public Class<?> loadClassFromSelf(String name) {
-    Class<?> clazz = findLoadedClass(name);
-    if (clazz == null) {
-      try {
-        return super.findClass(name);
-      } catch (ClassNotFoundException ignored) {
-        // return null when class is not found, so that loading strategy
-        // can try parent or sibling classloaders.
-      }
-    }
-    return clazz;
-  }
-
-  @Override
-  public Class<?> loadClassFromSiblings(String name) {
-    for (ClassloaderRef siblingRef : siblingRefs) {
-      Class<?> clazz = siblingRef.loadClassIfPresent(name);
-      if (clazz != null) {
-        return clazz;
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public Class<?> loadClassFromParent(String name) {
-    return parentRef.loadClassIfPresent(name);
-  }
-
-  @Override
-  public URL loadResourceFromSelf(String name) {
-    return super.findResource(name);
-  }
-
-  @Override
-  public URL loadResourceFromSiblings(String name) {
-    for (ClassloaderRef siblingRef : siblingRefs) {
-      URL url = siblingRef.loadResourceIfPresent(name);
-      if (url != null) {
-        return url;
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public URL loadResourceFromParent(String name) {
-    return parentRef.loadResourceIfPresent(name);
-  }
-
-  @Override
-  public void loadResourcesFromSelf(String name, Collection<URL> appendTo) {
-    try {
-      appendTo.addAll(Collections.list(super.findResources(name)));
-    } catch (IOException e) {
-      throw new IllegalStateException(String.format("Fail to load resources named '%s' from classloader %s", name, toString()), e);
-    }
-  }
-
-  @Override
-  public void loadResourcesFromSiblings(String name, Collection<URL> appendTo) {
-    for (ClassloaderRef siblingRef : siblingRefs) {
-      siblingRef.loadResources(name, appendTo);
-    }
-  }
-
-  @Override
-  public void loadResourcesFromParent(String name, Collection<URL> appendTo) {
-    parentRef.loadResources(name, appendTo);
-  }
-
-  @Override
-  public String toString() {
-    return String.format("ClassRealm{%s}", key);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/ClassloaderBuilder.java b/sonar-core/src/main/java/org/sonar/classloader/ClassloaderBuilder.java
deleted file mode 100644 (file)
index 0bea223..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static java.util.Collections.emptyList;
-
-/**
- * @since 0.1
- */
-public class ClassloaderBuilder {
-  private final Map<String, ClassRealm> previouslyCreatedClassLoaders;
-
-  private final Map<String, NewRealm> newRealmsByKey = new HashMap<>();
-
-  public ClassloaderBuilder() {
-    this(emptyList());
-  }
-
-  /**
-   * Creates a new classloader builder that can use a collection of previously created
-   * classloaders as parent or siblings when building the new classloaders.
-   *
-   * @param previouslyCreatedClassLoaders Collection of classloaders that can be used as a
-   *                                      parent or sibling. Must be of type {@link ClassRealm}.
-   */
-  public ClassloaderBuilder(Collection<ClassLoader> previouslyCreatedClassLoaders) {
-    this.previouslyCreatedClassLoaders = new HashMap<>();
-    for (ClassLoader cl : previouslyCreatedClassLoaders) {
-      if (!(cl instanceof ClassRealm)) {
-        throw new IllegalArgumentException("classloader not of type ClassRealm: " + cl);
-      }
-      ClassRealm classRealm = (ClassRealm) cl;
-      this.previouslyCreatedClassLoaders.put(classRealm.getKey(), classRealm);
-    }
-  }
-
-  public enum LoadingOrder {
-    /**
-     * Order: siblings, then parent, then self
-     */
-    PARENT_FIRST(ParentFirstStrategy.INSTANCE),
-
-    /**
-     * Order: siblings, then self, then parent
-     */
-    SELF_FIRST(SelfFirstStrategy.INSTANCE);
-
-    private final Strategy strategy;
-
-    LoadingOrder(Strategy strategy) {
-      this.strategy = strategy;
-    }
-  }
-
-  /**
-   * Wrapper of {@link ClassRealm} as long as associations are not fully
-   * defined
-   */
-  private static class NewRealm {
-    private final ClassRealm realm;
-
-    // key of the optional parent classloader
-    private String parentKey;
-
-    private final List<String> siblingKeys = new ArrayList<>();
-    private final Map<String, Mask> associatedMasks = new HashMap<>();
-
-    private NewRealm(ClassRealm realm) {
-      this.realm = realm;
-    }
-  }
-
-  /**
-   * Declares a new classloader based on system classloader.
-   */
-  public ClassloaderBuilder newClassloader(String key) {
-    return newClassloader(key, getSystemClassloader());
-  }
-
-  /**
-   * Declares a new classloader based on a given parent classloader. Key must be unique. An
-   * {@link IllegalArgumentException} is thrown if the key is already referenced.
-   * <p/>
-   * Default loading order is {@link LoadingOrder#PARENT_FIRST}.
-   */
-  public ClassloaderBuilder newClassloader(final String key, final ClassLoader baseClassloader) {
-    if (newRealmsByKey.containsKey(key)) {
-      throw new IllegalStateException(String.format("The classloader '%s' already exists. Can not create it twice.", key));
-    }
-    if (previouslyCreatedClassLoaders.containsKey(key)) {
-      throw new IllegalStateException(String.format("The classloader '%s' already exists in the list of previously created classloaders."
-        + " Can not create it twice.", key));
-    }
-    ClassRealm realm = AccessController.<PrivilegedAction<ClassRealm>>doPrivileged(() -> new ClassRealm(key, baseClassloader));
-    realm.setStrategy(LoadingOrder.PARENT_FIRST.strategy);
-    newRealmsByKey.put(key, new NewRealm(realm));
-    return this;
-  }
-
-  public ClassloaderBuilder setParent(String key, String parentKey, Mask mask) {
-    NewRealm newRealm = getOrFail(key);
-    newRealm.parentKey = parentKey;
-    newRealm.associatedMasks.put(parentKey, mask);
-    return this;
-  }
-
-  public ClassloaderBuilder setParent(String key, ClassLoader parent, Mask mask) {
-    NewRealm newRealm = getOrFail(key);
-    newRealm.realm.setParent(new DefaultClassloaderRef(parent, mask));
-    return this;
-  }
-
-  public ClassloaderBuilder addSibling(String key, String siblingKey, Mask mask) {
-    NewRealm newRealm = getOrFail(key);
-    newRealm.siblingKeys.add(siblingKey);
-    newRealm.associatedMasks.put(siblingKey, mask);
-    return this;
-  }
-
-  public ClassloaderBuilder addSibling(String key, ClassLoader sibling, Mask mask) {
-    NewRealm newRealm = getOrFail(key);
-    newRealm.realm.addSibling(new DefaultClassloaderRef(sibling, mask));
-    return this;
-  }
-
-  public ClassloaderBuilder addURL(String key, URL url) {
-    getOrFail(key).realm.addConstituent(url);
-    return this;
-  }
-
-  public ClassloaderBuilder setMask(String key, Mask mask) {
-    getOrFail(key).realm.setMask(mask);
-    return this;
-  }
-
-  public ClassloaderBuilder setExportMask(String key, Mask mask) {
-    getOrFail(key).realm.setExportMask(mask);
-    return this;
-  }
-
-  public ClassloaderBuilder setLoadingOrder(String key, LoadingOrder order) {
-    getOrFail(key).realm.setStrategy(order.strategy);
-    return this;
-  }
-
-  /**
-   * Returns the new classloaders, grouped by keys. The parent and sibling classloaders
-   * that are already existed (see {@link #setParent(String, ClassLoader, Mask)}
-   * and {@link #addSibling(String, ClassLoader, Mask)} are not included into result.
-   */
-  public Map<String, ClassLoader> build() {
-    Map<String, ClassLoader> result = new HashMap<>();
-
-    // all the classloaders are created. Associations can now be resolved.
-    for (Map.Entry<String, NewRealm> entry : newRealmsByKey.entrySet()) {
-      NewRealm newRealm = entry.getValue();
-      if (newRealm.parentKey != null) {
-        ClassRealm parent = getNewOrPreviousClassloader(newRealm.parentKey);
-        Mask parentMask = newRealm.associatedMasks.get(newRealm.parentKey);
-        parentMask = mergeWithExportMask(parentMask, newRealm.parentKey);
-        newRealm.realm.setParent(new DefaultClassloaderRef(parent, parentMask));
-      }
-      for (String siblingKey : newRealm.siblingKeys) {
-        ClassRealm sibling = getNewOrPreviousClassloader(siblingKey);
-        Mask siblingMask = newRealm.associatedMasks.get(siblingKey);
-        siblingMask = mergeWithExportMask(siblingMask, siblingKey);
-        newRealm.realm.addSibling(new DefaultClassloaderRef(sibling, siblingMask));
-      }
-      result.put(newRealm.realm.getKey(), newRealm.realm);
-    }
-    return result;
-  }
-
-  private Mask mergeWithExportMask(Mask mask, String exportKey) {
-    NewRealm newRealm = newRealmsByKey.get(exportKey);
-    if (newRealm != null) {
-      return Mask.builder().copy(mask).merge(newRealm.realm.getExportMask()).build();
-    }
-    ClassRealm realm = previouslyCreatedClassLoaders.get(exportKey);
-    if (realm != null) {
-      return Mask.builder().copy(mask).merge(realm.getExportMask()).build();
-    }
-    return mask;
-  }
-
-  private NewRealm getOrFail(String key) {
-    NewRealm newRealm = newRealmsByKey.get(key);
-    if (newRealm == null) {
-      throw new IllegalStateException(String.format("The classloader '%s' does not exist", key));
-    }
-    return newRealm;
-  }
-
-  private ClassRealm getNewOrPreviousClassloader(String key) {
-    NewRealm newRealm = newRealmsByKey.get(key);
-    if (newRealm != null) {
-      return newRealm.realm;
-    }
-    ClassRealm previousClassloader = previouslyCreatedClassLoaders.get(key);
-    if (previousClassloader != null) {
-      return previousClassloader;
-    }
-
-    throw new IllegalStateException(String.format("The classloader '%s' does not exist", key));
-  }
-
-  /**
-   * JRE system classloader. In Oracle JVM:
-   * - ClassLoader.getSystemClassLoader() is sun.misc.Launcher$AppClassLoader. It contains app classpath.
-   * - ClassLoader.getSystemClassLoader().getParent() is sun.misc.Launcher$ExtClassLoader. It is the JRE core classloader.
-   */
-  private static ClassLoader getSystemClassloader() {
-    ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
-    ClassLoader systemParent = systemClassLoader.getParent();
-    if (systemParent != null) {
-      systemClassLoader = systemParent;
-    }
-    return systemClassLoader;
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/ClassloaderRef.java b/sonar-core/src/main/java/org/sonar/classloader/ClassloaderRef.java
deleted file mode 100644 (file)
index 0e3b2ad..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.net.URL;
-import java.util.Collection;
-import javax.annotation.CheckForNull;
-
-interface ClassloaderRef {
-
-  /**
-   * Does not throw {@link java.lang.ClassNotFoundException} but returns null
-   * when class is not found
-   *
-   * @param name name of class, for example "org.foo.Bar"
-   */
-  @CheckForNull
-  Class<?> loadClassIfPresent(String name);
-
-  /**
-   * Searches for a resource. Returns null if not found.
-   *
-   * @param name name of resource, for example "org/foo/Bar.class" or "org/foo/config.xml"
-   */
-  @CheckForNull
-  URL loadResourceIfPresent(String name);
-
-  /**
-   * Searches for all the occurrences of a resource from hierarchy of classloaders.
-   * Results are appended to the parameter "appendTo". Order of resources is given by the
-   * hierarchy order of classloaders.
-   *
-   * @see #loadResourceIfPresent(String) for the format of resource name
-   */
-  void loadResources(String name, Collection<URL> appendTo);
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/DefaultClassloaderRef.java b/sonar-core/src/main/java/org/sonar/classloader/DefaultClassloaderRef.java
deleted file mode 100644 (file)
index 1d7f98f..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.Collection;
-import java.util.Enumeration;
-
-class DefaultClassloaderRef implements ClassloaderRef {
-  private final Mask mask;
-  private final ClassLoader classloader;
-
-  DefaultClassloaderRef(ClassLoader classloader, Mask mask) {
-    this.classloader = classloader;
-    this.mask = mask;
-  }
-
-  @Override
-  public Class loadClassIfPresent(String classname) {
-    if (mask.acceptClass(classname)) {
-      try {
-        return classloader.loadClass(classname);
-      } catch (ClassNotFoundException ignored) {
-        // excepted behavior. Return null if class does not exist in this classloader
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public URL loadResourceIfPresent(String name) {
-    if (mask.acceptResource(name)) {
-      return classloader.getResource(name);
-    }
-    return null;
-  }
-
-  @Override
-  public void loadResources(String name, Collection<URL> appendTo) {
-    if (mask.acceptResource(name)) {
-      try {
-        Enumeration<URL> resources = classloader.getResources(name);
-        while (resources.hasMoreElements()) {
-          appendTo.add(resources.nextElement());
-        }
-      } catch (IOException e) {
-        throw new IllegalStateException(String.format("Fail to load resources named '%s'", name), e);
-      }
-    }
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/Mask.java b/sonar-core/src/main/java/org/sonar/classloader/Mask.java
deleted file mode 100644 (file)
index 6d40f52..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import javax.annotation.Nullable;
-
-/**
- * A mask restricts access of a classloader to resources through inclusion and exclusion patterns.
- * By default all resources/classes are visible.
- * <p/>
- * Format of inclusion/exclusion patterns is the file path separated by slashes, for example
- * "org/foo/Bar.class" or "org/foo/config.xml". Wildcard patterns are not supported. Directories must end with
- * slash, for example "org/foo/" for excluding package org.foo and its sub-packages. Add the
- * exclusion "/" to exclude everything.
- *
- * @since 0.1
- */
-public class Mask {
-
-  private static final String ROOT = "/";
-
-  /**
-   * Accepts everything
-   *
-   * @since 1.1
-   */
-  public static final Mask ALL = Mask.builder().build();
-
-  /**
-   * Accepts nothing
-   *
-   * @since 1.1
-   */
-  public static final Mask NONE = Mask.builder().exclude(ROOT).build();
-
-  private final Set<String> inclusions;
-  private final Set<String> exclusions;
-
-  private Mask(Builder builder) {
-    this.inclusions = Collections.unmodifiableSet(builder.inclusions);
-    this.exclusions = Collections.unmodifiableSet(builder.exclusions);
-  }
-
-  /**
-   * Create a {@link Builder} for building immutable instances of {@link Mask}
-   *
-   * @since 1.1
-   */
-  public static Builder builder() {
-    return new Builder();
-  }
-
-  public Set<String> getInclusions() {
-    return inclusions;
-  }
-
-  public Set<String> getExclusions() {
-    return exclusions;
-  }
-
-  boolean acceptClass(String classname) {
-    if (inclusions.isEmpty() && exclusions.isEmpty()) {
-      return true;
-    }
-    return acceptResource(classToResource(classname));
-  }
-
-  boolean acceptResource(String name) {
-    boolean ok = true;
-    if (!inclusions.isEmpty()) {
-      ok = false;
-      for (String include : inclusions) {
-        if (matchPattern(name, include)) {
-          ok = true;
-          break;
-        }
-      }
-    }
-    if (ok) {
-      for (String exclude : exclusions) {
-        if (matchPattern(name, exclude)) {
-          ok = false;
-          break;
-        }
-      }
-    }
-    return ok;
-  }
-
-  private static boolean matchPattern(String name, String pattern) {
-    return pattern.equals(ROOT) || (pattern.endsWith("/") && name.startsWith(pattern)) || pattern.equals(name);
-  }
-
-  private static String classToResource(String classname) {
-    return classname.replace('.', '/') + ".class";
-  }
-
-
-  public static class Builder {
-    private final Set<String> inclusions = new HashSet<>();
-    private final Set<String> exclusions = new HashSet<>();
-
-    private Builder() {
-    }
-
-    public Builder include(String path, String... others) {
-      doInclude(path);
-      for (String other : others) {
-        doInclude(other);
-      }
-      return this;
-    }
-
-    public Builder exclude(String path, String... others) {
-      doExclude(path);
-      for (String other : others) {
-        doExclude(other);
-      }
-      return this;
-    }
-
-    public Builder copy(Mask with) {
-      this.inclusions.addAll(with.inclusions);
-      this.exclusions.addAll(with.exclusions);
-      return this;
-    }
-
-    public Builder merge(Mask with) {
-      List<String> lowestIncludes = new ArrayList<>();
-
-      if (inclusions.isEmpty()) {
-        lowestIncludes.addAll(with.inclusions);
-      } else if (with.inclusions.isEmpty()) {
-        lowestIncludes.addAll(inclusions);
-      } else {
-        for (String include : inclusions) {
-          for (String fromInclude : with.inclusions) {
-            overlappingInclude(include, fromInclude)
-              .ifPresent(lowestIncludes::add);
-          }
-        }
-      }
-      inclusions.clear();
-      inclusions.addAll(lowestIncludes);
-      exclusions.addAll(with.exclusions);
-      return this;
-    }
-
-    private static Optional<String> overlappingInclude(String include, String fromInclude) {
-      if (fromInclude.equals(include)) {
-        return Optional.of(fromInclude);
-      } else if (fromInclude.startsWith(include)) {
-        return Optional.of(fromInclude);
-      } else if (include.startsWith(fromInclude)) {
-        return Optional.of(include);
-      }
-      return Optional.empty();
-    }
-
-    public Mask build() {
-      return new Mask(this);
-    }
-
-    private void doInclude(@Nullable String path) {
-      this.inclusions.add(validatePath(path));
-    }
-
-    private void doExclude(@Nullable String path) {
-      this.exclusions.add(validatePath(path));
-    }
-
-    private static String validatePath(@Nullable String path) {
-      if (path == null) {
-        throw new IllegalArgumentException("Mask path must not be null");
-      }
-      if (path.startsWith("/") && path.length() > 1) {
-        throw new IllegalArgumentException("Mask path must not start with slash: ");
-      }
-      if (path.contains("*")) {
-        throw new IllegalArgumentException("Mask path is not a wildcard pattern and should not contain star characters (*): " + path);
-      }
-      return path;
-    }
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/NullClassloaderRef.java b/sonar-core/src/main/java/org/sonar/classloader/NullClassloaderRef.java
deleted file mode 100644 (file)
index 1f8fe7c..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.net.URL;
-import java.util.Collection;
-
-class NullClassloaderRef implements ClassloaderRef {
-
-  public static final NullClassloaderRef INSTANCE = new NullClassloaderRef();
-
-  private NullClassloaderRef() {
-  }
-
-  @Override
-  public Class loadClassIfPresent(String classname) {
-    return null;
-  }
-
-  @Override
-  public URL loadResourceIfPresent(String name) {
-    return null;
-  }
-
-  @Override
-  public void loadResources(String name, Collection<URL> appendTo) {
-    // do nothing
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/ParentFirstStrategy.java b/sonar-core/src/main/java/org/sonar/classloader/ParentFirstStrategy.java
deleted file mode 100644 (file)
index a322f82..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.net.URL;
-import java.util.Collection;
-
-class ParentFirstStrategy implements Strategy {
-  static final Strategy INSTANCE = new ParentFirstStrategy();
-
-  private ParentFirstStrategy() {
-  }
-
-  @Override
-  public Class<?> loadClass(StrategyContext context, String name) throws ClassNotFoundException {
-    Class<?> clazz = context.loadClassFromSiblings(name);
-    if (clazz == null) {
-      clazz = context.loadClassFromParent(name);
-      if (clazz == null) {
-        clazz = context.loadClassFromSelf(name);
-        if (clazz == null) {
-          throw new ClassNotFoundException(name);
-        }
-      }
-    }
-    return clazz;
-  }
-
-  @Override
-  public URL getResource(StrategyContext context, String name) {
-    URL url = context.loadResourceFromSiblings(name);
-    if (url == null) {
-      url = context.loadResourceFromParent(name);
-      if (url == null) {
-        url = context.loadResourceFromSelf(name);
-      }
-    }
-    return url;
-  }
-
-  @Override
-  public void getResources(StrategyContext context, String name, Collection<URL> appendTo) {
-    context.loadResourcesFromSiblings(name, appendTo);
-    context.loadResourcesFromParent(name, appendTo);
-    context.loadResourcesFromSelf(name, appendTo);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/SelfFirstStrategy.java b/sonar-core/src/main/java/org/sonar/classloader/SelfFirstStrategy.java
deleted file mode 100644 (file)
index 48bbb94..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.net.URL;
-import java.util.Collection;
-
-class SelfFirstStrategy implements Strategy {
-
-  static final SelfFirstStrategy INSTANCE = new SelfFirstStrategy();
-
-  private SelfFirstStrategy() {
-    // singleton instance
-  }
-
-  @Override
-  public Class<?> loadClass(StrategyContext context, String name) throws ClassNotFoundException {
-    Class<?> clazz = context.loadClassFromSiblings(name);
-    if (clazz == null) {
-      clazz = context.loadClassFromSelf(name);
-      if (clazz == null) {
-        clazz = context.loadClassFromParent(name);
-        if (clazz == null) {
-          throw new ClassNotFoundException(name);
-        }
-      }
-    }
-    return clazz;
-  }
-
-  @Override
-  public URL getResource(StrategyContext context, String name) {
-    URL url = context.loadResourceFromSiblings(name);
-    if (url == null) {
-      url = context.loadResourceFromSelf(name);
-      if (url == null) {
-        url = context.loadResourceFromParent(name);
-      }
-    }
-    return url;
-  }
-
-  @Override
-  public void getResources(StrategyContext context, String name, Collection<URL> appendTo) {
-    context.loadResourcesFromSiblings(name, appendTo);
-    context.loadResourcesFromSelf(name, appendTo);
-    context.loadResourcesFromParent(name, appendTo);
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/Strategy.java b/sonar-core/src/main/java/org/sonar/classloader/Strategy.java
deleted file mode 100644 (file)
index 39904ce..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.net.URL;
-import java.util.Collection;
-import javax.annotation.CheckForNull;
-
-interface Strategy {
-
-  Class<?> loadClass(StrategyContext context, String name) throws ClassNotFoundException;
-
-  @CheckForNull
-  URL getResource(StrategyContext context, String name);
-
-  void getResources(StrategyContext context, String name, Collection<URL> urls);
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/StrategyContext.java b/sonar-core/src/main/java/org/sonar/classloader/StrategyContext.java
deleted file mode 100644 (file)
index 23e705b..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.net.URL;
-import java.util.Collection;
-import javax.annotation.CheckForNull;
-
-interface StrategyContext {
-
-  @CheckForNull
-  Class<?> loadClassFromSiblings(String name);
-
-  @CheckForNull
-  Class<?> loadClassFromSelf(String name);
-
-  @CheckForNull
-  Class<?> loadClassFromParent(String name);
-
-  @CheckForNull
-  URL loadResourceFromSiblings(String name);
-
-  @CheckForNull
-  URL loadResourceFromSelf(String name);
-
-  @CheckForNull
-  URL loadResourceFromParent(String name);
-
-  void loadResourcesFromSiblings(String name, Collection<URL> appendTo);
-
-  void loadResourcesFromSelf(String name, Collection<URL> appendTo);
-
-  void loadResourcesFromParent(String name, Collection<URL> appendTo);
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/classloader/package-info.java b/sonar-core/src/main/java/org/sonar/classloader/package-info.java
deleted file mode 100644 (file)
index a99d9c6..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.classloader;
-
-import javax.annotation.ParametersAreNonnullByDefault;
-
index 9952a5fe1a3e8796425df59b6b79bfd13e75a235..8096cd012dba35012e40858c13676f0e55d623bc 100644 (file)
@@ -52,7 +52,6 @@ public class PluginClassLoader {
   private static final Version COMPATIBILITY_MODE_MAX_VERSION = Version.create("5.2");
 
   private final PluginClassloaderFactory classloaderFactory;
-  private final Map<PluginClassLoaderDef, ClassLoader> classLoaders = new HashMap<>();
 
   public PluginClassLoader(PluginClassloaderFactory classloaderFactory) {
     this.classloaderFactory = classloaderFactory;
@@ -64,9 +63,8 @@ public class PluginClassLoader {
 
   public Map<String, Plugin> load(Map<String, ExplodedPlugin> pluginsByKey) {
     Collection<PluginClassLoaderDef> defs = defineClassloaders(pluginsByKey);
-    Map<PluginClassLoaderDef, ClassLoader> newClassloaders = classloaderFactory.create(classLoaders, defs);
-    classLoaders.putAll(newClassloaders);
-    return instantiatePluginClasses(newClassloaders);
+    Map<PluginClassLoaderDef, ClassLoader> classloaders = classloaderFactory.create(defs);
+    return instantiatePluginClasses(classloaders);
   }
 
   /**
@@ -90,22 +88,20 @@ public class PluginClassLoader {
       def.addMainClass(info.getKey(), info.getMainClass());
 
       for (String defaultSharedResource : DEFAULT_SHARED_RESOURCES) {
-        def.getExportMask().include(String.format("%s/%s/api/", defaultSharedResource, info.getKey()));
+        def.getExportMask().addInclusion(String.format("%s/%s/api/", defaultSharedResource, info.getKey()));
       }
 
       // The plugins that extend other plugins can only add some files to classloader.
       // They can't change metadata like ordering strategy or compatibility mode.
       if (Strings.isNullOrEmpty(info.getBasePlugin())) {
         if (info.isUseChildFirstClassLoader()) {
-          LoggerFactory.getLogger(getClass()).warn("Plugin {} [{}] uses a child first classloader which is deprecated", info.getName(),
-            info.getKey());
+          LoggerFactory.getLogger(getClass()).warn("Plugin {} [{}] uses a child first classloader which is deprecated", info.getName(), info.getKey());
         }
         def.setSelfFirstStrategy(info.isUseChildFirstClassLoader());
         Version minSonarPluginApiVersion = info.getMinimalSonarPluginApiVersion();
         boolean compatibilityMode = minSonarPluginApiVersion != null && minSonarPluginApiVersion.compareToIgnoreQualifier(COMPATIBILITY_MODE_MAX_VERSION) < 0;
         if (compatibilityMode) {
-          LoggerFactory.getLogger(getClass()).warn("API compatibility mode is no longer supported. In case of error, plugin {} [{}] " +
-              "should package its dependencies.",
+          LoggerFactory.getLogger(getClass()).warn("API compatibility mode is no longer supported. In case of error, plugin {} [{}] should package its dependencies.",
             info.getName(), info.getKey());
         }
       }
index bb99e5fd17fb6e30428caef4055199427f62752a..9d581daeebd5b109ea47fd76e62824fc966db111 100644 (file)
@@ -33,12 +33,12 @@ import org.sonar.classloader.Mask;
 /**
  * Temporary information about the classLoader to be created for a plugin (or a group of plugins).
  */
-public class PluginClassLoaderDef {
+class PluginClassLoaderDef {
 
   private final String basePluginKey;
   private final Map<String, String> mainClassesByPluginKey = new HashMap<>();
   private final List<File> files = new ArrayList<>();
-  private final Mask.Builder mask = Mask.builder();
+  private final Mask mask = new Mask();
   private boolean selfFirstStrategy = false;
 
   PluginClassLoaderDef(String basePluginKey) {
@@ -58,7 +58,7 @@ public class PluginClassLoaderDef {
     this.files.addAll(f);
   }
 
-  Mask.Builder getExportMask() {
+  Mask getExportMask() {
     return mask;
   }
 
index 1647bbfde10c0a8485bf608b53525dce42e0d253..8205f78a9b5a4b680cb8cff53deb14fa73af400d 100644 (file)
@@ -24,10 +24,9 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
-import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.scanner.ScannerSide;
+import org.sonar.api.ce.ComputeEngineSide;
 import org.sonar.api.server.ServerSide;
 import org.sonar.classloader.ClassloaderBuilder;
 import org.sonar.classloader.Mask;
@@ -54,41 +53,35 @@ public class PluginClassloaderFactory {
   /**
    * Creates as many classloaders as requested by the input parameter.
    */
-  public Map<PluginClassLoaderDef, ClassLoader> create(Map<PluginClassLoaderDef, ClassLoader> previouslyCreatedClassloaders,
-    Collection<PluginClassLoaderDef> newDefs) {
+  public Map<PluginClassLoaderDef, ClassLoader> create(Collection<PluginClassLoaderDef> defs) {
     ClassLoader baseClassLoader = baseClassLoader();
 
-    Collection<PluginClassLoaderDef> allDefs = new HashSet<>();
-    allDefs.addAll(newDefs);
-    allDefs.addAll(previouslyCreatedClassloaders.keySet());
-
-    ClassloaderBuilder builder = new ClassloaderBuilder(previouslyCreatedClassloaders.values());
+    ClassloaderBuilder builder = new ClassloaderBuilder();
     builder.newClassloader(API_CLASSLOADER_KEY, baseClassLoader);
     builder.setMask(API_CLASSLOADER_KEY, apiMask());
 
-    for (PluginClassLoaderDef def : newDefs) {
+    for (PluginClassLoaderDef def : defs) {
       builder.newClassloader(def.getBasePluginKey());
-      builder.setParent(def.getBasePluginKey(), API_CLASSLOADER_KEY, Mask.ALL);
+      builder.setParent(def.getBasePluginKey(), API_CLASSLOADER_KEY, new Mask());
       builder.setLoadingOrder(def.getBasePluginKey(), def.isSelfFirstStrategy() ? SELF_FIRST : PARENT_FIRST);
       for (File jar : def.getFiles()) {
         builder.addURL(def.getBasePluginKey(), fileToUrl(jar));
       }
-      exportResources(def, builder, allDefs);
+      exportResources(def, builder, defs);
     }
 
-    return build(newDefs, builder);
+    return build(defs, builder);
   }
 
   /**
    * A plugin can export some resources to other plugins
    */
-  private static void exportResources(PluginClassLoaderDef newDef, ClassloaderBuilder builder,
-    Collection<PluginClassLoaderDef> allPlugins) {
+  private static void exportResources(PluginClassLoaderDef def, ClassloaderBuilder builder, Collection<PluginClassLoaderDef> allPlugins) {
     // export the resources to all other plugins
-    builder.setExportMask(newDef.getBasePluginKey(), newDef.getExportMask().build());
+    builder.setExportMask(def.getBasePluginKey(), def.getExportMask());
     for (PluginClassLoaderDef other : allPlugins) {
-      if (!other.getBasePluginKey().equals(newDef.getBasePluginKey())) {
-        builder.addSibling(newDef.getBasePluginKey(), other.getBasePluginKey(), Mask.ALL);
+      if (!other.getBasePluginKey().equals(def.getBasePluginKey())) {
+        builder.addSibling(def.getBasePluginKey(), other.getBasePluginKey(), new Mask());
       }
     }
   }
@@ -128,30 +121,29 @@ public class PluginClassloaderFactory {
    * a transitive dependency of sonar-plugin-api</p>
    */
   private static Mask apiMask() {
-    return Mask.builder()
-      .include("org/sonar/api/",
-        "org/sonar/check/",
-        "org/codehaus/stax2/",
-        "org/codehaus/staxmate/",
-        "com/ctc/wstx/",
-        "org/slf4j/",
+    return new Mask()
+      .addInclusion("org/sonar/api/")
+      .addInclusion("org/sonar/check/")
+      .addInclusion("org/codehaus/stax2/")
+      .addInclusion("org/codehaus/staxmate/")
+      .addInclusion("com/ctc/wstx/")
+      .addInclusion("org/slf4j/")
 
-        // SLF4J bridges. Do not let plugins re-initialize and configure their logging system
-        "org/apache/commons/logging/",
-        "org/apache/log4j/",
-        "ch/qos/logback/",
+      // SLF4J bridges. Do not let plugins re-initialize and configure their logging system
+      .addInclusion("org/apache/commons/logging/")
+      .addInclusion("org/apache/log4j/")
+      .addInclusion("ch/qos/logback/")
 
-        // Exposed by org.sonar.api.server.authentication.IdentityProvider
-        "javax/servlet/",
+      // Exposed by org.sonar.api.server.authentication.IdentityProvider
+      .addInclusion("javax/servlet/")
 
-        // required for some internal SonarSource plugins (billing, orchestrator, ...)
-        "org/sonar/server/platform/",
+      // required for some internal SonarSource plugins (billing, orchestrator, ...)
+      .addInclusion("org/sonar/server/platform/")
 
-        // required for commercial plugins at SonarSource
-        "com/sonarsource/plugins/license/api/")
+      // required for commercial plugins at SonarSource
+      .addInclusion("com/sonarsource/plugins/license/api/")
 
       // API exclusions
-      .exclude("org/sonar/api/internal/")
-      .build();
+      .addExclusion("org/sonar/api/internal/");
   }
 }
diff --git a/sonar-core/src/test/java/org/sonar/classloader/ClassloaderBuilderTest.java b/sonar-core/src/test/java/org/sonar/classloader/ClassloaderBuilderTest.java
deleted file mode 100644 (file)
index 93945be..0000000
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import java.io.File;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.io.IOUtils;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-
-public class ClassloaderBuilderTest {
-
-  ClassloaderBuilder sut = new ClassloaderBuilder();
-
-  @Test
-  public void minimal_system_classloader() throws Exception {
-    // create a classloader based on system classloader
-    // -> access only to JRE
-    Map<String, ClassLoader> classloaders = sut.newClassloader("example").build();
-
-    assertThat(classloaders).hasSize(1);
-    ClassLoader classloader = classloaders.get("example");
-    assertThat(classloader).hasToString("ClassRealm{example}");
-    assertThat(canLoadClass(classloader, HashMap.class.getName())).isTrue();
-    assertThat(canLoadClass(classloader, Test.class.getName())).isFalse();
-    assertThat(canLoadClass(classloader, "A")).isFalse();
-    assertThat(canLoadResource(classloader, "a.txt")).isFalse();
-  }
-
-  @Test
-  public void previous_classloader_not_returned_again() throws Exception {
-    Map<String, ClassLoader> classloaders1 = sut.newClassloader("example1").build();
-    Map<String, ClassLoader> classloaders2 = new ClassloaderBuilder(classloaders1.values())
-      .newClassloader("example2").build();
-
-    assertThat(classloaders2).containsOnlyKeys("example2");
-  }
-
-  @Test
-  public void fail_if_setting_attribute_to_previously_loaded_classloader() throws Exception {
-    Map<String, ClassLoader> classloaders1 = sut.newClassloader("example1").build();
-    ClassloaderBuilder builder = new ClassloaderBuilder(classloaders1.values())
-      .newClassloader("example2");
-
-    try {
-      builder.setMask("example1", Mask.ALL);
-      fail();
-    } catch (IllegalStateException e) {
-      // ok
-    }
-  }
-
-  /**
-   * Classloader based on another one (the junit env in this example). No parent-child hierarchy.
-   */
-  @Test
-  public void base_classloader() throws Exception {
-    //
-    Map<String, ClassLoader> classloaders = sut.newClassloader("example", getClass().getClassLoader()).build();
-
-    assertThat(classloaders).hasSize(1);
-    ClassLoader classloader = classloaders.get("example");
-    assertThat(canLoadClass(classloader, HashMap.class.getName())).isTrue();
-    assertThat(canLoadClass(classloader, Test.class.getName())).isTrue();
-    assertThat(canLoadClass(classloader, "A")).isFalse();
-    assertThat(canLoadResource(classloader, "a.txt")).isFalse();
-  }
-
-  @Test
-  public void classloader_constituents() throws Exception {
-    Map<String, ClassLoader> classloaders = sut
-      .newClassloader("the-cl")
-      .addURL("the-cl", new File("tester/a.jar").toURL())
-      .addURL("the-cl", new File("tester/b.jar").toURL())
-      .build();
-
-    assertThat(classloaders).hasSize(1);
-    ClassLoader self = classloaders.get("the-cl");
-    assertThat(canLoadClass(self, "A")).isTrue();
-    assertThat(canLoadResource(self, "a.txt")).isTrue();
-    assertThat(canLoadClass(self, "B")).isTrue();
-    assertThat(canLoadResource(self, "b.txt")).isTrue();
-    assertThat(canLoadClass(self, "C")).isFalse();
-    assertThat(canLoadResource(self, "c.txt")).isFalse();
-  }
-
-  /**
-   * Parent -> child -> grand-child classloaders. Default order strategy is parent-first
-   */
-  @Test
-  public void parent_child_relation() throws Exception {
-    // parent contains class A -> access to only A
-    // child contains class B -> access to A and B
-    // grand-child contains class C -> access to A, B and C
-    Map<String, ClassLoader> classloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-
-      // order of declaration is not important -> declare grand-child before child
-      .newClassloader("the-grand-child")
-      .addURL("the-grand-child", new File("tester/c.jar").toURL())
-      .setParent("the-grand-child", "the-child", Mask.ALL)
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/b.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.ALL)
-
-      .build();
-
-    assertThat(classloaders).hasSize(3);
-
-    ClassLoader parent = classloaders.get("the-parent");
-    assertThat(canLoadClass(parent, "A")).isTrue();
-    assertThat(canLoadClass(parent, "B")).isFalse();
-    assertThat(canLoadClass(parent, "C")).isFalse();
-    assertThat(canLoadResource(parent, "a.txt")).isTrue();
-    assertThat(canLoadResource(parent, "b.txt")).isFalse();
-    assertThat(canLoadResource(parent, "c.txt")).isFalse();
-
-    ClassLoader child = classloaders.get("the-child");
-    assertThat(canLoadClass(child, "A")).isTrue();
-    assertThat(canLoadClass(child, "B")).isTrue();
-    assertThat(canLoadClass(child, "C")).isFalse();
-    assertThat(canLoadResource(child, "a.txt")).isTrue();
-    assertThat(canLoadResource(child, "b.txt")).isTrue();
-    assertThat(canLoadResource(child, "c.txt")).isFalse();
-
-    ClassLoader grandChild = classloaders.get("the-grand-child");
-    assertThat(canLoadClass(grandChild, "A")).isTrue();
-    assertThat(canLoadClass(grandChild, "B")).isTrue();
-    assertThat(canLoadClass(grandChild, "C")).isTrue();
-    assertThat(canLoadResource(grandChild, "a.txt")).isTrue();
-    assertThat(canLoadResource(grandChild, "b.txt")).isTrue();
-    assertThat(canLoadResource(grandChild, "c.txt")).isTrue();
-  }
-
-  /**
-   * Parent classloader can be created outside {@link ClassloaderBuilder}.
-   * Default ordering strategy is parent-first.
-   */
-  @Test
-  public void existing_parent() throws Exception {
-    // parent contains JUnit
-    // child contains class A -> access to A and JUnit
-    ClassLoader parent = getClass().getClassLoader();
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/a.jar").toURL())
-      .setParent("the-child", parent, Mask.ALL)
-      .build();
-
-    assertThat(newClassloaders).hasSize(1);
-    assertThat(canLoadClass(parent, Test.class.getName())).isTrue();
-    assertThat(canLoadClass(parent, "A")).isFalse();
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, Test.class.getName())).isTrue();
-    assertThat(canLoadClass(child, "A")).isTrue();
-  }
-
-  @Test
-  public void parent_first_ordering() throws Exception {
-    // parent contains version 1 of A
-    // child contains version 2 of A
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/a_v2.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.ALL)
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-parent");
-    assertThat(canLoadMethod(parent, "A", "version1")).isTrue();
-    assertThat(canLoadMethod(parent, "A", "version2")).isFalse();
-    assertThat(IOUtils.toString(parent.getResource("a.txt"))).startsWith("version 1 of a.txt");
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadMethod(child, "A", "version1")).isTrue();
-    assertThat(canLoadMethod(child, "A", "version2")).isFalse();
-    assertThat(IOUtils.toString(child.getResource("a.txt"))).startsWith("version 1 of a.txt");
-  }
-
-  /**
-   * - parent contains B and version 1 of A
-   * - child contains version 2 of A -> sees B and version 2 of A
-   */
-  @Test
-  public void self_first_ordering() throws Exception {
-
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-      .addURL("the-parent", new File("tester/b.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/a_v2.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.ALL)
-      .setLoadingOrder("the-child", ClassloaderBuilder.LoadingOrder.SELF_FIRST)
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-parent");
-    assertThat(canLoadMethod(parent, "A", "version1")).isTrue();
-    assertThat(canLoadMethod(parent, "A", "version2")).isFalse();
-    assertThat(IOUtils.toString(parent.getResource("a.txt"))).startsWith("version 1 of a.txt");
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, "B")).isTrue();
-    assertThat(canLoadMethod(child, "A", "version1")).isFalse();
-    assertThat(canLoadMethod(child, "A", "version2")).isTrue();
-    assertThat(IOUtils.toString(child.getResource("a.txt"))).startsWith("version 2 of a.txt");
-    assertThat(Collections.list(child.getResources("b.txt"))).hasSize(1);
-    ArrayList<URL> resources = Collections.list(child.getResources("a.txt"));
-    assertThat(resources).hasSize(2);
-    assertThat(IOUtils.toString(resources.get(0))).startsWith("version 2 of a.txt");
-    assertThat(IOUtils.toString(resources.get(1))).startsWith("version 1 of a.txt");
-  }
-
-  /**
-   * Prevent a classloader from loading some resources that are available in its own constituents.
-   */
-  @Test
-  public void self_mask() throws Exception {
-    Map<String, ClassLoader> classloaders = sut
-      .newClassloader("the-cl")
-      .addURL("the-cl", new File("tester/a.jar").toURL())
-      .addURL("the-cl", new File("tester/b.jar").toURL())
-      .setMask("the-cl", Mask.builder().exclude("A.class", "a.txt").build())
-      .build();
-
-    ClassLoader cl = classloaders.get("the-cl");
-    assertThat(canLoadClass(cl, "A")).isFalse();
-    assertThat(canLoadClass(cl, "B")).isTrue();
-    assertThat(canLoadResource(cl, "a.txt")).isFalse();
-    assertThat(canLoadResource(cl, "b.txt")).isTrue();
-  }
-
-  /**
-   * Partial inheritance of parent classloader
-   */
-  @Test
-  public void parent_mask() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-      .addURL("the-parent", new File("tester/b.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/c.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.builder().exclude("A.class", "a.txt").build())
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-parent");
-    assertThat(canLoadClass(parent, "A")).isTrue();
-    assertThat(canLoadClass(parent, "B")).isTrue();
-    assertThat(canLoadClass(parent, "C")).isFalse();
-    assertThat(canLoadResource(parent, "a.txt")).isTrue();
-    assertThat(canLoadResource(parent, "b.txt")).isTrue();
-    assertThat(canLoadResource(parent, "c.txt")).isFalse();
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, "A")).isFalse();
-    assertThat(canLoadClass(child, "B")).isTrue();
-    assertThat(canLoadClass(child, "C")).isTrue();
-    assertThat(canLoadResource(child, "a.txt")).isFalse();
-    assertThat(canLoadResource(child, "b.txt")).isTrue();
-    assertThat(canLoadResource(child, "c.txt")).isTrue();
-  }
-
-  /**
-   * Parent classloader contains A and B, but exports only B to its children
-   */
-  @Test
-  public void export_mask() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-      .addURL("the-parent", new File("tester/b.jar").toURL())
-      .setExportMask("the-parent", Mask.builder().exclude("A.class", "a.txt").build())
-
-      .newClassloader("the-child")
-      .setParent("the-child", "the-parent", Mask.ALL)
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-parent");
-    assertThat(canLoadClass(parent, "A")).isTrue();
-    assertThat(canLoadClass(parent, "B")).isTrue();
-    assertThat(canLoadResource(parent, "a.txt")).isTrue();
-    assertThat(canLoadResource(parent, "b.txt")).isTrue();
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, "A")).isFalse();
-    assertThat(canLoadClass(child, "B")).isTrue();
-    assertThat(canLoadResource(child, "a.txt")).isFalse();
-    assertThat(canLoadResource(child, "b.txt")).isTrue();
-  }
-
-  /**
-   * Parent classloader contains A, B and C, but exports only B and C to its children.
-   * On the other side child classloader excludes B from its parent, so it benefits
-   * only from C
-   */
-  @Test
-  public void mix_of_import_and_export_masks() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-      .addURL("the-parent", new File("tester/b.jar").toURL())
-      .addURL("the-parent", new File("tester/c.jar").toURL())
-      .setExportMask("the-parent", Mask.builder().exclude("A.class", "a.txt").build())
-
-      .newClassloader("the-child")
-      .setParent("the-child", "the-parent", Mask.builder().exclude("B.class", "b.txt").build())
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-parent");
-    assertThat(canLoadClass(parent, "A")).isTrue();
-    assertThat(canLoadClass(parent, "B")).isTrue();
-    assertThat(canLoadClass(parent, "C")).isTrue();
-    assertThat(canLoadResource(parent, "a.txt")).isTrue();
-    assertThat(canLoadResource(parent, "b.txt")).isTrue();
-    assertThat(canLoadResource(parent, "c.txt")).isTrue();
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, "A")).isFalse();
-    assertThat(canLoadClass(child, "B")).isFalse();
-    assertThat(canLoadClass(child, "C")).isTrue();
-    assertThat(canLoadResource(child, "a.txt")).isFalse();
-    assertThat(canLoadResource(child, "b.txt")).isFalse();
-    assertThat(canLoadResource(child, "c.txt")).isTrue();
-  }
-
-  @Test
-  public void fail_to_create_the_same_classloader_twice() throws Exception {
-    sut.newClassloader("the-cl");
-    try {
-      sut.newClassloader("the-cl");
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e).hasMessage("The classloader 'the-cl' already exists. Can not create it twice.");
-    }
-  }
-
-  @Test
-  public void fail_to_create_the_same_previous_classloader_twice() throws Exception {
-    Map<String, ClassLoader> classloaders1 = sut.newClassloader("the-cl").build();
-    ClassloaderBuilder classloaderBuilder = new ClassloaderBuilder(classloaders1.values());
-    try {
-      classloaderBuilder.newClassloader("the-cl");
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e).hasMessage("The classloader 'the-cl' already exists in the list of previously created classloaders. " +
-        "Can not create it twice.");
-    }
-  }
-
-  @Test
-  public void fail_if_missing_declaration() throws Exception {
-    sut.newClassloader("the-cl");
-    sut.setParent("the-cl", "missing", Mask.ALL);
-    try {
-      sut.build();
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e).hasMessage("The classloader 'missing' does not exist");
-    }
-  }
-
-  @Test
-  public void sibling() throws Exception {
-    // sibling1 contains A
-    // sibling2 contains B
-    // child contains C -> see A, B and C
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("sib1")
-      .addURL("sib1", new File("tester/a.jar").toURL())
-
-      .newClassloader("sib2")
-      .addURL("sib2", new File("tester/b.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/c.jar").toURL())
-      .addSibling("the-child", "sib1", Mask.ALL)
-      .addSibling("the-child", "sib2", Mask.ALL)
-      .build();
-
-    ClassLoader sib1 = newClassloaders.get("sib1");
-    assertThat(canLoadClass(sib1, "A")).isTrue();
-    assertThat(canLoadClass(sib1, "B")).isFalse();
-    assertThat(canLoadClass(sib1, "C")).isFalse();
-    assertThat(canLoadResource(sib1, "a.txt")).isTrue();
-    assertThat(canLoadResource(sib1, "b.txt")).isFalse();
-    assertThat(canLoadResource(sib1, "c.txt")).isFalse();
-
-    ClassLoader sib2 = newClassloaders.get("sib2");
-    assertThat(canLoadClass(sib2, "A")).isFalse();
-    assertThat(canLoadClass(sib2, "B")).isTrue();
-    assertThat(canLoadClass(sib2, "C")).isFalse();
-    assertThat(canLoadResource(sib2, "a.txt")).isFalse();
-    assertThat(canLoadResource(sib2, "b.txt")).isTrue();
-    assertThat(canLoadResource(sib2, "c.txt")).isFalse();
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, "A")).isTrue();
-    assertThat(canLoadClass(child, "B")).isTrue();
-    assertThat(canLoadClass(child, "C")).isTrue();
-    assertThat(canLoadResource(child, "a.txt")).isTrue();
-    assertThat(canLoadResource(child, "b.txt")).isTrue();
-    assertThat(canLoadResource(child, "c.txt")).isTrue();
-  }
-
-  /**
-   * Sibling classloader can be created outside {@link ClassloaderBuilder}.
-   */
-  @Test
-  public void existing_sibling() throws Exception {
-    // sibling1 contains JUnit
-    // child contains A -> see JUnit and A
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/a.jar").toURL())
-      .addSibling("the-child", getClass().getClassLoader(), Mask.ALL)
-      .build();
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, Test.class.getName())).isTrue();
-    assertThat(canLoadClass(child, "A")).isTrue();
-  }
-
-  /**
-   * - sibling contains A and B
-   * - child contains C and excludes A from sibling -> sees only B and C
-   */
-  @Test
-  public void sibling_mask() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("sib1")
-      .addURL("sib1", new File("tester/a.jar").toURL())
-      .addURL("sib1", new File("tester/b.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/c.jar").toURL())
-      .addSibling("the-child", "sib1", Mask.builder().exclude("A.class", "a.txt").build())
-      .build();
-
-    ClassLoader sib1 = newClassloaders.get("sib1");
-    assertThat(canLoadClass(sib1, "A")).isTrue();
-    assertThat(canLoadClass(sib1, "B")).isTrue();
-    assertThat(canLoadResource(sib1, "a.txt")).isTrue();
-    assertThat(canLoadResource(sib1, "b.txt")).isTrue();
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, "A")).isFalse();
-    assertThat(canLoadClass(child, "B")).isTrue();
-    assertThat(canLoadClass(child, "C")).isTrue();
-    assertThat(canLoadResource(child, "a.txt")).isFalse();
-    assertThat(canLoadResource(child, "b.txt")).isTrue();
-    assertThat(canLoadResource(child, "c.txt")).isTrue();
-    assertThat(Collections.list(child.getResources("a.txt"))).isEmpty();
-    assertThat(Collections.list(child.getResources("b.txt"))).hasSize(1);
-    assertThat(Collections.list(child.getResources("c.txt"))).hasSize(1);
-  }
-
-  /**
-   * - sibling contains A and B but exports only B
-   * - child contains C -> sees only B and C
-   */
-  @Test
-  public void sibling_export_mask() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("sib1")
-      .addURL("sib1", new File("tester/a.jar").toURL())
-      .addURL("sib1", new File("tester/b.jar").toURL())
-      .setExportMask("sib1", Mask.builder().include("B.class", "b.txt").build())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/c.jar").toURL())
-      .addSibling("the-child", "sib1", Mask.ALL)
-      .build();
-
-    ClassLoader sib1 = newClassloaders.get("sib1");
-    assertThat(canLoadClass(sib1, "A")).isTrue();
-    assertThat(canLoadClass(sib1, "B")).isTrue();
-    assertThat(canLoadResource(sib1, "a.txt")).isTrue();
-    assertThat(canLoadResource(sib1, "b.txt")).isTrue();
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(canLoadClass(child, "A")).isFalse();
-    assertThat(canLoadClass(child, "B")).isTrue();
-    assertThat(canLoadClass(child, "C")).isTrue();
-    assertThat(canLoadResource(child, "a.txt")).isFalse();
-    assertThat(canLoadResource(child, "b.txt")).isTrue();
-    assertThat(canLoadResource(child, "c.txt")).isTrue();
-    assertThat(Collections.list(child.getResources("a.txt"))).isEmpty();
-    assertThat(Collections.list(child.getResources("b.txt"))).hasSize(1);
-    assertThat(Collections.list(child.getResources("c.txt"))).hasSize(1);
-  }
-
-  /**
-   * Sibling classloader is loaded previously self:
-   * - sibling has version 1 of A
-   * - self has version 2 of A -> sees version 1
-   */
-  @Test
-  public void sibling_prevails_over_self() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("sib")
-      .addURL("sib", new File("tester/a.jar").toURL())
-
-      .newClassloader("self")
-      .addURL("self", new File("tester/a_v2.jar").toURL())
-      .addSibling("self", "sib", Mask.ALL)
-      .build();
-
-    ClassLoader sib = newClassloaders.get("sib");
-    assertThat(canLoadMethod(sib, "A", "version1")).isTrue();
-    assertThat(canLoadMethod(sib, "A", "version2")).isFalse();
-    assertThat(IOUtils.toString(sib.getResource("a.txt"))).startsWith("version 1 of a.txt");
-
-    ClassLoader self = newClassloaders.get("self");
-    assertThat(canLoadMethod(self, "A", "version1")).isTrue();
-    assertThat(canLoadMethod(self, "A", "version2")).isFalse();
-    assertThat(IOUtils.toString(self.getResource("a.txt"))).startsWith("version 1 of a.txt");
-  }
-
-  /**
-   * Sibling classloader is always loaded previously self, even if self-first strategy:
-   * - sibling has version 1 of A
-   * - self has version 2 of A -> sees version 1
-   */
-  @Test
-  public void sibling_prevails_over_self_even_if_self_first() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("sib")
-      .addURL("sib", new File("tester/a.jar").toURL())
-
-      .newClassloader("self")
-      .addURL("self", new File("tester/a_v2.jar").toURL())
-      .addSibling("self", "sib", Mask.ALL)
-      .setLoadingOrder("self", ClassloaderBuilder.LoadingOrder.SELF_FIRST)
-      .build();
-
-    ClassLoader sib = newClassloaders.get("sib");
-    assertThat(canLoadMethod(sib, "A", "version1")).isTrue();
-    assertThat(canLoadMethod(sib, "A", "version2")).isFalse();
-    assertThat(IOUtils.toString(sib.getResource("a.txt"))).startsWith("version 1 of a.txt");
-
-    ClassLoader self = newClassloaders.get("self");
-    assertThat(canLoadMethod(self, "A", "version1")).isTrue();
-    assertThat(canLoadMethod(self, "A", "version2")).isFalse();
-    assertThat(IOUtils.toString(self.getResource("a.txt"))).startsWith("version 1 of a.txt");
-  }
-
-  /**
-   * https://github.com/SonarSource/sonar-classloader/issues/1
-   */
-  @Test
-  public void cycle_of_siblings() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("a")
-      .addURL("a", new File("tester/a.jar").toURL())
-
-      .newClassloader("b")
-      .addURL("b", new File("tester/b.jar").toURL())
-      .addSibling("a", "b", Mask.builder().include("B.class", "b.txt").build())
-      .addSibling("b", "a", Mask.builder().include("A.class", "a.txt").build())
-      .build();
-
-    ClassLoader a = newClassloaders.get("a");
-    assertThat(canLoadClass(a, "A")).isTrue();
-    assertThat(canLoadClass(a, "B")).isTrue();
-    assertThat(IOUtils.toString(a.getResource("a.txt"))).isNotEmpty();
-    assertThat(IOUtils.toString(a.getResource("b.txt"))).isNotEmpty();
-
-    ClassLoader b = newClassloaders.get("b");
-    assertThat(canLoadClass(b, "A")).isTrue();
-    assertThat(canLoadClass(b, "B")).isTrue();
-    assertThat(IOUtils.toString(b.getResource("a.txt"))).isNotEmpty();
-    assertThat(IOUtils.toString(b.getResource("b.txt"))).isNotEmpty();
-  }
-
-  @Test
-  public void getResources_from_parent_and_siblings() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-
-      .newClassloader("the-sib")
-      .addURL("the-sib", new File("tester/b.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/c.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.ALL)
-      .addSibling("the-child", "the-sib", Mask.ALL)
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-parent");
-    assertThat(Collections.list(parent.getResources("a.txt"))).hasSize(1);
-    assertThat(Collections.list(parent.getResources("b.txt"))).isEmpty();
-    assertThat(Collections.list(parent.getResources("c.txt"))).isEmpty();
-
-    ClassLoader child = newClassloaders.get("the-child");
-    assertThat(Collections.list(child.getResources("a.txt"))).hasSize(1);
-    assertThat(Collections.list(child.getResources("b.txt"))).hasSize(1);
-    assertThat(Collections.list(child.getResources("c.txt"))).hasSize(1);
-  }
-
-  @Test
-  public void getResources_from_previously_loaded_parent() throws Exception {
-    Map<String, ClassLoader> classloaders1 = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-      .build();
-
-
-    Map<String, ClassLoader> classloaders2 = new ClassloaderBuilder(classloaders1.values())
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/b.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.ALL)
-      .build();
-
-    ClassLoader parent = classloaders1.get("the-parent");
-    assertThat(Collections.list(parent.getResources("a.txt"))).hasSize(1);
-    assertThat(Collections.list(parent.getResources("b.txt"))).isEmpty();
-
-    ClassLoader child = classloaders2.get("the-child");
-    assertThat(Collections.list(child.getResources("a.txt"))).hasSize(1);
-    assertThat(Collections.list(child.getResources("b.txt"))).hasSize(1);
-  }
-
-  @Test
-  public void getResources_from_previously_loaded_sibling_based_on_export_mask() throws Exception {
-    Map<String, ClassLoader> classloaders1 = sut
-      .newClassloader("the-sib")
-      .addURL("the-sib", new File("tester/a.jar").toURL())
-      .setExportMask("the-sib", Mask.builder().include("A.java").build())
-      .build();
-
-    Map<String, ClassLoader> classloaders2 = new ClassloaderBuilder(classloaders1.values())
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/b.jar").toURL())
-      .addSibling("the-child", "the-sib", Mask.ALL)
-      .build();
-
-    ClassLoader parent = classloaders1.get("the-sib");
-    assertThat(Collections.list(parent.getResources("a.txt"))).hasSize(1);
-    assertThat(Collections.list(parent.getResources("A.java"))).hasSize(1);
-    assertThat(Collections.list(parent.getResources("b.txt"))).isEmpty();
-
-    ClassLoader child = classloaders2.get("the-child");
-    assertThat(Collections.list(child.getResources("a.txt"))).isEmpty();
-    assertThat(Collections.list(parent.getResources("A.java"))).hasSize(1);
-    assertThat(Collections.list(child.getResources("b.txt"))).hasSize(1);
-  }
-
-  @Test
-  public void getResources_from_previously_loaded_sibling() throws Exception {
-    Map<String, ClassLoader> classloaders1 = sut
-      .newClassloader("the-sib")
-      .addURL("the-sib", new File("tester/a.jar").toURL())
-      .build();
-
-    Map<String, ClassLoader> classloaders2 = new ClassloaderBuilder(classloaders1.values())
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/b.jar").toURL())
-      .addSibling("the-child", "the-sib", Mask.ALL)
-      .build();
-
-    ClassLoader parent = classloaders1.get("the-sib");
-    assertThat(Collections.list(parent.getResources("a.txt"))).hasSize(1);
-    assertThat(Collections.list(parent.getResources("b.txt"))).isEmpty();
-
-    ClassLoader child = classloaders2.get("the-child");
-    assertThat(Collections.list(child.getResources("a.txt"))).hasSize(1);
-    assertThat(Collections.list(child.getResources("b.txt"))).hasSize(1);
-  }
-
-  @Test
-  public void getResources_multiple_versions_with_parent_first_strategy() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/a_v2.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.ALL)
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-parent");
-    assertThat(Collections.list(parent.getResources("a.txt"))).hasSize(1);
-
-    ClassLoader child = newClassloaders.get("the-child");
-    List<URL> childResources = Collections.list(child.getResources("a.txt"));
-    assertThat(childResources).hasSize(2);
-    assertThat(IOUtils.toString(childResources.get(0))).startsWith("version 1 of a.txt");
-    assertThat(IOUtils.toString(childResources.get(1))).startsWith("version 2 of a.txt");
-  }
-
-  @Test
-  public void resource_not_found_in_parent_first_strategy() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/a_v2.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.ALL)
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-child");
-    assertThat(parent.getResource("missing")).isNull();
-    try {
-      parent.loadClass("missing");
-      fail();
-    } catch (ClassNotFoundException e) {
-      // ok
-    }
-  }
-
-  @Test
-  public void resource_not_found_in_self_first_strategy() throws Exception {
-    Map<String, ClassLoader> newClassloaders = sut
-      .newClassloader("the-parent")
-      .addURL("the-parent", new File("tester/a.jar").toURL())
-
-      .newClassloader("the-child")
-      .addURL("the-child", new File("tester/a_v2.jar").toURL())
-      .setParent("the-child", "the-parent", Mask.ALL)
-      .setLoadingOrder("the-child", ClassloaderBuilder.LoadingOrder.SELF_FIRST)
-      .build();
-
-    ClassLoader parent = newClassloaders.get("the-child");
-    assertThat(parent.getResource("missing")).isNull();
-    try {
-      parent.loadClass("missing");
-      fail();
-    } catch (ClassNotFoundException e) {
-      // ok
-    }
-  }
-
-  private boolean canLoadClass(ClassLoader classloader, String classname) {
-    try {
-      classloader.loadClass(classname);
-      return true;
-    } catch (ClassNotFoundException e) {
-      return false;
-    }
-  }
-
-  private boolean canLoadMethod(ClassLoader classloader, String classname, String methodName) {
-    try {
-      Class clazz = classloader.loadClass(classname);
-      return clazz.getMethod(methodName) != null;
-    } catch (Exception e) {
-      return false;
-    }
-  }
-
-  private boolean canLoadResource(ClassLoader classloader, String name) {
-    return classloader.getResource(name) != null;
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/classloader/MaskTest.java b/sonar-core/src/test/java/org/sonar/classloader/MaskTest.java
deleted file mode 100644 (file)
index a12260e..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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 3 of the License, or (at your option) any later version.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.classloader;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class MaskTest {
-
-  @Test
-  public void ALL_accepts_everything() throws Exception {
-    assertThat(Mask.ALL.acceptClass("org.sonar.Bar")).isTrue();
-    assertThat(Mask.ALL.acceptClass("Bar")).isTrue();
-  }
-
-  @Test
-  public void NONE_accepts_nothing() throws Exception {
-    assertThat(Mask.NONE.acceptClass("org.sonar.Bar")).isFalse();
-    assertThat(Mask.NONE.acceptClass("Bar")).isFalse();
-  }
-
-  @Test
-  public void include_class() throws Exception {
-    Mask mask = Mask.builder().include("org/sonar/Bar.class").build();
-    assertThat(mask.acceptClass("org.sonar.Bar")).isTrue();
-    assertThat(mask.acceptClass("org.sonar.qube.Bar")).isFalse();
-    assertThat(mask.acceptClass("org.sonar.Foo")).isFalse();
-    assertThat(mask.acceptClass("Bar")).isFalse();
-  }
-
-  @Test
-  public void include_class_of_root_package() throws Exception {
-    Mask mask = Mask.builder().include("Bar.class").build();
-    assertThat(mask.acceptClass("Bar")).isTrue();
-    assertThat(mask.acceptClass("Foo")).isFalse();
-  }
-
-  @Test
-  public void include_resource() throws Exception {
-    Mask mask = Mask.builder().include("org/sonar/Bar.class").build();
-    assertThat(mask.acceptResource("org/sonar/Bar.class")).isTrue();
-    assertThat(mask.acceptResource("org/sonar/qube/Bar.class")).isFalse();
-    assertThat(mask.acceptResource("org/sonar/Foo.class")).isFalse();
-    assertThat(mask.acceptResource("Bar.class")).isFalse();
-  }
-
-  @Test
-  public void include_package() throws Exception {
-    Mask mask = Mask.builder().include("org/sonar/", "org/other/").build();
-    assertThat(mask.acceptClass("Foo")).isFalse();
-    assertThat(mask.acceptClass("org.sonar.Bar")).isTrue();
-    assertThat(mask.acceptClass("org.sonarqube.Foo")).isFalse();
-    assertThat(mask.acceptClass("org.sonar.qube.Foo")).isTrue();
-    assertThat(mask.acceptClass("Bar")).isFalse();
-  }
-
-  @Test
-  public void exclude_class() throws Exception {
-    Mask mask = Mask.builder().exclude("org/sonar/Bar.class").build();
-    assertThat(mask.acceptClass("org.sonar.Bar")).isFalse();
-    assertThat(mask.acceptClass("org.sonar.qube.Bar")).isTrue();
-    assertThat(mask.acceptClass("org.sonar.Foo")).isTrue();
-    assertThat(mask.acceptClass("Bar")).isTrue();
-  }
-
-  @Test
-  public void exclude_package() throws Exception {
-    Mask mask = Mask.builder().exclude("org/sonar/", "org/other/").build();
-    assertThat(mask.acceptClass("Foo")).isTrue();
-    assertThat(mask.acceptClass("org.sonar.Bar")).isFalse();
-    assertThat(mask.acceptClass("org.sonarqube.Foo")).isTrue();
-    assertThat(mask.acceptClass("org.sonar.qube.Foo")).isFalse();
-    assertThat(mask.acceptClass("Bar")).isTrue();
-  }
-
-  @Test
-  public void exclusion_is_subset_of_inclusion() throws Exception {
-    Mask mask = Mask.builder()
-      .include("org/sonar/")
-      .exclude("org/sonar/qube/")
-      .build();
-    assertThat(mask.acceptClass("org.sonar.Foo")).isTrue();
-    assertThat(mask.acceptClass("org.sonar.Qube")).isTrue();
-    assertThat(mask.acceptClass("org.sonar.qube.Foo")).isFalse();
-  }
-
-  @Test
-  public void inclusion_is_subset_of_exclusion() throws Exception {
-    Mask mask = Mask.builder()
-      .include("org/sonar/qube/")
-      .exclude("org/sonar/")
-      .build();
-    assertThat(mask.acceptClass("org.sonar.Foo")).isFalse();
-    assertThat(mask.acceptClass("org.sonar.Qube")).isFalse();
-    assertThat(mask.acceptClass("org.sonar.qube.Foo")).isFalse();
-  }
-
-  @Test
-  public void exclude_everything() throws Exception {
-    Mask mask = Mask.builder().exclude("/").build();
-    assertThat(mask.acceptClass("org.sonar.Foo")).isFalse();
-    assertThat(mask.acceptClass("Foo")).isFalse();
-    assertThat(mask.acceptResource("config.xml")).isFalse();
-    assertThat(mask.acceptResource("org/config.xml")).isFalse();
-  }
-
-  @Test
-  public void include_everything() throws Exception {
-    Mask mask = Mask.builder().include("/").build();
-    assertThat(mask.acceptClass("org.sonar.Foo")).isTrue();
-    assertThat(mask.acceptClass("Foo")).isTrue();
-    assertThat(mask.acceptResource("config.xml")).isTrue();
-    assertThat(mask.acceptResource("org/config.xml")).isTrue();
-  }
-
-  @Test
-  public void merge_with_ALL() throws Exception {
-    Mask mask = Mask.builder()
-      .include("org/foo/")
-      .exclude("org/bar/")
-      .merge(Mask.ALL)
-      .build();
-
-    assertThat(mask.getInclusions()).containsOnly("org/foo/");
-    assertThat(mask.getExclusions()).containsOnly("org/bar/");
-  }
-
-  @Test
-  public void merge_exclusions() throws Exception {
-    Mask with = Mask.builder().exclude("bar/").build();
-    Mask mask = Mask.builder().exclude("org/foo/").merge(with).build();
-
-    assertThat(mask.getExclusions()).containsOnly("org/foo/", "bar/");
-  }
-
-  @Test
-  public void should_not_merge_disjoined_inclusions() throws Exception {
-    Mask with = Mask.builder().include("org/bar/").build();
-    Mask mask = Mask.builder().include("org/foo/").merge(with).build();
-
-    assertThat(mask.getInclusions()).isEmpty();
-    // TODO does that mean that merge result accepts everything ?
-  }
-
-  @Test
-  public void merge_inclusions() throws Exception {
-    Mask with = Mask.builder().include("org/foo/sub/", "org/bar/").build();
-    Mask mask = Mask.builder().include("org/foo/", "org/bar/sub/").merge(with).build();
-
-    assertThat(mask.getInclusions()).containsOnly("org/foo/sub/", "org/bar/sub/");
-  }
-}
index def7574bdc5544e4b9bf8b36e5d54f3b118089c7..d5a74e13704ae287f78c555f76cda9a535577851 100644 (file)
@@ -21,14 +21,12 @@ package org.sonar.core.platform;
 
 import com.sonarsource.plugins.license.api.FooBar;
 import java.io.File;
-import java.util.List;
 import java.util.Map;
 import org.apache.commons.lang.StringUtils;
 import org.junit.Test;
 import org.sonar.api.server.rule.RulesDefinition;
 
 import static java.util.Arrays.asList;
-import static java.util.Collections.emptyMap;
 import static org.assertj.core.api.Assertions.assertThat;
 
 public class PluginClassloaderFactoryTest {
@@ -43,7 +41,7 @@ public class PluginClassloaderFactoryTest {
   @Test
   public void create_isolated_classloader() {
     PluginClassLoaderDef def = basePluginDef();
-    Map<PluginClassLoaderDef, ClassLoader> map = factory.create(emptyMap(), asList(def));
+    Map<PluginClassLoaderDef, ClassLoader> map = factory.create(asList(def));
 
     assertThat(map).containsOnlyKeys(def);
     ClassLoader classLoader = map.get(def);
@@ -62,7 +60,7 @@ public class PluginClassloaderFactoryTest {
   public void classloader_exports_resources_to_other_classloaders() {
     PluginClassLoaderDef baseDef = basePluginDef();
     PluginClassLoaderDef dependentDef = dependentPluginDef();
-    Map<PluginClassLoaderDef, ClassLoader> map = factory.create(emptyMap(), asList(baseDef, dependentDef));
+    Map<PluginClassLoaderDef, ClassLoader> map = factory.create(asList(baseDef, dependentDef));
     ClassLoader baseClassloader = map.get(baseDef);
     ClassLoader dependentClassloader = map.get(dependentDef);
 
@@ -76,26 +74,10 @@ public class PluginClassloaderFactoryTest {
     assertThat(canLoadClass(baseClassloader, BASE_PLUGIN_CLASSNAME)).isTrue();
   }
 
-  @Test
-  public void classloader_exports_resources_to_other_classloaders_loaded_later() {
-    PluginClassLoaderDef baseDef = basePluginDef();
-    Map<PluginClassLoaderDef, ClassLoader> map1 = factory.create(emptyMap(), List.of(baseDef));
-
-    PluginClassLoaderDef dependentDef = dependentPluginDef();
-    Map<PluginClassLoaderDef, ClassLoader> map2 = factory.create(map1, List.of(dependentDef));
-
-    ClassLoader dependentClassloader = map2.get(dependentDef);
-
-    // base-plugin exports its API package to other plugins
-    assertThat(canLoadClass(dependentClassloader, "org.sonar.plugins.base.api.BaseApi")).isTrue();
-    assertThat(canLoadClass(dependentClassloader, BASE_PLUGIN_CLASSNAME)).isFalse();
-    assertThat(canLoadClass(dependentClassloader, DEPENDENT_PLUGIN_CLASSNAME)).isTrue();
-  }
-
   @Test
   public void classloader_exposes_license_api_from_main_classloader() {
     PluginClassLoaderDef def = basePluginDef();
-    Map<PluginClassLoaderDef, ClassLoader> map = factory.create(emptyMap(), asList(def));
+    Map<PluginClassLoaderDef, ClassLoader> map = factory.create(asList(def));
 
     assertThat(map).containsOnlyKeys(def);
     ClassLoader classLoader = map.get(def);
@@ -106,7 +88,7 @@ public class PluginClassloaderFactoryTest {
   private static PluginClassLoaderDef basePluginDef() {
     PluginClassLoaderDef def = new PluginClassLoaderDef(BASE_PLUGIN_KEY);
     def.addMainClass(BASE_PLUGIN_KEY, BASE_PLUGIN_CLASSNAME);
-    def.getExportMask().include("org/sonar/plugins/base/api/");
+    def.getExportMask().addInclusion("org/sonar/plugins/base/api/");
     def.addFiles(asList(fakePluginJar("base-plugin/target/base-plugin-0.1-SNAPSHOT.jar")));
     return def;
   }
@@ -114,7 +96,7 @@ public class PluginClassloaderFactoryTest {
   private static PluginClassLoaderDef dependentPluginDef() {
     PluginClassLoaderDef def = new PluginClassLoaderDef(DEPENDENT_PLUGIN_KEY);
     def.addMainClass(DEPENDENT_PLUGIN_KEY, DEPENDENT_PLUGIN_CLASSNAME);
-    def.getExportMask().include("org/sonar/plugins/dependent/api/");
+    def.getExportMask().addInclusion("org/sonar/plugins/dependent/api/");
     def.addFiles(asList(fakePluginJar("dependent-plugin/target/dependent-plugin-0.1-SNAPSHOT.jar")));
     return def;
   }
diff --git a/sonar-core/tester/a.jar b/sonar-core/tester/a.jar
deleted file mode 100644 (file)
index b2919e0..0000000
Binary files a/sonar-core/tester/a.jar and /dev/null differ
diff --git a/sonar-core/tester/a/A.class b/sonar-core/tester/a/A.class
deleted file mode 100644 (file)
index 1b88100..0000000
Binary files a/sonar-core/tester/a/A.class and /dev/null differ
diff --git a/sonar-core/tester/a/A.java b/sonar-core/tester/a/A.java
deleted file mode 100644 (file)
index a29a8ff..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-public class A {
-  public void version1() {
-
-  }
-}
diff --git a/sonar-core/tester/a/a.txt b/sonar-core/tester/a/a.txt
deleted file mode 100644 (file)
index 0fdd823..0000000
+++ /dev/null
@@ -1 +0,0 @@
-version 1 of a.txt
diff --git a/sonar-core/tester/a_v2.jar b/sonar-core/tester/a_v2.jar
deleted file mode 100644 (file)
index 1e0f89d..0000000
Binary files a/sonar-core/tester/a_v2.jar and /dev/null differ
diff --git a/sonar-core/tester/a_v2/A.class b/sonar-core/tester/a_v2/A.class
deleted file mode 100644 (file)
index d9e11d7..0000000
Binary files a/sonar-core/tester/a_v2/A.class and /dev/null differ
diff --git a/sonar-core/tester/a_v2/A.java b/sonar-core/tester/a_v2/A.java
deleted file mode 100644 (file)
index 4f3a882..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-public class A {
-
-  public void version2() {
-
-  }
-}
diff --git a/sonar-core/tester/a_v2/a.txt b/sonar-core/tester/a_v2/a.txt
deleted file mode 100644 (file)
index 09b8dbb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-version 2 of a.txt
diff --git a/sonar-core/tester/b.jar b/sonar-core/tester/b.jar
deleted file mode 100644 (file)
index 80985fa..0000000
Binary files a/sonar-core/tester/b.jar and /dev/null differ
diff --git a/sonar-core/tester/b/B.class b/sonar-core/tester/b/B.class
deleted file mode 100644 (file)
index 17df16a..0000000
Binary files a/sonar-core/tester/b/B.class and /dev/null differ
diff --git a/sonar-core/tester/b/B.java b/sonar-core/tester/b/B.java
deleted file mode 100644 (file)
index 66dd24c..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-public class B {
-}
diff --git a/sonar-core/tester/b/b.txt b/sonar-core/tester/b/b.txt
deleted file mode 100644 (file)
index 6178079..0000000
+++ /dev/null
@@ -1 +0,0 @@
-b
diff --git a/sonar-core/tester/build.sh b/sonar-core/tester/build.sh
deleted file mode 100644 (file)
index 823be76..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh
-
-rm *.jar
-
-javac a/*.java
-jar cvf a.jar -C a/ .
-
-javac b/*.java
-jar cvf b.jar -C b/ .
-
-javac c/*.java
-jar cvf c.jar -C c/ .
-
-javac a_v2/*.java
-jar cvf a_v2.jar -C a_v2 .
-
diff --git a/sonar-core/tester/c.jar b/sonar-core/tester/c.jar
deleted file mode 100644 (file)
index 76b546f..0000000
Binary files a/sonar-core/tester/c.jar and /dev/null differ
diff --git a/sonar-core/tester/c/C.class b/sonar-core/tester/c/C.class
deleted file mode 100644 (file)
index a9c2f96..0000000
Binary files a/sonar-core/tester/c/C.class and /dev/null differ
diff --git a/sonar-core/tester/c/C.java b/sonar-core/tester/c/C.java
deleted file mode 100644 (file)
index d405396..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-public class C {
-}
diff --git a/sonar-core/tester/c/c.txt b/sonar-core/tester/c/c.txt
deleted file mode 100644 (file)
index f2ad6c7..0000000
+++ /dev/null
@@ -1 +0,0 @@
-c