@VisibleForTesting
  Collection<PluginClassLoaderDef> defineClassloaders(Map<String, ExplodedPlugin> pluginsByKey) {
    Map<String, PluginClassLoaderDef> classloadersByBasePlugin = new HashMap<>();

    for (ExplodedPlugin plugin : pluginsByKey.values()) {
      PluginInfo info = plugin.getPluginInfo();
      String baseKey = basePluginKey(info, pluginsByKey);
      PluginClassLoaderDef def = classloadersByBasePlugin.get(baseKey);
      if (def == null) {
        def = new PluginClassLoaderDef(baseKey);
        classloadersByBasePlugin.put(baseKey, def);
      }
      def.addFiles(singleton(plugin.getMain()));
      def.addFiles(plugin.getLibs());
      def.addMainClass(info.getKey(), info.getMainClass());

      for (String defaultSharedResource : DEFAULT_SHARED_RESOURCES) {
        def.getExportMask().include(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());
        }
        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.",
            info.getName(), info.getKey());
        }
      }
    }
    return classloadersByBasePlugin.values();

  }
@Test
  public void test_plugins_sharing_the_same_classloader() throws Exception {
    File baseJarFile = temp.newFile();
    File extensionJar1 = temp.newFile();
    File extensionJar2 = temp.newFile();
    PluginInfo base = new PluginInfo("foo")
      .setJarFile(baseJarFile)
      .setMainClass("org.foo.FooPlugin")
      .setUseChildFirstClassLoader(false);

    PluginInfo extension1 = new PluginInfo("fooExtension1")
      .setJarFile(extensionJar1)
      .setMainClass("org.foo.Extension1Plugin")
      .setBasePlugin("foo");

    // This extension tries to change the classloader-ordering strategy of base plugin
    // (see setUseChildFirstClassLoader(true)).
    // That is not allowed and should be ignored -> strategy is still the one
    // defined on base plugin (parent-first in this example)
    PluginInfo extension2 = new PluginInfo("fooExtension2")
      .setJarFile(extensionJar2)
      .setMainClass("org.foo.Extension2Plugin")
      .setBasePlugin("foo")
      .setUseChildFirstClassLoader(true);

    ExplodedPlugin baseExplodedPlugin = createExplodedPlugin(base);
    ExplodedPlugin extension1ExplodedPlugin = createExplodedPlugin(extension1);
    ExplodedPlugin extension2ExplodedPlugin = createExplodedPlugin(extension2);
    Collection<PluginClassLoaderDef> defs = underTest.defineClassloaders(ImmutableMap.of(
      base.getKey(), baseExplodedPlugin,
      extension1.getKey(), extension1ExplodedPlugin,
      extension2.getKey(), extension2ExplodedPlugin));

    assertThat(defs).hasSize(1);
    PluginClassLoaderDef def = defs.iterator().next();
    assertThat(def.getBasePluginKey()).isEqualTo("foo");
    assertThat(def.isSelfFirstStrategy()).isFalse();

    assertThat(def.getFiles())
      .containsAll(baseExplodedPlugin.getLibs())
      .containsAll(extension1ExplodedPlugin.getLibs())
      .containsAll(extension2ExplodedPlugin.getLibs());
    assertThat(def.getMainClassesByPluginKey()).containsOnly(
      entry("foo", "org.foo.FooPlugin"),
      entry("fooExtension1", "org.foo.Extension1Plugin"),
      entry("fooExtension2", "org.foo.Extension2Plugin"));
  }