]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10541, SONAR-10331 Drop compatibility mode and clean plugin classloader
authorJulien HENRY <julien.henry@sonarsource.com>
Thu, 5 Jul 2018 09:51:17 +0000 (11:51 +0200)
committerSonarTech <sonartech@sonarsource.com>
Wed, 19 Sep 2018 08:54:37 +0000 (10:54 +0200)
29 files changed:
server/sonar-ce-task-projectanalysis/build.gradle
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
server/sonar-server-common/src/main/java/org/sonar/server/platform/ServerFileSystemImpl.java
server/sonar-server/build.gradle
settings.gradle
sonar-application/build.gradle
sonar-core/build.gradle
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/main/java/org/sonar/core/platform/PluginLoader.java
sonar-core/src/test/java/org/sonar/core/platform/PluginClassloaderFactoryTest.java
sonar-core/src/test/java/org/sonar/core/platform/PluginLoaderTest.java
sonar-duplications/build.gradle
sonar-duplications/src/main/java/org/sonar/duplications/CodeFragment.java [deleted file]
sonar-duplications/src/main/java/org/sonar/duplications/block/Block.java
sonar-duplications/src/main/java/org/sonar/duplications/index/ClonePart.java
sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/PmdBlockChunker.java
sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/TokenizerBridge.java
sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/TokensLine.java [deleted file]
sonar-duplications/src/main/java/org/sonar/duplications/statement/Statement.java
sonar-duplications/src/test/java/org/sonar/duplications/internal/pmd/PmdBlockChunkerTest.java
sonar-duplications/src/test/java/org/sonar/duplications/internal/pmd/TokenizerBridgeTest.java
sonar-plugin-api-deps/build.gradle [deleted file]
sonar-plugin-api/build.gradle
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/DefaultCpdTokens.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/TokensLine.java [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
sonar-plugin-api/src/main/java/org/sonar/api/server/authentication/IdentityProvider.java
sonar-scanner-engine/build.gradle

index 8b52c4232f200a07b5b1d5f16d358569c72b6a11..b73d4b2e72bdc05bea73b8e23358c1a112d1eff1 100644 (file)
@@ -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'
index bc7a95804b55921dec2f997b221f82a2db70d7c2..81fe42adca69073d783a21f914a32423dabf6c54 100644 (file)
@@ -150,7 +150,9 @@ public class ComputeEngineContainerImplTest {
     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());
index 9818d98584f3335b8d58f57f1b6dfa72ec447706..d596044e8e3382462520f9a336a73b398e86fb7f 100644 (file)
@@ -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;
@@ -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");
   }
@@ -91,4 +93,12 @@ public class ServerFileSystemImpl implements ServerFileSystem, org.sonar.api.pla
     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);
+    }
+  }
 }
index 19d0f661aa4edfcb624b45e5335d3e3d71f7167a..15111dfb774d10ca49b3784462408b921e03eabc 100644 (file)
@@ -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')
index 38a3b8713d5f46ec4d3782e1a46407e46ffa8a44..9ab4a914693a3f7ed595cc6bf21a92e6d3075a9c 100644 (file)
@@ -24,7 +24,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'
index 07929229da8befea33499d840c52457116ae8342..41cd8d85b18ce8565ca34863fc115e8ce51b7ef1 100644 (file)
@@ -131,8 +131,8 @@ zip.doFirst {
 }
 // Check the size of the archive
 zip.doLast {
-  def minLength = 160000000
-  def maxLength = 175000000
+  def minLength = 150000000
+  def maxLength = 165000000
   def length = new File(distsDir, archiveName).length()
   if (length < minLength)
     throw new GradleException("$archiveName size ($length) too small. Min is $minLength")
index a2d0f1bb1892198f2c7a565caf962b9069bc54db..aad84e6dbfef64d33afd4acdbb4bb5e832b3f2ac 100644 (file)
@@ -4,10 +4,6 @@ sonarqube {
   }
 }
 
-configurations {
-  includeInResources
-}
-
 dependencies {
   // please keep list ordered
 
@@ -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'
@@ -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 {
index c1c3584b58a6fafe210573b8e87caab1d84dcfd7..d228ee088bd9004efccf154f649b8d657d61f812 100644 (file)
@@ -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;
@@ -85,14 +80,6 @@ class PluginClassLoaderDef {
     }
   }
 
-  boolean isCompatibilityMode() {
-    return compatibilityMode;
-  }
-
-  void setCompatibilityMode(boolean b) {
-    this.compatibilityMode = b;
-  }
-
   @Override
   public boolean equals(@Nullable Object o) {
     if (this == o) {
index 0c69f978a096ae97509e1a260585b2a3d1849e39..bc584778d680d92b951298f970577a0990c8d6b4 100644 (file)
@@ -25,11 +25,9 @@ import java.net.URL;
 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;
 
@@ -40,8 +38,6 @@ import static org.sonar.classloader.ClassloaderBuilder.LoadingOrder.SELF_FIRST;
  * 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>
@@ -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.
    */
@@ -78,9 +67,6 @@ public class PluginClassloaderFactory {
       for (File jar : def.getFiles()) {
         builder.addURL(def.getBasePluginKey(), fileToUrl(jar));
       }
-      if (def.isCompatibilityMode()) {
-        builder.addURL(def.getBasePluginKey(), extractCompatibilityModeJar());
-      }
       exportResources(def, builder, defs);
     }
 
@@ -120,19 +106,6 @@ public class PluginClassloaderFactory {
     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();
@@ -149,31 +122,25 @@ public class PluginClassloaderFactory {
    */
   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
index f44a346336ea72755d2008d88a8d258e217c4116..7b045fe69619d025df7cc5564b3db2d41aa2ca8e 100644 (file)
@@ -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;
@@ -96,15 +96,14 @@ public class PluginLoader {
         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();
+
   }
 
   /**
index 9d825b758af58f77a3a410b404e2f408cf59c125..329a5431d7a20e9b05fa7c6ebed85abecc816909 100644 (file)
@@ -23,10 +23,8 @@ import com.sonarsource.plugins.license.api.FooBar;
 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;
@@ -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() {
@@ -61,20 +56,6 @@ public class PluginClassloaderFactoryTest {
     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();
index 76a1268f9334f5a71f67a97b3eede2a51a94a9a2..2a2ae2c3575977c1d52b924af33f9826773016d6 100644 (file)
@@ -21,13 +21,15 @@ package org.sonar.core.platform;
 
 import com.google.common.collect.ImmutableMap;
 import java.io.File;
-import java.io.IOException;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import org.assertj.core.data.MapEntry;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
 import org.sonar.updatecenter.common.Version;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -39,8 +41,11 @@ public class PluginLoaderTest {
   @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
+  @Rule
+  public LogTester logTester = new LogTester();
+
   private PluginClassloaderFactory classloaderFactory = mock(PluginClassloaderFactory.class);
-  private PluginLoader loader = new PluginLoader(new FakePluginExploder(), classloaderFactory);
+  private PluginLoader underTest = new PluginLoader(new FakePluginExploder(), classloaderFactory);
 
   @Test
   public void define_classloader() throws Exception {
@@ -50,7 +55,7 @@ public class PluginLoaderTest {
       .setMainClass("org.foo.FooPlugin")
       .setMinimalSqVersion(Version.create("5.2"));
 
-    Collection<PluginClassLoaderDef> defs = loader.defineClassloaders(ImmutableMap.of("foo", info));
+    Collection<PluginClassLoaderDef> defs = underTest.defineClassloaders(ImmutableMap.of("foo", info));
 
     assertThat(defs).hasSize(1);
     PluginClassLoaderDef def = defs.iterator().next();
@@ -59,21 +64,6 @@ public class PluginLoaderTest {
     assertThat(def.getFiles()).containsOnly(jarFile);
     assertThat(def.getMainClassesByPluginKey()).containsOnly(MapEntry.entry("foo", "org.foo.FooPlugin"));
     // TODO test mask - require change in sonar-classloader
-
-    // built with SQ 5.2+ -> does not need API compatibility mode
-    assertThat(def.isCompatibilityMode()).isFalse();
-  }
-
-  @Test
-  public void enable_compatibility_mode_if_plugin_is_built_before_5_2() throws Exception {
-    File jarFile = temp.newFile();
-    PluginInfo info = new PluginInfo("foo")
-      .setJarFile(jarFile)
-      .setMainClass("org.foo.FooPlugin")
-      .setMinimalSqVersion(Version.create("4.5.2"));
-
-    Collection<PluginClassLoaderDef> defs = loader.defineClassloaders(ImmutableMap.of("foo", info));
-    assertThat(defs.iterator().next().isCompatibilityMode()).isTrue();
   }
 
   /**
@@ -104,7 +94,7 @@ public class PluginLoaderTest {
       .setBasePlugin("foo")
       .setUseChildFirstClassLoader(true);
 
-    Collection<PluginClassLoaderDef> defs = loader.defineClassloaders(ImmutableMap.of(
+    Collection<PluginClassLoaderDef> defs = underTest.defineClassloaders(ImmutableMap.of(
       base.getKey(), base, extension1.getKey(), extension1, extension2.getKey(), extension2));
 
     assertThat(defs).hasSize(1);
@@ -120,22 +110,18 @@ public class PluginLoaderTest {
   }
 
   @Test
-  public void plugin_is_not_recognised_as_system_extension_if_key_is_governance_and_extends_another_plugin() throws IOException {
-    PluginInfo foo = createPluginInfo("foo");
-    PluginInfo governance = createPluginInfo("governance")
-      .setBasePlugin("foo");
-
-    Collection<PluginClassLoaderDef> defs = loader.defineClassloaders(ImmutableMap.of("foo", foo, "governance", governance));
-
-    assertThat(defs).extracting("compatibilityMode").containsOnly(false, false);
-  }
-
-  private PluginInfo createPluginInfo(String pluginKey) throws IOException {
+  public void log_warning_if_plugin_is_built_with_api_5_2_or_lower() throws Exception {
     File jarFile = temp.newFile();
-    return new PluginInfo(pluginKey)
+    PluginInfo info = new PluginInfo("foo")
       .setJarFile(jarFile)
-      .setMainClass("org.foo." + pluginKey + "Plugin")
-      .setMinimalSqVersion(Version.create("6.6"));
+      .setMainClass("org.foo.FooPlugin")
+      .setMinimalSqVersion(Version.create("4.5.2"));
+
+    Collection<PluginClassLoaderDef> defs = underTest.defineClassloaders(ImmutableMap.of("foo", info));
+    assertThat(defs).extracting(PluginClassLoaderDef::getBasePluginKey).containsExactly("foo");
+
+    List<String> warnings = logTester.logs(LoggerLevel.WARN);
+    assertThat(warnings).contains("API compatibility mode is no longer supported. In case of error, plugin foo [foo] should package its dependencies.");
   }
 
   /**
index a45feb6dca7dfe8f8a19e184fcf6a63af039c224..79e4b2246408a681ea9728503481b8817f6c3ace 100644 (file)
@@ -8,6 +8,7 @@ dependencies {
   // please keep list ordered
 
   compile 'org.codehaus.sonar:sonar-channel'
+  compile project(':sonar-plugin-api')
 
   compileOnly 'com.google.code.findbugs:jsr305'
 
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/CodeFragment.java b/sonar-duplications/src/main/java/org/sonar/duplications/CodeFragment.java
deleted file mode 100644 (file)
index 450259c..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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.duplications;
-
-
-/**
- * TODO Enforce contracts of this interface in concrete classes by using preconditions, currently this leads to failures of tests.
- *
- * <p>This interface is not intended to be implemented by clients.</p>
- *
- * @since 2.14
- */
-public interface CodeFragment {
-
-  /**
-   * Number of line where fragment starts.
-   * Numbering starts from 1.
-   */
-  int getStartLine();
-
-  /**
-   * Number of line where fragment ends.
-   * Numbering starts from 1.
-   */
-  int getEndLine();
-
-}
index 7b2e5fe3dce0109a7660612aca366b17cd016422..76b8bbc4b36caa4e1940459e27bd1c9612c39495 100644 (file)
  */
 package org.sonar.duplications.block;
 
-import org.sonar.duplications.CodeFragment;
-
 /**
  * Represents part of source code between two lines.
  * If two blocks have the same {@link #getBlockHash() hash}, then we assume that there is a duplication in a code, which they represent.
  */
-public final class Block implements CodeFragment {
+public final class Block {
 
   private final String resourceId;
   private final ByteArray blockHash;
@@ -127,12 +125,10 @@ public final class Block implements CodeFragment {
     return indexInFile;
   }
 
-  @Override
   public int getStartLine() {
     return startLine;
   }
 
-  @Override
   public int getEndLine() {
     return endLine;
   }
index da8cd64c543a58349d0c422bc27458d22a15fee2..5b62937268a27ceafdf6fee8b2a8f53fdbdd1d61 100644 (file)
@@ -19,9 +19,7 @@
  */
 package org.sonar.duplications.index;
 
-import org.sonar.duplications.CodeFragment;
-
-public class ClonePart implements CodeFragment {
+public class ClonePart {
 
   private final String resourceId;
   private final int startUnit;
@@ -48,12 +46,10 @@ public class ClonePart implements CodeFragment {
     return startUnit;
   }
 
-  @Override
   public int getStartLine() {
     return startLine;
   }
 
-  @Override
   public int getEndLine() {
     return endLine;
   }
index 50a32621f0aa346262694713b8f5ebc5751cb7aa..1e11b40dc9c51aa7b74a9840d282a52523c1d56e 100644 (file)
@@ -21,9 +21,8 @@ package org.sonar.duplications.internal.pmd;
 
 import java.util.ArrayList;
 import java.util.List;
-
 import javax.annotation.concurrent.Immutable;
-
+import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
 import org.sonar.duplications.block.Block;
 import org.sonar.duplications.block.ByteArray;
 
index 44f1576dc75a4b2508dcfa76e4d99a59db3dd350..e98f30e9e006a6dadb930c19579b751e73c54e86 100644 (file)
@@ -26,6 +26,7 @@ import net.sourceforge.pmd.cpd.SourceCode;
 import net.sourceforge.pmd.cpd.TokenEntry;
 import net.sourceforge.pmd.cpd.Tokenizer;
 import net.sourceforge.pmd.cpd.Tokens;
+import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
 import org.sonar.duplications.block.Block;
 import org.sonar.duplications.cpd.FileCodeLoaderWithoutCache;
 
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/TokensLine.java b/sonar-duplications/src/main/java/org/sonar/duplications/internal/pmd/TokensLine.java
deleted file mode 100644 (file)
index 62f3059..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 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.duplications.internal.pmd;
-
-import org.sonar.duplications.CodeFragment;
-
-/**
- * Immutable code fragment, which formed from tokens of one line.
- */
-public class TokensLine implements CodeFragment {
-
-  private final String value;
-
-  private final int startLine;
-  private final int hashCode;
-
-  private final int startUnit;
-  private final int endUnit;
-
-  public TokensLine(int startUnit, int endUnit, int startLine, String value) {
-    if (startLine <= 0) {
-      throw new IllegalArgumentException("Start line should be strictly positive");
-    }
-    // TODO do we have requirements for length and hashcode ?
-    this.startLine = startLine;
-    this.value = value;
-    this.hashCode = value.hashCode();
-
-    this.startUnit = startUnit;
-    this.endUnit = endUnit;
-  }
-
-  public String getValue() {
-    return value;
-  }
-
-  @Override
-  public int getStartLine() {
-    return startLine;
-  }
-
-  /**
-   * Same as {@link #getStartLine()}
-   */
-  @Override
-  public int getEndLine() {
-    return startLine;
-  }
-
-  public int getHashCode() {
-    return hashCode;
-  }
-
-  public int getStartUnit() {
-    return startUnit;
-  }
-
-  public int getEndUnit() {
-    return endUnit;
-  }
-
-}
index a18c66353815bd32134d737eb7bf981c7f84ebf3..c6a84d59a7b06fb1a280f1d4153fc6d5695fe712 100644 (file)
@@ -21,10 +21,9 @@ package org.sonar.duplications.statement;
 
 import java.util.List;
 import javax.annotation.Nullable;
-import org.sonar.duplications.CodeFragment;
 import org.sonar.duplications.token.Token;
 
-public class Statement implements CodeFragment {
+public class Statement {
 
   private final int startLine;
   private final int endLine;
@@ -54,12 +53,10 @@ public class Statement implements CodeFragment {
     this.endLine = tokens.get(tokens.size() - 1).getLine();
   }
 
-  @Override
   public int getStartLine() {
     return startLine;
   }
 
-  @Override
   public int getEndLine() {
     return endLine;
   }
index 4335be00567e336baa628c158c57678f84e3f38f..99d895c0b9b28090cf1f0ddcea0c93003bcf8a8d 100644 (file)
  */
 package org.sonar.duplications.internal.pmd;
 
+import java.util.Arrays;
+import java.util.List;
 import org.junit.Test;
+import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
 import org.sonar.duplications.block.Block;
 import org.sonar.duplications.block.ByteArray;
 
-import java.util.Arrays;
-import java.util.List;
-
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
 
index 7ff5dbe30d4a25e5e25f46dfcbd3f4f65e3c05e5..12f58bd8c9accd65c7df3721b6afb4284d01acde 100644 (file)
@@ -30,6 +30,7 @@ import net.sourceforge.pmd.cpd.Tokenizer;
 import net.sourceforge.pmd.cpd.Tokens;
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
diff --git a/sonar-plugin-api-deps/build.gradle b/sonar-plugin-api-deps/build.gradle
deleted file mode 100644 (file)
index e8620ce..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-sonarqube {
-  properties {
-    property 'sonar.projectName', "${projectTitle} :: Plugin API Dependencies"
-  }
-}
-
-apply plugin: 'com.github.johnrengelman.shadow'
-
-dependencies {
-  // Versions must not be changed and overridden from root build.gradle (see dependencyManagement section).
-  // These are the versions defined in SQ 5.1
-  compile 'com.google.code.gson:gson:2.3.1'
-  compile 'com.google.guava:guava:10.0.1'
-  compile 'commons-beanutils:commons-beanutils:1.9.3'
-  compile 'commons-codec:commons-codec:1.8'
-  compile 'commons-collections:commons-collections:3.2.2'
-  compile 'org.apache.commons:commons-email:1.3.2'
-  compile 'commons-io:commons-io:2.4'
-  compile 'commons-lang:commons-lang:2.6'
-  compile('dom4j:dom4j:1.6.1') {
-    exclude group: 'xml-apis'
-  }
-  compile 'org.picocontainer:picocontainer:2.14.3'
-  compile 'org.slf4j:slf4j-api:1.7.10'
-  compile 'ch.qos.logback:logback-classic:1.1.2'
-  compile 'ch.qos.logback:logback-core:1.1.2'
-  compile('org.apache.maven:maven-core:3.0.5') {
-    exclude group: 'classworlds', module: 'classworlds'
-    exclude group: 'org.sonatype.sisu', module: 'sisu-guava'
-  }
-  compile 'org.apache.maven:maven-artifact:3.0.5'
-  compile('org.codehaus.sonar:sonar-squid:4.1') {
-    exclude group: 'org.codehaus.sonar', module: 'sonar-check-api'
-  }
-  compile('org.codehaus.sonar:sonar-java-api:5.1') {
-    exclude group: 'org.codehaus.sonar', module: 'sonar-deprecated'
-    exclude group: 'org.codehaus.sonar', module: 'sonar-plugin-api'
-  }
-}
-
-// This JAR is cached because used as a resource in sonar-core:
-shadowJar.outputs.cacheIf { true }
index 047cf35b69580c7b1fa8f8de1043be3e8cfd759b..e9c781e7e472733ee6f686136eda7478240e5c5d 100644 (file)
@@ -17,9 +17,6 @@ dependencies {
 
   // shaded, but not relocated
   compile project(':sonar-check-api')
-  compile(project(':sonar-duplications')) {
-    exclude group: 'org.slf4', module: 'slf4j-api'
-  }
 
   shadow 'org.codehaus.staxmate:staxmate'
   shadow 'org.codehaus.woodstox:stax2-api'
index 16ac7816508df5a88535f482ddbdc10c44845f81..06c5e30c0dd03072f5ae1d9069b32ddd231bc44a 100644 (file)
@@ -30,7 +30,6 @@ import org.sonar.api.batch.sensor.cpd.NewCpdTokens;
 import org.sonar.api.batch.sensor.internal.DefaultStorable;
 import org.sonar.api.batch.sensor.internal.SensorStorage;
 import org.sonar.api.config.Configuration;
-import org.sonar.duplications.internal.pmd.TokensLine;
 
 import static com.google.common.base.Preconditions.checkState;
 import static java.util.Collections.unmodifiableList;
@@ -39,7 +38,7 @@ import static java.util.Objects.requireNonNull;
 public class DefaultCpdTokens extends DefaultStorable implements NewCpdTokens {
 
   private final Configuration config;
-  private final ArrayList<TokensLine> result = new ArrayList<>();
+  private final List<TokensLine> result = new ArrayList<>();
   private InputFile inputFile;
   private int startLine = Integer.MIN_VALUE;
   private int startIndex = 0;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/TokensLine.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/internal/TokensLine.java
new file mode 100644 (file)
index 0000000..648fddb
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.api.batch.sensor.cpd.internal;
+
+/**
+ * Immutable code fragment, which formed from tokens of one line.
+ */
+public class TokensLine {
+
+  private final String value;
+
+  private final int startLine;
+  private final int hashCode;
+
+  private final int startUnit;
+  private final int endUnit;
+
+  public TokensLine(int startUnit, int endUnit, int startLine, String value) {
+    if (startLine <= 0) {
+      throw new IllegalArgumentException("Start line should be strictly positive");
+    }
+    // TODO do we have requirements for length and hashcode ?
+    this.startLine = startLine;
+    this.value = value;
+    this.hashCode = value.hashCode();
+
+    this.startUnit = startUnit;
+    this.endUnit = endUnit;
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  public int getStartLine() {
+    return startLine;
+  }
+
+  /**
+   * Same as {@link #getStartLine()}
+   */
+  public int getEndLine() {
+    return startLine;
+  }
+
+  public int getHashCode() {
+    return hashCode;
+  }
+
+  public int getStartUnit() {
+    return startUnit;
+  }
+
+  public int getEndUnit() {
+    return endUnit;
+  }
+
+}
index 76977f55bd7defbbcdb6e312168eb05395e8db6b..3559ebdb2582a348a899d46682003c1dfdc8f202 100644 (file)
@@ -53,6 +53,7 @@ import org.sonar.api.batch.sensor.coverage.NewCoverage;
 import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage;
 import org.sonar.api.batch.sensor.cpd.NewCpdTokens;
 import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens;
+import org.sonar.api.batch.sensor.cpd.internal.TokensLine;
 import org.sonar.api.batch.sensor.error.AnalysisError;
 import org.sonar.api.batch.sensor.error.NewAnalysisError;
 import org.sonar.api.batch.sensor.error.internal.DefaultAnalysisError;
@@ -80,7 +81,6 @@ import org.sonar.api.internal.SonarRuntimeImpl;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.Version;
-import org.sonar.duplications.internal.pmd.TokensLine;
 
 import static java.util.Collections.unmodifiableMap;
 
index 3b0e01073e9864fd52b6e475868f7cf6cd4a8928..fff63e272fdfec304f12d6a75d38ebbd76810265 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.api.server.authentication;
 
+import org.sonar.api.ExtensionPoint;
 import org.sonar.api.server.ServerSide;
 
 /**
@@ -32,6 +33,7 @@ import org.sonar.api.server.ServerSide;
  * @since 5.4
  */
 @ServerSide
+@ExtensionPoint
 public interface IdentityProvider {
 
   /**
index 2442d85d34d17d68945676e6db811af19b5ab24f..9ad0ce807ba2e908917deb07666d924faf61a610 100644 (file)
@@ -30,6 +30,7 @@ dependencies {
   compile project(':sonar-core')
   compile project(':sonar-scanner-protocol')
   compile project(':sonar-ws')
+  compile project(':sonar-duplications')
   runtime project(path: ':sonar-plugin-api', configuration: 'shadow')
   compileOnly project(path: ':sonar-plugin-api')