Skip to content

Commit

Permalink
SONAR-10541, SONAR-10331 Drop compatibility mode and clean plugin cla…
Browse files Browse the repository at this point in the history
…ssloader
  • Loading branch information
henryju authored and SonarTech committed Jul 17, 2018
1 parent 8bbe579 commit 8cfc544
Show file tree
Hide file tree
Showing 29 changed files with 70 additions and 254 deletions.
3 changes: 2 additions & 1 deletion server/sonar-ce-task-projectanalysis/build.gradle
Expand Up @@ -42,7 +42,8 @@ dependencies {
compileOnly project(':server:sonar-db-dao')
compileOnly project(':server:sonar-process')
compileOnly project(':server:sonar-server-common')
compileOnly project(path: ':sonar-plugin-api')
compileOnly project(':sonar-plugin-api')
compileOnly project(':sonar-duplications')

testCompile 'com.google.code.findbugs:jsr305'
testCompile 'com.h2database:h2'
Expand Down
Expand Up @@ -150,7 +150,9 @@ private Properties getProperties() throws IOException {
Properties properties = ProcessProperties.defaults();
File homeDir = tempFolder.newFolder();
File dataDir = new File(homeDir, "data");
dataDir.mkdirs();
File tmpDir = new File(homeDir, "tmp");
tmpDir.mkdirs();
properties.setProperty(PATH_HOME.getKey(), homeDir.getAbsolutePath());
properties.setProperty(PATH_DATA.getKey(), dataDir.getAbsolutePath());
properties.setProperty(PATH_TEMP.getKey(), tmpDir.getAbsolutePath());
Expand Down
Expand Up @@ -20,6 +20,8 @@
package org.sonar.server.platform;

import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.picocontainer.Startable;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.Logger;
Expand All @@ -39,9 +41,9 @@ public class ServerFileSystemImpl implements ServerFileSystem, org.sonar.api.pla
private final File uninstallDir;

public ServerFileSystemImpl(Configuration config) {
this.homeDir = new File(config.get(PATH_HOME.getKey()).get());
this.tempDir = new File(config.get(PATH_TEMP.getKey()).get());
File dataDir = new File(config.get(PATH_DATA.getKey()).get());
this.homeDir = createDir(new File(config.get(PATH_HOME.getKey()).get()));
this.tempDir = createDir(new File(config.get(PATH_TEMP.getKey()).get()));
File dataDir = createDir(new File(config.get(PATH_DATA.getKey()).get()));
this.deployDir = new File(dataDir, "web/deploy");
this.uninstallDir = new File(getTempDir(), "uninstalled-plugins");
}
Expand Down Expand Up @@ -91,4 +93,12 @@ public File getUninstalledPluginsDir() {
return uninstallDir;
}

private static File createDir(File dir) {
try {
FileUtils.forceMkdir(dir);
return dir;
} catch (IOException e) {
throw new IllegalStateException("Fail to create directory " + dir, e);
}
}
}
6 changes: 2 additions & 4 deletions server/sonar-server/build.gradle
Expand Up @@ -55,10 +55,8 @@ dependencies {
compile project(':server:sonar-server-common')
compile project(':sonar-core')
compile project(':sonar-scanner-protocol')
compile(project(':sonar-markdown')) {
// already shaded with sonar-plugin-api
exclude group: 'org.codehaus.sonar', module: 'sonar-channel'
}
compile project(':sonar-markdown')
compile project(':sonar-duplications')
runtime project(path: ':sonar-plugin-api', configuration: 'shadow')
compileOnly project(path: ':sonar-plugin-api')
compile project(':sonar-ws')
Expand Down
1 change: 0 additions & 1 deletion settings.gradle
Expand Up @@ -25,7 +25,6 @@ include 'sonar-core'
include 'sonar-duplications'
include 'sonar-markdown'
include 'sonar-plugin-api'
include 'sonar-plugin-api-deps'
include 'sonar-scanner-engine'
include 'sonar-scanner-engine-shaded'
include 'sonar-scanner-protocol'
Expand Down
4 changes: 2 additions & 2 deletions sonar-application/build.gradle
Expand Up @@ -127,8 +127,8 @@ zip.doFirst {
}
// Check the size of the archive
zip.doLast {
def minLength = 150000000
def maxLength = 170000000
def minLength = 140000000
def maxLength = 160000000
def length = new File(distsDir, archiveName).length()
if (length < minLength)
throw new GradleException("$archiveName size ($length) too small. Min is $minLength")
Expand Down
14 changes: 0 additions & 14 deletions sonar-core/build.gradle
Expand Up @@ -4,10 +4,6 @@ sonarqube {
}
}

configurations {
includeInResources
}

dependencies {
// please keep list ordered

Expand All @@ -24,8 +20,6 @@ dependencies {

compileOnly 'com.google.code.findbugs:jsr305'

includeInResources project(path: ':sonar-plugin-api-deps', configuration: 'shadow')

testCompile 'com.tngtech.java:junit-dataprovider'
testCompile 'junit:junit'
testCompile 'org.assertj:assertj-core'
Expand All @@ -36,14 +30,6 @@ dependencies {
testCompileOnly 'com.google.code.findbugs:jsr305'
}

// sonar-plugin-api.jar is copied into target JAR file
processResources {
into('/') {
from configurations.includeInResources
rename '(.*)-' + project.version + '-all.jar', '$1.jar'
}
}

// Used by sonar-db-core to run DB Unit Tests
artifactoryPublish.skip = false
publishing {
Expand Down
Expand Up @@ -41,11 +41,6 @@ class PluginClassLoaderDef {
private final Mask mask = new Mask();
private boolean selfFirstStrategy = false;

/**
* Compatibility with API classloader as defined before version 5.2
*/
private boolean compatibilityMode = false;

PluginClassLoaderDef(String basePluginKey) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(basePluginKey));
this.basePluginKey = basePluginKey;
Expand Down Expand Up @@ -85,14 +80,6 @@ void addMainClass(String pluginKey, @Nullable String mainClass) {
}
}

boolean isCompatibilityMode() {
return compatibilityMode;
}

void setCompatibilityMode(boolean b) {
this.compatibilityMode = b;
}

@Override
public boolean equals(@Nullable Object o) {
if (this == o) {
Expand Down
Expand Up @@ -25,11 +25,9 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.TempFolder;
import org.sonar.classloader.ClassloaderBuilder;
import org.sonar.classloader.Mask;

Expand All @@ -40,8 +38,6 @@
* Builds the graph of classloaders to be used to instantiate plugins. It deals with:
* <ul>
* <li>isolation of plugins against core classes (except api)</li>
* <li>backward-compatibility with plugins built for versions of SQ lower than 5.2. At that time
* API declared transitive dependencies that were automatically available to plugins</li>
* <li>sharing of some packages between plugins</li>
* <li>loading of the libraries embedded in plugin JAR files (directory META-INF/libs)</li>
* </ul>
Expand All @@ -54,13 +50,6 @@ public class PluginClassloaderFactory {
// underscores are used to not conflict with plugin keys (if someday a plugin key is "api")
private static final String API_CLASSLOADER_KEY = "_api_";

private final TempFolder temp;
private URL compatibilityModeJar;

public PluginClassloaderFactory(TempFolder temp) {
this.temp = temp;
}

/**
* Creates as many classloaders as requested by the input parameter.
*/
Expand All @@ -78,9 +67,6 @@ public Map<PluginClassLoaderDef, ClassLoader> create(Collection<PluginClassLoade
for (File jar : def.getFiles()) {
builder.addURL(def.getBasePluginKey(), fileToUrl(jar));
}
if (def.isCompatibilityMode()) {
builder.addURL(def.getBasePluginKey(), extractCompatibilityModeJar());
}
exportResources(def, builder, defs);
}

Expand Down Expand Up @@ -120,19 +106,6 @@ ClassLoader baseClassLoader() {
return getClass().getClassLoader();
}

private URL extractCompatibilityModeJar() {
if (compatibilityModeJar == null) {
File jar = temp.newFile("sonar-plugin-api-deps", "jar");
try {
FileUtils.copyURLToFile(getClass().getResource("/sonar-plugin-api-deps.jar"), jar);
compatibilityModeJar = jar.toURI().toURL();
} catch (Exception e) {
throw new IllegalStateException("Can not extract sonar-plugin-api-deps.jar to " + jar.getAbsolutePath(), e);
}
}
return compatibilityModeJar;
}

private static URL fileToUrl(File file) {
try {
return file.toURI().toURL();
Expand All @@ -149,31 +122,25 @@ private static URL fileToUrl(File file) {
*/
private static Mask apiMask() {
return new Mask()
.addInclusion("org/sonar/api/")
.addInclusion("org/sonar/channel/")
.addInclusion("org/sonar/api/")
.addInclusion("org/sonar/check/")
.addInclusion("org/sonar/colorizer/")
.addInclusion("org/sonar/duplications/")
.addInclusion("org/sonar/graph/")
.addInclusion("org/sonar/plugins/emailnotifications/api/")
.addInclusion("net/sourceforge/pmd/")
.addInclusion("org/apache/maven/")
.addInclusion("org/codehaus/stax2/")
.addInclusion("org/codehaus/staxmate/")
.addInclusion("com/ctc/wstx/")
.addInclusion("org/slf4j/")
.addInclusion("javax/servlet/")

// 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/")

// required for internal libs at SonarSource
// Exposed by org.sonar.api.server.authentication.IdentityProvider
.addInclusion("javax/servlet/")

// required for some internal SonarSource plugins (billing, orchestrator, ...)
.addInclusion("org/sonar/server/platform/")
.addInclusion("org/sonar/core/persistence/")
.addInclusion("org/sonar/core/properties/")
.addInclusion("org/sonar/server/views/")

// required for commercial plugins at SonarSource
.addInclusion("com/sonarsource/plugins/license/api/")

// API exclusions
Expand Down
Expand Up @@ -50,7 +50,7 @@ public class PluginLoader {

private static final String[] DEFAULT_SHARED_RESOURCES = {"org/sonar/plugins", "com/sonar/plugins", "com/sonarsource/plugins"};

public static final Version COMPATIBILITY_MODE_MAX_VERSION = Version.create("5.2");
private static final Version COMPATIBILITY_MODE_MAX_VERSION = Version.create("5.2");

private final PluginJarExploder jarExploder;
private final PluginClassloaderFactory classloaderFactory;
Expand Down Expand Up @@ -96,15 +96,14 @@ Collection<PluginClassLoaderDef> defineClassloaders(Map<String, PluginInfo> info
def.setSelfFirstStrategy(info.isUseChildFirstClassLoader());
Version minSqVersion = info.getMinimalSqVersion();
boolean compatibilityMode = minSqVersion != null && minSqVersion.compareToIgnoreQualifier(COMPATIBILITY_MODE_MAX_VERSION) < 0;
def.setCompatibilityMode(compatibilityMode);
if (compatibilityMode) {
Loggers.get(getClass()).debug("API compatibility mode is enabled on plugin {} [{}] " +
"(built with API lower than {})",
info.getName(), info.getKey(), COMPATIBILITY_MODE_MAX_VERSION);
Loggers.get(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();

}

/**
Expand Down
Expand Up @@ -114,7 +114,7 @@ public static boolean deleteQuietly(@Nullable File file) {
* <li>No exceptions are thrown when a file or directory cannot be deleted.</li>
* </ul>
*
* @param file file or directory to delete, can be {@code null}
* @param path file or directory to delete, can be {@code null}
* @return {@code true} if the file or directory was deleted, otherwise {@code false}
*/
public static boolean deleteQuietly(@Nullable Path path) {
Expand Down
Expand Up @@ -23,10 +23,8 @@
import java.io.File;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.api.utils.internal.JUnitTempFolder;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
Expand All @@ -38,10 +36,7 @@ public class PluginClassloaderFactoryTest {
static final String BASE_PLUGIN_KEY = "base";
static final String DEPENDENT_PLUGIN_KEY = "dependent";

@Rule
public JUnitTempFolder temp = new JUnitTempFolder();

PluginClassloaderFactory factory = new PluginClassloaderFactory(temp);
PluginClassloaderFactory factory = new PluginClassloaderFactory();

@Test
public void create_isolated_classloader() {
Expand All @@ -61,20 +56,6 @@ public void create_isolated_classloader() {
assertThat(canLoadClass(classLoader, StringUtils.class.getCanonicalName())).isFalse();
}

@Test
public void create_classloader_compatible_with_with_old_api_dependencies() {
PluginClassLoaderDef def = basePluginDef();
def.setCompatibilityMode(true);
ClassLoader classLoader = factory.create(asList(def)).get(def);

// Plugin can access to API and its transitive dependencies as defined in version 5.1.
// It can not access to core classes though, even if it was possible in previous versions.
assertThat(canLoadClass(classLoader, RulesDefinition.class.getCanonicalName())).isTrue();
assertThat(canLoadClass(classLoader, StringUtils.class.getCanonicalName())).isTrue();
assertThat(canLoadClass(classLoader, BASE_PLUGIN_CLASSNAME)).isTrue();
assertThat(canLoadClass(classLoader, PluginClassloaderFactory.class.getCanonicalName())).isFalse();
}

@Test
public void classloader_exports_resources_to_other_classloaders() {
PluginClassLoaderDef baseDef = basePluginDef();
Expand Down

0 comments on commit 8cfc544

Please sign in to comment.