org.sonar.core.platform.PluginLoaderTest.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.core.platform.PluginLoaderTest.java

Source

/*
 * SonarQube, open source software quality management tool.
 * Copyright (C) 2008-2014 SonarSource
 * mailto:contact AT sonarsource DOT com
 *
 * SonarQube 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.
 *
 * SonarQube 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.core.platform;

import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.assertj.core.data.MapEntry;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.Plugin;
import org.sonar.api.utils.ZipUtils;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;

public class PluginLoaderTest {

    @Rule
    public TemporaryFolder temp = new TemporaryFolder();

    @Test
    public void load_and_unload_plugins() {
        File checkstyleJar = FileUtils
                .toFile(getClass().getResource("/org/sonar/core/plugins/sonar-checkstyle-plugin-2.8.jar"));
        PluginInfo checkstyleInfo = PluginInfo.create(checkstyleJar);

        PluginLoader loader = new PluginLoader(new TempPluginExploder());
        Map<String, Plugin> instances = loader.load(ImmutableMap.of("checkstyle", checkstyleInfo));

        assertThat(instances).containsOnlyKeys("checkstyle");
        Plugin checkstyleInstance = instances.get("checkstyle");
        assertThat(checkstyleInstance.getClass().getName())
                .isEqualTo("org.sonar.plugins.checkstyle.CheckstylePlugin");

        loader.unload(instances.values());
        // TODO test that classloaders are closed. Two strategies:
        //
    }

    @Test
    public void define_classloader() throws Exception {
        File jarFile = temp.newFile();
        PluginInfo info = new PluginInfo("foo").setJarFile(jarFile).setMainClass("org.foo.FooPlugin");

        PluginLoader loader = new PluginLoader(new FakePluginExploder());
        Collection<ClassloaderDef> defs = loader.defineClassloaders(ImmutableMap.of("foo", info));

        assertThat(defs).hasSize(1);
        ClassloaderDef def = defs.iterator().next();
        assertThat(def.getBasePluginKey()).isEqualTo("foo");
        assertThat(def.isSelfFirstStrategy()).isFalse();
        assertThat(def.getFiles()).containsOnly(jarFile);
        assertThat(def.getMainClassesByPluginKey()).containsOnly(MapEntry.entry("foo", "org.foo.FooPlugin"));
        // TODO test mask - require change in sonar-classloader
    }

    /**
     * A plugin can be extended by other plugins. In this case they share the same classloader.
     * The first plugin is named "base plugin".
     */
    @Test
    public void define_same_classloader_for_multiple_plugins() throws Exception {
        File baseJarFile = temp.newFile(), extensionJar1 = temp.newFile(), 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);

        PluginLoader loader = new PluginLoader(new FakePluginExploder());

        Collection<ClassloaderDef> defs = loader.defineClassloaders(ImmutableMap.of(base.getKey(), base,
                extension1.getKey(), extension1, extension2.getKey(), extension2));

        assertThat(defs).hasSize(1);
        ClassloaderDef def = defs.iterator().next();
        assertThat(def.getBasePluginKey()).isEqualTo("foo");
        assertThat(def.isSelfFirstStrategy()).isFalse();
        assertThat(def.getFiles()).containsOnly(baseJarFile, extensionJar1, extensionJar2);
        assertThat(def.getMainClassesByPluginKey()).containsOnly(entry("foo", "org.foo.FooPlugin"),
                entry("fooExtension1", "org.foo.Extension1Plugin"),
                entry("fooExtension2", "org.foo.Extension2Plugin"));
        // TODO test mask - require change in sonar-classloader
    }

    /**
     * Does not unzip jar file. It directly returns the JAR file defined on PluginInfo.
     */
    private static class FakePluginExploder extends PluginExploder {
        @Override
        public ExplodedPlugin explode(PluginInfo info) {
            return new ExplodedPlugin(info.getKey(), info.getNonNullJarFile(), Collections.<File>emptyList());
        }
    }

    private class TempPluginExploder extends PluginExploder {
        @Override
        public ExplodedPlugin explode(PluginInfo info) {
            try {
                File tempDir = temp.newFolder();
                ZipUtils.unzip(info.getNonNullJarFile(), tempDir, newLibFilter());
                return explodeFromUnzippedDir(info.getKey(), info.getNonNullJarFile(), tempDir);

            } catch (IOException e) {
                throw new IllegalStateException(e);
            }
        }
    }
}