summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2015-04-24 09:15:05 +0200
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-05-11 10:21:55 +0200
commit14a5c982e5f1b28354a853073bd3e225b3914abe (patch)
treee298a2948f49628880f8d5290451adc14a920613
parentcba928d505985972e13c8e895b490a52702af925 (diff)
downloadsonarqube-14a5c982e5f1b28354a853073bd3e225b3914abe.tar.gz
sonarqube-14a5c982e5f1b28354a853073bd3e225b3914abe.zip
SONAR-6370 isolate plugin classloader from core
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/charts/package-info.java3
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/package-info.java3
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/notifications/alerts/package-info.java3
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/package-info.java3
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/package-info.java3
-rw-r--r--pom.xml10
-rw-r--r--server/sonar-server/pom.xml12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrator.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelPluginRepository.java22
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java25
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java32
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java26
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/InstalledPluginReferentialFactory.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java24
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/PluginReferentialMetadataConverter.java22
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java43
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarInstaller.java62
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java286
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java355
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginUnzipper.java65
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/CancelAllPluginsWsAction.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledPluginsWsAction.java25
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java29
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java28
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UninstallPluginsWsAction.java34
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/search/IndexQueue.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/startup/GeneratePluginIndex.java15
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java39
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/debt/DebtModelPluginRepositoryTest.java14
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/es/EsTester.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerFileSystemTest.java14
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/RailsAppsDeployerTest.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java60
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/InstalledPluginReferentialFactoryTest.java26
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/MimeTypesTest.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java31
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/PluginReferentialMetadataConverterTest.java18
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java309
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java297
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginUnzipperTest.java64
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/TestProjectUtils.java (renamed from sonar-core/src/main/java/org/sonar/core/plugins/ResourcesClassloader.java)35
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/CancelAllPluginsWsActionTest.java8
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledPluginsWsActionTest.java48
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java30
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java13
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UninstallPluginsWsActionTest.java21
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/startup/GeneratePluginIndexTest.java23
-rw-r--r--server/sonar-server/src/test/projects/.gitignore7
-rw-r--r--server/sonar-server/src/test/projects/README.txt3
-rw-r--r--server/sonar-server/src/test/projects/pom.xml19
-rw-r--r--server/sonar-server/src/test/projects/test-base-plugin-v2/pom.xml36
-rw-r--r--server/sonar-server/src/test/projects/test-base-plugin-v2/src/BasePlugin.java11
-rw-r--r--server/sonar-server/src/test/projects/test-base-plugin-v2/target/test-base-plugin-0.2-SNAPSHOT.jarbin0 -> 2437 bytes
-rw-r--r--server/sonar-server/src/test/projects/test-base-plugin/pom.xml36
-rw-r--r--server/sonar-server/src/test/projects/test-base-plugin/src/BasePlugin.java11
-rw-r--r--server/sonar-server/src/test/projects/test-base-plugin/target/test-base-plugin-0.1-SNAPSHOT.jarbin0 -> 2437 bytes
-rw-r--r--server/sonar-server/src/test/projects/test-core-plugin/pom.xml36
-rw-r--r--server/sonar-server/src/test/projects/test-core-plugin/src/CorePlugin.java11
-rw-r--r--server/sonar-server/src/test/projects/test-core-plugin/target/test-core-plugin-0.1-SNAPSHOT.jarbin0 -> 2412 bytes
-rw-r--r--server/sonar-server/src/test/projects/test-extend-plugin/pom.xml37
-rw-r--r--server/sonar-server/src/test/projects/test-extend-plugin/src/ExtendPlugin.java11
-rw-r--r--server/sonar-server/src/test/projects/test-extend-plugin/target/test-extend-plugin-0.1-SNAPSHOT.jarbin0 -> 2481 bytes
-rw-r--r--server/sonar-server/src/test/projects/test-libs-plugin/pom.xml49
-rw-r--r--server/sonar-server/src/test/projects/test-libs-plugin/src/LibsPlugin.java11
-rw-r--r--server/sonar-server/src/test/projects/test-libs-plugin/target/test-libs-plugin-0.1-SNAPSHOT.jarbin0 -> 40097 bytes
-rw-r--r--server/sonar-server/src/test/projects/test-require-plugin/pom.xml37
-rw-r--r--server/sonar-server/src/test/projects/test-require-plugin/src/RequirePlugin.java11
-rw-r--r--server/sonar-server/src/test/projects/test-require-plugin/target/test-require-plugin-0.1-SNAPSHOT.jarbin0 -> 2488 bytes
-rw-r--r--server/sonar-server/src/test/projects/test-requirenew-plugin/pom.xml37
-rw-r--r--server/sonar-server/src/test/projects/test-requirenew-plugin/src/RequirePlugin.java11
-rw-r--r--server/sonar-server/src/test/projects/test-requirenew-plugin/target/test-requirenew-plugin-0.1-SNAPSHOT.jarbin0 -> 2553 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/extension.jarbin885 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/foo-plugin.jarbin1460 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/sonar-build-breaker-plugin-0.1.jarbin5027 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginDownloaderTest/foo-plugin-1.0.jarbin955 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginExtensionMetadataTest/version1/extension.jarbin885 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginExtensionMetadataTest/version2/extension.jarbin898 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/foo-plugin-1.0.jarbin1076 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/foo-plugin-2.0.jarbin1077 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/not-a-plugin.jarbin960 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/old-plugin.jarbin980 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataTest/foo-plugin.jarbin1460 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/bar-plugin-1.0.jarbin714 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/foo-plugin-1.0.jarbin955 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/foo-plugin-2.0.jarbin901 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/not-a-plugin.jarbin396 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/require-sq-2.5.jarbin12689 -> 0 bytes
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jarbin7456 -> 0 bytes
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/updatecenter_controller.rb6
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginInstaller.java (renamed from sonar-batch/src/main/java/org/sonar/batch/bootstrap/DefaultPluginsRepository.java)70
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginPredicate.java121
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java183
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginUnzipper.java77
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java23
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java68
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginInstaller.java (renamed from sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginsRepository.java)31
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java61
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/mediumtest/FakePluginInstaller.java (renamed from sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginJarInstaller.java)37
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ScanTask.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginInstallerTest.java (renamed from sonar-batch/src/test/java/org/sonar/batch/bootstrap/DefaultPluginsRepositoryTest.java)36
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginPredicateTest.java157
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java450
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginUnzipperTest.java (renamed from sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginJarInstallerTest.java)32
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java42
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalContainerTest.java32
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/deprecated/decorator/DecoratorsSelectorTest.java2
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java2
-rw-r--r--sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginUnzipperTest/sonar-checkstyle-plugin-2.8.jar (renamed from sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginJarInstallerTest/sonar-checkstyle-plugin-2.8.jar)bin1026947 -> 1026947 bytes
-rw-r--r--sonar-check-api/src/main/java/org/sonar/check/package-info.java3
-rw-r--r--sonar-colorizer/src/main/java/org/sonar/colorizer/package-info.java3
-rw-r--r--sonar-core/pom.xml14
-rw-r--r--sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java59
-rw-r--r--sonar-core/src/main/java/org/sonar/core/i18n/I18nClassloader.java36
-rw-r--r--sonar-core/src/main/java/org/sonar/core/issue/workflow/package-info.java3
-rw-r--r--sonar-core/src/main/java/org/sonar/core/notification/package-info.java3
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java (renamed from sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java)15
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/ComponentKeys.java (renamed from sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentKeys.java)9
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/PicoUtils.java (renamed from sonar-plugin-api/src/main/java/org/sonar/api/platform/PicoUtils.java)3
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/PluginInfo.java353
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/PluginLoader.java199
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/PluginRepository.java (renamed from sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginRepository.java)27
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/PluginUnzipper.java (renamed from sonar-core/src/test/java/org/sonar/core/plugins/ResourcesClassloaderTest.java)26
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/UnzippedPlugin.java62
-rw-r--r--sonar-core/src/main/java/org/sonar/core/platform/package-info.java (renamed from server/sonar-server/src/test/java/org/sonar/server/platform/SonarHomeTest.java)14
-rw-r--r--sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java310
-rw-r--r--sonar-core/src/main/java/org/sonar/core/plugins/PluginClassloaders.java253
-rw-r--r--sonar-core/src/main/java/org/sonar/core/plugins/PluginJarInstaller.java111
-rw-r--r--sonar-core/src/main/java/org/sonar/core/plugins/RemotePlugin.java3
-rw-r--r--sonar-core/src/main/java/org/sonar/core/plugins/package-info.java4
-rw-r--r--sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java12
-rw-r--r--sonar-core/src/test/java/org/sonar/core/i18n/I18nClassloaderTest.java4
-rw-r--r--sonar-core/src/test/java/org/sonar/core/platform/ComponentContainerTest.java (renamed from sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java)14
-rw-r--r--sonar-core/src/test/java/org/sonar/core/platform/ComponentKeysTest.java (renamed from sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentKeysTest.java)11
-rw-r--r--sonar-core/src/test/java/org/sonar/core/platform/PicoUtilsTest.java (renamed from sonar-plugin-api/src/test/java/org/sonar/api/platform/PicoUtilsTest.java)4
-rw-r--r--sonar-core/src/test/java/org/sonar/core/platform/PluginInfoTest.java203
-rw-r--r--sonar-core/src/test/java/org/sonar/core/platform/PluginLoaderTest.java131
-rw-r--r--sonar-core/src/test/java/org/sonar/core/platform/PluginUnzipperTest.java81
-rw-r--r--sonar-core/src/test/java/org/sonar/core/plugins/DefaultPluginMetadataTest.java145
-rw-r--r--sonar-core/src/test/java/org/sonar/core/plugins/PluginClassloadersTest.java129
-rw-r--r--sonar-core/src/test/java/org/sonar/core/plugins/PluginJarInstallerTest.java99
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/plugins/PluginClassloadersTest/bar.jarbin1057 -> 0 bytes
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/plugins/PluginClassloadersTest/foo.jarbin313 -> 0 bytes
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/plugins/checkstyle-extension.xml1
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/plugins/fake2-plugin-1.1.jarbin2673 -> 0 bytes
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/plugins/sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jarbin5597 -> 0 bytes
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/plugins/sonar-cobertura-plugin-3.1.1.jarbin14560 -> 0 bytes
-rw-r--r--sonar-core/src/test/resources/org/sonar/core/plugins/sonar-switch-off-violations-plugin-1.1.jarbin12689 -> 0 bytes
-rw-r--r--sonar-deprecated/src/main/java/org/sonar/api/charts/package-info.java3
-rw-r--r--sonar-home/src/main/java/org/sonar/home/cache/FileCache.java44
-rw-r--r--sonar-home/src/test/java/org/sonar/home/cache/FileCacheTest.java29
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginMetadata.java74
161 files changed, 3457 insertions, 3110 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/charts/package-info.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/charts/package-info.java
index 080a6b643ec..6d9fc80d519 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/charts/package-info.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/charts/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.plugins.core.charts;
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/package-info.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/package-info.java
index 30550df1482..d901586ae25 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/package-info.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/dashboards/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.plugins.core.dashboards;
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/notifications/alerts/package-info.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/notifications/alerts/package-info.java
index a2cb7d768c1..5e28de8ee2c 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/notifications/alerts/package-info.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/notifications/alerts/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.plugins.core.notifications.alerts;
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/package-info.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/package-info.java
index 03fd8c46350..df9ccea5073 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/package-info.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/security/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.plugins.core.security;
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/package-info.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/package-info.java
index 870522ec56f..8d487ae9500 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/package-info.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.plugins.core.timemachine;
diff --git a/pom.xml b/pom.xml
index 2dee8a71b58..3d6388fb8b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -597,6 +597,11 @@
</dependency>
<dependency>
<groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-classloader</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
<artifactId>sonar-markdown</artifactId>
<version>${project.version}</version>
</dependency>
@@ -708,11 +713,6 @@
</exclusions>
</dependency>
<dependency>
- <groupId>org.codehaus.plexus</groupId>
- <artifactId>plexus-classworlds</artifactId>
- <version>2.5.1</version>
- </dependency>
- <dependency>
<groupId>com.tinkerpop.blueprints</groupId>
<artifactId>blueprints-core</artifactId>
<version>2.2.0</version>
diff --git a/server/sonar-server/pom.xml b/server/sonar-server/pom.xml
index 78e7f995a1e..fd3ee697d4f 100644
--- a/server/sonar-server/pom.xml
+++ b/server/sonar-server/pom.xml
@@ -248,7 +248,19 @@
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
+
</resources>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>false</filtering>
+ </testResource>
+ <testResource>
+ <directory>src/test/projects</directory>
+ <filtering>false</filtering>
+ </testResource>
+
+ </testResources>
<plugins>
<plugin>
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java
index 95ad3ef370e..d95084053ae 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationContainer.java
@@ -19,7 +19,7 @@
*/
package org.sonar.server.computation;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.core.issue.db.UpdateConflictResolver;
import org.sonar.server.computation.issue.*;
import org.sonar.server.computation.measure.MetricCache;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrator.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrator.java
index b506fc5244a..7158b0d5e6d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrator.java
@@ -29,9 +29,9 @@ import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.persistence.DdlUtils;
import org.sonar.server.db.DbClient;
-import org.sonar.server.plugins.ServerPluginRepository;
import com.google.common.annotations.VisibleForTesting;
+import org.sonar.server.plugins.ServerPluginRepository;
/**
* Restore schema by executing DDL scripts. Only H2 database is supported.
@@ -46,10 +46,10 @@ public class DatabaseMigrator implements ServerComponent, Startable {
private final ServerUpgradeStatus serverUpgradeStatus;
/**
- * ServerPluginRepository is used to ensure H2 schema creation is done only after copy of bundle plugins have been done
+ * ServerPluginInstaller is used to ensure H2 schema creation is done only after copy of bundle plugins have been done
*/
public DatabaseMigrator(DbClient dbClient, MigrationStep[] migrations, ServerUpgradeStatus serverUpgradeStatus,
- ServerPluginRepository serverPluginRepository) {
+ ServerPluginRepository unused) {
this.dbClient = dbClient;
this.migrations = migrations;
this.serverUpgradeStatus = serverUpgradeStatus;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelPluginRepository.java b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelPluginRepository.java
index b0e1cb6bd20..da45c47bf68 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelPluginRepository.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelPluginRepository.java
@@ -25,9 +25,9 @@ import com.google.common.collect.Maps;
import org.apache.commons.io.Charsets;
import org.picocontainer.Startable;
import org.sonar.api.Plugin;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import java.io.InputStreamReader;
import java.io.Reader;
@@ -45,7 +45,7 @@ import static com.google.common.collect.Lists.newArrayList;
* they must be named "<pluginKey>-model.xml".
* </p>
*/
-public class DebtModelPluginRepository implements ServerExtension, Startable {
+public class DebtModelPluginRepository implements ServerComponent, Startable {
public static final String DEFAULT_MODEL = "technical-debt";
@@ -87,14 +87,12 @@ public class DebtModelPluginRepository implements ServerExtension, Startable {
contributingPluginKeyToClassLoader = Maps.newTreeMap();
// Add default model
contributingPluginKeyToClassLoader.put(DEFAULT_MODEL, getClass().getClassLoader());
- for (PluginMetadata metadata : pluginRepository.getMetadata()) {
- String pluginKey = metadata.getKey();
- Plugin plugin = pluginRepository.getPlugin(pluginKey);
- if (plugin != null) {
- ClassLoader classLoader = plugin.getClass().getClassLoader();
- if (classLoader.getResource(getXMLFilePath(pluginKey)) != null) {
- contributingPluginKeyToClassLoader.put(pluginKey, classLoader);
- }
+ for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
+ String pluginKey = pluginInfo.getKey();
+ Plugin plugin = pluginRepository.getPluginInstance(pluginKey);
+ ClassLoader classLoader = plugin.getClass().getClassLoader();
+ if (classLoader.getResource(getXMLFilePath(pluginKey)) != null) {
+ contributingPluginKeyToClassLoader.put(pluginKey, classLoader);
}
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java b/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java
index df520c3900a..5258e753057 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java
@@ -127,27 +127,16 @@ public class DefaultServerFileSystem implements ServerFileSystem, Startable {
return new File(getHomeDir(), "extensions/downloads");
}
- public File getTrashPluginsDir() {
- return new File(getHomeDir(), "extensions/trash");
- }
-
- public List<File> getCorePlugins() {
- File corePluginsDir = new File(getHomeDir(), "lib/core-plugins");
- return getFiles(corePluginsDir, "jar");
- }
-
- public List<File> getBundledPlugins() {
- File corePluginsDir = new File(getHomeDir(), "lib/bundled-plugins");
- return getFiles(corePluginsDir, "jar");
+ public File getInstalledPluginsDir() {
+ return new File(getHomeDir(), "extensions/plugins");
}
- public List<File> getUserPlugins() {
- File pluginsDir = getUserPluginsDir();
- return getFiles(pluginsDir, "jar");
+ public File getBundledPluginsDir() {
+ return new File(getHomeDir(), "lib/bundled-plugins");
}
- public File getUserPluginsDir() {
- return new File(getHomeDir(), "extensions/plugins");
+ public File getCorePluginsDir() {
+ return new File(getHomeDir(), "lib/core-plugins");
}
public File getDeprecatedPluginsDir() {
@@ -172,7 +161,7 @@ public class DefaultServerFileSystem implements ServerFileSystem, Startable {
}
private List<File> getFiles(File dir, String... fileSuffixes) {
- List<File> files = new ArrayList<File>();
+ List<File> files = new ArrayList<>();
if (dir != null && dir.exists()) {
if (fileSuffixes != null && fileSuffixes.length > 0) {
files.addAll(FileUtils.listFiles(dir, fileSuffixes, false));
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index 5d857910be2..4f28227339e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -19,16 +19,17 @@
*/
package org.sonar.server.platform;
-import java.util.Collection;
-import java.util.Properties;
-import javax.annotation.CheckForNull;
-import javax.servlet.ServletContext;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.persistence.DatabaseVersion;
+import javax.annotation.CheckForNull;
+import javax.servlet.ServletContext;
+import java.util.Collection;
+import java.util.Properties;
+
/**
* @since 2.2
*/
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java b/server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java
index c034a78ee38..8f7cb251897 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java
@@ -25,11 +25,11 @@ import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
import org.sonar.api.Plugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.platform.ServerFileSystem;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import javax.annotation.Nullable;
@@ -47,28 +47,26 @@ public class RailsAppsDeployer implements Startable {
private static final Logger LOG = Loggers.get(RailsAppsDeployer.class);
private static final String ROR_PATH = "org/sonar/ror/";
- private final ServerFileSystem fileSystem;
+ private final ServerFileSystem fs;
private final PluginRepository pluginRepository;
- public RailsAppsDeployer(ServerFileSystem fileSystem, PluginRepository pluginRepository) {
- this.fileSystem = fileSystem;
+ public RailsAppsDeployer(ServerFileSystem fs, PluginRepository pluginRepository) {
+ this.fs = fs;
this.pluginRepository = pluginRepository;
}
@Override
public void start() {
- LOG.info("Deploy Ruby on Rails applications");
+ LOG.info("Deploying Ruby on Rails applications");
File appsDir = prepareRailsDirectory();
- for (PluginMetadata pluginMetadata : pluginRepository.getMetadata()) {
- String pluginKey = pluginMetadata.getKey();
- Plugin plugin = pluginRepository.getPlugin(pluginKey);
- if (plugin != null) {
- try {
- deployRailsApp(appsDir, pluginKey, plugin.getClass().getClassLoader());
- } catch (Exception e) {
- throw new IllegalStateException("Fail to deploy Ruby on Rails application: " + pluginKey, e);
- }
+ for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
+ String pluginKey = pluginInfo.getKey();
+ Plugin plugin = pluginRepository.getPluginInstance(pluginKey);
+ try {
+ deployRailsApp(appsDir, pluginKey, plugin.getClass().getClassLoader());
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format("Fail to deploy Ruby on Rails application of plugin [%s]", pluginKey), e);
}
}
}
@@ -80,7 +78,7 @@ public class RailsAppsDeployer implements Startable {
@VisibleForTesting
File prepareRailsDirectory() {
- File appsDir = new File(fileSystem.getTempDir(), "ror");
+ File appsDir = new File(fs.getTempDir(), "ror");
prepareDir(appsDir);
return appsDir;
}
@@ -88,7 +86,7 @@ public class RailsAppsDeployer implements Startable {
@VisibleForTesting
static void deployRailsApp(File appsDir, final String pluginKey, ClassLoader appClassLoader) {
if (hasRailsApp(pluginKey, appClassLoader)) {
- LOG.info("Deploy app: " + pluginKey);
+ LOG.info("Deploying app: " + pluginKey);
File appDir = new File(appsDir, pluginKey);
ClassLoaderUtils.copyResources(appClassLoader, pathToRubyInitFile(pluginKey), appDir, new Function<String, String>() {
@Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
index b6347f84e61..6844878d9b9 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
@@ -22,7 +22,6 @@ package org.sonar.server.platform;
import com.google.common.collect.Lists;
import org.sonar.api.config.EmailSettings;
import org.sonar.api.issue.action.Actions;
-import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.profiles.AnnotationProfileParser;
import org.sonar.api.profiles.XMLProfileParser;
import org.sonar.api.profiles.XMLProfileSerializer;
@@ -58,6 +57,8 @@ import org.sonar.core.persistence.DefaultDatabase;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.persistence.SemaphoreUpdater;
import org.sonar.core.persistence.SemaphoresImpl;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.PluginLoader;
import org.sonar.core.purge.PurgeProfiler;
import org.sonar.core.qualitygate.db.ProjectQgateAssociationDao;
import org.sonar.core.qualitygate.db.QualityGateConditionDao;
@@ -216,9 +217,8 @@ import org.sonar.server.platform.ws.UpgradesSystemWsAction;
import org.sonar.server.plugins.InstalledPluginReferentialFactory;
import org.sonar.server.plugins.PluginDownloader;
import org.sonar.server.plugins.ServerExtensionInstaller;
-import org.sonar.server.plugins.ServerPluginJarInstaller;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
import org.sonar.server.plugins.ServerPluginRepository;
+import org.sonar.server.plugins.ServerPluginUnzipper;
import org.sonar.server.plugins.UpdateCenterClient;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
import org.sonar.server.plugins.ws.AvailablePluginsWsAction;
@@ -519,10 +519,10 @@ class ServerComponents {
PlatformRubyBridge.class,
// plugins
- ServerPluginJarsInstaller.class,
- ServerPluginJarInstaller.class,
- InstalledPluginReferentialFactory.class,
ServerPluginRepository.class,
+ ServerPluginUnzipper.class,
+ PluginLoader.class,
+ InstalledPluginReferentialFactory.class,
ServerExtensionInstaller.class,
// depends on plugins
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java
index 9ec58dc4044..591168f2831 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java
@@ -22,12 +22,13 @@ package org.sonar.server.platform.monitoring;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.updatecenter.common.Version;
+
+import javax.annotation.Nonnull;
import java.util.LinkedHashMap;
-import java.util.List;
/**
* Installed plugins (excluding core plugins)
@@ -47,21 +48,24 @@ public class PluginsMonitor implements Monitor {
@Override
public LinkedHashMap<String, Object> attributes() {
LinkedHashMap<String, Object> attributes = new LinkedHashMap<>();
- for (PluginMetadata plugin : plugins()) {
+ for (PluginInfo plugin : plugins()) {
LinkedHashMap<String, Object> pluginAttributes = new LinkedHashMap<>();
pluginAttributes.put("Name", plugin.getName());
- pluginAttributes.put("Version", plugin.getVersion());
+ Version version = plugin.getVersion();
+ if (version != null) {
+ pluginAttributes.put("Version", version.getName());
+ }
attributes.put(plugin.getKey(), pluginAttributes);
}
return attributes;
}
- private List<PluginMetadata> plugins() {
- return Lists.newArrayList(Iterables.filter(repository.getMetadata(), new Predicate<PluginMetadata>() {
+ private Iterable<PluginInfo> plugins() {
+ return Iterables.filter(repository.getPluginInfos(), new Predicate<PluginInfo>() {
@Override
- public boolean apply(PluginMetadata input) {
- return !input.isCore();
+ public boolean apply(@Nonnull PluginInfo info) {
+ return !info.isCore();
}
- }));
+ });
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/InstalledPluginReferentialFactory.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/InstalledPluginReferentialFactory.java
index 257cd22ca05..599899c475c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/InstalledPluginReferentialFactory.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/InstalledPluginReferentialFactory.java
@@ -20,7 +20,7 @@
package org.sonar.server.plugins;
import org.picocontainer.Startable;
-import org.sonar.api.platform.PluginRepository;
+import org.sonar.core.platform.PluginRepository;
import org.sonar.updatecenter.common.PluginReferential;
public class InstalledPluginReferentialFactory implements Startable {
@@ -51,7 +51,7 @@ public class InstalledPluginReferentialFactory implements Startable {
}
private void init() {
- installedPluginReferential = PluginReferentialMetadataConverter.getInstalledPluginReferential(pluginRepository.getMetadata());
+ installedPluginReferential = PluginReferentialMetadataConverter.getInstalledPluginReferential(pluginRepository.getPluginInfos());
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java
index 1e2dd190f49..b17ac977342 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java
@@ -25,7 +25,7 @@ import org.sonar.api.utils.HttpDownloader;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.server.platform.DefaultServerFileSystem;
import org.sonar.updatecenter.common.Release;
import org.sonar.updatecenter.common.Version;
@@ -48,6 +48,10 @@ import static org.apache.commons.io.FileUtils.forceMkdir;
import static org.apache.commons.io.FileUtils.toFile;
import static org.apache.commons.lang.StringUtils.substringAfterLast;
+/**
+ * Downloads plugins from update center. Files are copied in the directory extensions/downloads and then
+ * moved to extensions/plugins after server restart.
+ */
public class PluginDownloader implements Startable {
private static final Logger LOG = Loggers.get(PluginDownloader.class);
@@ -56,21 +60,17 @@ public class PluginDownloader implements Startable {
private final UpdateCenterMatrixFactory updateCenterMatrixFactory;
private final HttpDownloader downloader;
- private final ServerPluginJarInstaller installer;
private final File downloadDir;
public PluginDownloader(UpdateCenterMatrixFactory updateCenterMatrixFactory, HttpDownloader downloader,
- DefaultServerFileSystem fileSystem, ServerPluginJarInstaller installer) {
+ DefaultServerFileSystem fileSystem) {
this.updateCenterMatrixFactory = updateCenterMatrixFactory;
this.downloader = downloader;
- this.installer = installer;
this.downloadDir = fileSystem.getDownloadedPluginsDir();
}
/**
- * Delete the temporary files remaining from previous downloads
- *
- * @see #downloadRelease(org.sonar.updatecenter.common.Release)
+ * Deletes the temporary files remaining from previous downloads
*/
@Override
public void start() {
@@ -112,10 +112,10 @@ public class PluginDownloader implements Startable {
}
/**
- * @return the list of download plugins as {@link DefaultPluginMetadata} instances
+ * @return the list of download plugins as {@link PluginInfo} instances
*/
- public Collection<DefaultPluginMetadata> getDownloadedPlugins() {
- return newArrayList(transform(listPlugins(this.downloadDir), installer.fileToPlugin()));
+ public Collection<PluginInfo> getDownloadedPlugins() {
+ return newArrayList(transform(listPlugins(this.downloadDir), PluginInfo.JarToPluginInfo.INSTANCE));
}
public void download(String pluginKey, Version version) {
@@ -154,10 +154,10 @@ public class PluginDownloader implements Startable {
}
private static Collection<File> listTempFile(File dir) {
- return FileUtils.listFiles(dir, new String[]{TMP_SUFFIX}, false);
+ return FileUtils.listFiles(dir, new String[] {TMP_SUFFIX}, false);
}
private static Collection<File> listPlugins(File dir) {
- return FileUtils.listFiles(dir, new String[]{PLUGIN_EXTENSION}, false);
+ return FileUtils.listFiles(dir, new String[] {PLUGIN_EXTENSION}, false);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginReferentialMetadataConverter.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginReferentialMetadataConverter.java
index 30646c02a95..70afcb42068 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginReferentialMetadataConverter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginReferentialMetadataConverter.java
@@ -19,10 +19,11 @@
*/
package org.sonar.server.plugins;
-import org.sonar.api.platform.PluginMetadata;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.updatecenter.common.PluginManifest;
import org.sonar.updatecenter.common.PluginReferential;
import org.sonar.updatecenter.common.PluginReferentialManifestConverter;
+import org.sonar.updatecenter.common.Version;
import java.util.Collection;
import java.util.List;
@@ -35,14 +36,14 @@ public class PluginReferentialMetadataConverter {
// Only static call
}
- public static PluginReferential getInstalledPluginReferential(Collection<PluginMetadata> metadata) {
+ public static PluginReferential getInstalledPluginReferential(Collection<PluginInfo> metadata) {
List<PluginManifest> pluginManifestList = getPluginManifestList(metadata);
return PluginReferentialManifestConverter.fromPluginManifests(pluginManifestList);
}
- private static List<PluginManifest> getPluginManifestList(Collection<PluginMetadata> metadata) {
+ private static List<PluginManifest> getPluginManifestList(Collection<PluginInfo> metadata) {
List<PluginManifest> pluginManifestList = newArrayList();
- for (PluginMetadata plugin : metadata) {
+ for (PluginInfo plugin : metadata) {
if (!plugin.isCore()) {
pluginManifestList.add(toPluginManifest(plugin));
}
@@ -50,20 +51,23 @@ public class PluginReferentialMetadataConverter {
return pluginManifestList;
}
- private static PluginManifest toPluginManifest(PluginMetadata metadata) {
+ private static PluginManifest toPluginManifest(PluginInfo metadata) {
PluginManifest pluginManifest = new PluginManifest();
pluginManifest.setKey(metadata.getKey());
pluginManifest.setName(metadata.getName());
- pluginManifest.setVersion(metadata.getVersion());
+ Version version = metadata.getVersion();
+ if (version != null) {
+ pluginManifest.setVersion(version.getName());
+ }
pluginManifest.setDescription(metadata.getDescription());
pluginManifest.setMainClass(metadata.getMainClass());
- pluginManifest.setOrganization(metadata.getOrganization());
+ pluginManifest.setOrganization(metadata.getOrganizationName());
pluginManifest.setOrganizationUrl(metadata.getOrganizationUrl());
pluginManifest.setLicense(metadata.getLicense());
- pluginManifest.setHomepage(metadata.getHomepage());
+ pluginManifest.setHomepage(metadata.getHomepageUrl());
pluginManifest.setIssueTrackerUrl(metadata.getIssueTrackerUrl());
pluginManifest.setBasePlugin(metadata.getBasePlugin());
- pluginManifest.setRequirePlugins(metadata.getRequiredPlugins().toArray(new String []{}));
+ pluginManifest.setRequirePlugins(metadata.getRequiredPlugins().toArray(new String[] {}));
return pluginManifest;
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java
index c084470711c..e9297de4353 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerExtensionInstaller.java
@@ -24,40 +24,43 @@ import com.google.common.collect.ListMultimap;
import org.sonar.api.Extension;
import org.sonar.api.ExtensionProvider;
import org.sonar.api.Plugin;
+import org.sonar.api.ServerComponent;
import org.sonar.api.ServerExtension;
-import org.sonar.api.platform.ComponentContainer;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import java.util.Map;
/**
- * This class adds to picocontainer the server extensions provided by plugins
+ * Loads the plugins server extensions and injects them to DI container
*/
-public class ServerExtensionInstaller {
- private PluginRepository pluginRepository;
+public class ServerExtensionInstaller implements ServerComponent {
+
+ private final PluginRepository pluginRepository;
public ServerExtensionInstaller(PluginRepository pluginRepository) {
this.pluginRepository = pluginRepository;
}
public void installExtensions(ComponentContainer container) {
- ListMultimap<PluginMetadata, Object> installedExtensionsByPlugin = ArrayListMultimap.create();
+ ListMultimap<PluginInfo, Object> installedExtensionsByPlugin = ArrayListMultimap.create();
- for (PluginMetadata pluginMetadata : pluginRepository.getMetadata()) {
- Plugin plugin = pluginRepository.getPlugin(pluginMetadata.getKey());
- container.addExtension(pluginMetadata, plugin);
+ for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
+ String pluginKey = pluginInfo.getKey();
+ Plugin plugin = pluginRepository.getPluginInstance(pluginKey);
+ container.addExtension(pluginInfo, plugin);
for (Object extension : plugin.getExtensions()) {
- if (installExtension(container, pluginMetadata, extension, true) != null) {
- installedExtensionsByPlugin.put(pluginMetadata, extension);
+ if (installExtension(container, pluginInfo, extension, true) != null) {
+ installedExtensionsByPlugin.put(pluginInfo, extension);
} else {
- container.declareExtension(pluginMetadata, extension);
+ container.declareExtension(pluginInfo, extension);
}
}
}
- for (Map.Entry<PluginMetadata, Object> entry : installedExtensionsByPlugin.entries()) {
- PluginMetadata plugin = entry.getKey();
+ for (Map.Entry<PluginInfo, Object> entry : installedExtensionsByPlugin.entries()) {
+ PluginInfo plugin = entry.getKey();
Object extension = entry.getValue();
if (isExtensionProvider(extension)) {
ExtensionProvider provider = (ExtensionProvider) container.getComponentByKey(extension);
@@ -66,25 +69,25 @@ public class ServerExtensionInstaller {
}
}
- private void installProvider(ComponentContainer container, PluginMetadata plugin, ExtensionProvider provider) {
+ private void installProvider(ComponentContainer container, PluginInfo pluginInfo, ExtensionProvider provider) {
Object obj = provider.provide();
if (obj != null) {
if (obj instanceof Iterable) {
for (Object ext : (Iterable) obj) {
- installExtension(container, plugin, ext, false);
+ installExtension(container, pluginInfo, ext, false);
}
} else {
- installExtension(container, plugin, obj, false);
+ installExtension(container, pluginInfo, obj, false);
}
}
}
- Object installExtension(ComponentContainer container, PluginMetadata pluginMetadata, Object extension, boolean acceptProvider) {
+ Object installExtension(ComponentContainer container, PluginInfo pluginInfo, Object extension, boolean acceptProvider) {
if (isType(extension, ServerExtension.class)) {
if (!acceptProvider && isExtensionProvider(extension)) {
throw new IllegalStateException("ExtensionProvider can not include providers itself: " + extension);
}
- container.addExtension(pluginMetadata, extension);
+ container.addExtension(pluginInfo, extension);
return extension;
}
return null;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarInstaller.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarInstaller.java
deleted file mode 100644
index 777a197defd..00000000000
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarInstaller.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.server.plugins;
-
-import org.apache.commons.io.FileUtils;
-import org.sonar.api.utils.ZipUtils;
-import org.sonar.core.plugins.DefaultPluginMetadata;
-import org.sonar.core.plugins.PluginJarInstaller;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.zip.ZipEntry;
-
-public class ServerPluginJarInstaller extends PluginJarInstaller {
-
- public void installToDir(DefaultPluginMetadata metadata, File pluginBasedir) {
- try {
- File pluginFile = metadata.getFile();
- File deployedPlugin = copyPlugin(pluginBasedir, pluginFile);
- install(metadata, pluginBasedir, deployedPlugin);
- } catch (IOException e) {
- throw new IllegalStateException(FAIL_TO_INSTALL_PLUGIN + metadata, e);
- }
- }
-
- private File copyPlugin(File pluginBasedir, File pluginFile) throws IOException {
- FileUtils.forceMkdir(pluginBasedir);
- File targetFile = new File(pluginBasedir, pluginFile.getName());
- FileUtils.copyFile(pluginFile, targetFile);
- return targetFile;
- }
-
- @Override
- protected File extractPluginDependencies(File pluginFile, File pluginBasedir) throws IOException {
- ZipUtils.unzip(pluginFile, pluginBasedir, new LibFilter());
- return pluginBasedir;
- }
-
- private static final class LibFilter implements ZipUtils.ZipEntryFilter {
- @Override
- public boolean accept(ZipEntry entry) {
- return entry.getName().startsWith("META-INF/lib");
- }
- }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java
deleted file mode 100644
index 9b9ce32dc81..00000000000
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarsInstaller.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * 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.server.plugins;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.Maps;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.Server;
-import org.sonar.api.platform.ServerUpgradeStatus;
-import org.sonar.api.utils.MessageException;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.core.plugins.DefaultPluginMetadata;
-import org.sonar.server.platform.DefaultServerFileSystem;
-import org.sonar.updatecenter.common.PluginReferential;
-
-import javax.annotation.Nonnull;
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static com.google.common.collect.Iterables.transform;
-import static com.google.common.collect.Lists.newArrayList;
-import static java.lang.String.format;
-import static org.apache.commons.io.FileUtils.cleanDirectory;
-import static org.apache.commons.io.FileUtils.copyFile;
-import static org.apache.commons.io.FileUtils.deleteDirectory;
-import static org.apache.commons.io.FileUtils.deleteQuietly;
-import static org.apache.commons.io.FileUtils.forceMkdir;
-import static org.apache.commons.io.FileUtils.listFiles;
-import static org.apache.commons.io.FileUtils.moveFile;
-import static org.apache.commons.io.FileUtils.moveFileToDirectory;
-import static org.apache.commons.lang.StringUtils.isNotBlank;
-
-public class ServerPluginJarsInstaller {
-
- private static final Logger LOG = Loggers.get(ServerPluginJarsInstaller.class);
- private static final String FILE_EXTENSION_JAR = "jar";
- private static final Joiner SLASH_JOINER = Joiner.on(" / ").skipNulls();
-
- private final Server server;
- private final DefaultServerFileSystem fs;
- private final ServerPluginJarInstaller installer;
- private final Map<String, PluginMetadata> pluginByKeys = Maps.newHashMap();
- private final ServerUpgradeStatus serverUpgradeStatus;
- private static final Set<String> BLACKLISTED_PLUGINS = new HashSet<String>(Arrays.asList("scmactivity", "issuesreport"));
-
- public ServerPluginJarsInstaller(Server server, ServerUpgradeStatus serverUpgradeStatus,
- DefaultServerFileSystem fs, ServerPluginJarInstaller installer) {
- this.server = server;
- this.serverUpgradeStatus = serverUpgradeStatus;
- this.fs = fs;
- this.installer = installer;
- }
-
- public void install() {
- Profiler profiler = Profiler.create(LOG).startInfo("Install plugins");
- deleteTrash();
- loadInstalledPlugins();
- copyBundledPlugins();
- moveDownloadedPlugins();
- loadCorePlugins();
- deployPlugins();
- profiler.stopDebug();
- }
-
- private void deleteTrash() {
- File trashDir = fs.getTrashPluginsDir();
- try {
- if (trashDir.exists()) {
- deleteDirectory(trashDir);
- }
- } catch (IOException e) {
- throw new IllegalStateException("Fail to clean the plugin trash directory: " + trashDir, e);
- }
- }
-
- private void loadInstalledPlugins() {
- for (File file : fs.getUserPlugins()) {
- PluginMetadata metadata = installer.fileToPlugin().apply(file);
- if (isNotBlank(metadata.getKey())) {
- loadInstalledPlugin(metadata);
- }
- }
- }
-
- private void loadInstalledPlugin(PluginMetadata metadata) {
- if (BLACKLISTED_PLUGINS.contains(metadata.getKey())) {
- LOG.warn("Plugin {} is blacklisted. Please uninstall it.", metadata.getName());
- } else {
- PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
- if (existing != null) {
- throw MessageException.of(format("Found two files for the same plugin '%s': %s and %s",
- metadata.getKey(), metadata.getFile().getName(), existing.getFile().getName()));
- }
- }
- }
-
- private void moveDownloadedPlugins() {
- if (fs.getDownloadedPluginsDir().exists()) {
- for (File sourceFile : listJarFiles(fs.getDownloadedPluginsDir())) {
- overridePlugin(sourceFile, true);
- }
- }
- }
-
- private void copyBundledPlugins() {
- if (serverUpgradeStatus.isFreshInstall()) {
- for (File sourceFile : fs.getBundledPlugins()) {
- PluginMetadata metadata = installer.fileToPlugin().apply(sourceFile);
- // lib/bundled-plugins should be copied only if the plugin is not already
- // available in extensions/plugins
- if (!pluginByKeys.containsKey(metadata.getKey())) {
- overridePlugin(sourceFile, false);
- }
- }
- }
- }
-
- private void overridePlugin(File sourceFile, boolean deleteSource) {
- File destDir = fs.getUserPluginsDir();
- File destFile = new File(destDir, sourceFile.getName());
- if (destFile.exists()) {
- // plugin with same filename already installed
- deleteQuietly(destFile);
- }
-
- try {
- if (deleteSource) {
- moveFile(sourceFile, destFile);
- } else {
- copyFile(sourceFile, destFile, true);
- }
- } catch (IOException e) {
- LOG.error(format("Fail to move or copy plugin: %s to %s",
- sourceFile.getAbsolutePath(), destFile.getAbsolutePath()), e);
- }
-
- PluginMetadata metadata = installer.fileToPlugin().apply(destFile);
- if (isNotBlank(metadata.getKey())) {
- PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
- if (existing != null) {
- if (!existing.getFile().getName().equals(destFile.getName())) {
- deleteQuietly(existing.getFile());
- }
- LOG.info("Plugin " + metadata.getKey() + " replaced by new version");
- }
- }
- }
-
- private void loadCorePlugins() {
- for (File file : fs.getCorePlugins()) {
- PluginMetadata metadata = installer.fileToCorePlugin().apply(file);
- PluginMetadata existing = pluginByKeys.put(metadata.getKey(), metadata);
- if (existing != null) {
- throw new IllegalStateException("Found two plugins with the same key '" + metadata.getKey() + "': " + metadata.getFile().getName() + " and "
- + existing.getFile().getName());
- }
- }
- }
-
- public void uninstall(String pluginKey) {
- for (String key : getPluginReferential().findLastReleasesWithDependencies(pluginKey)) {
- uninstallPlugin(key);
- }
- }
-
- private void uninstallPlugin(String pluginKey) {
- PluginMetadata metadata = pluginByKeys.get(pluginKey);
- if (metadata != null && !metadata.isCore()) {
- try {
- File masterFile = new File(fs.getUserPluginsDir(), metadata.getFile().getName());
- moveFileToDirectory(masterFile, fs.getTrashPluginsDir(), true);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to uninstall plugin: " + pluginKey, e);
- }
- }
- }
-
- public List<String> getUninstalledPluginFilenames() {
- if (!fs.getTrashPluginsDir().exists()) {
- return Collections.emptyList();
- }
-
- return newArrayList(transform(listJarFiles(fs.getTrashPluginsDir()), FileToName.INSTANCE));
- }
-
- /**
- * @return the list of plugins to be uninstalled as {@link DefaultPluginMetadata} instances
- */
- public Collection<DefaultPluginMetadata> getUninstalledPlugins() {
- if (!fs.getTrashPluginsDir().exists()) {
- return Collections.emptyList();
- }
-
- return newArrayList(transform(listJarFiles(fs.getTrashPluginsDir()), installer.fileToPlugin()));
- }
-
- public void cancelUninstalls() {
- if (fs.getTrashPluginsDir().exists()) {
- for (File file : listJarFiles(fs.getTrashPluginsDir())) {
- try {
- moveFileToDirectory(file, fs.getUserPluginsDir(), false);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to cancel plugin uninstalls", e);
- }
- }
- }
- }
-
- private void deployPlugins() {
- for (PluginMetadata metadata : pluginByKeys.values()) {
- deploy((DefaultPluginMetadata) metadata);
- }
- }
-
- private void deploy(DefaultPluginMetadata plugin) {
- LOG.info("Deploy plugin {}", SLASH_JOINER.join(plugin.getName(), plugin.getVersion(), plugin.getImplementationBuild()));
-
- if (!plugin.isCompatibleWith(server.getVersion())) {
- throw MessageException.of(format(
- "Plugin %s needs a more recent version of SonarQube than %s. At least %s is expected",
- plugin.getKey(), server.getVersion(), plugin.getSonarVersion()));
- }
-
- try {
- File pluginDeployDir = new File(fs.getDeployedPluginsDir(), plugin.getKey());
- forceMkdir(pluginDeployDir);
- cleanDirectory(pluginDeployDir);
-
- installer.installToDir(plugin, pluginDeployDir);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to deploy the plugin " + plugin, e);
- }
- }
-
- public Collection<PluginMetadata> getMetadata() {
- return pluginByKeys.values();
- }
-
- public PluginMetadata getMetadata(String pluginKey) {
- return pluginByKeys.get(pluginKey);
- }
-
- private PluginReferential getPluginReferential() {
- return PluginReferentialMetadataConverter.getInstalledPluginReferential(getMetadata());
- }
-
- private static Collection<File> listJarFiles(File pluginDir) {
- return listFiles(pluginDir, new String[] {FILE_EXTENSION_JAR}, false);
- }
-
- private enum FileToName implements Function<File, String> {
- INSTANCE;
-
- @Override
- public String apply(@Nonnull File file) {
- return file.getName();
- }
- }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java
index 16028617966..cb9db1f4042 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java
@@ -19,76 +19,361 @@
*/
package org.sonar.server.plugins;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Ordering;
+import org.apache.commons.io.FileUtils;
import org.picocontainer.Startable;
-import org.sonar.api.utils.log.Loggers;
import org.sonar.api.Plugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-import org.sonar.core.plugins.PluginClassloaders;
+import org.sonar.api.platform.Server;
+import org.sonar.api.platform.ServerUpgradeStatus;
+import org.sonar.api.utils.MessageException;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginLoader;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.server.platform.DefaultServerFileSystem;
+
+import javax.annotation.Nonnull;
-import javax.annotation.CheckForNull;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Lists.newArrayList;
+import static java.lang.String.format;
+import static org.apache.commons.io.FileUtils.copyFile;
+import static org.apache.commons.io.FileUtils.deleteQuietly;
+import static org.apache.commons.io.FileUtils.moveFile;
+import static org.apache.commons.io.FileUtils.moveFileToDirectory;
/**
- * This class loads JAR files and initializes classloaders of plugins
+ * Manages installation and loading of plugins:
+ * <ul>
+ * <li>installation of bundled plugins on first server startup</li>
+ * <li>installation of new plugins (effective after server startup)</li>
+ * <li>un-installation of plugins (effective after server startup)</li>
+ * <li>cancel pending installations/un-installations</li>
+ * <li>load plugin bytecode</li>
+ * </ul>
*/
public class ServerPluginRepository implements PluginRepository, Startable {
- private final ServerPluginJarsInstaller jarsInstaller;
- private final PluginClassloaders classloaders;
- private Map<String, Plugin> pluginsByKey;
+ private static final Logger LOG = Loggers.get(ServerPluginRepository.class);
+ private static final String FILE_EXTENSION_JAR = "jar";
+ private static final Set<String> DEFAULT_BLACKLISTED_PLUGINS = ImmutableSet.of("scmactivity", "issuesreport");
+ private static final Joiner SLASH_JOINER = Joiner.on(" / ").skipNulls();
+
+ private final Server server;
+ private final DefaultServerFileSystem fs;
+ private final ServerUpgradeStatus upgradeStatus;
+ private final PluginLoader loader;
+ private Set<String> blacklistedPluginKeys = DEFAULT_BLACKLISTED_PLUGINS;
- public ServerPluginRepository(ServerPluginJarsInstaller jarsInstaller) {
- this.classloaders = new PluginClassloaders(getClass().getClassLoader());
- this.jarsInstaller = jarsInstaller;
+ // following fields are available after startup
+ private final Map<String, PluginInfo> pluginInfosByKeys = new HashMap<>();
+ private final Map<String, Plugin> pluginInstancesByKeys = new HashMap<>();
+
+ public ServerPluginRepository(Server server, ServerUpgradeStatus upgradeStatus,
+ DefaultServerFileSystem fs, PluginLoader loader) {
+ this.server = server;
+ this.upgradeStatus = upgradeStatus;
+ this.fs = fs;
+ this.loader = loader;
+ }
+
+ @VisibleForTesting
+ void setBlacklistedPluginKeys(Set<String> keys) {
+ this.blacklistedPluginKeys = keys;
}
@Override
public void start() {
- jarsInstaller.install();
- Collection<PluginMetadata> metadata = jarsInstaller.getMetadata();
- pluginsByKey = classloaders.init(metadata);
+ loadPreInstalledPlugins();
+ copyBundledPlugins();
+ moveDownloadedPlugins();
+ loadCorePlugins();
+ unloadIncompatiblePlugins();
+ logInstalledPlugins();
+ loadInstances();
}
@Override
public void stop() {
- classloaders.clean();
+ // close classloaders
+ loader.unload(pluginInstancesByKeys.values());
+
+ pluginInstancesByKeys.clear();
+ pluginInfosByKeys.clear();
}
- @Override
- public Plugin getPlugin(String key) {
- return pluginsByKey.get(key);
+ /**
+ * Load the plugins that are located in extensions/plugins. Blacklisted plugins are
+ * deleted.
+ */
+ private void loadPreInstalledPlugins() {
+ for (File file : listJarFiles(fs.getInstalledPluginsDir())) {
+ PluginInfo info = PluginInfo.create(file);
+ registerPluginInfo(info);
+ }
+ }
+
+ /**
+ * Move the plugins recently downloaded to extensions/plugins.
+ */
+ private void moveDownloadedPlugins() {
+ if (fs.getDownloadedPluginsDir().exists()) {
+ for (File sourceFile : listJarFiles(fs.getDownloadedPluginsDir())) {
+ overrideAndRegisterPlugin(sourceFile, true);
+ }
+ }
+ }
+
+ /**
+ * Copies the plugins bundled with SonarQube distribution to directory extensions/plugins.
+ * Does nothing if not a fresh installation.
+ */
+ private void copyBundledPlugins() {
+ if (upgradeStatus.isFreshInstall()) {
+ for (File sourceFile : listJarFiles(fs.getBundledPluginsDir())) {
+ PluginInfo info = PluginInfo.create(sourceFile);
+ // lib/bundled-plugins should be copied only if the plugin is not already
+ // available in extensions/plugins
+ if (!pluginInfosByKeys.containsKey(info.getKey())) {
+ overrideAndRegisterPlugin(sourceFile, false);
+ }
+ }
+ }
+ }
+
+ private void registerPluginInfo(PluginInfo info) {
+ if (blacklistedPluginKeys.contains(info.getKey())) {
+ LOG.warn("Plugin {} [{}] is blacklisted and is being uninstalled.", info.getName(), info.getKey());
+ deleteQuietly(info.getFile());
+ return;
+ }
+ PluginInfo existing = pluginInfosByKeys.put(info.getKey(), info);
+ if (existing != null) {
+ throw MessageException.of(format("Found two files for the same plugin [%s]: %s and %s",
+ info.getKey(), info.getFile().getName(), existing.getFile().getName()));
+ }
+
+ }
+
+ /**
+ * Move or copy plugin to directory extensions/plugins. If a version of this plugin
+ * already exists then it's deleted.
+ */
+ private void overrideAndRegisterPlugin(File sourceFile, boolean deleteSource) {
+ File destDir = fs.getInstalledPluginsDir();
+ File destFile = new File(destDir, sourceFile.getName());
+ if (destFile.exists()) {
+ // plugin with same filename already installed
+ deleteQuietly(destFile);
+ }
+
+ try {
+ if (deleteSource) {
+ moveFile(sourceFile, destFile);
+ } else {
+ copyFile(sourceFile, destFile, true);
+ }
+ } catch (IOException e) {
+ LOG.error(format("Fail to move or copy plugin: %s to %s",
+ sourceFile.getAbsolutePath(), destFile.getAbsolutePath()), e);
+ }
+
+ PluginInfo info = PluginInfo.create(destFile);
+ PluginInfo existing = pluginInfosByKeys.put(info.getKey(), info);
+ if (existing != null) {
+ if (!existing.getFile().getName().equals(destFile.getName())) {
+ deleteQuietly(existing.getFile());
+ }
+ LOG.info("Plugin {} [{}] updated to version {}", info.getName(), info.getKey(), info.getVersion());
+ } else {
+ LOG.info("Plugin {} [{}] installed", info.getName(), info.getKey());
+ }
+ }
+
+ private void loadCorePlugins() {
+ for (File file : listJarFiles(fs.getCorePluginsDir())) {
+ PluginInfo info = PluginInfo.create(file).setCore(true);
+ registerPluginInfo(info);
+ }
+ }
+
+ /**
+ * Removes the plugins that are not compatible with current environment. In some cases
+ * plugin files can be deleted.
+ */
+ private void unloadIncompatiblePlugins() {
+ // loop as long as the previous loop ignored some plugins. That allows to support dependencies
+ // on many levels, for example D extends C, which extends B, which requires A. If A is not installed,
+ // then B, C and D must be ignored. That's not possible to achieve this algorithm with a single
+ // iteration over plugins.
+ List<String> removedKeys = new ArrayList<>();
+ do {
+ removedKeys.clear();
+ for (PluginInfo plugin : pluginInfosByKeys.values()) {
+ if (!Strings.isNullOrEmpty(plugin.getBasePlugin()) && !pluginInfosByKeys.containsKey(plugin.getBasePlugin())) {
+ // this plugin extends a plugin that is not installed
+ LOG.warn("Plugin {} [{}] is ignored because its base plugin [{}] is not installed", plugin.getName(), plugin.getKey(), plugin.getBasePlugin());
+ removedKeys.add(plugin.getKey());
+ }
+
+ if (!plugin.isCompatibleWith(server.getVersion())) {
+ LOG.warn("Plugin {} [{}] is ignored because it requires at least SonarQube {}", plugin.getName(), plugin.getKey(), plugin.getMinimalSqVersion());
+ removedKeys.add(plugin.getKey());
+ }
+
+ for (PluginInfo.RequiredPlugin requiredPlugin : plugin.getRequiredPlugins()) {
+ PluginInfo available = pluginInfosByKeys.get(requiredPlugin.getKey());
+ if (available == null) {
+ // this plugin requires a plugin that is not installed
+ LOG.warn("Plugin {} [{}] is ignored because the required plugin [{}] is not installed", plugin.getName(), plugin.getKey(), requiredPlugin.getKey());
+ removedKeys.add(plugin.getKey());
+ } else if (requiredPlugin.getMinimalVersion().compareToIgnoreQualifier(available.getVersion()) > 0) {
+ LOG.warn("Plugin {} [{}] is ignored because the version {} of required plugin [{}] is not supported", plugin.getName(), plugin.getKey(),
+ requiredPlugin.getKey(), requiredPlugin.getMinimalVersion());
+ removedKeys.add(plugin.getKey());
+ }
+ }
+ }
+ for (String removedKey : removedKeys) {
+ pluginInfosByKeys.remove(removedKey);
+ }
+ } while (!removedKeys.isEmpty());
+ }
+
+ private void logInstalledPlugins() {
+ List<PluginInfo> orderedPlugins = Ordering.natural().sortedCopy(pluginInfosByKeys.values());
+ for (PluginInfo plugin : orderedPlugins) {
+ LOG.info("Plugin: {}", SLASH_JOINER.join(plugin.getName(), plugin.getVersion(), plugin.getImplementationBuild()));
+ }
}
- @CheckForNull
- public ClassLoader getClassLoader(String pluginKey) {
- return classloaders.get(pluginKey);
+ private void loadInstances() {
+ pluginInstancesByKeys.clear();
+ pluginInstancesByKeys.putAll(loader.load(pluginInfosByKeys));
}
- @CheckForNull
- public Class getClass(String pluginKey, String classname) {
- Class clazz = null;
- ClassLoader classloader = getClassLoader(pluginKey);
- if (classloader != null) {
+ /**
+ * Uninstall a plugin and its dependents (the plugins that require the plugin to be uninstalled)
+ */
+ public void uninstall(String pluginKey) {
+ for (PluginInfo otherPlugin : pluginInfosByKeys.values()) {
+ if (!otherPlugin.getKey().equals(pluginKey)) {
+ for (PluginInfo.RequiredPlugin requiredPlugin : otherPlugin.getRequiredPlugins()) {
+ if (requiredPlugin.getKey().equals(pluginKey)) {
+ uninstall(otherPlugin.getKey());
+ }
+ }
+ }
+ }
+
+ PluginInfo info = pluginInfosByKeys.get(pluginKey);
+ if (!info.isCore()) {
try {
- clazz = classloader.loadClass(classname);
+ // we don't reuse info.getFile() just to be sure that file is located in from extensions/plugins
+ File masterFile = new File(fs.getInstalledPluginsDir(), info.getFile().getName());
+ moveFileToDirectory(masterFile, uninstalledPluginsDir(), true);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to uninstall plugin [" + pluginKey + "]", e);
+ }
+ }
+ }
+
+ public List<String> getUninstalledPluginFilenames() {
+ return newArrayList(transform(listJarFiles(uninstalledPluginsDir()), FileToName.INSTANCE));
+ }
- } catch (ClassNotFoundException e) {
- Loggers.get(getClass()).warn("Class not found in plugin " + pluginKey + ": " + classname, e);
+ /**
+ * @return the list of plugins to be uninstalled as {@link PluginInfo} instances
+ */
+ public Collection<PluginInfo> getUninstalledPlugins() {
+ return newArrayList(transform(listJarFiles(uninstalledPluginsDir()), PluginInfo.JarToPluginInfo.INSTANCE));
+ }
+
+ public void cancelUninstalls() {
+ for (File file : listJarFiles(uninstalledPluginsDir())) {
+ try {
+ moveFileToDirectory(file, fs.getInstalledPluginsDir(), false);
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to cancel plugin uninstalls", e);
}
}
- return clazz;
+ }
+
+ public Map<String, PluginInfo> getPluginInfosByKeys() {
+ return pluginInfosByKeys;
+ }
+
+ @Override
+ public Collection<PluginInfo> getPluginInfos() {
+ return pluginInfosByKeys.values();
+ }
+
+ @Override
+ public PluginInfo getPluginInfo(String key) {
+ PluginInfo info = pluginInfosByKeys.get(key);
+ if (info == null) {
+ throw new IllegalArgumentException(String.format("Plugin [%s] does not exist", key));
+ }
+ return info;
}
@Override
- public Collection<PluginMetadata> getMetadata() {
- return jarsInstaller.getMetadata();
+ public Plugin getPluginInstance(String key) {
+ Plugin plugin = pluginInstancesByKeys.get(key);
+ if (plugin == null) {
+ throw new IllegalArgumentException(String.format("Plugin [%s] does not exist", key));
+ }
+ return plugin;
}
@Override
- public PluginMetadata getMetadata(String pluginKey) {
- return jarsInstaller.getMetadata(pluginKey);
+ public boolean hasPlugin(String key) {
+ return pluginInfosByKeys.containsKey(key);
}
+ private enum FileToName implements Function<File, String> {
+ INSTANCE;
+
+ @Override
+ public String apply(@Nonnull File file) {
+ return file.getName();
+ }
+
+ }
+
+ /**
+ * @return existing trash dir
+ */
+ private File uninstalledPluginsDir() {
+ File dir = new File(fs.getTempDir(), "uninstalled-plugins");
+ try {
+ FileUtils.forceMkdir(dir);
+ return dir;
+ } catch (IOException e) {
+ throw new IllegalStateException("Fail to create temp directory: " + dir.getAbsolutePath(), e);
+ }
+ }
+
+ private static Collection<File> listJarFiles(File dir) {
+ if (dir.exists()) {
+ return FileUtils.listFiles(dir, new String[] {FILE_EXTENSION_JAR}, false);
+ }
+ return Collections.emptyList();
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginUnzipper.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginUnzipper.java
new file mode 100644
index 00000000000..59bc5a850fa
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginUnzipper.java
@@ -0,0 +1,65 @@
+/*
+ * 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.server.plugins;
+
+import org.apache.commons.io.FileUtils;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.utils.ZipUtils;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginUnzipper;
+import org.sonar.core.platform.UnzippedPlugin;
+import org.sonar.server.platform.DefaultServerFileSystem;
+
+import java.io.File;
+
+import static org.apache.commons.io.FileUtils.cleanDirectory;
+import static org.apache.commons.io.FileUtils.forceMkdir;
+
+public class ServerPluginUnzipper extends PluginUnzipper implements ServerComponent {
+
+ private final DefaultServerFileSystem fs;
+
+ public ServerPluginUnzipper(DefaultServerFileSystem fs) {
+ this.fs = fs;
+ }
+
+ /**
+ * JAR files of directory extensions/plugins can be moved when server is up and plugins are uninstalled.
+ * For this reason these files must not be locked by classloaders. They are copied to the directory
+ * web/deploy/plugins in order to be loaded by {@link org.sonar.core.platform.PluginLoader}.
+ */
+ @Override
+ public UnzippedPlugin unzip(PluginInfo pluginInfo) {
+ File toDir = new File(fs.getDeployedPluginsDir(), pluginInfo.getKey());
+ try {
+ forceMkdir(toDir);
+ cleanDirectory(toDir);
+
+ File jarSource = pluginInfo.getFile();
+ File jarTarget = new File(toDir, jarSource.getName());
+ FileUtils.copyFile(jarSource, jarTarget);
+ ZipUtils.unzip(jarSource, toDir, newLibFilter());
+ return UnzippedPlugin.createFromUnzippedDir(pluginInfo.getKey(), jarTarget, toDir);
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format(
+ "Fail to unzip plugin [%s] %s to %s", pluginInfo.getKey(), pluginInfo.getFile().getAbsolutePath(), toDir.getAbsolutePath()), e);
+ }
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java
index 8d24a1ae5f0..9a7ab9c3690 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/StaticResourcesServlet.java
@@ -22,8 +22,10 @@ package org.sonar.server.plugins;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
+import org.sonar.api.Plugin;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.platform.PluginRepository;
import org.sonar.server.platform.Platform;
import javax.servlet.ServletException;
@@ -45,29 +47,25 @@ public class StaticResourcesServlet extends HttpServlet {
String pluginKey = getPluginKey(request);
String resource = getResourcePath(request);
- ServerPluginRepository pluginRepository = Platform.getInstance().getContainer().getComponentByType(ServerPluginRepository.class);
- ClassLoader classLoader = pluginRepository.getClassLoader(pluginKey);
- if (classLoader == null) {
- LOG.error("Plugin not found: " + pluginKey);
+ PluginRepository pluginRepository = Platform.getInstance().getContainer().getComponentByType(PluginRepository.class);
+ if (!pluginRepository.hasPlugin(pluginKey)) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
InputStream in = null;
OutputStream out = null;
try {
- in = classLoader.getResourceAsStream(resource);
+ in = pluginRepository.getPluginInstance(pluginKey).getClass().getClassLoader().getResourceAsStream(resource);
if (in != null) {
// mime type must be set before writing response body
completeContentType(response, resource);
out = response.getOutputStream();
IOUtils.copy(in, out);
-
} else {
- LOG.error("Unable to find resource '" + resource + "' in plugin '" + pluginKey + "'");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
} catch (Exception e) {
- LOG.error("Unable to load static resource '" + resource + "' from plugin '" + pluginKey + "'", e);
+ LOG.error(String.format("Unable to load resource [%s] from plugin [%s]", resource, pluginKey), e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} finally {
IOUtils.closeQuietly(in);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/CancelAllPluginsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/CancelAllPluginsWsAction.java
index 93124251589..3899e50985d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/CancelAllPluginsWsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/CancelAllPluginsWsAction.java
@@ -24,17 +24,17 @@ import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
+import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.user.UserSession;
public class CancelAllPluginsWsAction implements PluginsWsAction {
private final PluginDownloader pluginDownloader;
- private final ServerPluginJarsInstaller pluginJarsInstaller;
+ private final ServerPluginRepository pluginRepository;
- public CancelAllPluginsWsAction(PluginDownloader pluginDownloader, ServerPluginJarsInstaller pluginJarsInstaller) {
+ public CancelAllPluginsWsAction(PluginDownloader pluginDownloader, ServerPluginRepository pluginRepository) {
this.pluginDownloader = pluginDownloader;
- this.pluginJarsInstaller = pluginJarsInstaller;
+ this.pluginRepository = pluginRepository;
}
@Override
@@ -52,7 +52,7 @@ public class CancelAllPluginsWsAction implements PluginsWsAction {
UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
pluginDownloader.cancelDownloads();
- pluginJarsInstaller.cancelUninstalls();
+ pluginRepository.cancelUninstalls();
response.noContent();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledPluginsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledPluginsWsAction.java
index c84b730c96c..dc2f3ff4be7 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledPluginsWsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/InstalledPluginsWsAction.java
@@ -22,14 +22,15 @@ package org.sonar.server.plugins.ws;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.io.Resources;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.server.plugins.ServerPluginRepository;
import javax.annotation.Nullable;
+
import java.util.Collection;
import java.util.SortedSet;
@@ -42,10 +43,10 @@ import static org.sonar.server.plugins.ws.PluginWSCommons.NAME_KEY_PLUGIN_METADA
public class InstalledPluginsWsAction implements PluginsWsAction {
private static final String ARRAY_PLUGINS = "plugins";
- private final PluginRepository pluginRepository;
+ private final ServerPluginRepository pluginRepository;
private final PluginWSCommons pluginWSCommons;
- public InstalledPluginsWsAction(PluginRepository pluginRepository,
+ public InstalledPluginsWsAction(ServerPluginRepository pluginRepository,
PluginWSCommons pluginWSCommons) {
this.pluginRepository = pluginRepository;
this.pluginWSCommons = pluginWSCommons;
@@ -62,39 +63,39 @@ public class InstalledPluginsWsAction implements PluginsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
- Collection<PluginMetadata> pluginMetadatas = retrieveAndSortPluginMetadata();
+ Collection<PluginInfo> infos = retrieveAndSortPluginMetadata();
JsonWriter jsonWriter = response.newJsonWriter();
jsonWriter.setSerializeEmptys(false);
jsonWriter.beginObject();
- writeMetadataList(jsonWriter, pluginMetadatas);
+ writeMetadataList(jsonWriter, infos);
jsonWriter.endObject();
jsonWriter.close();
}
- private SortedSet<PluginMetadata> retrieveAndSortPluginMetadata() {
+ private SortedSet<PluginInfo> retrieveAndSortPluginMetadata() {
return ImmutableSortedSet.copyOf(
NAME_KEY_PLUGIN_METADATA_COMPARATOR,
- filter(pluginRepository.getMetadata(), NotCorePluginsPredicate.INSTANCE)
+ filter(pluginRepository.getPluginInfos(), NotCorePluginsPredicate.INSTANCE)
);
}
- private void writeMetadataList(JsonWriter jsonWriter, Collection<PluginMetadata> pluginMetadatas) {
+ private void writeMetadataList(JsonWriter jsonWriter, Collection<PluginInfo> pluginMetadatas) {
jsonWriter.name(ARRAY_PLUGINS);
jsonWriter.beginArray();
- for (PluginMetadata pluginMetadata : pluginMetadatas) {
+ for (PluginInfo pluginMetadata : pluginMetadatas) {
pluginWSCommons.writePluginMetadata(jsonWriter, pluginMetadata);
}
jsonWriter.endArray();
}
- private enum NotCorePluginsPredicate implements Predicate<PluginMetadata> {
+ private enum NotCorePluginsPredicate implements Predicate<PluginInfo> {
INSTANCE;
@Override
- public boolean apply(@Nullable PluginMetadata input) {
+ public boolean apply(@Nullable PluginInfo input) {
return input != null && !input.isCore();
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java
index 8c55caeaf68..29eb3cc9b53 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PendingPluginsWsAction.java
@@ -19,14 +19,13 @@
*/
package org.sonar.server.plugins.ws;
-import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
+import org.sonar.server.plugins.ServerPluginRepository;
import java.util.Collection;
@@ -43,24 +42,24 @@ public class PendingPluginsWsAction implements PluginsWsAction {
private static final String ARRAY_REMOVING = "removing";
private final PluginDownloader pluginDownloader;
- private final ServerPluginJarsInstaller serverPluginJarsInstaller;
+ private final ServerPluginRepository installer;
private final PluginWSCommons pluginWSCommons;
public PendingPluginsWsAction(PluginDownloader pluginDownloader,
- ServerPluginJarsInstaller serverPluginJarsInstaller,
- PluginWSCommons pluginWSCommons) {
+ ServerPluginRepository installer,
+ PluginWSCommons pluginWSCommons) {
this.pluginDownloader = pluginDownloader;
- this.serverPluginJarsInstaller = serverPluginJarsInstaller;
+ this.installer = installer;
this.pluginWSCommons = pluginWSCommons;
}
@Override
public void define(WebService.NewController controller) {
controller.createAction("pending")
- .setDescription("Get the list of plugins which will either be installed or removed at the next startup of the SonarQube instance, sorted by plugin name")
- .setSince("5.2")
- .setHandler(this)
- .setResponseExample(getResource(this.getClass(), "example-pending_plugins.json"));
+ .setDescription("Get the list of plugins which will either be installed or removed at the next startup of the SonarQube instance, sorted by plugin name")
+ .setSince("5.2")
+ .setHandler(this)
+ .setResponseExample(getResource(this.getClass(), "example-pending_plugins.json"));
}
@Override
@@ -80,8 +79,8 @@ public class PendingPluginsWsAction implements PluginsWsAction {
private void writeInstalling(JsonWriter jsonWriter) {
jsonWriter.name(ARRAY_INSTALLING);
jsonWriter.beginArray();
- Collection<DefaultPluginMetadata> plugins = pluginDownloader.getDownloadedPlugins();
- for (PluginMetadata pluginMetadata : copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) {
+ Collection<PluginInfo> plugins = pluginDownloader.getDownloadedPlugins();
+ for (PluginInfo pluginMetadata : copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) {
pluginWSCommons.writePluginMetadata(jsonWriter, pluginMetadata);
}
jsonWriter.endArray();
@@ -90,8 +89,8 @@ public class PendingPluginsWsAction implements PluginsWsAction {
private void writeRemoving(JsonWriter jsonWriter) {
jsonWriter.name(ARRAY_REMOVING);
jsonWriter.beginArray();
- Collection<DefaultPluginMetadata> plugins = serverPluginJarsInstaller.getUninstalledPlugins();
- for (PluginMetadata pluginMetadata : copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) {
+ Collection<PluginInfo> plugins = installer.getUninstalledPlugins();
+ for (PluginInfo pluginMetadata : copyOf(NAME_KEY_PLUGIN_METADATA_COMPARATOR, plugins)) {
pluginWSCommons.writePluginMetadata(jsonWriter, pluginMetadata);
}
jsonWriter.endArray();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java
index 08cc27555b4..c2f8a8b6b63 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/PluginWSCommons.java
@@ -24,13 +24,14 @@ import com.google.common.base.Function;
import com.google.common.collect.Ordering;
import java.util.Comparator;
import javax.annotation.Nonnull;
-import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.updatecenter.common.Artifact;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.PluginUpdate;
import org.sonar.updatecenter.common.Release;
import org.sonar.updatecenter.common.UpdateCenter;
+import org.sonar.updatecenter.common.Version;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
@@ -59,7 +60,7 @@ public class PluginWSCommons {
static final String PROPERTY_IMPLEMENTATION_BUILD = "implementationBuild";
static final String PROPERTY_CHANGE_LOG_URL = "changeLogUrl";
- public static final Ordering<PluginMetadata> NAME_KEY_PLUGIN_METADATA_COMPARATOR = Ordering.natural()
+ public static final Ordering<PluginInfo> NAME_KEY_PLUGIN_METADATA_COMPARATOR = Ordering.natural()
.onResultOf(PluginMetadataToName.INSTANCE)
.compound(Ordering.natural().onResultOf(PluginMetadataToKey.INSTANCE));
public static final Comparator<Plugin> NAME_KEY_PLUGIN_ORDERING = Ordering.from(CASE_INSENSITIVE_ORDER)
@@ -70,23 +71,26 @@ public class PluginWSCommons {
public static final Comparator<PluginUpdate> NAME_KEY_PLUGIN_UPDATE_ORDERING = Ordering.from(NAME_KEY_PLUGIN_ORDERING)
.onResultOf(PluginUpdateToPlugin.INSTANCE);
- public void writePluginMetadata(JsonWriter jsonWriter, PluginMetadata pluginMetadata) {
+ public void writePluginMetadata(JsonWriter jsonWriter, PluginInfo info) {
jsonWriter.beginObject();
- writeMetadata(jsonWriter, pluginMetadata);
+ writeMetadata(jsonWriter, info);
jsonWriter.endObject();
}
- public void writeMetadata(JsonWriter jsonWriter, PluginMetadata pluginMetadata) {
+ public void writeMetadata(JsonWriter jsonWriter, PluginInfo pluginMetadata) {
jsonWriter.prop(PROPERTY_KEY, pluginMetadata.getKey());
jsonWriter.prop(PROPERTY_NAME, pluginMetadata.getName());
jsonWriter.prop(PROPERTY_DESCRIPTION, pluginMetadata.getDescription());
- jsonWriter.prop(PROPERTY_VERSION, pluginMetadata.getVersion());
+ Version version = pluginMetadata.getVersion();
+ if (version != null) {
+ jsonWriter.prop(PROPERTY_VERSION, version.getName());
+ }
jsonWriter.prop(PROPERTY_LICENSE, pluginMetadata.getLicense());
- jsonWriter.prop(PROPERTY_ORGANIZATION_NAME, pluginMetadata.getOrganization());
+ jsonWriter.prop(PROPERTY_ORGANIZATION_NAME, pluginMetadata.getOrganizationName());
jsonWriter.prop(PROPERTY_ORGANIZATION_URL, pluginMetadata.getOrganizationUrl());
- jsonWriter.prop(PROPERTY_HOMEPAGE, pluginMetadata.getHomepage());
+ jsonWriter.prop(PROPERTY_HOMEPAGE, pluginMetadata.getHomepageUrl());
jsonWriter.prop(PROPERTY_ISSUE_TRACKER_URL, pluginMetadata.getIssueTrackerUrl());
jsonWriter.prop(PROPERTY_IMPLEMENTATION_BUILD, pluginMetadata.getImplementationBuild());
}
@@ -221,20 +225,20 @@ public class PluginWSCommons {
}
}
- private enum PluginMetadataToName implements Function<PluginMetadata, String> {
+ private enum PluginMetadataToName implements Function<PluginInfo, String> {
INSTANCE;
@Override
- public String apply(@Nonnull PluginMetadata input) {
+ public String apply(@Nonnull PluginInfo input) {
return input.getName();
}
}
- private enum PluginMetadataToKey implements Function<PluginMetadata, String> {
+ private enum PluginMetadataToKey implements Function<PluginInfo, String> {
INSTANCE;
@Override
- public String apply(@Nonnull PluginMetadata input) {
+ public String apply(@Nonnull PluginInfo input) {
return input.getKey();
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UninstallPluginsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UninstallPluginsWsAction.java
index bb2e9e1c43a..98399499acd 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UninstallPluginsWsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ws/UninstallPluginsWsAction.java
@@ -19,18 +19,13 @@
*/
package org.sonar.server.plugins.ws;
-import com.google.common.base.Predicate;
-import javax.annotation.Nullable;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
+import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.user.UserSession;
-import static com.google.common.collect.Iterables.find;
import static java.lang.String.format;
/**
@@ -39,12 +34,10 @@ import static java.lang.String.format;
public class UninstallPluginsWsAction implements PluginsWsAction {
private static final String PARAM_KEY = "key";
- private final PluginRepository pluginRepository;
- private final ServerPluginJarsInstaller pluginJarsInstaller;
+ private final ServerPluginRepository pluginRepository;
- public UninstallPluginsWsAction(PluginRepository pluginRepository, ServerPluginJarsInstaller pluginJarsInstaller) {
+ public UninstallPluginsWsAction(ServerPluginRepository pluginRepository) {
this.pluginRepository = pluginRepository;
- this.pluginJarsInstaller = pluginJarsInstaller;
}
@Override
@@ -66,27 +59,14 @@ public class UninstallPluginsWsAction implements PluginsWsAction {
UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
String key = request.mandatoryParam(PARAM_KEY);
ensurePluginIsInstalled(key);
- pluginJarsInstaller.uninstall(key);
+ pluginRepository.uninstall(key);
response.noContent();
}
+ // FIXME should be moved to {@link ServerPluginRepository#uninstall(String)}
private void ensurePluginIsInstalled(String key) {
- if (find(pluginRepository.getMetadata(), new PluginKeyPredicate(key), null) == null) {
- throw new IllegalArgumentException(
- format("No plugin with key '%s' or plugin '%s' is not installed", key, key));
- }
- }
-
- private static class PluginKeyPredicate implements Predicate<PluginMetadata> {
- private final String key;
-
- public PluginKeyPredicate(String key) {
- this.key = key;
- }
-
- @Override
- public boolean apply(@Nullable PluginMetadata input) {
- return input != null && key.equals(input.getKey());
+ if (!pluginRepository.hasPlugin(key)) {
+ throw new IllegalArgumentException(format("Plugin [%s] is not installed", key));
}
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/IndexQueue.java b/server/sonar-server/src/main/java/org/sonar/server/search/IndexQueue.java
index c29cd525cc9..d20d2c4e825 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/search/IndexQueue.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/search/IndexQueue.java
@@ -29,7 +29,7 @@ import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.sonar.api.ServerComponent;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.cluster.WorkQueue;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/startup/GeneratePluginIndex.java b/server/sonar-server/src/main/java/org/sonar/server/startup/GeneratePluginIndex.java
index d79adb553c2..4fe91fb829f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/startup/GeneratePluginIndex.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/startup/GeneratePluginIndex.java
@@ -22,9 +22,9 @@ package org.sonar.server.startup;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.CharUtils;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import org.sonar.core.plugins.RemotePlugin;
import org.sonar.server.platform.DefaultServerFileSystem;
@@ -33,10 +33,7 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
-/**
- * @since 2.11
- */
-public final class GeneratePluginIndex {
+public final class GeneratePluginIndex implements ServerComponent {
private DefaultServerFileSystem fileSystem;
private PluginRepository repository;
@@ -54,8 +51,8 @@ public final class GeneratePluginIndex {
FileUtils.forceMkdir(indexFile.getParentFile());
Writer writer = new FileWriter(indexFile, false);
try {
- for (PluginMetadata metadata : repository.getMetadata()) {
- writer.append(RemotePlugin.create((DefaultPluginMetadata) metadata).marshal());
+ for (PluginInfo pluginInfo : repository.getPluginInfos()) {
+ writer.append(RemotePlugin.create(pluginInfo).marshal());
writer.append(CharUtils.LF);
}
writer.flush();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
index 4c2ed9deef1..71a39f1e1f9 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
@@ -27,13 +27,12 @@ import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+
+import org.sonar.api.Plugin;
import org.sonar.api.config.License;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
-import org.sonar.api.platform.ComponentContainer;
import org.sonar.api.platform.NewUserHandler;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.ResourceType;
import org.sonar.api.resources.ResourceTypes;
@@ -44,6 +43,9 @@ import org.sonar.api.web.RubyRailsWebservice;
import org.sonar.api.web.Widget;
import org.sonar.core.persistence.Database;
import org.sonar.core.persistence.DatabaseVersion;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import org.sonar.core.resource.ResourceIndexerDao;
import org.sonar.core.timemachine.Periods;
import org.sonar.process.ProcessProperties;
@@ -58,7 +60,6 @@ import org.sonar.server.platform.ServerSettings;
import org.sonar.server.platform.SettingsChangeNotifier;
import org.sonar.server.plugins.InstalledPluginReferentialFactory;
import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.plugins.UpdateCenterMatrixFactory;
import org.sonar.server.rule.RuleRepositories;
@@ -149,15 +150,15 @@ public final class JRubyFacade {
}
public void uninstallPlugin(String pluginKey) {
- get(ServerPluginJarsInstaller.class).uninstall(pluginKey);
+ get(ServerPluginRepository.class).uninstall(pluginKey);
}
public void cancelPluginUninstalls() {
- get(ServerPluginJarsInstaller.class).cancelUninstalls();
+ get(ServerPluginRepository.class).cancelUninstalls();
}
public List<String> getPluginUninstalls() {
- return get(ServerPluginJarsInstaller.class).getUninstalledPluginFilenames();
+ return get(ServerPluginRepository.class).getUninstalledPluginFilenames();
}
public UpdateCenter getUpdatePluginCenter(boolean forceReload) {
@@ -173,12 +174,11 @@ public final class JRubyFacade {
return get(PropertyDefinitions.class);
}
- public boolean hasPlugin(String key) {
- return get(PluginRepository.class).getPlugin(key) != null;
- }
-
- public Collection<PluginMetadata> getPluginsMetadata() {
- return get(PluginRepository.class).getMetadata();
+ /**
+ * Used for WS api/updatecenter/installed_plugins, to be replaced by api/plugins/installed.
+ */
+ public Collection<PluginInfo> getPluginInfos() {
+ return get(PluginRepository.class).getPluginInfos();
}
public List<ViewProxy<Widget>> getWidgets(String resourceScope, String resourceQualifier, String resourceLanguage, Object[] availableMeasures) {
@@ -285,12 +285,13 @@ public final class JRubyFacade {
}
public Object getComponentByClassname(String pluginKey, String className) {
- Object component = null;
- Class<?> componentClass = get(ServerPluginRepository.class).getClass(pluginKey, className);
- if (componentClass != null) {
- component = get(componentClass);
+ Plugin plugin = get(PluginRepository.class).getPluginInstance(pluginKey);
+ try {
+ Class componentClass = plugin.getClass().getClassLoader().loadClass(className);
+ return get(componentClass);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(String.format("Class [%s] not found in plugin [%s]", className, pluginKey), e);
}
- return component;
}
private JRubyI18n getJRubyI18n() {
@@ -391,7 +392,7 @@ public final class JRubyFacade {
ComponentContainer container = Platform.getInstance().getContainer();
DatabaseMigration databaseMigration = container.getComponentByType(DatabaseMigration.class);
if (databaseMigration.status() == DatabaseMigration.Status.RUNNING
- || databaseMigration.status() == DatabaseMigration.Status.FAILED) {
+ || databaseMigration.status() == DatabaseMigration.Status.FAILED) {
return false;
}
if (databaseMigration.status() == DatabaseMigration.Status.SUCCEEDED) {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/debt/DebtModelPluginRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/debt/DebtModelPluginRepositoryTest.java
index 942bb973c09..730584d829b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/debt/DebtModelPluginRepositoryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/debt/DebtModelPluginRepositoryTest.java
@@ -28,8 +28,8 @@ import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.sonar.api.SonarPlugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import java.io.FileInputStream;
import java.io.InputStream;
@@ -54,17 +54,15 @@ public class DebtModelPluginRepositoryTest {
@Test
public void test_component_initialization() throws Exception {
// we do have the "csharp-model.xml" file in src/test/resources
- PluginMetadata csharpPluginMetadata = mock(PluginMetadata.class);
- when(csharpPluginMetadata.getKey()).thenReturn("csharp");
+ PluginInfo csharpPluginMetadata = new PluginInfo("csharp");
// but we don' have the "php-model.xml" one
- PluginMetadata phpPluginMetadata = mock(PluginMetadata.class);
- when(phpPluginMetadata.getKey()).thenReturn("php");
+ PluginInfo phpPluginMetadata = new PluginInfo("php");
PluginRepository repository = mock(PluginRepository.class);
- when(repository.getMetadata()).thenReturn(Lists.newArrayList(csharpPluginMetadata, phpPluginMetadata));
+ when(repository.getPluginInfos()).thenReturn(Lists.newArrayList(csharpPluginMetadata, phpPluginMetadata));
FakePlugin fakePlugin = new FakePlugin();
- when(repository.getPlugin(anyString())).thenReturn(fakePlugin);
+ when(repository.getPluginInstance(anyString())).thenReturn(fakePlugin);
modelFinder = new DebtModelPluginRepository(repository, TEST_XML_PREFIX_PATH);
// when
diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/EsTester.java b/server/sonar-server/src/test/java/org/sonar/server/es/EsTester.java
index 5c49de4aef1..e8df89bb003 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/es/EsTester.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/es/EsTester.java
@@ -41,7 +41,7 @@ import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeBuilder;
import org.elasticsearch.search.SearchHit;
import org.junit.rules.ExternalResource;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.server.search.BaseDoc;
import org.sonar.test.TestUtils;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerFileSystemTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerFileSystemTest.java
index c06a7887022..57bf62c771a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerFileSystemTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/DefaultServerFileSystemTest.java
@@ -38,20 +38,6 @@ public class DefaultServerFileSystemTest {
public TemporaryFolder temp = new TemporaryFolder();
@Test
- public void find_plugins() throws Exception {
- List<File> plugins = new DefaultServerFileSystem(
- new File(Resources.getResource(PATH + "shouldFindPlugins").toURI()), temp.newFolder(), null).getUserPlugins();
- assertThat(plugins).hasSize(2);
- }
-
- @Test
- public void not_fail_if_no_plugins() throws Exception {
- List<File> plugins = new DefaultServerFileSystem(
- new File(Resources.getResource(PATH + "shouldNotFailIfNoPlugins").toURI()), temp.newFolder(), null).getUserPlugins();
- assertThat(plugins).isEmpty();
- }
-
- @Test
public void find_checkstyle_extensions() throws Exception {
ServerFileSystem fs = new DefaultServerFileSystem(
new File(Resources.getResource(PATH + "shouldFindCheckstyleExtensions").toURI()), temp.newFolder(), null);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/RailsAppsDeployerTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/RailsAppsDeployerTest.java
index a64486ca9d9..d110225210d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/RailsAppsDeployerTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/RailsAppsDeployerTest.java
@@ -23,9 +23,9 @@ import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.platform.ServerFileSystem;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import java.io.File;
import java.net.URL;
@@ -77,7 +77,7 @@ public class RailsAppsDeployerTest {
when(fileSystem.getTempDir()).thenReturn(tempDir);
PluginRepository pluginRepository = mock(PluginRepository.class);
- when(pluginRepository.getMetadata()).thenReturn(Collections.<PluginMetadata>emptyList());
+ when(pluginRepository.getPluginInfos()).thenReturn(Collections.<PluginInfo>emptyList());
new RailsAppsDeployer(fileSystem, pluginRepository).start();
File appDir = new File(tempDir, "ror");
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java
index ef082c716b2..9e70d80a699 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java
@@ -21,22 +21,22 @@
package org.sonar.server.platform.monitoring;
import org.junit.Test;
-import org.sonar.api.Plugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.updatecenter.common.Version;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Arrays;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class PluginsMonitorTest {
- PluginsMonitor sut = new PluginsMonitor(new FakePluginRepository());;
+ PluginRepository repo = mock(PluginRepository.class);
+ PluginsMonitor sut = new PluginsMonitor(repo);
@Test
public void name() {
@@ -44,42 +44,28 @@ public class PluginsMonitorTest {
}
@Test
- public void plugin_name_and_version() {
+ public void plugin_name_and_version() throws Exception {
+ when(repo.getPluginInfos()).thenReturn(Arrays.asList(
+ new PluginInfo("key-1")
+ .setName("plugin-1")
+ .setVersion(Version.create("1.1")),
+ new PluginInfo("key-2")
+ .setName("plugin-2")
+ .setVersion(Version.create("2.2")),
+ new PluginInfo("no-version")
+ .setName("No Version")));
+
LinkedHashMap<String, Object> attributes = sut.attributes();
assertThat(attributes).containsKeys("key-1", "key-2");
assertThat((Map) attributes.get("key-1"))
.containsEntry("Name", "plugin-1")
.containsEntry("Version", "1.1");
- assertThat((Map)attributes.get("key-2"))
+ assertThat((Map) attributes.get("key-2"))
.containsEntry("Name", "plugin-2")
.containsEntry("Version", "2.2");
- }
-
- private static class FakePluginRepository implements PluginRepository {
-
- @Override
- public Plugin getPlugin(String key) {
- return null;
- }
-
- @Override
- public Collection<PluginMetadata> getMetadata() {
- List<PluginMetadata> plugins = new ArrayList<>();
- plugins.add(DefaultPluginMetadata
- .create("key-1")
- .setName("plugin-1")
- .setVersion("1.1"));
- plugins.add(DefaultPluginMetadata
- .create("key-2")
- .setName("plugin-2")
- .setVersion("2.2"));
- return plugins;
- }
-
- @Override
- public PluginMetadata getMetadata(String pluginKey) {
- return null;
- }
+ assertThat((Map) attributes.get("no-version"))
+ .containsEntry("Name", "No Version")
+ .doesNotContainKey("Version");
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/InstalledPluginReferentialFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/InstalledPluginReferentialFactoryTest.java
index 40e1ada4f35..58c0e12c449 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/InstalledPluginReferentialFactoryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/InstalledPluginReferentialFactoryTest.java
@@ -20,9 +20,8 @@
package org.sonar.server.plugins;
import org.junit.Test;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
@@ -33,23 +32,22 @@ public class InstalledPluginReferentialFactoryTest {
@Test
public void should_create_plugin_referential() {
- PluginMetadata metadata = mock(DefaultPluginMetadata.class);
- when(metadata.getKey()).thenReturn("foo");
+ PluginInfo info = new PluginInfo("foo");
PluginRepository pluginRepository = mock(PluginRepository.class);
- when(pluginRepository.getMetadata()).thenReturn(newArrayList(metadata));
- InstalledPluginReferentialFactory installedPluginReferentialFactory = new InstalledPluginReferentialFactory(pluginRepository);
+ when(pluginRepository.getPluginInfos()).thenReturn(newArrayList(info));
+ InstalledPluginReferentialFactory factory = new InstalledPluginReferentialFactory(pluginRepository);
- assertThat(installedPluginReferentialFactory.getInstalledPluginReferential()).isNull();
- installedPluginReferentialFactory.start();
- assertThat(installedPluginReferentialFactory.getInstalledPluginReferential()).isNotNull();
- assertThat(installedPluginReferentialFactory.getInstalledPluginReferential().getPlugins()).hasSize(1);
+ assertThat(factory.getInstalledPluginReferential()).isNull();
+ factory.start();
+ assertThat(factory.getInstalledPluginReferential()).isNotNull();
+ assertThat(factory.getInstalledPluginReferential().getPlugins()).hasSize(1);
}
@Test(expected = RuntimeException.class)
public void should_encapsulate_exception() {
PluginRepository pluginRepository = mock(PluginRepository.class);
- when(pluginRepository.getMetadata()).thenThrow(new IllegalArgumentException());
- InstalledPluginReferentialFactory installedPluginReferentialFactory = new InstalledPluginReferentialFactory(pluginRepository);
- installedPluginReferentialFactory.start();
+ when(pluginRepository.getPluginInfos()).thenThrow(new IllegalArgumentException());
+ InstalledPluginReferentialFactory factory = new InstalledPluginReferentialFactory(pluginRepository);
+ factory.start();
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/MimeTypesTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/MimeTypesTest.java
index 6c5f4412026..25b5b4978c4 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/MimeTypesTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/MimeTypesTest.java
@@ -20,6 +20,7 @@
package org.sonar.server.plugins;
import org.junit.Test;
+import org.sonar.test.TestUtils;
import static org.assertj.core.api.Assertions.assertThat;
@@ -35,4 +36,9 @@ public class MimeTypesTest {
assertThat(MimeTypes.getByFilename("static/sqale/sqale.css")).isEqualTo("text/css");
assertThat(MimeTypes.getByFilename("sqale.css")).isEqualTo("text/css");
}
+
+ @Test
+ public void only_statics() throws Exception {
+ assertThat(TestUtils.hasOnlyPrivateConstructors(MimeTypes.class)).isTrue();
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java
index bf460fffd2b..a5178f40383 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginDownloaderTest.java
@@ -29,11 +29,12 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.sonar.api.utils.HttpDownloader;
import org.sonar.api.utils.SonarException;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.server.platform.DefaultServerFileSystem;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.Release;
import org.sonar.updatecenter.common.UpdateCenter;
+import org.sonar.updatecenter.common.Version;
import java.io.File;
import java.net.URI;
@@ -66,7 +67,6 @@ public class PluginDownloaderTest {
UpdateCenter updateCenter;
HttpDownloader httpDownloader;
PluginDownloader pluginDownloader;
- ServerPluginJarInstaller installer;
@Before
public void before() throws Exception {
@@ -88,8 +88,7 @@ public class PluginDownloaderTest {
downloadDir = testFolder.newFolder("downloads");
when(defaultServerFileSystem.getDownloadedPluginsDir()).thenReturn(downloadDir);
- installer = new ServerPluginJarInstaller();
- pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, defaultServerFileSystem, installer);
+ pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, defaultServerFileSystem);
}
@After
@@ -155,7 +154,7 @@ public class PluginDownloaderTest {
File downloadDir = testFolder.newFile();
when(defaultServerFileSystem.getDownloadedPluginsDir()).thenReturn(downloadDir);
- pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, defaultServerFileSystem, installer);
+ pluginDownloader = new PluginDownloader(updateCenterMatrixFactory, httpDownloader, defaultServerFileSystem);
try {
pluginDownloader.start();
fail();
@@ -220,26 +219,18 @@ public class PluginDownloaderTest {
pluginDownloader.start();
assertThat(pluginDownloader.getDownloadedPluginFilenames()).hasSize(0);
- copyFileToDirectory(new File(resource("foo-plugin-1.0.jar")), downloadDir);
+ copyFileToDirectory(TestProjectUtils.jarOf("test-base-plugin"), downloadDir);
assertThat(pluginDownloader.getDownloadedPlugins()).hasSize(1);
- DefaultPluginMetadata metadata = pluginDownloader.getDownloadedPlugins().iterator().next();
- assertThat(metadata.getKey()).isEqualTo("foo");
- assertThat(metadata.getName()).isEqualTo("Foo");
- assertThat(metadata.getVersion()).isEqualTo("1.0");
- assertThat(metadata.getOrganization()).isEqualTo("SonarSource");
- assertThat(metadata.getOrganizationUrl()).isEqualTo("http://www.sonarsource.org");
- assertThat(metadata.getLicense()).isEqualTo("LGPL 3");
- assertThat(metadata.getMainClass()).isEqualTo("foo.Main");
- }
-
- private URI resource(String fileName) throws URISyntaxException {
- URL resource = getClass().getResource(getClass().getSimpleName() + "/" + fileName);
- return resource.toURI();
+ PluginInfo info = pluginDownloader.getDownloadedPlugins().iterator().next();
+ assertThat(info.getKey()).isEqualTo("testbase");
+ assertThat(info.getName()).isEqualTo("Base Plugin");
+ assertThat(info.getVersion()).isEqualTo(Version.create("0.1-SNAPSHOT"));
+ assertThat(info.getMainClass()).isEqualTo("BasePlugin");
}
@Test
- public void getDownloadedPluginFilenames_reads_plugin_metadata_of_files_in_download_folder() throws Exception {
+ public void getDownloadedPluginFilenames_reads_plugin_info_of_files_in_download_folder() throws Exception {
pluginDownloader.start();
assertThat(pluginDownloader.getDownloadedPlugins()).hasSize(0);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginReferentialMetadataConverterTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginReferentialMetadataConverterTest.java
index a7cc85c9694..c7891203caa 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginReferentialMetadataConverterTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/PluginReferentialMetadataConverterTest.java
@@ -20,23 +20,19 @@
package org.sonar.server.plugins;
import org.junit.Test;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.updatecenter.common.PluginReferential;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
public class PluginReferentialMetadataConverterTest {
@Test
- public void should_convert_metadata_to_plugin_referential() {
- PluginMetadata metadata = mock(DefaultPluginMetadata.class);
- when(metadata.getKey()).thenReturn("foo");
+ public void should_convert_info_to_plugin_referential() {
+ PluginInfo info = new PluginInfo("foo");
- PluginReferential pluginReferential = PluginReferentialMetadataConverter.getInstalledPluginReferential(newArrayList(metadata));
+ PluginReferential pluginReferential = PluginReferentialMetadataConverter.getInstalledPluginReferential(newArrayList(info));
assertThat(pluginReferential).isNotNull();
assertThat(pluginReferential.getPlugins()).hasSize(1);
assertThat(pluginReferential.getPlugins().get(0).getKey()).isEqualTo("foo");
@@ -44,11 +40,9 @@ public class PluginReferentialMetadataConverterTest {
@Test
public void should_not_add_core_plugin() {
- PluginMetadata metadata = mock(DefaultPluginMetadata.class);
- when(metadata.getKey()).thenReturn("foo");
- when(metadata.isCore()).thenReturn(true);
+ PluginInfo info = new PluginInfo("foo").setCore(true);
- PluginReferential pluginReferential = PluginReferentialMetadataConverter.getInstalledPluginReferential(newArrayList(metadata));
+ PluginReferential pluginReferential = PluginReferentialMetadataConverter.getInstalledPluginReferential(newArrayList(info));
assertThat(pluginReferential).isNotNull();
assertThat(pluginReferential.getPlugins()).hasSize(0);
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java
deleted file mode 100644
index 8edde701e28..00000000000
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginJarsInstallerTest.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * 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.server.plugins;
-
-import com.google.common.io.Resources;
-import org.apache.commons.io.FileUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.Server;
-import org.sonar.api.platform.ServerUpgradeStatus;
-import org.sonar.api.utils.MessageException;
-import org.sonar.core.plugins.DefaultPluginMetadata;
-import org.sonar.server.platform.DefaultServerFileSystem;
-
-import java.io.File;
-import java.util.Collection;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ServerPluginJarsInstallerTest {
-
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- DefaultServerFileSystem fileSystem;
- File homeDir, pluginsDir, downloadsDir, bundledDir, trashDir, coreDir;
- ServerPluginJarInstaller jarInstaller;
- ServerPluginJarsInstaller jarsInstaller;
- Server server = mock(Server.class);
- ServerUpgradeStatus upgradeStatus = mock(ServerUpgradeStatus.class);
-
- @Before
- public void before() throws Exception {
- when(server.getVersion()).thenReturn("3.1");
- when(server.getDeployDir()).thenReturn(temp.newFolder("deploy"));
-
- homeDir = temp.newFolder("home");
- pluginsDir = new File(homeDir, "extensions/plugins");
- FileUtils.forceMkdir(pluginsDir);
- downloadsDir = new File(homeDir, "extensions/downloads");
- trashDir = new File(homeDir, "extensions/trash");
- bundledDir = new File(homeDir, "lib/bundled-plugins");
- coreDir = new File(homeDir, "lib/core-plugins");
- FileUtils.forceMkdir(bundledDir);
-
- fileSystem = new DefaultServerFileSystem(homeDir, temp.newFolder(), server);
- jarInstaller = new ServerPluginJarInstaller();
- jarsInstaller = new ServerPluginJarsInstaller(server, upgradeStatus, fileSystem, jarInstaller);
- }
-
- private File jar(String name) throws Exception {
- return new File(Resources.getResource(getClass(), "ServerPluginJarsInstallerTest/" + name).toURI());
- }
-
- @Test
- public void copy_bundled_plugin_on_fresh_install() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(true);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), bundledDir);
-
- jarsInstaller.install();
-
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(1);
- assertThat(new File(pluginsDir, "foo-plugin-1.0.jar")).exists().isFile();
- PluginMetadata plugin = jarsInstaller.getMetadata("foo");
- assertThat(plugin.getName()).isEqualTo("Foo");
- assertThat(plugin.getDeployedFiles()).hasSize(1);
- assertThat(plugin.isCore()).isFalse();
- assertThat(plugin.isUseChildFirstClassLoader()).isFalse();
- }
-
- @Test
- public void do_not_copy_bundled_plugin_on_non_fresh_install() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), bundledDir);
-
- jarsInstaller.install();
-
- assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).isEmpty();
- }
-
- @Test
- public void do_not_copy_bundled_plugin_if_already_installed() throws Exception {
- // fresh install but plugins are already packaged in extensions/plugins
- when(upgradeStatus.isFreshInstall()).thenReturn(true);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), bundledDir);
- FileUtils.copyFileToDirectory(jar("foo-plugin-2.0.jar"), pluginsDir);
- FileUtils.copyFileToDirectory(jar("bar-plugin-1.0.jar"), pluginsDir);
-
- jarsInstaller.install();
-
- // do not copy foo 1.0
- assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).hasSize(2);
- assertThat(new File(pluginsDir, "foo-plugin-2.0.jar")).exists().isFile();
- assertThat(new File(pluginsDir, "bar-plugin-1.0.jar")).exists().isFile();
- PluginMetadata plugin = jarsInstaller.getMetadata("foo");
- assertThat(plugin.getVersion()).isEqualTo("2.0");
- }
-
- @Test
- public void deploy_installed_plugin() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), pluginsDir);
-
- jarsInstaller.install();
-
- // check that the plugin is registered
- assertThat(jarsInstaller.getMetadata()).hasSize(1);
- PluginMetadata plugin = jarsInstaller.getMetadata("foo");
- assertThat(plugin.getName()).isEqualTo("Foo");
- assertThat(plugin.getDeployedFiles()).hasSize(1);
- assertThat(plugin.isCore()).isFalse();
- assertThat(plugin.isUseChildFirstClassLoader()).isFalse();
-
- // check that the file is still present in extensions/plugins
- assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).hasSize(1);
- assertThat(new File(pluginsDir, "foo-plugin-1.0.jar")).exists().isFile();
- }
-
- @Test
- public void ignore_non_plugin_jars() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- FileUtils.copyFileToDirectory(jar("not-a-plugin.jar"), pluginsDir);
-
- jarsInstaller.install();
-
- // nothing to install but keep the file
- assertThat(jarsInstaller.getMetadata()).isEmpty();
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(1);
- assertThat(new File(pluginsDir, "not-a-plugin.jar")).exists().isFile();
- }
-
- @Test
- public void fail_if_plugin_requires_greater_SQ_version() throws Exception {
- exception.expect(MessageException.class);
- exception.expectMessage("Plugin switchoffviolations needs a more recent version of SonarQube than 2.0. At least 2.5 is expected");
-
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- when(server.getVersion()).thenReturn("2.0");
- FileUtils.copyFileToDirectory(jar("require-sq-2.5.jar"), pluginsDir);
-
- jarsInstaller.install();
- }
-
- @Test
- public void move_downloaded_plugins() throws Exception {
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), downloadsDir);
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
-
- jarsInstaller.install();
-
- assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).hasSize(1);
- assertThat(FileUtils.listFiles(downloadsDir, new String[] {"jar"}, false)).isEmpty();
- assertThat(new File(pluginsDir, "foo-plugin-1.0.jar")).exists().isFile();
- }
-
- @Test
- public void downloaded_plugins_overrides_existing_plugin() throws Exception {
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), pluginsDir);
- FileUtils.copyFileToDirectory(jar("foo-plugin-2.0.jar"), downloadsDir);
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
-
- jarsInstaller.install();
-
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(1);
- assertThat(FileUtils.listFiles(downloadsDir, new String[] {"jar"}, false)).isEmpty();
- assertThat(new File(pluginsDir, "foo-plugin-2.0.jar")).exists().isFile();
- }
-
- @Test
- public void downloaded_plugins_overrides_existing_plugin_even_if_same_filename() throws Exception {
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), pluginsDir, true);
- // foo-plugin-1.0.jar in extensions/downloads is in fact version 2.0. It's used to verify
- // that it has correctly overridden extensions/plugins/foo-plugin-1.0.jar
- FileUtils.copyFile(jar("foo-plugin-2.0.jar"), new File(downloadsDir, "foo-plugin-1.0.jar"));
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
-
- jarsInstaller.install();
-
- PluginMetadata plugin = jarsInstaller.getMetadata("foo");
- assertThat(plugin).isNotNull();
- assertThat(plugin.getVersion()).isEqualTo("2.0");
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(1);
- assertThat(FileUtils.listFiles(downloadsDir, new String[] {"jar"}, false)).isEmpty();
- File installed = new File(pluginsDir, "foo-plugin-1.0.jar");
- assertThat(installed).exists().isFile();
- }
-
- @Test
- public void delete_trash() throws Exception {
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), trashDir);
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
-
- jarsInstaller.install();
-
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).isEmpty();
- assertThat(trashDir).doesNotExist();
- }
-
- @Test
- public void fail_if_two_installed_plugins_with_same_key() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), pluginsDir);
- FileUtils.copyFileToDirectory(jar("foo-plugin-2.0.jar"), pluginsDir);
-
- try {
- jarsInstaller.install();
- fail();
- } catch (MessageException e) {
- assertThat(e.getMessage())
- .contains("Found two files for the same plugin 'foo'")
- .contains("foo-plugin-1.0.jar")
- .contains("foo-plugin-2.0.jar");
- }
- }
-
- @Test
- public void uninstall_plugin() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), pluginsDir);
-
- jarsInstaller.install();
- jarsInstaller.uninstall("foo");
-
- assertThat(FileUtils.listFiles(pluginsDir, new String[]{"jar"}, false)).isEmpty();
- assertThat(FileUtils.listFiles(trashDir, new String[] {"jar"}, false)).hasSize(1);
- assertThat(jarsInstaller.getUninstalledPluginFilenames()).containsOnly("foo-plugin-1.0.jar");
- }
-
- @Test
- public void pending_removals_reads_metadata() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), pluginsDir);
-
- jarsInstaller.install();
- jarsInstaller.uninstall("foo");
-
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).isEmpty();
- assertThat(FileUtils.listFiles(trashDir, new String[] {"jar"}, false)).hasSize(1);
- Collection<DefaultPluginMetadata> removals = jarsInstaller.getUninstalledPlugins();
- assertThat(removals).hasSize(1);
- PluginMetadata metadata = removals.iterator().next();
- assertThat(metadata.getKey()).isEqualTo("foo");
- assertThat(metadata.getName()).isEqualTo("Foo");
- assertThat(metadata.getVersion()).isEqualTo("1.0");
- assertThat(metadata.getOrganization()).isEqualTo("SonarSource");
- assertThat(metadata.getOrganizationUrl()).isEqualTo("http://www.sonarsource.org");
- assertThat(metadata.getLicense()).isEqualTo("LGPL 3");
- assertThat(metadata.getMainClass()).isEqualTo("foo.Main");
- }
-
- @Test
- public void cancel_uninstallation() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), pluginsDir);
-
- jarsInstaller.install();
- jarsInstaller.uninstall("foo");
- jarsInstaller.cancelUninstalls();
-
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(1);
- assertThat(FileUtils.listFiles(trashDir, new String[] {"jar"}, false)).hasSize(0);
- assertThat(jarsInstaller.getUninstalledPluginFilenames()).isEmpty();
- }
-
- @Test
- public void deploy_core_plugins() throws Exception {
- when(upgradeStatus.isFreshInstall()).thenReturn(false);
- FileUtils.copyFileToDirectory(jar("foo-plugin-1.0.jar"), coreDir);
-
- jarsInstaller.install();
-
- // do not deploy in extensions/plugins
- assertThat(FileUtils.listFiles(pluginsDir, new String[] {"jar"}, false)).hasSize(0);
-
- // do not remove from lib/core-plugins
- assertThat(FileUtils.listFiles(coreDir, new String[] {"jar"}, false)).hasSize(1);
-
- PluginMetadata plugin = jarsInstaller.getMetadata("foo");
- assertThat(plugin).isNotNull();
- assertThat(plugin.isCore()).isTrue();
- }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java
index 5f1898dae31..ea87cb3af88 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginRepositoryTest.java
@@ -19,47 +19,298 @@
*/
package org.sonar.server.plugins;
-import com.google.common.io.Resources;
+import com.google.common.collect.ImmutableSet;
+import org.apache.commons.io.FileUtils;
import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
+import org.sonar.api.platform.Server;
+import org.sonar.api.platform.ServerUpgradeStatus;
+import org.sonar.api.utils.MessageException;
+import org.sonar.core.platform.PluginLoader;
+import org.sonar.server.platform.DefaultServerFileSystem;
+import org.sonar.updatecenter.common.Version;
import java.io.File;
-import java.util.Arrays;
+import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ServerPluginRepositoryTest {
- ServerPluginRepository repository;
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ Server server = mock(Server.class);
+ ServerUpgradeStatus upgradeStatus = mock(ServerUpgradeStatus.class);
+ DefaultServerFileSystem fs = mock(DefaultServerFileSystem.class, Mockito.RETURNS_DEEP_STUBS);
+ PluginLoader pluginLoader = new PluginLoader(new ServerPluginUnzipper(fs));
+ ServerPluginRepository underTest = new ServerPluginRepository(server, upgradeStatus, fs, pluginLoader);
+
+ @Before
+ public void setUp() throws IOException {
+ when(fs.getBundledPluginsDir()).thenReturn(temp.newFolder());
+ when(fs.getCorePluginsDir()).thenReturn(temp.newFolder());
+ when(fs.getDeployedPluginsDir()).thenReturn(temp.newFolder());
+ when(fs.getDownloadedPluginsDir()).thenReturn(temp.newFolder());
+ when(fs.getHomeDir()).thenReturn(temp.newFolder());
+ when(fs.getInstalledPluginsDir()).thenReturn(temp.newFolder());
+ when(fs.getTempDir()).thenReturn(temp.newFolder());
+ when(server.getVersion()).thenReturn("5.2");
+ }
@After
- public void stop() {
- if (repository != null) {
- repository.stop();
+ public void tearDown() throws Exception {
+ underTest.stop();
+ }
+
+ /**
+ * The first server startup (fresh db) installs bundled plugins and instantiates bundled + core plugins.
+ */
+ @Test
+ public void first_startup_installs_bundled_plugins() throws Exception {
+ copyTestPluginTo("test-base-plugin", fs.getBundledPluginsDir());
+ copyTestPluginTo("test-core-plugin", fs.getCorePluginsDir());
+ when(upgradeStatus.isFreshInstall()).thenReturn(true);
+
+ underTest.start();
+
+ // both plugins are installed
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("core", "testbase");
+ assertThat(underTest.getPluginInstance("core").getClass().getName()).isEqualTo("CorePlugin");
+ assertThat(underTest.getPluginInstance("testbase").getClass().getName()).isEqualTo("BasePlugin");
+ assertThat(underTest.hasPlugin("testbase")).isTrue();
+ }
+
+ @Test
+ public void bundled_plugins_are_not_installed_if_not_fresh_server() throws Exception {
+ copyTestPluginTo("test-base-plugin", fs.getBundledPluginsDir());
+ when(upgradeStatus.isFreshInstall()).thenReturn(false);
+
+ underTest.start();
+
+ assertThat(underTest.getPluginInfos()).isEmpty();
+ }
+
+ @Test
+ public void standard_startup_loads_core_and_installed_plugins() throws Exception {
+ copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+ copyTestPluginTo("test-core-plugin", fs.getCorePluginsDir());
+
+ underTest.start();
+
+ // both plugins are installed
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("core", "testbase");
+ assertThat(underTest.getPluginInstance("core").getClass().getName()).isEqualTo("CorePlugin");
+ assertThat(underTest.getPluginInstance("testbase").getClass().getName()).isEqualTo("BasePlugin");
+ }
+
+ /**
+ * That sounds impossible, there are still core plugins for now, but it's still valuable
+ * to test sensibility to null values.
+ */
+ @Test
+ public void no_plugins_at_all_on_startup() throws Exception {
+ underTest.start();
+
+ assertThat(underTest.getPluginInfos()).isEmpty();
+ assertThat(underTest.getPluginInfosByKeys()).isEmpty();
+ assertThat(underTest.getUninstalledPlugins()).isEmpty();
+ assertThat(underTest.hasPlugin("testbase")).isFalse();
+ }
+
+ @Test
+ public void fail_if_multiple_jars_for_same_installed_plugin_on_startup() throws Exception {
+ copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+ copyTestPluginTo("test-base-plugin-v2", fs.getInstalledPluginsDir());
+
+ try {
+ underTest.start();
+ fail();
+ } catch (MessageException e) {
+ assertThat(e)
+ .hasMessageStartingWith("Found two files for the same plugin [testbase]: ")
+ // order is not guaranteed, so assertion is split
+ .hasMessageContaining("test-base-plugin-0.1-SNAPSHOT.jar")
+ .hasMessageContaining("test-base-plugin-0.2-SNAPSHOT.jar");
}
}
@Test
- public void testStart() throws Exception {
- ServerPluginJarsInstaller deployer = mock(ServerPluginJarsInstaller.class);
- File pluginFile = new File(Resources.getResource("org/sonar/server/plugins/ServerPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar").toURI());
- PluginMetadata plugin = DefaultPluginMetadata.create(pluginFile)
- .setKey("artifactsize")
- .setMainClass("org.sonar.plugins.artifactsize.ArtifactSizePlugin")
- .addDeployedFile(pluginFile);
- when(deployer.getMetadata()).thenReturn(Arrays.asList(plugin));
+ public void install_downloaded_plugins_on_startup() throws Exception {
+ File downloadedJar = copyTestPluginTo("test-base-plugin", fs.getDownloadedPluginsDir());
+
+ underTest.start();
+
+ // plugin is moved to extensions/plugins then loaded
+ assertThat(downloadedJar).doesNotExist();
+ assertThat(new File(fs.getInstalledPluginsDir(), downloadedJar.getName())).isFile().exists();
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase");
+ assertThat(underTest.getPluginInstance("testbase").getClass().getName()).isEqualTo("BasePlugin");
+ }
+
+ @Test
+ public void downloaded_file_overrides_existing_installed_file_on_startup() throws Exception {
+ File installedV1 = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+ File downloadedV2 = copyTestPluginTo("test-base-plugin-v2", fs.getDownloadedPluginsDir());
+
+ underTest.start();
+
+ // plugin is moved to extensions/plugins and replaces v1
+ assertThat(downloadedV2).doesNotExist();
+ assertThat(installedV1).doesNotExist();
+ assertThat(new File(fs.getInstalledPluginsDir(), downloadedV2.getName())).exists();
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase");
+ assertThat(underTest.getPluginInfo("testbase").getVersion()).isEqualTo(Version.create("0.2-SNAPSHOT"));
+ }
+
+ @Test
+ public void blacklisted_plugin_is_automatically_uninstalled_on_startup() throws Exception {
+ underTest.setBlacklistedPluginKeys(ImmutableSet.of("testbase", "issuesreport"));
+ File jar = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
- repository = new ServerPluginRepository(deployer);
- repository.start();
+ // plugin is not installed and file is deleted
+ assertThat(underTest.getPluginInfos()).isEmpty();
+ assertThat(jar).doesNotExist();
+ }
+
+ @Test
+ public void test_plugin_requirements_at_startup() throws Exception {
+ copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+ copyTestPluginTo("test-require-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
+
+ // both plugins are installed
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase", "testrequire");
+ }
+
+ @Test
+ public void plugin_is_ignored_if_required_plugin_is_missing_at_startup() throws Exception {
+ copyTestPluginTo("test-require-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
+
+ // plugin is not installed as test-base-plugin is missing
+ assertThat(underTest.getPluginInfosByKeys()).isEmpty();
+ }
+
+ @Test
+ public void plugin_is_ignored_if_required_plugin_is_too_old_at_startup() throws Exception {
+ copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+ copyTestPluginTo("test-requirenew-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
+
+ // the plugin "requirenew" is not installed as it requires base 0.2+ to be installed.
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase");
+ }
+
+ @Test
+ public void plugin_is_ignored_at_startup_if_unsupported_sq() throws Exception {
+ when(server.getVersion()).thenReturn("1.0");
+ copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
+
+ // plugin requires SQ 4.5.1 but SQ 1.0 is installed
+ assertThat(underTest.getPluginInfos()).isEmpty();
+ }
+
+ @Test
+ public void uninstall() throws Exception {
+ File installedJar = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase");
+ underTest.uninstall("testbase");
+
+ assertThat(installedJar).doesNotExist();
+ // still up. Will be dropped after next startup
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase");
+ assertThat(underTest.getUninstalledPluginFilenames()).containsOnly(installedJar.getName());
+ assertThat(underTest.getUninstalledPlugins()).extracting("key").containsOnly("testbase");
+ }
+
+ @Test
+ public void uninstall_dependents() throws Exception {
+ File base = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+ File extension = copyTestPluginTo("test-require-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
+ assertThat(underTest.getPluginInfos()).hasSize(2);
+ underTest.uninstall("testbase");
+
+ assertThat(base).doesNotExist();
+ assertThat(extension).doesNotExist();
+ assertThat(underTest.getUninstalledPluginFilenames()).containsOnly(base.getName(), extension.getName());
+ assertThat(underTest.getUninstalledPlugins()).extracting("key").containsOnly("testbase", "testrequire");
+ }
+
+ @Test
+ public void cancel_uninstall() throws Exception {
+ File base = copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+ underTest.start();
+
+ underTest.uninstall("testbase");
+ assertThat(base).doesNotExist();
+
+ underTest.cancelUninstalls();
+ assertThat(base).exists();
+ assertThat(underTest.getUninstalledPluginFilenames()).isEmpty();
+ assertThat(underTest.getUninstalledPlugins()).isEmpty();
+ }
+
+ @Test
+ public void install_plugin_and_its_extension_plugins_at_startup() throws Exception {
+ copyTestPluginTo("test-base-plugin", fs.getInstalledPluginsDir());
+ copyTestPluginTo("test-extend-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
+
+ // both plugins are installed
+ assertThat(underTest.getPluginInfosByKeys()).containsOnlyKeys("testbase", "testextend");
+ }
+
+ @Test
+ public void extension_plugin_is_ignored_if_base_plugin_is_missing_at_startup() throws Exception {
+ copyTestPluginTo("test-extend-plugin", fs.getInstalledPluginsDir());
+
+ underTest.start();
+
+ // plugin is not installed as its base plugin is not installed
+ assertThat(underTest.getPluginInfos()).isEmpty();
+ }
+
+ @Test
+ public void fail_is_missing_required_plugin() throws Exception {
+ try {
+ underTest.getPluginInfo("unknown");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Plugin [unknown] does not exist");
+ }
+
+ try {
+ underTest.getPluginInstance("unknown");
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Plugin [unknown] does not exist");
+ }
+ }
- assertThat(repository.getPlugin("artifactsize")).isNotNull();
- assertThat(repository.getClassLoader("artifactsize")).isNotNull();
- assertThat(repository.getClass("artifactsize", "org.sonar.plugins.artifactsize.ArtifactSizeMetrics")).isNotNull();
- assertThat(repository.getClass("artifactsize", "org.Unknown")).isNull();
- assertThat(repository.getClass("other", "org.sonar.plugins.artifactsize.ArtifactSizeMetrics")).isNull();
+ private File copyTestPluginTo(String testPluginName, File toDir) throws IOException {
+ File jar = TestProjectUtils.jarOf(testPluginName);
+ // file is copied because it's supposed to be moved by the test
+ FileUtils.copyFileToDirectory(jar, toDir);
+ return new File(toDir, jar.getName());
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginUnzipperTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginUnzipperTest.java
new file mode 100644
index 00000000000..efea25d39e8
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ServerPluginUnzipperTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.server.plugins;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.UnzippedPlugin;
+import org.sonar.server.platform.DefaultServerFileSystem;
+
+import java.io.File;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ServerPluginUnzipperTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ DefaultServerFileSystem fs = mock(DefaultServerFileSystem.class);
+ ServerPluginUnzipper underTest = new ServerPluginUnzipper(fs);
+
+ @Test
+ public void copy_all_classloader_files_to_dedicated_directory() throws Exception {
+ File deployDir = temp.newFolder();
+ when(fs.getDeployedPluginsDir()).thenReturn(deployDir);
+ File jar = TestProjectUtils.jarOf("test-libs-plugin");
+ PluginInfo info = PluginInfo.create(jar);
+
+ UnzippedPlugin unzipped = underTest.unzip(info);
+
+ // all the files loaded by classloaders (JAR + META-INF/libs/*.jar) are copied to the dedicated directory
+ // web/deploy/{pluginKey}
+ File pluginDeployDir = new File(deployDir, "testlibs");
+
+ assertThat(unzipped.getKey()).isEqualTo("testlibs");
+ assertThat(unzipped.getMain()).isFile().exists().hasParent(pluginDeployDir);
+ assertThat(unzipped.getLibs()).extracting("name").containsOnly("commons-daemon-1.0.15.jar", "commons-email-20030310.165926.jar");
+ for (File lib : unzipped.getLibs()) {
+ assertThat(lib).exists().isFile();
+ assertThat(lib.getCanonicalPath()).startsWith(pluginDeployDir.getCanonicalPath());
+ }
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/plugins/ResourcesClassloader.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/TestProjectUtils.java
index 04aea1fb391..00d579118ee 100644
--- a/sonar-core/src/main/java/org/sonar/core/plugins/ResourcesClassloader.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/TestProjectUtils.java
@@ -17,33 +17,24 @@
* 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.plugins;
+package org.sonar.server.plugins;
-import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.io.FileUtils;
-import java.net.URL;
-import java.net.URLClassLoader;
+import java.io.File;
import java.util.Collection;
-/**
- * This class loader is used to load resources from a list of URLs - see SONAR-1861.
- */
-public class ResourcesClassloader extends URLClassLoader {
- private Collection<URL> urls;
-
- public ResourcesClassloader(Collection<URL> urls, ClassLoader parent) {
- super(new URL[] {}, parent);
- this.urls = Lists.newArrayList(urls);
- }
+public class TestProjectUtils {
- @Override
- public URL findResource(String name) {
- for (URL url : urls) {
- if (StringUtils.endsWith(url.getPath(), name)) {
- return url;
- }
+ /**
+ * Get the artifact of plugins stored in src/test/projects
+ */
+ public static File jarOf(String dirName) {
+ File target = FileUtils.toFile(TestProjectUtils.class.getResource(String.format("/%s/target/", dirName)));
+ Collection<File> jars = FileUtils.listFiles(target, new String[] {"jar"}, false);
+ if (jars == null || jars.size() != 1) {
+ throw new IllegalArgumentException("Test project is badly defined: " + dirName);
}
- return null;
+ return jars.iterator().next();
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/CancelAllPluginsWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/CancelAllPluginsWsActionTest.java
index 4ff9f43f340..3d2260eba4f 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/CancelAllPluginsWsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/CancelAllPluginsWsActionTest.java
@@ -28,7 +28,7 @@ import org.sonar.api.server.ws.WebService;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
+import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.ws.WsTester;
@@ -41,8 +41,8 @@ public class CancelAllPluginsWsActionTest {
private static final String DUMMY_CONTROLLER_KEY = "dummy";
private PluginDownloader pluginDownloader = mock(PluginDownloader.class);
- private ServerPluginJarsInstaller pluginJarsInstaller = mock(ServerPluginJarsInstaller.class);
- private CancelAllPluginsWsAction underTest = new CancelAllPluginsWsAction(pluginDownloader, pluginJarsInstaller);
+ private ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
+ private CancelAllPluginsWsAction underTest = new CancelAllPluginsWsAction(pluginDownloader, pluginRepository);
private Request request = mock(Request.class);
private WsTester.TestResponse response = new WsTester.TestResponse();
@@ -90,7 +90,7 @@ public class CancelAllPluginsWsActionTest {
underTest.handle(request, response);
verify(pluginDownloader, times(1)).cancelDownloads();
- verify(pluginJarsInstaller, times(1)).cancelUninstalls();
+ verify(pluginRepository, times(1)).cancelUninstalls();
assertThat(response.outputAsString()).isEmpty();
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledPluginsWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledPluginsWsActionTest.java
index 3780d88af00..11a544e1d23 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledPluginsWsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/InstalledPluginsWsActionTest.java
@@ -19,17 +19,17 @@
*/
package org.sonar.server.plugins.ws;
-import java.io.File;
import org.junit.Test;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.ws.WsTester;
+import org.sonar.updatecenter.common.Version;
+
+import java.io.File;
import static com.google.common.collect.ImmutableList.of;
-import static java.lang.String.valueOf;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -42,12 +42,12 @@ public class InstalledPluginsWsActionTest {
" \"plugins\":" + "[]" +
"}";
- private PluginRepository pluginRepository = mock(PluginRepository.class);
+ private ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
private InstalledPluginsWsAction underTest = new InstalledPluginsWsAction(pluginRepository, new PluginWSCommons());
private Request request = mock(Request.class);
private WsTester.TestResponse response = new WsTester.TestResponse();
- private PluginMetadata corePlugin = corePlugin("core1", 10);
+ private PluginInfo corePlugin = corePlugin("core1", "1.0");
@Test
public void action_installed_is_defined() {
@@ -75,7 +75,7 @@ public class InstalledPluginsWsActionTest {
@Test
public void core_plugin_are_not_returned() throws Exception {
- when(pluginRepository.getMetadata()).thenReturn(of(corePlugin));
+ when(pluginRepository.getPluginInfos()).thenReturn(of(corePlugin));
underTest.handle(request, response);
@@ -84,9 +84,9 @@ public class InstalledPluginsWsActionTest {
@Test
public void empty_fields_are_not_serialized_to_json() throws Exception {
- when(pluginRepository.getMetadata()).thenReturn(
+ when(pluginRepository.getPluginInfos()).thenReturn(
of(
- (PluginMetadata) DefaultPluginMetadata.create("").setName("").setCore(false)
+ new PluginInfo("").setName("").setCore(false)
)
);
@@ -98,14 +98,14 @@ public class InstalledPluginsWsActionTest {
@Test
public void verify_properties_displayed_in_json_per_plugin() throws Exception {
String jarFilename = getClass().getSimpleName() + "/" + "some.jar";
- when(pluginRepository.getMetadata()).thenReturn(of(
- (PluginMetadata) DefaultPluginMetadata.create("plugKey").setName("plugName").setCore(false)
+ when(pluginRepository.getPluginInfos()).thenReturn(of(
+ new PluginInfo("plugKey").setName("plugName").setCore(false)
.setDescription("desc_it")
- .setVersion(valueOf(10))
+ .setVersion(Version.create("1.0"))
.setLicense("license_hey")
- .setOrganization("org_name")
+ .setOrganizationName("org_name")
.setOrganizationUrl("org_url")
- .setHomepage("homepage_url")
+ .setHomepageUrl("homepage_url")
.setIssueTrackerUrl("issueTracker_url")
.setFile(new File(getClass().getResource(jarFilename).toURI()))
.setImplementationBuild("sou_rev_sha1")
@@ -122,7 +122,7 @@ public class InstalledPluginsWsActionTest {
" \"key\": \"plugKey\"," +
" \"name\": \"plugName\"," +
" \"description\": \"desc_it\"," +
- " \"version\": \"10\"," +
+ " \"version\": \"1.0\"," +
" \"license\": \"license_hey\"," +
" \"organizationName\": \"org_name\"," +
" \"organizationUrl\": \"org_url\"," +
@@ -137,7 +137,7 @@ public class InstalledPluginsWsActionTest {
@Test
public void plugins_are_sorted_by_name_then_key_and_only_one_plugin_can_have_a_specific_name() throws Exception {
- when(pluginRepository.getMetadata()).thenReturn(
+ when(pluginRepository.getPluginInfos()).thenReturn(
of(
plugin("A", "name2"),
plugin("B", "name1"),
@@ -163,7 +163,7 @@ public class InstalledPluginsWsActionTest {
@Test
public void only_one_plugin_can_have_a_specific_name_and_key() throws Exception {
- when(pluginRepository.getMetadata()).thenReturn(
+ when(pluginRepository.getPluginInfos()).thenReturn(
of(
plugin("A", "name2"),
plugin("A", "name2")
@@ -183,15 +183,15 @@ public class InstalledPluginsWsActionTest {
assertThat(response.outputAsString()).containsOnlyOnce("name2");
}
- private static PluginMetadata corePlugin(String key, int version) {
- return DefaultPluginMetadata.create(key).setName(key).setCore(true).setVersion(valueOf(version));
+ private static PluginInfo corePlugin(String key, String version) {
+ return new PluginInfo(key).setName(key).setCore(true).setVersion(Version.create(version));
}
- private static PluginMetadata plugin(String key, String name, int version) {
- return DefaultPluginMetadata.create(key).setName(name).setCore(false).setVersion(valueOf(version));
+ private static PluginInfo plugin(String key, String name, String version) {
+ return new PluginInfo(key).setName(name).setCore(false).setVersion(Version.create(version));
}
- private static PluginMetadata plugin(String key, String name) {
- return DefaultPluginMetadata.create(key).setName(name).setCore(false).setVersion("1.0");
+ private static PluginInfo plugin(String key, String name) {
+ return new PluginInfo(key).setName(name).setCore(false).setVersion(Version.create("1.0"));
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java
index 558ed57839a..1849151312a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PendingPluginsWsActionTest.java
@@ -23,39 +23,39 @@ import java.io.File;
import org.junit.Test;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
+import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.ws.WsTester;
+import org.sonar.updatecenter.common.Version;
import static com.google.common.collect.ImmutableList.of;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import static org.sonar.core.plugins.DefaultPluginMetadata.create;
import static org.sonar.test.JsonAssert.assertJson;
public class PendingPluginsWsActionTest {
- public static final DefaultPluginMetadata GIT_PLUGIN_METADATA = create("scmgit")
+ public static final PluginInfo GIT_PLUGIN_INFO = new PluginInfo("scmgit")
.setName("Git")
.setDescription("Git SCM Provider.")
- .setVersion("1.0")
+ .setVersion(Version.create("1.0"))
.setLicense("GNU LGPL 3")
- .setOrganization("SonarSource")
+ .setOrganizationName("SonarSource")
.setOrganizationUrl("http://www.sonarsource.com")
- .setHomepage("http://redirect.sonarsource.com/plugins/scmgit.html")
+ .setHomepageUrl("http://redirect.sonarsource.com/plugins/scmgit.html")
.setIssueTrackerUrl("http://jira.codehaus.org/browse/SONARSCGIT")
.setFile(new File("/home/user/sonar-scm-git-plugin-1.0.jar"))
.setImplementationBuild("9ce9d330c313c296fab051317cc5ad4b26319e07");
private static final String DUMMY_CONTROLLER_KEY = "dummy";
- public static final DefaultPluginMetadata PLUGIN_2_2 = create("key2").setName("name2");
- public static final DefaultPluginMetadata PLUGIN_2_1 = create("key1").setName("name2");
- public static final DefaultPluginMetadata PLUGIN_0_0 = create("key0").setName("name0");
+ public static final PluginInfo PLUGIN_2_2 = new PluginInfo("key2").setName("name2");
+ public static final PluginInfo PLUGIN_2_1 = new PluginInfo("key1").setName("name2");
+ public static final PluginInfo PLUGIN_0_0 = new PluginInfo("key0").setName("name0");
private PluginDownloader pluginDownloader = mock(PluginDownloader.class);
- private ServerPluginJarsInstaller serverPluginJarsInstaller = mock(ServerPluginJarsInstaller.class);
- private PendingPluginsWsAction underTest = new PendingPluginsWsAction(pluginDownloader, serverPluginJarsInstaller, new PluginWSCommons());
+ private ServerPluginRepository serverPluginRepository = mock(ServerPluginRepository.class);
+ private PendingPluginsWsAction underTest = new PendingPluginsWsAction(pluginDownloader, serverPluginRepository, new PluginWSCommons());
private Request request = mock(Request.class);
private WsTester.TestResponse response = new WsTester.TestResponse();
@@ -91,7 +91,7 @@ public class PendingPluginsWsActionTest {
@Test
public void verify_properties_displayed_in_json_per_installing_plugin() throws Exception {
- when(pluginDownloader.getDownloadedPlugins()).thenReturn(of(GIT_PLUGIN_METADATA));
+ when(pluginDownloader.getDownloadedPlugins()).thenReturn(of(GIT_PLUGIN_INFO));
underTest.handle(request, response);
@@ -119,7 +119,7 @@ public class PendingPluginsWsActionTest {
@Test
public void verify_properties_displayed_in_json_per_removing_plugin() throws Exception {
- when(serverPluginJarsInstaller.getUninstalledPlugins()).thenReturn(of(GIT_PLUGIN_METADATA));
+ when(serverPluginRepository.getUninstalledPlugins()).thenReturn(of(GIT_PLUGIN_INFO));
underTest.handle(request, response);
@@ -180,7 +180,7 @@ public class PendingPluginsWsActionTest {
@Test
public void removing_plugin_are_sorted_and_unique() throws Exception {
- when(serverPluginJarsInstaller.getUninstalledPlugins()).thenReturn(of(
+ when(serverPluginRepository.getUninstalledPlugins()).thenReturn(of(
PLUGIN_2_2,
PLUGIN_2_1,
PLUGIN_2_2,
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java
index 831bdbd7b78..e055635b343 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/PluginWSCommonsTest.java
@@ -22,7 +22,7 @@ package org.sonar.server.plugins.ws;
import java.io.File;
import org.junit.Test;
import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.server.ws.WsTester;
import org.sonar.updatecenter.common.Plugin;
import org.sonar.updatecenter.common.PluginUpdate;
@@ -31,7 +31,6 @@ import org.sonar.updatecenter.common.Version;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.utils.DateUtils.parseDate;
-import static org.sonar.core.plugins.DefaultPluginMetadata.create;
import static org.sonar.server.plugins.ws.PluginWSCommons.toJSon;
import static org.sonar.test.JsonAssert.assertJson;
import static org.sonar.updatecenter.common.PluginUpdate.Status.COMPATIBLE;
@@ -40,14 +39,14 @@ import static org.sonar.updatecenter.common.PluginUpdate.Status.INCOMPATIBLE;
import static org.sonar.updatecenter.common.PluginUpdate.Status.REQUIRE_SONAR_UPGRADE;
public class PluginWSCommonsTest {
- private static final DefaultPluginMetadata GIT_PLUGIN_METADATA = create("scmgit")
+ private static final PluginInfo GIT_PLUGIN_METADATA = new PluginInfo("scmgit")
.setName("Git")
.setDescription("Git SCM Provider.")
- .setVersion("1.0")
+ .setVersion(Version.create("1.0"))
.setLicense("GNU LGPL 3")
- .setOrganization("SonarSource")
+ .setOrganizationName("SonarSource")
.setOrganizationUrl("http://www.sonarsource.com")
- .setHomepage("http://redirect.sonarsource.com/plugins/scmgit.html")
+ .setHomepageUrl("http://redirect.sonarsource.com/plugins/scmgit.html")
.setIssueTrackerUrl("http://jira.codehaus.org/browse/SONARSCGIT")
.setFile(new File("/home/user/sonar-scm-git-plugin-1.0.jar"));
private static final Plugin PLUGIN = new Plugin("p_key")
@@ -202,7 +201,7 @@ public class PluginWSCommonsTest {
PluginUpdate pluginUpdate = new PluginUpdate();
pluginUpdate.setRelease(
new Release(PLUGIN, version("1.0")).addOutgoingDependency(RELEASE)
- );
+ );
jsonWriter.beginObject();
underTest.writeUpdate(jsonWriter, pluginUpdate);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UninstallPluginsWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UninstallPluginsWsActionTest.java
index fa8adaa0f98..85a3bba714f 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UninstallPluginsWsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/UninstallPluginsWsActionTest.java
@@ -19,19 +19,15 @@
*/
package org.sonar.server.plugins.ws;
-import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.plugins.DefaultPluginMetadata;
import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
+import org.sonar.server.plugins.ServerPluginRepository;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.ws.WsTester;
@@ -45,11 +41,10 @@ public class UninstallPluginsWsActionTest {
private static final String CONTROLLER_KEY = "api/plugins";
private static final String ACTION_KEY = "uninstall";
private static final String KEY_PARAM = "key";
- private static final String PLUGIN_KEY = "pluginKey";
+ private static final String PLUGIN_KEY = "findbugs";
- private PluginRepository pluginRepository = mock(PluginRepository.class);
- private ServerPluginJarsInstaller pluginJarsInstaller = mock(ServerPluginJarsInstaller.class);
- private UninstallPluginsWsAction underTest = new UninstallPluginsWsAction(pluginRepository, pluginJarsInstaller);
+ private ServerPluginRepository pluginRepository = mock(ServerPluginRepository.class);
+ private UninstallPluginsWsAction underTest = new UninstallPluginsWsAction(pluginRepository);
private WsTester wsTester = new WsTester(new PluginsWs(underTest));
private Request invalidRequest = wsTester.newGetRequest(CONTROLLER_KEY, ACTION_KEY);
@@ -109,20 +104,18 @@ public class UninstallPluginsWsActionTest {
@Test
public void IAE_is_raised_when_plugin_is_not_installed() throws Exception {
expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("No plugin with key 'pluginKey'");
+ expectedException.expectMessage("Plugin [findbugs] is not installed");
underTest.handle(validRequest, response);
}
@Test
public void if_plugin_is_installed_uninstallation_is_triggered() throws Exception {
- when(pluginRepository.getMetadata()).thenReturn(ImmutableList.<PluginMetadata>of(
- DefaultPluginMetadata.create(PLUGIN_KEY)
- ));
+ when(pluginRepository.hasPlugin(PLUGIN_KEY)).thenReturn(true);
underTest.handle(validRequest, response);
- verify(pluginJarsInstaller).uninstall(PLUGIN_KEY);
+ verify(pluginRepository).uninstall(PLUGIN_KEY);
assertThat(response.outputAsString()).isEmpty();
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/startup/GeneratePluginIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/startup/GeneratePluginIndexTest.java
index cc96395bc62..8af9cb1eb7c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/startup/GeneratePluginIndexTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/startup/GeneratePluginIndexTest.java
@@ -25,9 +25,8 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import org.sonar.server.platform.DefaultServerFileSystem;
import java.io.File;
@@ -45,8 +44,8 @@ public class GeneratePluginIndexTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- private DefaultServerFileSystem fileSystem;
- private File index;
+ DefaultServerFileSystem fileSystem;
+ File index;
@Before
public void createIndexFile() {
@@ -58,9 +57,9 @@ public class GeneratePluginIndexTest {
@Test
public void shouldWriteIndex() throws IOException {
PluginRepository repository = mock(PluginRepository.class);
- PluginMetadata sqale = newMetadata("sqale");
- PluginMetadata checkstyle = newMetadata("checkstyle");
- when(repository.getMetadata()).thenReturn(Arrays.asList(sqale, checkstyle));
+ PluginInfo sqale = newInfo("sqale");
+ PluginInfo checkstyle = newInfo("checkstyle");
+ when(repository.getPluginInfos()).thenReturn(Arrays.asList(sqale, checkstyle));
new GeneratePluginIndex(fileSystem, repository).start();
@@ -70,11 +69,7 @@ public class GeneratePluginIndexTest {
assertThat(lines.get(1), containsString("checkstyle"));
}
- private PluginMetadata newMetadata(String pluginKey) throws IOException {
- PluginMetadata plugin = mock(DefaultPluginMetadata.class);
- when(plugin.getKey()).thenReturn(pluginKey);
- File pluginFile = temp.newFile(pluginKey + ".jar");
- when(plugin.getFile()).thenReturn(pluginFile);
- return plugin;
+ private PluginInfo newInfo(String pluginKey) throws IOException {
+ return new PluginInfo(pluginKey).setFile(temp.newFile(pluginKey + ".jar"));
}
}
diff --git a/server/sonar-server/src/test/projects/.gitignore b/server/sonar-server/src/test/projects/.gitignore
new file mode 100644
index 00000000000..a945b8525e6
--- /dev/null
+++ b/server/sonar-server/src/test/projects/.gitignore
@@ -0,0 +1,7 @@
+# see README.txt
+!*/target/
+*/target/classes/
+*/target/maven-archiver/
+*/target/maven-status/
+*/target/test-*/
+
diff --git a/server/sonar-server/src/test/projects/README.txt b/server/sonar-server/src/test/projects/README.txt
new file mode 100644
index 00000000000..c53a66d52f2
--- /dev/null
+++ b/server/sonar-server/src/test/projects/README.txt
@@ -0,0 +1,3 @@
+This directory provides the fake plugins used by tests. These tests are rarely changed, so generated
+artifacts are stored in Git repository (see .gitignore). It avoids from adding unnecessary modules
+to build.
diff --git a/server/sonar-server/src/test/projects/pom.xml b/server/sonar-server/src/test/projects/pom.xml
new file mode 100644
index 00000000000..f244768228e
--- /dev/null
+++ b/server/sonar-server/src/test/projects/pom.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.codehaus.sonar.tests</groupId>
+ <artifactId>parent</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <modules>
+ <module>test-base-plugin</module>
+ <module>test-base-plugin-v2</module>
+ <module>test-core-plugin</module>
+ <module>test-extend-plugin</module>
+ <module>test-libs-plugin</module>
+ <module>test-require-plugin</module>
+ <module>test-requirenew-plugin</module>
+ </modules>
+
+</project>
diff --git a/server/sonar-server/src/test/projects/test-base-plugin-v2/pom.xml b/server/sonar-server/src/test/projects/test-base-plugin-v2/pom.xml
new file mode 100644
index 00000000000..21f7ed5558d
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-base-plugin-v2/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.codehaus.sonar.tests</groupId>
+ <artifactId>test-base-plugin</artifactId>
+ <version>0.2-SNAPSHOT</version>
+ <packaging>sonar-plugin</packaging>
+ <name>Base Plugin</name>
+ <description>Simple standalone plugin. Used by other fake plugins.</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-plugin-api</artifactId>
+ <version>4.5.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-packaging-maven-plugin</artifactId>
+ <version>1.13</version>
+ <extensions>true</extensions>
+ <configuration>
+ <pluginKey>testbase</pluginKey>
+ <pluginClass>BasePlugin</pluginClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/server/sonar-server/src/test/projects/test-base-plugin-v2/src/BasePlugin.java b/server/sonar-server/src/test/projects/test-base-plugin-v2/src/BasePlugin.java
new file mode 100644
index 00000000000..57b4a5dfb98
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-base-plugin-v2/src/BasePlugin.java
@@ -0,0 +1,11 @@
+import org.sonar.api.SonarPlugin;
+
+import java.util.Collections;
+import java.util.List;
+
+public class BasePlugin extends SonarPlugin {
+
+ public List getExtensions() {
+ return Collections.emptyList();
+ }
+}
diff --git a/server/sonar-server/src/test/projects/test-base-plugin-v2/target/test-base-plugin-0.2-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-base-plugin-v2/target/test-base-plugin-0.2-SNAPSHOT.jar
new file mode 100644
index 00000000000..9bd9e0e0fc1
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-base-plugin-v2/target/test-base-plugin-0.2-SNAPSHOT.jar
Binary files differ
diff --git a/server/sonar-server/src/test/projects/test-base-plugin/pom.xml b/server/sonar-server/src/test/projects/test-base-plugin/pom.xml
new file mode 100644
index 00000000000..61b994c4754
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-base-plugin/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.codehaus.sonar.tests</groupId>
+ <artifactId>test-base-plugin</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>sonar-plugin</packaging>
+ <name>Base Plugin</name>
+ <description>Simple standalone plugin. Used by other fake plugins.</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-plugin-api</artifactId>
+ <version>4.5.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-packaging-maven-plugin</artifactId>
+ <version>1.13</version>
+ <extensions>true</extensions>
+ <configuration>
+ <pluginKey>testbase</pluginKey>
+ <pluginClass>BasePlugin</pluginClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/server/sonar-server/src/test/projects/test-base-plugin/src/BasePlugin.java b/server/sonar-server/src/test/projects/test-base-plugin/src/BasePlugin.java
new file mode 100644
index 00000000000..57b4a5dfb98
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-base-plugin/src/BasePlugin.java
@@ -0,0 +1,11 @@
+import org.sonar.api.SonarPlugin;
+
+import java.util.Collections;
+import java.util.List;
+
+public class BasePlugin extends SonarPlugin {
+
+ public List getExtensions() {
+ return Collections.emptyList();
+ }
+}
diff --git a/server/sonar-server/src/test/projects/test-base-plugin/target/test-base-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-base-plugin/target/test-base-plugin-0.1-SNAPSHOT.jar
new file mode 100644
index 00000000000..2a6148ce7b6
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-base-plugin/target/test-base-plugin-0.1-SNAPSHOT.jar
Binary files differ
diff --git a/server/sonar-server/src/test/projects/test-core-plugin/pom.xml b/server/sonar-server/src/test/projects/test-core-plugin/pom.xml
new file mode 100644
index 00000000000..fc3f082f6ec
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-core-plugin/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.codehaus.sonar.tests</groupId>
+ <artifactId>test-core-plugin</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>sonar-plugin</packaging>
+ <name>Test Core Plugin</name>
+ <description>Fake core plugin used by tests</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-plugin-api</artifactId>
+ <version>4.5.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-packaging-maven-plugin</artifactId>
+ <version>1.13</version>
+ <extensions>true</extensions>
+ <configuration>
+ <pluginKey>core</pluginKey>
+ <pluginClass>CorePlugin</pluginClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/server/sonar-server/src/test/projects/test-core-plugin/src/CorePlugin.java b/server/sonar-server/src/test/projects/test-core-plugin/src/CorePlugin.java
new file mode 100644
index 00000000000..910204d87ea
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-core-plugin/src/CorePlugin.java
@@ -0,0 +1,11 @@
+import org.sonar.api.SonarPlugin;
+
+import java.util.Collections;
+import java.util.List;
+
+public class CorePlugin extends SonarPlugin {
+
+ public List getExtensions() {
+ return Collections.emptyList();
+ }
+}
diff --git a/server/sonar-server/src/test/projects/test-core-plugin/target/test-core-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-core-plugin/target/test-core-plugin-0.1-SNAPSHOT.jar
new file mode 100644
index 00000000000..62eba2aa80f
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-core-plugin/target/test-core-plugin-0.1-SNAPSHOT.jar
Binary files differ
diff --git a/server/sonar-server/src/test/projects/test-extend-plugin/pom.xml b/server/sonar-server/src/test/projects/test-extend-plugin/pom.xml
new file mode 100644
index 00000000000..9b20de15a6a
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-extend-plugin/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.codehaus.sonar.tests</groupId>
+ <artifactId>test-extend-plugin</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>sonar-plugin</packaging>
+ <name>Test Extend Plugin</name>
+ <description>Fake plugin that extends the plugin with key "base"</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-plugin-api</artifactId>
+ <version>4.5.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-packaging-maven-plugin</artifactId>
+ <version>1.13</version>
+ <extensions>true</extensions>
+ <configuration>
+ <pluginKey>testextend</pluginKey>
+ <pluginClass>ExtendPlugin</pluginClass>
+ <basePlugin>testbase</basePlugin>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/server/sonar-server/src/test/projects/test-extend-plugin/src/ExtendPlugin.java b/server/sonar-server/src/test/projects/test-extend-plugin/src/ExtendPlugin.java
new file mode 100644
index 00000000000..826e1842bbb
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-extend-plugin/src/ExtendPlugin.java
@@ -0,0 +1,11 @@
+import org.sonar.api.SonarPlugin;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ExtendPlugin extends SonarPlugin {
+
+ public List getExtensions() {
+ return Collections.emptyList();
+ }
+}
diff --git a/server/sonar-server/src/test/projects/test-extend-plugin/target/test-extend-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-extend-plugin/target/test-extend-plugin-0.1-SNAPSHOT.jar
new file mode 100644
index 00000000000..7a81fdf0cce
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-extend-plugin/target/test-extend-plugin-0.1-SNAPSHOT.jar
Binary files differ
diff --git a/server/sonar-server/src/test/projects/test-libs-plugin/pom.xml b/server/sonar-server/src/test/projects/test-libs-plugin/pom.xml
new file mode 100644
index 00000000000..e7d242135db
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-libs-plugin/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.codehaus.sonar.tests</groupId>
+ <artifactId>test-libs-plugin</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>sonar-plugin</packaging>
+ <name>Test Libs Plugin</name>
+ <description>Fake plugin that embeds some libraries</description>
+
+ <dependencies>
+ <!-- embedded libs. Chosen because small ! -->
+ <dependency>
+ <groupId>commons-email</groupId>
+ <artifactId>commons-email</artifactId>
+ <version>20030310.165926</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-daemon</groupId>
+ <artifactId>commons-daemon</artifactId>
+ <version>1.0.15</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-plugin-api</artifactId>
+ <version>4.5.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-packaging-maven-plugin</artifactId>
+ <version>1.13</version>
+ <extensions>true</extensions>
+ <configuration>
+ <pluginKey>testlibs</pluginKey>
+ <pluginClass>LibsPlugin</pluginClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/server/sonar-server/src/test/projects/test-libs-plugin/src/LibsPlugin.java b/server/sonar-server/src/test/projects/test-libs-plugin/src/LibsPlugin.java
new file mode 100644
index 00000000000..965c9ac7496
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-libs-plugin/src/LibsPlugin.java
@@ -0,0 +1,11 @@
+import org.sonar.api.SonarPlugin;
+
+import java.util.Collections;
+import java.util.List;
+
+public class LibsPlugin extends SonarPlugin {
+
+ public List getExtensions() {
+ return Collections.emptyList();
+ }
+}
diff --git a/server/sonar-server/src/test/projects/test-libs-plugin/target/test-libs-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-libs-plugin/target/test-libs-plugin-0.1-SNAPSHOT.jar
new file mode 100644
index 00000000000..85e4772f474
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-libs-plugin/target/test-libs-plugin-0.1-SNAPSHOT.jar
Binary files differ
diff --git a/server/sonar-server/src/test/projects/test-require-plugin/pom.xml b/server/sonar-server/src/test/projects/test-require-plugin/pom.xml
new file mode 100644
index 00000000000..1f77e233f62
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-require-plugin/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.codehaus.sonar.tests</groupId>
+ <artifactId>test-require-plugin</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>sonar-plugin</packaging>
+ <name>Test Require Plugin</name>
+ <description>This fake plugin depends on test-base-plugin</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-plugin-api</artifactId>
+ <version>4.5.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-packaging-maven-plugin</artifactId>
+ <version>1.13</version>
+ <extensions>true</extensions>
+ <configuration>
+ <pluginKey>testrequire</pluginKey>
+ <pluginClass>RequirePlugin</pluginClass>
+ <requirePlugins>testbase:0.1</requirePlugins>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/server/sonar-server/src/test/projects/test-require-plugin/src/RequirePlugin.java b/server/sonar-server/src/test/projects/test-require-plugin/src/RequirePlugin.java
new file mode 100644
index 00000000000..440f73bfb58
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-require-plugin/src/RequirePlugin.java
@@ -0,0 +1,11 @@
+import org.sonar.api.SonarPlugin;
+
+import java.util.Collections;
+import java.util.List;
+
+public class RequirePlugin extends SonarPlugin {
+
+ public List getExtensions() {
+ return Collections.emptyList();
+ }
+}
diff --git a/server/sonar-server/src/test/projects/test-require-plugin/target/test-require-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-require-plugin/target/test-require-plugin-0.1-SNAPSHOT.jar
new file mode 100644
index 00000000000..ac1f9f68e46
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-require-plugin/target/test-require-plugin-0.1-SNAPSHOT.jar
Binary files differ
diff --git a/server/sonar-server/src/test/projects/test-requirenew-plugin/pom.xml b/server/sonar-server/src/test/projects/test-requirenew-plugin/pom.xml
new file mode 100644
index 00000000000..ca207b10c19
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-requirenew-plugin/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.codehaus.sonar.tests</groupId>
+ <artifactId>test-requirenew-plugin</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>sonar-plugin</packaging>
+ <name>Test Require New Plugin</name>
+ <description>This fake plugin requires a version of test-base-plugin that is not installed</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-plugin-api</artifactId>
+ <version>4.5.4</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-packaging-maven-plugin</artifactId>
+ <version>1.13</version>
+ <extensions>true</extensions>
+ <configuration>
+ <pluginKey>testrequire</pluginKey>
+ <pluginClass>RequirePlugin</pluginClass>
+ <requirePlugins>testbase:0.2</requirePlugins>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/server/sonar-server/src/test/projects/test-requirenew-plugin/src/RequirePlugin.java b/server/sonar-server/src/test/projects/test-requirenew-plugin/src/RequirePlugin.java
new file mode 100644
index 00000000000..440f73bfb58
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-requirenew-plugin/src/RequirePlugin.java
@@ -0,0 +1,11 @@
+import org.sonar.api.SonarPlugin;
+
+import java.util.Collections;
+import java.util.List;
+
+public class RequirePlugin extends SonarPlugin {
+
+ public List getExtensions() {
+ return Collections.emptyList();
+ }
+}
diff --git a/server/sonar-server/src/test/projects/test-requirenew-plugin/target/test-requirenew-plugin-0.1-SNAPSHOT.jar b/server/sonar-server/src/test/projects/test-requirenew-plugin/target/test-requirenew-plugin-0.1-SNAPSHOT.jar
new file mode 100644
index 00000000000..3437dfee71c
--- /dev/null
+++ b/server/sonar-server/src/test/projects/test-requirenew-plugin/target/test-requirenew-plugin-0.1-SNAPSHOT.jar
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/extension.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/extension.jar
deleted file mode 100644
index e788522ba71..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/extension.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/foo-plugin.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/foo-plugin.jar
deleted file mode 100644
index 7bcf027151a..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/foo-plugin.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/sonar-build-breaker-plugin-0.1.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/sonar-build-breaker-plugin-0.1.jar
deleted file mode 100644
index 0eb5f40bb8c..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginClassLoadersTest/sonar-build-breaker-plugin-0.1.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginDownloaderTest/foo-plugin-1.0.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginDownloaderTest/foo-plugin-1.0.jar
deleted file mode 100644
index 3b3ed4b1b78..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginDownloaderTest/foo-plugin-1.0.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginExtensionMetadataTest/version1/extension.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginExtensionMetadataTest/version1/extension.jar
deleted file mode 100644
index e788522ba71..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginExtensionMetadataTest/version1/extension.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginExtensionMetadataTest/version2/extension.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginExtensionMetadataTest/version2/extension.jar
deleted file mode 100644
index 636176b3092..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginExtensionMetadataTest/version2/extension.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/foo-plugin-1.0.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/foo-plugin-1.0.jar
deleted file mode 100644
index b60ea353a21..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/foo-plugin-1.0.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/foo-plugin-2.0.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/foo-plugin-2.0.jar
deleted file mode 100644
index 2e0488cebdf..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/foo-plugin-2.0.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/not-a-plugin.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/not-a-plugin.jar
deleted file mode 100644
index f35e77146cc..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/not-a-plugin.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/old-plugin.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/old-plugin.jar
deleted file mode 100644
index abb19c057b5..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataLoaderTest/old-plugin.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataTest/foo-plugin.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataTest/foo-plugin.jar
deleted file mode 100644
index 7bcf027151a..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/PluginMetadataTest/foo-plugin.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/bar-plugin-1.0.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/bar-plugin-1.0.jar
deleted file mode 100644
index acf4fa40269..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/bar-plugin-1.0.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/foo-plugin-1.0.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/foo-plugin-1.0.jar
deleted file mode 100644
index 3b3ed4b1b78..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/foo-plugin-1.0.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/foo-plugin-2.0.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/foo-plugin-2.0.jar
deleted file mode 100644
index b781205e0d0..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/foo-plugin-2.0.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/not-a-plugin.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/not-a-plugin.jar
deleted file mode 100644
index 11b72f4f8eb..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/not-a-plugin.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/require-sq-2.5.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/require-sq-2.5.jar
deleted file mode 100644
index 8044dff8988..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginJarsInstallerTest/require-sq-2.5.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar b/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar
deleted file mode 100644
index 19533234582..00000000000
--- a/server/sonar-server/src/test/resources/org/sonar/server/plugins/ServerPluginRepositoryTest/sonar-artifact-size-plugin-0.2.jar
+++ /dev/null
Binary files differ
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/updatecenter_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/updatecenter_controller.rb
index 555eb77744d..74833832017 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/updatecenter_controller.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/updatecenter_controller.rb
@@ -48,7 +48,7 @@ class Api::UpdatecenterController < Api::ApiController
hash={}
hash['key']=plugin.getKey()
hash['name']=plugin.getName()
- hash['version']=plugin.getVersion() || '-'
+ hash['version']=plugin.getVersion().getName()
hash
end
@@ -58,13 +58,13 @@ class Api::UpdatecenterController < Api::ApiController
xml.plugin do
xml.key(plugin.getKey())
xml.name(plugin.getName())
- xml.version(plugin.getVersion() || '-')
+ xml.version(plugin.getVersion().getName())
end
end
end
end
def user_plugins
- java_facade.getPluginsMetadata().select{|plugin| !plugin.isCore()}.to_a.sort
+ java_facade.getPluginInfos().select{|plugin| !plugin.isCore()}.to_a.sort
end
end
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java
index 0f1eea698ea..1575f757006 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java
@@ -32,7 +32,7 @@ import org.sonar.api.batch.postjob.PostJob;
import org.sonar.api.batch.postjob.PostJobContext;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.AnnotationUtils;
import org.sonar.api.utils.dag.DirectAcyclicGraph;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DefaultPluginsRepository.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginInstaller.java
index 2687ebc56df..6e2c5886c60 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/DefaultPluginsRepository.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginInstaller.java
@@ -19,13 +19,14 @@
*/
package org.sonar.batch.bootstrap;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import org.apache.commons.lang.CharUtils;
import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.SonarPlugin;
-import org.sonar.api.platform.PluginMetadata;
+import org.sonar.api.Plugin;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.core.plugins.RemotePlugin;
import org.sonar.core.plugins.RemotePluginFile;
import org.sonar.home.cache.FileCache;
@@ -33,26 +34,52 @@ import org.sonar.home.cache.FileCache;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
- * A {@link PluginsRepository} implementation that put downloaded plugins in a FS cache.
+ * Downloads the plugins installed on server and stores them in a local user cache
+ * (see {@link FileCacheProvider}).
*/
-public class DefaultPluginsRepository implements PluginsRepository {
+public class BatchPluginInstaller implements PluginInstaller {
- private static final Logger LOG = LoggerFactory.getLogger(DefaultPluginsRepository.class);
+ private static final Logger LOG = Loggers.get(BatchPluginInstaller.class);
- private ServerClient server;
- private FileCache fileCache;
+ private final ServerClient server;
+ private final FileCache fileCache;
+ private final BatchPluginPredicate pluginPredicate;
- public DefaultPluginsRepository(FileCache fileCache, ServerClient server) {
+ public BatchPluginInstaller(ServerClient server, FileCache fileCache, BatchPluginPredicate pluginPredicate) {
this.server = server;
this.fileCache = fileCache;
+ this.pluginPredicate = pluginPredicate;
}
@Override
- public File pluginFile(final RemotePlugin remote) {
+ public Map<String, PluginInfo> installRemotes() {
+ Map<String, PluginInfo> infosByKey = new HashMap<>();
+ for (RemotePlugin remotePlugin : listRemotePlugins()) {
+ if (pluginPredicate.apply(remotePlugin.getKey())) {
+ File jarFile = download(remotePlugin);
+ PluginInfo info = PluginInfo.create(jarFile);
+ infosByKey.put(info.getKey(), info);
+ }
+ }
+ return infosByKey;
+ }
+
+ /**
+ * Returns empty on purpose. This method is used only by tests.
+ * @see org.sonar.batch.mediumtest.BatchMediumTester
+ */
+ @Override
+ public Map<String, Plugin> installLocals() {
+ return Collections.emptyMap();
+ }
+
+ @VisibleForTesting
+ File download(final RemotePlugin remote) {
try {
final RemotePluginFile file = remote.file();
return fileCache.get(file.getFilename(), file.getHash(), new FileCache.Downloader() {
@@ -73,27 +100,24 @@ public class DefaultPluginsRepository implements PluginsRepository {
}
}
- @Override
- public List<RemotePlugin> pluginList() {
+ /**
+ * Gets information about the plugins installed on server (filename, checksum)
+ */
+ @VisibleForTesting
+ List<RemotePlugin> listRemotePlugins() {
String url = "/deploy/plugins/index.txt";
try {
LOG.debug("Download index of plugins");
String indexContent = server.request(url);
String[] rows = StringUtils.split(indexContent, CharUtils.LF);
- List<RemotePlugin> remoteLocations = Lists.newArrayList();
+ List<RemotePlugin> result = Lists.newArrayList();
for (String row : rows) {
- remoteLocations.add(RemotePlugin.unmarshal(row));
+ result.add(RemotePlugin.unmarshal(row));
}
- return remoteLocations;
+ return result;
} catch (Exception e) {
- throw new IllegalStateException("Fail to download plugins index: " + url, e);
+ throw new IllegalStateException("Fail to download list of plugins: " + url, e);
}
}
-
- @Override
- public Map<PluginMetadata, SonarPlugin> localPlugins() {
- return Collections.emptyMap();
- }
-
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginPredicate.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginPredicate.java
new file mode 100644
index 00000000000..f283dcd7247
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginPredicate.java
@@ -0,0 +1,121 @@
+/*
+ * 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.batch.bootstrap;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+import javax.annotation.Nonnull;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Sets.newHashSet;
+
+/**
+ * Filters the plugins to be enabled during analysis
+ */
+public class BatchPluginPredicate implements Predicate<String>, BatchComponent {
+
+ private static final Logger LOG = Loggers.get(BatchPluginPredicate.class);
+
+ private static final String CORE_PLUGIN_KEY = "core";
+ private static final String BUILDBREAKER_PLUGIN_KEY = "buildbreaker";
+ private static final String PROPERTY_IS_DEPRECATED_MSG = "Property {0} is deprecated. Please use {1} instead.";
+
+ private final Set<String> whites = newHashSet(), blacks = newHashSet();
+ private final DefaultAnalysisMode mode;
+
+ public BatchPluginPredicate(Settings settings, DefaultAnalysisMode mode) {
+ this.mode = mode;
+ if (settings.hasKey(CoreProperties.BATCH_INCLUDE_PLUGINS)) {
+ whites.addAll(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_INCLUDE_PLUGINS)));
+ }
+ if (settings.hasKey(CoreProperties.BATCH_EXCLUDE_PLUGINS)) {
+ blacks.addAll(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_EXCLUDE_PLUGINS)));
+ }
+ if (mode.isPreview()) {
+ // These default values are not supported by Settings because the class CorePlugin
+ // is not loaded yet.
+ if (settings.hasKey(CoreProperties.DRY_RUN_INCLUDE_PLUGINS)) {
+ LOG.warn(MessageFormat.format(PROPERTY_IS_DEPRECATED_MSG, CoreProperties.DRY_RUN_INCLUDE_PLUGINS, CoreProperties.PREVIEW_INCLUDE_PLUGINS));
+ whites.addAll(propertyValues(settings,
+ CoreProperties.DRY_RUN_INCLUDE_PLUGINS, CoreProperties.PREVIEW_INCLUDE_PLUGINS_DEFAULT_VALUE));
+ } else {
+ whites.addAll(propertyValues(settings,
+ CoreProperties.PREVIEW_INCLUDE_PLUGINS, CoreProperties.PREVIEW_INCLUDE_PLUGINS_DEFAULT_VALUE));
+ }
+ if (settings.hasKey(CoreProperties.DRY_RUN_EXCLUDE_PLUGINS)) {
+ LOG.warn(MessageFormat.format(PROPERTY_IS_DEPRECATED_MSG, CoreProperties.DRY_RUN_EXCLUDE_PLUGINS, CoreProperties.PREVIEW_EXCLUDE_PLUGINS));
+ blacks.addAll(propertyValues(settings,
+ CoreProperties.DRY_RUN_EXCLUDE_PLUGINS, CoreProperties.PREVIEW_EXCLUDE_PLUGINS_DEFAULT_VALUE));
+ } else {
+ blacks.addAll(propertyValues(settings,
+ CoreProperties.PREVIEW_EXCLUDE_PLUGINS, CoreProperties.PREVIEW_EXCLUDE_PLUGINS_DEFAULT_VALUE));
+ }
+ }
+ if (!whites.isEmpty()) {
+ LOG.info("Include plugins: " + Joiner.on(", ").join(whites));
+ }
+ if (!blacks.isEmpty()) {
+ LOG.info("Exclude plugins: " + Joiner.on(", ").join(blacks));
+ }
+ }
+
+ @Override
+ public boolean apply(@Nonnull String pluginKey) {
+ if (CORE_PLUGIN_KEY.equals(pluginKey)) {
+ return !mode.isMediumTest();
+ }
+
+ if (BUILDBREAKER_PLUGIN_KEY.equals(pluginKey) && mode.isPreview()) {
+ LOG.info("Build Breaker plugin is no more supported in preview/incremental mode");
+ return false;
+ }
+
+ // FIXME what happens if there are only white-listed plugins ?
+ List<String> mergeList = newArrayList(blacks);
+ mergeList.removeAll(whites);
+ return mergeList.isEmpty() || !mergeList.contains(pluginKey);
+ }
+
+ Set<String> getWhites() {
+ return whites;
+ }
+
+ Set<String> getBlacks() {
+ return blacks;
+ }
+
+ static List<String> propertyValues(Settings settings, String key, String defaultValue) {
+ String s = StringUtils.defaultIfEmpty(settings.getString(key), defaultValue);
+ return Lists.newArrayList(Splitter.on(",").trimResults().split(s));
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java
index b8a44c0d97c..b20c85114ed 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginRepository.java
@@ -19,174 +19,69 @@
*/
package org.sonar.batch.bootstrap;
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.CoreProperties;
+import org.picocontainer.Startable;
import org.sonar.api.Plugin;
-import org.sonar.api.SonarPlugin;
-import org.sonar.api.config.Settings;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-import org.sonar.core.plugins.PluginClassloaders;
-import org.sonar.core.plugins.RemotePlugin;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginLoader;
+import org.sonar.core.platform.PluginRepository;
-import java.io.File;
-import java.text.MessageFormat;
-import java.util.*;
+import java.util.Collection;
+import java.util.Map;
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Sets.newHashSet;
+public class BatchPluginRepository implements PluginRepository, Startable {
-public class BatchPluginRepository implements PluginRepository {
+ private final PluginInstaller installer;
+ private final PluginLoader loader;
- private static final Logger LOG = LoggerFactory.getLogger(BatchPluginRepository.class);
- private static final String CORE_PLUGIN = "core";
+ private Map<String, Plugin> pluginInstancesByKeys;
+ private Map<String, PluginInfo> infosByKeys;
- private PluginsRepository pluginsReferential;
- private Map<String, Plugin> pluginsByKey;
- private Map<String, PluginMetadata> metadataByKey;
- private Settings settings;
- private PluginClassloaders classLoaders;
- private final DefaultAnalysisMode analysisMode;
- private final BatchPluginJarInstaller pluginInstaller;
-
- public BatchPluginRepository(PluginsRepository pluginsReferential, Settings settings, DefaultAnalysisMode analysisMode,
- BatchPluginJarInstaller pluginInstaller) {
- this.pluginsReferential = pluginsReferential;
- this.settings = settings;
- this.analysisMode = analysisMode;
- this.pluginInstaller = pluginInstaller;
+ public BatchPluginRepository(PluginInstaller installer, PluginLoader loader) {
+ this.installer = installer;
+ this.loader = loader;
}
+ @Override
public void start() {
- LOG.info("Install plugins");
- doStart(pluginsReferential.pluginList());
-
- Map<PluginMetadata, SonarPlugin> localPlugins = pluginsReferential.localPlugins();
- if (!localPlugins.isEmpty()) {
- LOG.info("Install local plugins");
- for (Map.Entry<PluginMetadata, SonarPlugin> pluginByMetadata : localPlugins.entrySet()) {
- metadataByKey.put(pluginByMetadata.getKey().getKey(), pluginByMetadata.getKey());
- pluginsByKey.put(pluginByMetadata.getKey().getKey(), pluginByMetadata.getValue());
- }
- }
- }
+ infosByKeys = installer.installRemotes();
+ pluginInstancesByKeys = loader.load(infosByKeys);
- void doStart(List<RemotePlugin> remotePlugins) {
- PluginFilter filter = new PluginFilter(settings, analysisMode);
- metadataByKey = Maps.newHashMap();
- for (RemotePlugin remote : remotePlugins) {
- if (filter.accepts(remote.getKey())) {
- File pluginFile = pluginsReferential.pluginFile(remote);
- PluginMetadata metadata = pluginInstaller.installToCache(pluginFile, remote.isCore());
- if (StringUtils.isBlank(metadata.getBasePlugin()) || filter.accepts(metadata.getBasePlugin())) {
- metadataByKey.put(metadata.getKey(), metadata);
- } else {
- LOG.debug("Excluded plugin: " + metadata.getKey());
- }
- }
+ // this part is only used by tests
+ for (Map.Entry<String, Plugin> entry : installer.installLocals().entrySet()) {
+ String pluginKey = entry.getKey();
+ infosByKeys.put(pluginKey, new PluginInfo(pluginKey));
+ pluginInstancesByKeys.put(pluginKey, entry.getValue());
}
- classLoaders = new PluginClassloaders(Thread.currentThread().getContextClassLoader());
- pluginsByKey = classLoaders.init(metadataByKey.values());
}
+ @Override
public void stop() {
- if (classLoaders != null) {
- classLoaders.clean();
- classLoaders = null;
- }
- }
+ // close plugin classloaders
+ loader.unload(pluginInstancesByKeys.values());
- @Override
- public Plugin getPlugin(String key) {
- return pluginsByKey.get(key);
+ pluginInstancesByKeys.clear();
+ infosByKeys.clear();
}
@Override
- public Collection<PluginMetadata> getMetadata() {
- return metadataByKey.values();
+ public Collection<PluginInfo> getPluginInfos() {
+ return infosByKeys.values();
}
@Override
- public PluginMetadata getMetadata(String pluginKey) {
- return metadataByKey.get(pluginKey);
+ public PluginInfo getPluginInfo(String key) {
+ // TODO check null result
+ return infosByKeys.get(key);
}
- public Map<PluginMetadata, Plugin> getPluginsByMetadata() {
- Map<PluginMetadata, Plugin> result = Maps.newHashMap();
- for (Map.Entry<String, PluginMetadata> entry : metadataByKey.entrySet()) {
- String pluginKey = entry.getKey();
- PluginMetadata metadata = entry.getValue();
- result.put(metadata, pluginsByKey.get(pluginKey));
- }
- return result;
+ @Override
+ public Plugin getPluginInstance(String key) {
+ // TODO check null result
+ return pluginInstancesByKeys.get(key);
}
- static class PluginFilter {
- private static final String BUILDBREAKER_PLUGIN_KEY = "buildbreaker";
- private static final String PROPERTY_IS_DEPRECATED_MSG = "Property {0} is deprecated. Please use {1} instead.";
- Set<String> whites = newHashSet(), blacks = newHashSet();
- private DefaultAnalysisMode mode;
-
- PluginFilter(Settings settings, DefaultAnalysisMode mode) {
- this.mode = mode;
- if (settings.hasKey(CoreProperties.BATCH_INCLUDE_PLUGINS)) {
- whites.addAll(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_INCLUDE_PLUGINS)));
- }
- if (settings.hasKey(CoreProperties.BATCH_EXCLUDE_PLUGINS)) {
- blacks.addAll(Arrays.asList(settings.getStringArray(CoreProperties.BATCH_EXCLUDE_PLUGINS)));
- }
- if (mode.isPreview()) {
- // These default values are not supported by Settings because the class CorePlugin
- // is not loaded yet.
- if (settings.hasKey(CoreProperties.DRY_RUN_INCLUDE_PLUGINS)) {
- LOG.warn(MessageFormat.format(PROPERTY_IS_DEPRECATED_MSG, CoreProperties.DRY_RUN_INCLUDE_PLUGINS, CoreProperties.PREVIEW_INCLUDE_PLUGINS));
- whites.addAll(propertyValues(settings,
- CoreProperties.DRY_RUN_INCLUDE_PLUGINS, CoreProperties.PREVIEW_INCLUDE_PLUGINS_DEFAULT_VALUE));
- } else {
- whites.addAll(propertyValues(settings,
- CoreProperties.PREVIEW_INCLUDE_PLUGINS, CoreProperties.PREVIEW_INCLUDE_PLUGINS_DEFAULT_VALUE));
- }
- if (settings.hasKey(CoreProperties.DRY_RUN_EXCLUDE_PLUGINS)) {
- LOG.warn(MessageFormat.format(PROPERTY_IS_DEPRECATED_MSG, CoreProperties.DRY_RUN_EXCLUDE_PLUGINS, CoreProperties.PREVIEW_EXCLUDE_PLUGINS));
- blacks.addAll(propertyValues(settings,
- CoreProperties.DRY_RUN_EXCLUDE_PLUGINS, CoreProperties.PREVIEW_EXCLUDE_PLUGINS_DEFAULT_VALUE));
- } else {
- blacks.addAll(propertyValues(settings,
- CoreProperties.PREVIEW_EXCLUDE_PLUGINS, CoreProperties.PREVIEW_EXCLUDE_PLUGINS_DEFAULT_VALUE));
- }
- }
- if (!whites.isEmpty()) {
- LOG.info("Include plugins: " + Joiner.on(", ").join(whites));
- }
- if (!blacks.isEmpty()) {
- LOG.info("Exclude plugins: " + Joiner.on(", ").join(blacks));
- }
- }
-
- static List<String> propertyValues(Settings settings, String key, String defaultValue) {
- String s = StringUtils.defaultIfEmpty(settings.getString(key), defaultValue);
- return Lists.newArrayList(Splitter.on(",").trimResults().split(s));
- }
-
- boolean accepts(String pluginKey) {
- if (CORE_PLUGIN.equals(pluginKey)) {
- return !mode.isMediumTest();
- }
-
- if (BUILDBREAKER_PLUGIN_KEY.equals(pluginKey) && mode.isPreview()) {
- LOG.info("Build Breaker plugin is no more supported in preview/incremental mode");
- return false;
- }
-
- List<String> mergeList = newArrayList(blacks);
- mergeList.removeAll(whites);
- return mergeList.isEmpty() || !mergeList.contains(pluginKey);
- }
+ @Override
+ public boolean hasPlugin(String key) {
+ return infosByKeys.containsKey(key);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginUnzipper.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginUnzipper.java
new file mode 100644
index 00000000000..29f554ddc89
--- /dev/null
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginUnzipper.java
@@ -0,0 +1,77 @@
+/*
+ * 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.batch.bootstrap;
+
+import org.apache.commons.io.FileUtils;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.utils.ZipUtils;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginUnzipper;
+import org.sonar.core.platform.UnzippedPlugin;
+import org.sonar.home.cache.FileCache;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class BatchPluginUnzipper extends PluginUnzipper implements BatchComponent {
+
+ private final FileCache fileCache;
+
+ public BatchPluginUnzipper(FileCache fileCache) {
+ this.fileCache = fileCache;
+ }
+
+ @Override
+ public UnzippedPlugin unzip(PluginInfo info) {
+ try {
+ File dir = unzipFile(info.getFile());
+ return UnzippedPlugin.createFromUnzippedDir(info.getKey(), info.getFile(), dir);
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format("Fail to open plugin [%s]: %s", info.getKey(), info.getFile().getAbsolutePath()), e);
+ }
+ }
+
+ private File unzipFile(File cachedFile) throws IOException {
+ String filename = cachedFile.getName();
+ File destDir = new File(cachedFile.getParentFile(), filename + "_unzip");
+ File lockFile = new File(cachedFile.getParentFile(), filename + "_unzip.lock");
+ if (!destDir.exists()) {
+ FileOutputStream out = new FileOutputStream(lockFile);
+ try {
+ java.nio.channels.FileLock lock = out.getChannel().lock();
+ try {
+ // Recheck in case of concurrent processes
+ if (!destDir.exists()) {
+ File tempDir = fileCache.createTempDir();
+ ZipUtils.unzip(cachedFile, tempDir, newLibFilter());
+ FileUtils.moveDirectory(tempDir, destDir);
+ }
+ } finally {
+ lock.release();
+ }
+ } finally {
+ out.close();
+ FileUtils.deleteQuietly(lockFile);
+ }
+ }
+ return destDir;
+ }
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java
index 86599f96774..165aa83e649 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/ExtensionInstaller.java
@@ -21,22 +21,22 @@ package org.sonar.batch.bootstrap;
import org.sonar.api.ExtensionProvider;
import org.sonar.api.Plugin;
-import org.sonar.api.platform.ComponentContainer;
-import org.sonar.api.platform.PluginMetadata;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import javax.annotation.Nullable;
import java.util.List;
-import java.util.Map;
public class ExtensionInstaller {
- private final BatchPluginRepository pluginRepository;
+ private final PluginRepository pluginRepository;
private final EnvironmentInformation env;
private final DefaultAnalysisMode analysisMode;
- public ExtensionInstaller(BatchPluginRepository pluginRepository, EnvironmentInformation env, DefaultAnalysisMode analysisMode) {
+ public ExtensionInstaller(PluginRepository pluginRepository, EnvironmentInformation env, DefaultAnalysisMode analysisMode) {
this.pluginRepository = pluginRepository;
this.env = env;
this.analysisMode = analysisMode;
@@ -50,11 +50,10 @@ public class ExtensionInstaller {
}
// plugin extensions
- for (Map.Entry<PluginMetadata, Plugin> entry : pluginRepository.getPluginsByMetadata().entrySet()) {
- PluginMetadata metadata = entry.getKey();
- Plugin plugin = entry.getValue();
+ for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
+ Plugin plugin = pluginRepository.getPluginInstance(pluginInfo.getKey());
for (Object extension : plugin.getExtensions()) {
- doInstall(container, matcher, metadata, extension);
+ doInstall(container, matcher, pluginInfo, extension);
}
}
List<ExtensionProvider> providers = container.getComponentsByType(ExtensionProvider.class);
@@ -71,13 +70,13 @@ public class ExtensionInstaller {
return this;
}
- private void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginMetadata metadata, Object extension) {
+ private void doInstall(ComponentContainer container, ExtensionMatcher matcher, @Nullable PluginInfo pluginInfo, Object extension) {
if (ExtensionUtils.supportsEnvironment(extension, env)
&& (analysisMode.isDb() || !ExtensionUtils.requiresDB(extension))
&& matcher.accept(extension)) {
- container.addExtension(metadata, extension);
+ container.addExtension(pluginInfo, extension);
} else {
- container.declareExtension(metadata, extension);
+ container.declareExtension(pluginInfo, extension);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
index 7aaf0f6be32..09d217122af 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalContainer.java
@@ -21,28 +21,44 @@ package org.sonar.batch.bootstrap;
import org.sonar.api.Plugin;
import org.sonar.api.config.EmailSettings;
-import org.sonar.api.platform.ComponentContainer;
-import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.utils.Durations;
-import org.sonar.core.util.DefaultHttpDownloader;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.UriReader;
import org.sonar.api.utils.internal.TempFolderCleaner;
import org.sonar.batch.components.PastSnapshotFinder;
-import org.sonar.batch.deprecated.components.*;
+import org.sonar.batch.deprecated.components.PastSnapshotFinderByDate;
+import org.sonar.batch.deprecated.components.PastSnapshotFinderByDays;
+import org.sonar.batch.deprecated.components.PastSnapshotFinderByPreviousAnalysis;
+import org.sonar.batch.deprecated.components.PastSnapshotFinderByPreviousVersion;
+import org.sonar.batch.deprecated.components.PastSnapshotFinderByVersion;
import org.sonar.batch.issue.tracking.DefaultServerLineHashesLoader;
import org.sonar.batch.issue.tracking.ServerLineHashesLoader;
import org.sonar.batch.platform.DefaultServer;
-import org.sonar.batch.repository.*;
+import org.sonar.batch.repository.DefaultGlobalRepositoriesLoader;
+import org.sonar.batch.repository.DefaultProjectRepositoriesLoader;
+import org.sonar.batch.repository.DefaultServerIssuesLoader;
+import org.sonar.batch.repository.GlobalRepositoriesLoader;
+import org.sonar.batch.repository.GlobalRepositoriesProvider;
+import org.sonar.batch.repository.ProjectRepositoriesLoader;
+import org.sonar.batch.repository.ServerIssuesLoader;
import org.sonar.batch.repository.user.UserRepository;
import org.sonar.core.cluster.NullQueue;
import org.sonar.core.config.Logback;
import org.sonar.core.i18n.DefaultI18n;
import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.core.persistence.*;
+import org.sonar.core.persistence.DaoUtils;
+import org.sonar.core.persistence.DatabaseVersion;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.persistence.SemaphoreUpdater;
+import org.sonar.core.persistence.SemaphoresImpl;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginLoader;
+import org.sonar.core.platform.PluginRepository;
import org.sonar.core.purge.PurgeProfiler;
import org.sonar.core.rule.CacheRuleFinder;
import org.sonar.core.user.HibernateUserFinder;
+import org.sonar.core.util.DefaultHttpDownloader;
import org.sonar.jpa.dao.MeasuresDao;
import org.sonar.jpa.session.DefaultDatabaseConnector;
import org.sonar.jpa.session.JpaDatabaseSession;
@@ -79,11 +95,15 @@ public class GlobalContainer extends ComponentContainer {
private void addBootstrapComponents() {
add(
+ // plugins
BatchPluginRepository.class,
- BatchPluginJarInstaller.class,
+ PluginLoader.class,
+ BatchPluginUnzipper.class,
+ BatchPluginPredicate.class,
+ ExtensionInstaller.class,
+
GlobalSettings.class,
ServerClient.class,
- ExtensionInstaller.class,
Logback.class,
DefaultServer.class,
new TempFolderProvider(),
@@ -95,20 +115,16 @@ public class GlobalContainer extends ComponentContainer {
DefaultI18n.class,
new GlobalRepositoriesProvider(),
UserRepository.class);
- if (getComponentByType(PluginsRepository.class) == null) {
- add(DefaultPluginsRepository.class);
- }
- if (getComponentByType(GlobalRepositoriesLoader.class) == null) {
- add(DefaultGlobalRepositoriesLoader.class);
- }
- if (getComponentByType(ProjectRepositoriesLoader.class) == null) {
- add(DefaultProjectRepositoriesLoader.class);
- }
- if (getComponentByType(ServerIssuesLoader.class) == null) {
- add(DefaultServerIssuesLoader.class);
- }
- if (getComponentByType(ServerLineHashesLoader.class) == null) {
- add(DefaultServerLineHashesLoader.class);
+ addIfMissing(BatchPluginInstaller.class, PluginInstaller.class);
+ addIfMissing(DefaultGlobalRepositoriesLoader.class, GlobalRepositoriesLoader.class);
+ addIfMissing(DefaultProjectRepositoriesLoader.class, ProjectRepositoriesLoader.class);
+ addIfMissing(DefaultServerIssuesLoader.class, ServerIssuesLoader.class);
+ addIfMissing(DefaultServerLineHashesLoader.class, ServerLineHashesLoader.class);
+ }
+
+ public void addIfMissing(Object object, Class objectType) {
+ if (getComponentByType(objectType) == null) {
+ add(object);
}
}
@@ -147,10 +163,10 @@ public class GlobalContainer extends ComponentContainer {
}
private void installPlugins() {
- for (Map.Entry<PluginMetadata, Plugin> entry : getComponentByType(BatchPluginRepository.class).getPluginsByMetadata().entrySet()) {
- PluginMetadata metadata = entry.getKey();
- Plugin plugin = entry.getValue();
- addExtension(metadata, plugin);
+ PluginRepository pluginRepository = getComponentByType(PluginRepository.class);
+ for (PluginInfo pluginInfo : pluginRepository.getPluginInfos()) {
+ Plugin instance = pluginRepository.getPluginInstance(pluginInfo.getKey());
+ addExtension(pluginInfo, instance);
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginsRepository.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginInstaller.java
index 58473fd6af1..97eb513d4a6 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginsRepository.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/PluginInstaller.java
@@ -19,33 +19,24 @@
*/
package org.sonar.batch.bootstrap;
-import org.sonar.api.SonarPlugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.core.plugins.RemotePlugin;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.Plugin;
+import org.sonar.core.platform.PluginInfo;
-import java.io.File;
-import java.util.List;
import java.util.Map;
-/**
- * Plugin referential.
- * @since 4.4
- */
-public interface PluginsRepository {
+public interface PluginInstaller extends BatchComponent {
/**
- * Return list of remote plugins to be installed
+ * Gets the list of plugins installed on server and downloads them if not
+ * already in local cache.
+ * @return information about all installed plugins, grouped by key
*/
- List<RemotePlugin> pluginList();
+ Map<String, PluginInfo> installRemotes();
/**
- * Return location of a given plugin on the local FS.
+ * Used only by tests.
+ * @see org.sonar.batch.mediumtest.BatchMediumTester
*/
- File pluginFile(RemotePlugin remote);
-
- /**
- * Return the list of local plugins to be installed
- */
- Map<PluginMetadata, SonarPlugin> localPlugins();
-
+ Map<String, Plugin> installLocals();
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
index b3fd7e46392..fce09a6cd1c 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/TaskContainer.java
@@ -23,7 +23,7 @@ import org.sonar.batch.components.PastMeasuresLoader;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.CoreProperties;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.task.Task;
import org.sonar.api.task.TaskComponent;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
index e274375076b..09871955a38 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java
@@ -28,27 +28,31 @@ import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.batch.bootstrap.PluginsRepository;
import org.sonar.batch.bootstrap.TaskProperties;
import org.sonar.batch.bootstrapper.Batch;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
import org.sonar.batch.issue.tracking.ServerLineHashesLoader;
-import org.sonar.batch.protocol.input.*;
+import org.sonar.batch.protocol.input.ActiveRule;
import org.sonar.batch.protocol.input.BatchInput.ServerIssue;
+import org.sonar.batch.protocol.input.FileData;
+import org.sonar.batch.protocol.input.GlobalRepositories;
+import org.sonar.batch.protocol.input.ProjectRepositories;
import org.sonar.batch.report.ReportPublisher;
import org.sonar.batch.repository.GlobalRepositoriesLoader;
import org.sonar.batch.repository.ProjectRepositoriesLoader;
import org.sonar.batch.repository.ServerIssuesLoader;
import org.sonar.core.component.ComponentKeys;
-import org.sonar.core.plugins.DefaultPluginMetadata;
-import org.sonar.core.plugins.RemotePlugin;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
/**
* Main utility class for writing batch medium tests.
@@ -70,22 +74,22 @@ public class BatchMediumTester {
public static class BatchMediumTesterBuilder {
private final FakeGlobalRepositoriesLoader globalRefProvider = new FakeGlobalRepositoriesLoader();
private final FakeProjectRepositoriesLoader projectRefProvider = new FakeProjectRepositoriesLoader();
- private final FakePluginsRepository pluginsReferential = new FakePluginsRepository();
+ private final FakePluginInstaller pluginInstaller = new FakePluginInstaller();
private final FakeServerIssuesLoader serverIssues = new FakeServerIssuesLoader();
private final FakeServerLineHashesLoader serverLineHashes = new FakeServerLineHashesLoader();
- private final Map<String, String> bootstrapProperties = new HashMap<String, String>();
+ private final Map<String, String> bootstrapProperties = new HashMap<>();
public BatchMediumTester build() {
return new BatchMediumTester(this);
}
public BatchMediumTesterBuilder registerPlugin(String pluginKey, File location) {
- pluginsReferential.addPlugin(pluginKey, location);
+ pluginInstaller.add(pluginKey, location);
return this;
}
public BatchMediumTesterBuilder registerPlugin(String pluginKey, SonarPlugin instance) {
- pluginsReferential.addPlugin(pluginKey, instance);
+ pluginInstaller.add(pluginKey, instance);
return this;
}
@@ -164,7 +168,7 @@ public class BatchMediumTester {
.setEnableLoggingConfiguration(true)
.addComponents(
new EnvironmentInformation("mediumTest", "1.0"),
- builder.pluginsReferential,
+ builder.pluginInstaller,
builder.globalRefProvider,
builder.projectRefProvider,
builder.serverIssues,
@@ -280,41 +284,6 @@ public class BatchMediumTester {
}
- private static class FakePluginsRepository implements PluginsRepository {
-
- private List<RemotePlugin> pluginList = new ArrayList<RemotePlugin>();
- private Map<RemotePlugin, File> pluginFiles = new HashMap<RemotePlugin, File>();
- Map<PluginMetadata, SonarPlugin> localPlugins = new HashMap<PluginMetadata, SonarPlugin>();
-
- @Override
- public List<RemotePlugin> pluginList() {
- return pluginList;
- }
-
- @Override
- public File pluginFile(RemotePlugin remote) {
- return pluginFiles.get(remote);
- }
-
- public FakePluginsRepository addPlugin(String pluginKey, File location) {
- RemotePlugin plugin = new RemotePlugin(pluginKey, false);
- pluginList.add(plugin);
- pluginFiles.put(plugin, location);
- return this;
- }
-
- public FakePluginsRepository addPlugin(String pluginKey, SonarPlugin pluginInstance) {
- localPlugins.put(DefaultPluginMetadata.create(pluginKey), pluginInstance);
- return this;
- }
-
- @Override
- public Map<PluginMetadata, SonarPlugin> localPlugins() {
- return localPlugins;
- }
-
- }
-
private static class FakeServerIssuesLoader implements ServerIssuesLoader {
private List<ServerIssue> serverIssues = new ArrayList<>();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginJarInstaller.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/FakePluginInstaller.java
index 8866cf7fc0f..cbd837c66c9 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginJarInstaller.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/FakePluginInstaller.java
@@ -17,33 +17,38 @@
* 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.batch.bootstrap;
+package org.sonar.batch.mediumtest;
-import org.sonar.api.BatchComponent;
-import org.sonar.core.plugins.DefaultPluginMetadata;
-import org.sonar.core.plugins.PluginJarInstaller;
-import org.sonar.home.cache.FileCache;
+import org.sonar.api.Plugin;
+import org.sonar.batch.bootstrap.PluginInstaller;
+import org.sonar.core.platform.PluginInfo;
import java.io.File;
-import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
-public class BatchPluginJarInstaller extends PluginJarInstaller implements BatchComponent {
+public class FakePluginInstaller implements PluginInstaller {
- private FileCache cache;
+ private final Map<String, PluginInfo> infosByKeys = new HashMap<>();
+ private final Map<String, Plugin> instancesByKeys = new HashMap<>();
- public BatchPluginJarInstaller(FileCache cache) {
- this.cache = cache;
+ public FakePluginInstaller add(String pluginKey, File jarFile) {
+ infosByKeys.put(pluginKey, PluginInfo.create(jarFile));
+ return this;
}
- public DefaultPluginMetadata installToCache(File pluginFile, boolean isCore) {
- DefaultPluginMetadata metadata = extractMetadata(pluginFile, isCore);
- install(metadata, null, pluginFile);
- return metadata;
+ public FakePluginInstaller add(String pluginKey, Plugin instance) {
+ instancesByKeys.put(pluginKey, instance);
+ return this;
}
@Override
- protected File extractPluginDependencies(File pluginFile, File pluginBasedir) throws IOException {
- return cache.unzip(pluginFile);
+ public Map<String, PluginInfo> installRemotes() {
+ return infosByKeys;
}
+ @Override
+ public Map<String, Plugin> installLocals() {
+ return instancesByKeys;
+ }
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
index 75281a9e961..f8312429543 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java
@@ -27,7 +27,7 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.rule.CheckFactory;
import org.sonar.api.checks.NoSonarFilter;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.api.scan.filesystem.FileExclusions;
import org.sonar.batch.ProjectTree;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index ebf3d5c2d87..12a23bf62e4 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -26,7 +26,7 @@ import org.sonar.api.batch.InstantiationStrategy;
import org.sonar.api.batch.bootstrap.ProjectBootstrapper;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.config.Settings;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.resources.Languages;
import org.sonar.api.resources.Project;
import org.sonar.api.scan.filesystem.PathResolver;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ScanTask.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ScanTask.java
index 0064d028ea8..bb3f0f8a021 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ScanTask.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ScanTask.java
@@ -20,7 +20,7 @@
package org.sonar.batch.scan;
import org.sonar.api.CoreProperties;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.task.Task;
import org.sonar.api.task.TaskDefinition;
import org.sonar.batch.DefaultProjectTree;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java
index 14fde3895ef..6f7e0c11e32 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchExtensionDictionnaryTest.java
@@ -24,7 +24,7 @@ import org.junit.Test;
import org.sonar.api.BatchExtension;
import org.sonar.api.batch.*;
import org.sonar.api.batch.postjob.PostJobContext;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.batch.postjob.PostJobOptimizer;
import org.sonar.batch.sensor.DefaultSensorContext;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DefaultPluginsRepositoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginInstallerTest.java
index 57e940ab7ae..03c3707919b 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/DefaultPluginsRepositoryTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginInstallerTest.java
@@ -36,7 +36,7 @@ import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-public class DefaultPluginsRepositoryTest {
+public class BatchPluginInstallerTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@@ -44,34 +44,30 @@ public class DefaultPluginsRepositoryTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
+ FileCache fileCache = mock(FileCache.class);
+ BatchPluginPredicate pluginPredicate = mock(BatchPluginPredicate.class);
+
@Test
- public void should_request_list_of_plugins() {
- FileCache cache = mock(FileCache.class);
+ public void listRemotePlugins() {
+
ServerClient server = mock(ServerClient.class);
- when(server.request("/deploy/plugins/index.txt")).thenReturn("checkstyle,true\nsqale,false");
- DefaultPluginsRepository downloader = new DefaultPluginsRepository(cache, server);
-
- List<RemotePlugin> plugins = downloader.pluginList();
- assertThat(plugins).hasSize(2);
- assertThat(plugins.get(0).getKey()).isEqualTo("checkstyle");
- assertThat(plugins.get(0).isCore()).isTrue();
- assertThat(plugins.get(1).getKey()).isEqualTo("sqale");
- assertThat(plugins.get(1).isCore()).isFalse();
+ when(server.request("/deploy/plugins/index.txt")).thenReturn("checkstyle,false\nsqale,false");
+ BatchPluginInstaller installer = new BatchPluginInstaller(server, fileCache, pluginPredicate);
+
+ List<RemotePlugin> remotePlugins = installer.listRemotePlugins();
+ assertThat(remotePlugins).extracting("key").containsOnly("checkstyle", "sqale");
}
@Test
public void should_download_plugin() throws Exception {
- FileCache cache = mock(FileCache.class);
-
File pluginJar = temp.newFile();
- when(cache.get(eq("checkstyle-plugin.jar"), eq("fakemd5_1"), any(FileCache.Downloader.class))).thenReturn(pluginJar);
+ when(fileCache.get(eq("checkstyle-plugin.jar"), eq("fakemd5_1"), any(FileCache.Downloader.class))).thenReturn(pluginJar);
ServerClient server = mock(ServerClient.class);
- DefaultPluginsRepository downloader = new DefaultPluginsRepository(cache, server);
+ BatchPluginInstaller installer = new BatchPluginInstaller(server, fileCache, pluginPredicate);
- RemotePlugin plugin = new RemotePlugin("checkstyle", true)
- .setFile("checkstyle-plugin.jar", "fakemd5_1");
- File file = downloader.pluginFile(plugin);
+ RemotePlugin remote = new RemotePlugin("checkstyle", true).setFile("checkstyle-plugin.jar", "fakemd5_1");
+ File file = installer.download(remote);
assertThat(file).isEqualTo(pluginJar);
}
@@ -83,6 +79,6 @@ public class DefaultPluginsRepositoryTest {
ServerClient server = mock(ServerClient.class);
doThrow(new IllegalStateException()).when(server).request("/deploy/plugins/index.txt");
- new DefaultPluginsRepository(mock(FileCache.class), server).pluginList();
+ new BatchPluginInstaller(server, fileCache, pluginPredicate).installRemotes();
}
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginPredicateTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginPredicateTest.java
new file mode 100644
index 00000000000..9dcebd6d07f
--- /dev/null
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginPredicateTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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.batch.bootstrap;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Settings;
+import org.sonar.home.cache.FileCache;
+import org.sonar.home.cache.FileCacheBuilder;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class BatchPluginPredicateTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ DefaultAnalysisMode mode = mock(DefaultAnalysisMode.class);
+ FileCache cache;
+ File userHome;
+
+ @Before
+ public void before() throws IOException {
+ userHome = temp.newFolder();
+ cache = new FileCacheBuilder().setUserHome(userHome).build();
+ }
+
+ @Test
+ public void shouldAlwaysAcceptIfNoWhiteListAndBlackList() {
+ BatchPluginPredicate predicate = new BatchPluginPredicate(new Settings(), mode);
+ assertThat(predicate.apply("pmd")).isTrue();
+ assertThat(predicate.apply("buildbreaker")).isTrue();
+ }
+
+ @Test
+ public void shouldBlackListBuildBreakerInPreviewMode() {
+ when(mode.isPreview()).thenReturn(true);
+ BatchPluginPredicate predicate = new BatchPluginPredicate(new Settings(), mode);
+ assertThat(predicate.apply("buildbreaker")).isFalse();
+ }
+
+ @Test
+ public void whiteListShouldTakePrecedenceOverBlackList() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs")
+ .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura,pmd");
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.apply("pmd")).isTrue();
+ }
+
+ @Test
+ public void corePluginShouldAlwaysBeInWhiteList() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs");
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.apply("core")).isTrue();
+ }
+
+ @Test
+ public void corePluginShouldNeverBeInBlackList() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "core,findbugs");
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.apply("core")).isTrue();
+ }
+
+ @Test
+ public void check_white_list_with_black_list() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs")
+ .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura");
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.apply("checkstyle")).isTrue();
+ assertThat(predicate.apply("pmd")).isTrue();
+ assertThat(predicate.apply("cobertura")).isFalse();
+ }
+
+ @Test
+ public void check_white_list_when_plugin_is_in_both_list() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "cobertura,checkstyle,pmd,findbugs")
+ .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura");
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.apply("checkstyle")).isTrue();
+ assertThat(predicate.apply("pmd")).isTrue();
+ assertThat(predicate.apply("cobertura")).isTrue();
+ }
+
+ @Test
+ public void check_black_list_if_no_white_list() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd,findbugs");
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.apply("checkstyle")).isFalse();
+ assertThat(predicate.apply("pmd")).isFalse();
+ assertThat(predicate.apply("cobertura")).isTrue();
+ }
+
+ @Test
+ public void should_concatenate_preview_predicates() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.PREVIEW_INCLUDE_PLUGINS, "cockpit")
+ .setProperty(CoreProperties.PREVIEW_EXCLUDE_PLUGINS, "views")
+ .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd");
+ when(mode.isPreview()).thenReturn(true);
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.getWhites()).containsOnly("cockpit");
+ assertThat(predicate.getBlacks()).containsOnly("views", "checkstyle", "pmd");
+ }
+
+ @Test
+ public void should_concatenate_deprecated_dry_run_predicates() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.DRY_RUN_INCLUDE_PLUGINS, "cockpit")
+ .setProperty(CoreProperties.DRY_RUN_EXCLUDE_PLUGINS, "views")
+ .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd");
+ when(mode.isPreview()).thenReturn(true);
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.getWhites()).containsOnly("cockpit");
+ assertThat(predicate.getBlacks()).containsOnly("views", "checkstyle", "pmd");
+ }
+
+ @Test
+ public void inclusions_and_exclusions_should_be_trimmed() {
+ Settings settings = new Settings()
+ .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle, pmd, findbugs")
+ .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura, pmd");
+ BatchPluginPredicate predicate = new BatchPluginPredicate(settings, mode);
+ assertThat(predicate.apply("pmd")).isTrue();
+ }
+
+}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java
index 66a499b01c0..7c82edbb64f 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginRepositoryTest.java
@@ -17,219 +17,237 @@
* 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.batch.bootstrap;
-
-import com.google.common.io.Resources;
-import org.apache.commons.io.FileUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Settings;
-import org.sonar.core.plugins.RemotePlugin;
-import org.sonar.home.cache.FileCache;
-import org.sonar.home.cache.FileCacheBuilder;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class BatchPluginRepositoryTest {
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- private BatchPluginRepository repository;
- private DefaultAnalysisMode mode;
- private FileCache cache;
- private File userHome;
-
- @Before
- public void before() throws IOException {
- mode = mock(DefaultAnalysisMode.class);
- when(mode.isPreview()).thenReturn(false);
- userHome = temp.newFolder();
- cache = new FileCacheBuilder().setUserHome(userHome).build();
- }
-
- @After
- public void tearDown() {
- if (repository != null) {
- repository.stop();
- }
- }
-
- @Test
- public void shouldLoadPlugin() throws Exception {
- RemotePlugin checkstyle = new RemotePlugin("checkstyle", true);
-
- DefaultPluginsRepository downloader = mock(DefaultPluginsRepository.class);
- when(downloader.pluginFile(checkstyle)).thenReturn(fileFromCache("sonar-checkstyle-plugin-2.8.jar"));
-
- repository = new BatchPluginRepository(downloader, new Settings(), mode, new BatchPluginJarInstaller(cache));
-
- repository.doStart(Arrays.asList(checkstyle));
-
- assertThat(repository.getPlugin("checkstyle")).isNotNull();
- assertThat(repository.getMetadata()).hasSize(1);
- assertThat(repository.getMetadata("checkstyle").getName()).isEqualTo("Checkstyle");
- assertThat(repository.getMetadata("checkstyle").getDeployedFiles()).hasSize(4); // plugin + 3 dependencies
- }
-
- @Test
- public void shouldLoadPluginExtension() throws Exception {
- RemotePlugin checkstyle = new RemotePlugin("checkstyle", true);
- RemotePlugin checkstyleExt = new RemotePlugin("checkstyleextensions", false);
-
- DefaultPluginsRepository downloader = mock(DefaultPluginsRepository.class);
- when(downloader.pluginFile(checkstyle)).thenReturn(fileFromCache("sonar-checkstyle-plugin-2.8.jar"));
- when(downloader.pluginFile(checkstyleExt)).thenReturn(fileFromCache("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar"));
-
- repository = new BatchPluginRepository(downloader, new Settings(), mode, new BatchPluginJarInstaller(cache));
-
- repository.doStart(Arrays.asList(checkstyle, checkstyleExt));
-
- assertThat(repository.getPlugin("checkstyle")).isNotNull();
- assertThat(repository.getPlugin("checkstyleextensions")).isNotNull();
- assertThat(repository.getMetadata()).hasSize(2);
- assertThat(repository.getMetadata("checkstyle").getName()).isEqualTo("Checkstyle");
- assertThat(repository.getMetadata("checkstyleextensions").getVersion()).isEqualTo("0.1-SNAPSHOT");
- }
-
- @Test
- public void shouldExcludePluginAndItsExtensions() throws Exception {
- RemotePlugin checkstyle = new RemotePlugin("checkstyle", true);
- RemotePlugin checkstyleExt = new RemotePlugin("checkstyleextensions", false);
-
- DefaultPluginsRepository downloader = mock(DefaultPluginsRepository.class);
- when(downloader.pluginFile(checkstyle)).thenReturn(fileFromCache("sonar-checkstyle-plugin-2.8.jar"));
- when(downloader.pluginFile(checkstyleExt)).thenReturn(fileFromCache("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar"));
-
- Settings settings = new Settings();
- settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle");
- repository = new BatchPluginRepository(downloader, settings, mode, new BatchPluginJarInstaller(cache));
-
- repository.doStart(Arrays.asList(checkstyle, checkstyleExt));
-
- assertThat(repository.getMetadata()).isEmpty();
- }
-
- private File fileFromCache(String filename) throws Exception {
- File file = new File(Resources.getResource("org/sonar/batch/bootstrap/BatchPluginRepositoryTest/" + filename).toURI());
- File destDir = new File(userHome, "cache/foomd5");
- FileUtils.forceMkdir(destDir);
- FileUtils.copyFileToDirectory(file, destDir);
- return new File(destDir, filename);
- }
-
- @Test
- public void shouldAlwaysAcceptIfNoWhiteListAndBlackList() {
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(new Settings(), mode);
- assertThat(filter.accepts("pmd")).isTrue();
- assertThat(filter.accepts("buildbreaker")).isTrue();
- }
-
- @Test
- public void shouldBlackListBuildBreakerInPreviewMode() {
- when(mode.isPreview()).thenReturn(true);
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(new Settings(), mode);
- assertThat(filter.accepts("buildbreaker")).isFalse();
- }
-
- @Test
- public void whiteListShouldTakePrecedenceOverBlackList() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs")
- .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura,pmd");
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.accepts("pmd")).isTrue();
- }
-
- @Test
- public void corePluginShouldAlwaysBeInWhiteList() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs");
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.accepts("core")).isTrue();
- }
-
- @Test
- public void corePluginShouldNeverBeInBlackList() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "core,findbugs");
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.accepts("core")).isTrue();
- }
-
- @Test
- public void check_white_list_with_black_list() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs")
- .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura");
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.accepts("checkstyle")).isTrue();
- assertThat(filter.accepts("pmd")).isTrue();
- assertThat(filter.accepts("cobertura")).isFalse();
- }
-
- @Test
- public void check_white_list_when_plugin_is_in_both_list() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "cobertura,checkstyle,pmd,findbugs")
- .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura");
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.accepts("checkstyle")).isTrue();
- assertThat(filter.accepts("pmd")).isTrue();
- assertThat(filter.accepts("cobertura")).isTrue();
- }
-
- @Test
- public void check_black_list_if_no_white_list() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd,findbugs");
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.accepts("checkstyle")).isFalse();
- assertThat(filter.accepts("pmd")).isFalse();
- assertThat(filter.accepts("cobertura")).isTrue();
- }
-
- @Test
- public void should_concatenate_preview_filters() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.PREVIEW_INCLUDE_PLUGINS, "cockpit")
- .setProperty(CoreProperties.PREVIEW_EXCLUDE_PLUGINS, "views")
- .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd");
- when(mode.isPreview()).thenReturn(true);
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.whites).containsOnly("cockpit");
- assertThat(filter.blacks).containsOnly("views", "checkstyle", "pmd");
- }
-
- @Test
- public void should_concatenate_deprecated_dry_run_filters() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.DRY_RUN_INCLUDE_PLUGINS, "cockpit")
- .setProperty(CoreProperties.DRY_RUN_EXCLUDE_PLUGINS, "views")
- .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd");
- when(mode.isPreview()).thenReturn(true);
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.whites).containsOnly("cockpit");
- assertThat(filter.blacks).containsOnly("views", "checkstyle", "pmd");
- }
-
- @Test
- public void inclusions_and_exclusions_should_be_trimmed() {
- Settings settings = new Settings()
- .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle, pmd, findbugs")
- .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura, pmd");
- BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
- assertThat(filter.accepts("pmd")).isTrue();
- }
-
-}
+///*
+// * 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.batch.bootstrap;
+//
+//import com.google.common.io.Resources;
+//import org.apache.commons.io.FileUtils;
+//import org.junit.After;
+//import org.junit.Before;
+//import org.junit.Rule;
+//import org.junit.Test;
+//import org.junit.rules.TemporaryFolder;
+//import org.sonar.api.CoreProperties;
+//import org.sonar.api.config.Settings;
+//import org.sonar.core.plugins.RemotePlugin;
+//import org.sonar.home.cache.FileCache;
+//import org.sonar.home.cache.FileCacheBuilder;
+//
+//import java.io.File;
+//import java.io.IOException;
+//import java.util.Arrays;
+//
+//import static org.mockito.Mockito.mock;
+//import static org.mockito.Mockito.when;
+//
+//public class BatchPluginRepositoryTest {
+//
+// @Rule
+// public TemporaryFolder temp = new TemporaryFolder();
+//
+// private BatchPluginRepository repository;
+// private DefaultAnalysisMode mode;
+// private FileCache cache;
+// private File userHome;
+//
+// @Before
+// public void before() throws IOException {
+// mode = mock(DefaultAnalysisMode.class);
+// when(mode.isPreview()).thenReturn(false);
+// userHome = temp.newFolder();
+// cache = new FileCacheBuilder().setUserHome(userHome).build();
+// }
+//
+// @After
+// public void tearDown() {
+// if (repository != null) {
+// repository.stop();
+// }
+// }
+//
+// @Test
+// public void shouldLoadPlugin() throws Exception {
+// RemotePlugin checkstyle = new RemotePlugin("checkstyle", true);
+//
+// DefaultPluginRepository installer = mock(DefaultPluginsRepository.class);
+// when(installer.pluginFile(checkstyle)).thenReturn(fileFromCache("sonar-checkstyle-plugin-2.8.jar"));
+//
+// repository = new BatchPluginRepository(installer, new Settings(), mode, new BatchPluginJarInstaller(cache));
+//
+// repository.doStart(Arrays.asList(checkstyle));
+//
+// assertThat(repository.getPlugin("checkstyle")).isNotNull();
+// assertThat(repository.getMetadata()).hasSize(1);
+// assertThat(repository.getMetadata("checkstyle").getName()).isEqualTo("Checkstyle");
+// assertThat(repository.getMetadata("checkstyle").getDeployedFiles()).hasSize(4); // plugin + 3 dependencies
+// }
+//
+// @Test
+// public void shouldLoadPluginExtension() throws Exception {
+// RemotePlugin checkstyle = new RemotePlugin("checkstyle", true);
+// RemotePlugin checkstyleExt = new RemotePlugin("checkstyleextensions", false);
+//
+// DefaultPluginsRepository downloader = mock(DefaultPluginsRepository.class);
+// when(downloader.pluginFile(checkstyle)).thenReturn(fileFromCache("sonar-checkstyle-plugin-2.8.jar"));
+// when(downloader.pluginFile(checkstyleExt)).thenReturn(fileFromCache("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar"));
+//
+// repository = new BatchPluginRepository(downloader, new Settings(), mode, new BatchPluginJarInstaller(cache));
+//
+// repository.doStart(Arrays.asList(checkstyle, checkstyleExt));
+//
+// assertThat(repository.getPlugin("checkstyle")).isNotNull();
+// assertThat(repository.getPlugin("checkstyleextensions")).isNotNull();
+// assertThat(repository.getMetadata()).hasSize(2);
+// assertThat(repository.getMetadata("checkstyle").getName()).isEqualTo("Checkstyle");
+// assertThat(repository.getMetadata("checkstyleextensions").getVersion()).isEqualTo("0.1-SNAPSHOT");
+// }
+//
+// @Test
+// public void shouldExcludePluginAndItsExtensions() throws Exception {
+// RemotePlugin checkstyle = new RemotePlugin("checkstyle", true);
+// RemotePlugin checkstyleExt = new RemotePlugin("checkstyleextensions", false);
+//
+// DefaultPluginsRepository downloader = mock(DefaultPluginsRepository.class);
+// when(downloader.pluginFile(checkstyle)).thenReturn(fileFromCache("sonar-checkstyle-plugin-2.8.jar"));
+// when(downloader.pluginFile(checkstyleExt)).thenReturn(fileFromCache("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar"));
+//
+// Settings settings = new Settings();
+// settings.setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle");
+// repository = new BatchPluginRepository(downloader, settings, mode, new BatchPluginJarInstaller(cache));
+//
+// repository.doStart(Arrays.asList(checkstyle, checkstyleExt));
+//
+// assertThat(repository.getMetadata()).isEmpty();
+// }
+//
+// private File fileFromCache(String filename) throws Exception {
+// File file = new File(Resources.getResource("org/sonar/batch/bootstrap/BatchPluginRepositoryTest/" + filename).toURI());
+// File destDir = new File(userHome, "cache/foomd5");
+// FileUtils.forceMkdir(destDir);
+// FileUtils.copyFileToDirectory(file, destDir);
+// return new File(destDir, filename);
+// }
+//
+// @Test
+// public void shouldAlwaysAcceptIfNoWhiteListAndBlackList() {
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(new Settings(), mode);
+// assertThat(filter.accepts("pmd")).isTrue();
+// assertThat(filter.accepts("buildbreaker")).isTrue();
+// }
+//
+// @Test
+// public void shouldBlackListBuildBreakerInPreviewMode() {
+// when(mode.isPreview()).thenReturn(true);
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(new Settings(), mode);
+// assertThat(filter.accepts("buildbreaker")).isFalse();
+// }
+//
+// @Test
+// public void whiteListShouldTakePrecedenceOverBlackList() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs")
+// .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura,pmd");
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.accepts("pmd")).isTrue();
+// }
+//
+// @Test
+// public void corePluginShouldAlwaysBeInWhiteList() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs");
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.accepts("core")).isTrue();
+// }
+//
+// @Test
+// public void corePluginShouldNeverBeInBlackList() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "core,findbugs");
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.accepts("core")).isTrue();
+// }
+//
+// @Test
+// public void check_white_list_with_black_list() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle,pmd,findbugs")
+// .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura");
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.accepts("checkstyle")).isTrue();
+// assertThat(filter.accepts("pmd")).isTrue();
+// assertThat(filter.accepts("cobertura")).isFalse();
+// }
+//
+// @Test
+// public void check_white_list_when_plugin_is_in_both_list() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "cobertura,checkstyle,pmd,findbugs")
+// .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura");
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.accepts("checkstyle")).isTrue();
+// assertThat(filter.accepts("pmd")).isTrue();
+// assertThat(filter.accepts("cobertura")).isTrue();
+// }
+//
+// @Test
+// public void check_black_list_if_no_white_list() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd,findbugs");
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.accepts("checkstyle")).isFalse();
+// assertThat(filter.accepts("pmd")).isFalse();
+// assertThat(filter.accepts("cobertura")).isTrue();
+// }
+//
+// @Test
+// public void should_concatenate_preview_filters() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.PREVIEW_INCLUDE_PLUGINS, "cockpit")
+// .setProperty(CoreProperties.PREVIEW_EXCLUDE_PLUGINS, "views")
+// .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd");
+// when(mode.isPreview()).thenReturn(true);
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.whites).containsOnly("cockpit");
+// assertThat(filter.blacks).containsOnly("views", "checkstyle", "pmd");
+// }
+//
+// @Test
+// public void should_concatenate_deprecated_dry_run_filters() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.DRY_RUN_INCLUDE_PLUGINS, "cockpit")
+// .setProperty(CoreProperties.DRY_RUN_EXCLUDE_PLUGINS, "views")
+// .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "checkstyle,pmd");
+// when(mode.isPreview()).thenReturn(true);
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.whites).containsOnly("cockpit");
+// assertThat(filter.blacks).containsOnly("views", "checkstyle", "pmd");
+// }
+//
+// @Test
+// public void inclusions_and_exclusions_should_be_trimmed() {
+// Settings settings = new Settings()
+// .setProperty(CoreProperties.BATCH_INCLUDE_PLUGINS, "checkstyle, pmd, findbugs")
+// .setProperty(CoreProperties.BATCH_EXCLUDE_PLUGINS, "cobertura, pmd");
+// BatchPluginRepository.PluginFilter filter = new BatchPluginRepository.PluginFilter(settings, mode);
+// assertThat(filter.accepts("pmd")).isTrue();
+// }
+//
+//}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginJarInstallerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginUnzipperTest.java
index 2209c57431a..06a25148775 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginJarInstallerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/BatchPluginUnzipperTest.java
@@ -24,7 +24,9 @@ import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import org.sonar.core.plugins.DefaultPluginMetadata;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.UnzippedPlugin;
+import org.sonar.home.cache.FileCache;
import org.sonar.home.cache.FileCacheBuilder;
import java.io.File;
@@ -32,35 +34,37 @@ import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
-public class BatchPluginJarInstallerTest {
-
- private BatchPluginJarInstaller extractor;
+public class BatchPluginUnzipperTest {
@ClassRule
- public static TemporaryFolder temporaryFolder = new TemporaryFolder();
+ public static TemporaryFolder temp = new TemporaryFolder();
- private File userHome;
+ File userHome;
+ BatchPluginUnzipper underTest;
@Before
public void setUp() throws IOException {
- userHome = temporaryFolder.newFolder();
- extractor = new BatchPluginJarInstaller(new FileCacheBuilder().setUserHome(userHome).build());
+ userHome = temp.newFolder();
+ FileCache fileCache = new FileCacheBuilder().setUserHome(userHome).build();
+ underTest = new BatchPluginUnzipper(fileCache);
}
@Test
- public void should_copy_and_extract_dependencies() throws IOException {
+ public void copy_and_extract_libs() throws IOException {
File fileFromCache = getFileFromCache("sonar-checkstyle-plugin-2.8.jar");
- DefaultPluginMetadata metadata = extractor.installToCache(fileFromCache, true);
+ UnzippedPlugin unzipped = underTest.unzip(PluginInfo.create(fileFromCache));
- assertThat(metadata.getKey()).isEqualTo("checkstyle");
+ assertThat(unzipped.getKey()).isEqualTo("checkstyle");
+ assertThat(unzipped.getMain()).isFile().exists();
+ assertThat(unzipped.getLibs()).extracting("name").containsOnly("antlr-2.7.6.jar", "checkstyle-5.1.jar", "commons-cli-1.0.jar");
assertThat(new File(fileFromCache.getParent(), "sonar-checkstyle-plugin-2.8.jar")).exists();
assertThat(new File(fileFromCache.getParent(), "sonar-checkstyle-plugin-2.8.jar_unzip/META-INF/lib/checkstyle-5.1.jar")).exists();
}
@Test
- public void should_extract_only_dependencies() throws IOException {
+ public void extract_only_libs() throws IOException {
File fileFromCache = getFileFromCache("sonar-checkstyle-plugin-2.8.jar");
- extractor.installToCache(fileFromCache, true);
+ underTest.unzip(PluginInfo.create(fileFromCache));
assertThat(new File(fileFromCache.getParent(), "sonar-checkstyle-plugin-2.8.jar")).exists();
assertThat(new File(fileFromCache.getParent(), "sonar-checkstyle-plugin-2.8.jar_unzip/META-INF/MANIFEST.MF")).doesNotExist();
@@ -68,7 +72,7 @@ public class BatchPluginJarInstallerTest {
}
File getFileFromCache(String filename) throws IOException {
- File src = FileUtils.toFile(BatchPluginJarInstallerTest.class.getResource("/org/sonar/batch/bootstrap/BatchPluginJarInstallerTest/" + filename));
+ File src = FileUtils.toFile(BatchPluginUnzipperTest.class.getResource("/org/sonar/batch/bootstrap/BatchPluginUnzipperTest/" + filename));
File destFile = new File(new File(userHome, "" + filename.hashCode()), filename);
FileUtils.copyFile(src, destFile);
return destFile;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java
index 0647b0e22ec..b01040b29cd 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/ExtensionInstallerTest.java
@@ -19,7 +19,6 @@
*/
package org.sonar.batch.bootstrap;
-import com.google.common.collect.Maps;
import org.apache.commons.lang.ClassUtils;
import org.junit.Before;
import org.junit.Test;
@@ -28,13 +27,12 @@ import org.sonar.api.ExtensionProvider;
import org.sonar.api.Plugin;
import org.sonar.api.SonarPlugin;
import org.sonar.api.batch.SupportedEnvironment;
-import org.sonar.api.platform.ComponentContainer;
-import org.sonar.api.platform.PluginMetadata;
import org.sonar.batch.bootstrapper.EnvironmentInformation;
+import org.sonar.core.platform.ComponentContainer;
+import org.sonar.core.platform.PluginInfo;
import java.util.Arrays;
import java.util.List;
-import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -42,19 +40,15 @@ import static org.mockito.Mockito.when;
public class ExtensionInstallerTest {
- private DefaultAnalysisMode mode;
- PluginMetadata metadata = mock(PluginMetadata.class);
+ DefaultAnalysisMode mode;
+ BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class);
- Map<PluginMetadata, Plugin> newPlugin(final Object... extensions) {
- Map<PluginMetadata, Plugin> result = Maps.newHashMap();
- result.put(metadata,
- new SonarPlugin() {
- public List getExtensions() {
- return Arrays.asList(extensions);
- }
+ private static Plugin newPluginInstance(final Object... extensions) {
+ return new SonarPlugin() {
+ public List getExtensions() {
+ return Arrays.asList(extensions);
}
- );
- return result;
+ };
}
@Before
@@ -64,8 +58,9 @@ public class ExtensionInstallerTest {
@Test
public void should_filter_extensions_to_install() {
- BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class);
- when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(Foo.class, Bar.class));
+ when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo")));
+ when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(Foo.class, Bar.class));
+
ComponentContainer container = new ComponentContainer();
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), mode);
installer.install(container, new FooMatcher());
@@ -76,8 +71,8 @@ public class ExtensionInstallerTest {
@Test
public void should_execute_extension_provider() {
- BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class);
- when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(new FooProvider(), new BarProvider()));
+ when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo")));
+ when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(new FooProvider(), new BarProvider()));
ComponentContainer container = new ComponentContainer();
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), mode);
@@ -89,8 +84,8 @@ public class ExtensionInstallerTest {
@Test
public void should_provide_list_of_extensions() {
- BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class);
- when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(new FooBarProvider()));
+ when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo")));
+ when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(new FooBarProvider()));
ComponentContainer container = new ComponentContainer();
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), mode);
@@ -102,9 +97,8 @@ public class ExtensionInstallerTest {
@Test
public void should_not_install_on_unsupported_environment() {
- BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class);
- when(pluginRepository.getPluginsByMetadata()).thenReturn(newPlugin(Foo.class, MavenExtension.class, AntExtension.class, new BarProvider()));
-
+ when(pluginRepository.getPluginInfos()).thenReturn(Arrays.asList(new PluginInfo("foo")));
+ when(pluginRepository.getPluginInstance("foo")).thenReturn(newPluginInstance(Foo.class, MavenExtension.class, AntExtension.class, new BarProvider()));
ComponentContainer container = new ComponentContainer();
ExtensionInstaller installer = new ExtensionInstaller(pluginRepository, new EnvironmentInformation("ant", "1.7"), mode);
diff --git a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalContainerTest.java b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalContainerTest.java
index 9fce2c7a951..ac87c52fa51 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalContainerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/bootstrap/GlobalContainerTest.java
@@ -19,25 +19,15 @@
*/
package org.sonar.batch.bootstrap;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import org.junit.Test;
import org.sonar.api.BatchExtension;
-import org.sonar.api.Plugin;
-import org.sonar.api.SonarPlugin;
-import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.utils.TempFolder;
import org.sonar.core.config.Logback;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
public class GlobalContainerTest {
@Test
@@ -58,22 +48,6 @@ public class GlobalContainerTest {
assertThat(container.getComponentByType(Bar.class)).isNotNull();
}
- @Test
- public void should_install_plugins() {
- PluginMetadata metadata = mock(PluginMetadata.class);
- FakePlugin plugin = new FakePlugin();
- BatchPluginRepository pluginRepository = mock(BatchPluginRepository.class);
- when(pluginRepository.getPluginsByMetadata()).thenReturn(ImmutableMap.<PluginMetadata, Plugin>of(
- metadata, plugin
- ));
-
- GlobalContainer container = spy(GlobalContainer.create(Collections.<String, String>emptyMap(), Lists.<Object>newArrayList(pluginRepository)));
- doNothing().when(container).executeTask(Collections.<String, String>emptyMap());
- container.doAfterStart();
-
- assertThat(container.getComponentsByType(Plugin.class)).containsOnly(plugin);
- }
-
public static class Foo implements BatchExtension {
}
@@ -82,10 +56,4 @@ public class GlobalContainerTest {
}
- public static class FakePlugin extends SonarPlugin {
-
- public List getExtensions() {
- return Arrays.asList(Foo.class, Bar.class);
- }
- }
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/deprecated/decorator/DecoratorsSelectorTest.java b/sonar-batch/src/test/java/org/sonar/batch/deprecated/decorator/DecoratorsSelectorTest.java
index fd9a9ed3727..3b7340689db 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/deprecated/decorator/DecoratorsSelectorTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/deprecated/decorator/DecoratorsSelectorTest.java
@@ -25,7 +25,7 @@ import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.batch.DependedUpon;
import org.sonar.api.measures.*;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.batch.bootstrap.BatchExtensionDictionnary;
diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java
index 5c98be19187..b4f7dc49ce3 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/scan/ProjectScanContainerTest.java
@@ -30,7 +30,7 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
-import org.sonar.api.platform.ComponentContainer;
+import org.sonar.core.platform.ComponentContainer;
import org.sonar.api.task.TaskExtension;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.TempFolder;
diff --git a/sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginJarInstallerTest/sonar-checkstyle-plugin-2.8.jar b/sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginUnzipperTest/sonar-checkstyle-plugin-2.8.jar
index f937399bec5..f937399bec5 100644
--- a/sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginJarInstallerTest/sonar-checkstyle-plugin-2.8.jar
+++ b/sonar-batch/src/test/resources/org/sonar/batch/bootstrap/BatchPluginUnzipperTest/sonar-checkstyle-plugin-2.8.jar
Binary files differ
diff --git a/sonar-check-api/src/main/java/org/sonar/check/package-info.java b/sonar-check-api/src/main/java/org/sonar/check/package-info.java
index b1f3232a62f..bd348edb5c0 100644
--- a/sonar-check-api/src/main/java/org/sonar/check/package-info.java
+++ b/sonar-check-api/src/main/java/org/sonar/check/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.check;
diff --git a/sonar-colorizer/src/main/java/org/sonar/colorizer/package-info.java b/sonar-colorizer/src/main/java/org/sonar/colorizer/package-info.java
index 551a67c296f..d0abbe987a4 100644
--- a/sonar-colorizer/src/main/java/org/sonar/colorizer/package-info.java
+++ b/sonar-colorizer/src/main/java/org/sonar/colorizer/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.colorizer;
diff --git a/sonar-core/pom.xml b/sonar-core/pom.xml
index 41ae4b71bff..ea0fd0be8f8 100644
--- a/sonar-core/pom.xml
+++ b/sonar-core/pom.xml
@@ -20,14 +20,12 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>org.codehaus.sonar</groupId>
+ <artifactId>sonar-classloader</artifactId>
+ </dependency>
+ <dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sonar-plugin-api</artifactId>
- <exclusions>
- <exclusion>
- <groupId>classworlds</groupId>
- <artifactId>classworlds</artifactId>
- </exclusion>
- </exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
@@ -90,10 +88,6 @@
<artifactId>commons-dbutils</artifactId>
</dependency>
<dependency>
- <groupId>org.codehaus.plexus</groupId>
- <artifactId>plexus-classworlds</artifactId>
- </dependency>
- <dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
</dependency>
diff --git a/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java b/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java
index 02281c51f9e..8190b0f6e3e 100644
--- a/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java
+++ b/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java
@@ -20,41 +20,49 @@
package org.sonar.core.i18n;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Maps;
+import com.google.common.base.Preconditions;
import org.apache.commons.io.IOUtils;
import org.picocontainer.Startable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.BatchExtension;
-import org.sonar.api.ServerExtension;
import org.sonar.api.i18n.I18n;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.utils.SonarException;
import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
-import java.util.*;
-
-public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Startable {
-
- private static final Logger LOG = LoggerFactory.getLogger(DefaultI18n.class);
-
- public static final String BUNDLE_PACKAGE = "org.sonar.l10n.";
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+public class DefaultI18n implements I18n, Startable {
+
+ private static final Logger LOG = Loggers.get(DefaultI18n.class);
+ private static final String BUNDLE_PACKAGE = "org.sonar.l10n.";
+
+ private final PluginRepository pluginRepository;
+ private final ResourceBundle.Control control;
+ private final System2 system2;
- private PluginRepository pluginRepository;
+ // the following fields are available after startup
private ClassLoader classloader;
private Map<String, String> propertyToBundles;
- private final ResourceBundle.Control control;
- private final System2 system2;
public DefaultI18n(PluginRepository pluginRepository) {
this(pluginRepository, System2.INSTANCE);
@@ -68,9 +76,7 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start
this.control = new ResourceBundle.Control() {
@Override
public Locale getFallbackLocale(String baseName, Locale locale) {
- if (baseName == null) {
- throw new NullPointerException();
- }
+ Preconditions.checkNotNull(baseName);
Locale defaultLocale = Locale.ENGLISH;
return locale.equals(defaultLocale) ? null : defaultLocale;
}
@@ -85,16 +91,16 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start
@VisibleForTesting
void doStart(ClassLoader classloader) {
this.classloader = classloader;
- propertyToBundles = Maps.newHashMap();
- Collection<PluginMetadata> metadata = pluginRepository.getMetadata();
- if (metadata.isEmpty()) {
+ this.propertyToBundles = new HashMap<>();
+ Collection<PluginInfo> infos = pluginRepository.getPluginInfos();
+ if (infos.isEmpty()) {
addPlugin("core");
} else {
- for (PluginMetadata plugin : pluginRepository.getMetadata()) {
+ for (PluginInfo plugin : infos) {
addPlugin(plugin.getKey());
}
}
- LOG.debug(String.format("Loaded %d properties from l10n bundles", propertyToBundles.size()));
+ LOG.debug("Loaded {} properties from l10n bundles", propertyToBundles.size());
}
private void addPlugin(String pluginKey) {
@@ -113,6 +119,9 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start
@Override
public void stop() {
+ if (classloader instanceof Closeable) {
+ IOUtils.closeQuietly((Closeable)classloader);
+ }
classloader = null;
propertyToBundles = null;
}
diff --git a/sonar-core/src/main/java/org/sonar/core/i18n/I18nClassloader.java b/sonar-core/src/main/java/org/sonar/core/i18n/I18nClassloader.java
index d0eb0510763..9647eb784ca 100644
--- a/sonar-core/src/main/java/org/sonar/core/i18n/I18nClassloader.java
+++ b/sonar-core/src/main/java/org/sonar/core/i18n/I18nClassloader.java
@@ -19,35 +19,30 @@
*/
package org.sonar.core.i18n;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import org.sonar.api.Plugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
+/**
+ * Aggregation of all plugin and core classloaders, used to search for all l10n bundles
+ */
class I18nClassloader extends URLClassLoader {
- private static List<ClassLoader> classLoadersFromPlugin(PluginRepository pluginRepository) {
- List<ClassLoader> list = Lists.newArrayList();
- for (PluginMetadata metadata : pluginRepository.getMetadata()) {
- Plugin plugin = pluginRepository.getPlugin(metadata.getKey());
- list.add(plugin.getClass().getClassLoader());
- }
- return list;
- }
-
- private ClassLoader[] pluginClassloaders;
+ private final ClassLoader[] pluginClassloaders;
public I18nClassloader(PluginRepository pluginRepository) {
- this(classLoadersFromPlugin(pluginRepository));
+ this(allPluginClassloaders(pluginRepository));
}
+ @VisibleForTesting
I18nClassloader(List<ClassLoader> pluginClassloaders) {
super(new URL[0]);
- pluginClassloaders.add(getClass().getClassLoader());
this.pluginClassloaders = pluginClassloaders.toArray(new ClassLoader[pluginClassloaders.size()]);
}
@@ -59,7 +54,7 @@ class I18nClassloader extends URLClassLoader {
return url;
}
}
- return null;
+ return getClass().getClassLoader().getResource(name);
}
@Override
@@ -71,4 +66,15 @@ class I18nClassloader extends URLClassLoader {
public String toString() {
return "i18n-classloader";
}
+
+ private static List<ClassLoader> allPluginClassloaders(PluginRepository pluginRepository) {
+ // accepted limitation: some plugins extend base plugins, sharing the same classloader, so
+ // there may be duplicated classloaders in the list.
+ List<ClassLoader> list = Lists.newArrayList();
+ for (PluginInfo info : pluginRepository.getPluginInfos()) {
+ Plugin plugin = pluginRepository.getPluginInstance(info.getKey());
+ list.add(plugin.getClass().getClassLoader());
+ }
+ return list;
+ }
}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/workflow/package-info.java b/sonar-core/src/main/java/org/sonar/core/issue/workflow/package-info.java
index 2d51c65fac8..f4dc7f69eca 100644
--- a/sonar-core/src/main/java/org/sonar/core/issue/workflow/package-info.java
+++ b/sonar-core/src/main/java/org/sonar/core/issue/workflow/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.core.issue.workflow;
diff --git a/sonar-core/src/main/java/org/sonar/core/notification/package-info.java b/sonar-core/src/main/java/org/sonar/core/notification/package-info.java
index de0f088a8f3..c53b6d4b186 100644
--- a/sonar-core/src/main/java/org/sonar/core/notification/package-info.java
+++ b/sonar-core/src/main/java/org/sonar/core/notification/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.core.notification;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java
index e8555ed4e35..868208b12a0 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentContainer.java
+++ b/sonar-core/src/main/java/org/sonar/core/platform/ComponentContainer.java
@@ -17,7 +17,7 @@
* 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.platform;
+package org.sonar.core.platform;
import com.google.common.collect.Iterables;
import org.picocontainer.Characteristics;
@@ -36,9 +36,6 @@ import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
-/**
- * @since 2.12
- */
public class ComponentContainer implements BatchComponent, ServerComponent {
// no need for multiple children
@@ -183,14 +180,14 @@ public class ComponentContainer implements BatchComponent, ServerComponent {
return this;
}
- public ComponentContainer addExtension(@Nullable PluginMetadata plugin, Object extension) {
+ public ComponentContainer addExtension(@Nullable PluginInfo pluginInfo, Object extension) {
Object key = componentKeys.of(extension);
try {
pico.as(Characteristics.CACHE).addComponent(key, extension);
} catch (Throwable t) {
throw new IllegalStateException("Unable to register extension " + getName(extension), t);
}
- declareExtension(plugin, extension);
+ declareExtension(pluginInfo, extension);
return this;
}
@@ -201,8 +198,8 @@ public class ComponentContainer implements BatchComponent, ServerComponent {
return getName(extension.getClass());
}
- public void declareExtension(@Nullable PluginMetadata plugin, Object extension) {
- propertyDefinitions.addComponent(extension, plugin != null ? plugin.getName() : "");
+ public void declareExtension(@Nullable PluginInfo pluginInfo, Object extension) {
+ propertyDefinitions.addComponent(extension, pluginInfo != null ? pluginInfo.getName() : "");
}
public ComponentContainer addPicoAdapter(ComponentAdapter adapter) {
@@ -234,7 +231,7 @@ public class ComponentContainer implements BatchComponent, ServerComponent {
return new ComponentContainer(this);
}
- static MutablePicoContainer createPicoContainer() {
+ public static MutablePicoContainer createPicoContainer() {
ReflectionLifecycleStrategy lifecycleStrategy = new ReflectionLifecycleStrategy(new NullComponentMonitor(), "start", "stop", "close");
return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, null);
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentKeys.java b/sonar-core/src/main/java/org/sonar/core/platform/ComponentKeys.java
index 56de51f17e1..be315cd9cf7 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentKeys.java
+++ b/sonar-core/src/main/java/org/sonar/core/platform/ComponentKeys.java
@@ -17,9 +17,8 @@
* 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.platform;
+package org.sonar.core.platform;
-import com.google.common.annotations.VisibleForTesting;
import org.sonar.api.utils.internal.Uuids;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
@@ -28,19 +27,15 @@ import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
-/**
- * @since 3.7.1
- */
class ComponentKeys {
private static final Pattern IDENTITY_HASH_PATTERN = Pattern.compile(".+@[a-f0-9]+");
- private final Set<Class> objectsWithoutToString = new HashSet<Class>();
+ private final Set<Class> objectsWithoutToString = new HashSet<>();
Object of(Object component) {
return of(component, Loggers.get(ComponentKeys.class));
}
- @VisibleForTesting
Object of(Object component, Logger log) {
if (component instanceof Class) {
return component;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/PicoUtils.java b/sonar-core/src/main/java/org/sonar/core/platform/PicoUtils.java
index b14d886196b..ee4e1ae42a5 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/PicoUtils.java
+++ b/sonar-core/src/main/java/org/sonar/core/platform/PicoUtils.java
@@ -17,7 +17,7 @@
* 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.platform;
+package org.sonar.core.platform;
import com.google.common.base.Throwables;
import org.picocontainer.PicoLifecycleException;
@@ -25,6 +25,7 @@ import org.picocontainer.PicoLifecycleException;
class PicoUtils {
private PicoUtils() {
+ // only static methods
}
static Throwable sanitize(Throwable t) {
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/PluginInfo.java b/sonar-core/src/main/java/org/sonar/core/platform/PluginInfo.java
new file mode 100644
index 00000000000..e5509bbc7e7
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/platform/PluginInfo.java
@@ -0,0 +1,353 @@
+/*
+ * 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.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.updatecenter.common.PluginManifest;
+import org.sonar.updatecenter.common.Version;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PluginInfo implements Comparable<PluginInfo> {
+
+ public static class RequiredPlugin {
+ private final String key;
+ private final Version minimalVersion;
+
+ public RequiredPlugin(String key, Version minimalVersion) {
+ this.key = key;
+ this.minimalVersion = minimalVersion;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public Version getMinimalVersion() {
+ return minimalVersion;
+ }
+
+ public static RequiredPlugin parse(String s) {
+ if (!s.matches("\\w+:.+")) {
+ throw new IllegalArgumentException("Manifest field does not have correct format: " + s);
+ }
+ String[] fields = StringUtils.split(s, ':');
+ return new RequiredPlugin(fields[0], Version.create(fields[1]).removeQualifier());
+ }
+ }
+
+ private File file;
+ private String key;
+ private String name;
+ private Version version;
+ private Version minimalSqVersion;
+ private String mainClass;
+ private String description;
+ private String organizationName;
+ private String organizationUrl;
+ private String license;
+ private String homepageUrl;
+ private String issueTrackerUrl;
+ private boolean useChildFirstClassLoader;
+ private String basePlugin;
+ private boolean core;
+ private String implementationBuild;
+ private final List<RequiredPlugin> requiredPlugins = new ArrayList<>();
+
+ public PluginInfo() {
+ }
+
+ /**
+ * For tests only
+ */
+ public PluginInfo(String key) {
+ this.key = key;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @CheckForNull
+ public Version getVersion() {
+ return version;
+ }
+
+ @CheckForNull
+ public Version getMinimalSqVersion() {
+ return minimalSqVersion;
+ }
+
+ public String getMainClass() {
+ return mainClass;
+ }
+
+ @CheckForNull
+ public String getDescription() {
+ return description;
+ }
+
+ @CheckForNull
+ public String getOrganizationName() {
+ return organizationName;
+ }
+
+ @CheckForNull
+ public String getOrganizationUrl() {
+ return organizationUrl;
+ }
+
+ @CheckForNull
+ public String getLicense() {
+ return license;
+ }
+
+ @CheckForNull
+ public String getHomepageUrl() {
+ return homepageUrl;
+ }
+
+ @CheckForNull
+ public String getIssueTrackerUrl() {
+ return issueTrackerUrl;
+ }
+
+ public boolean isUseChildFirstClassLoader() {
+ return useChildFirstClassLoader;
+ }
+
+ @CheckForNull
+ public String getBasePlugin() {
+ return basePlugin;
+ }
+
+ public boolean isCore() {
+ return core;
+ }
+
+ @CheckForNull
+ public String getImplementationBuild() {
+ return implementationBuild;
+ }
+
+ public List<RequiredPlugin> getRequiredPlugins() {
+ return requiredPlugins;
+ }
+
+ /**
+ * Required
+ */
+ public PluginInfo setFile(File file) {
+ this.file = file;
+ return this;
+ }
+
+ /**
+ * Required
+ */
+ public PluginInfo setKey(String key) {
+ this.key = key;
+ return this;
+ }
+
+ /**
+ * Required
+ */
+ public PluginInfo setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Required
+ */
+ public PluginInfo setVersion(Version version) {
+ this.version = version;
+ return this;
+ }
+
+ public PluginInfo setMinimalSqVersion(@Nullable Version v) {
+ this.minimalSqVersion = v;
+ return this;
+ }
+
+ /**
+ * Required
+ */
+ public PluginInfo setMainClass(String mainClass) {
+ this.mainClass = mainClass;
+ return this;
+ }
+
+ public PluginInfo setDescription(@Nullable String description) {
+ this.description = description;
+ return this;
+ }
+
+ public PluginInfo setOrganizationName(@Nullable String s) {
+ this.organizationName = s;
+ return this;
+ }
+
+ public PluginInfo setOrganizationUrl(@Nullable String s) {
+ this.organizationUrl = s;
+ return this;
+ }
+
+ public PluginInfo setLicense(@Nullable String license) {
+ this.license = license;
+ return this;
+ }
+
+ public PluginInfo setHomepageUrl(@Nullable String s) {
+ this.homepageUrl = s;
+ return this;
+ }
+
+ public PluginInfo setIssueTrackerUrl(@Nullable String s) {
+ this.issueTrackerUrl = s;
+ return this;
+ }
+
+ public PluginInfo setUseChildFirstClassLoader(boolean b) {
+ this.useChildFirstClassLoader = b;
+ return this;
+ }
+
+ public PluginInfo setBasePlugin(@Nullable String s) {
+ this.basePlugin = s;
+ return this;
+ }
+
+ public PluginInfo setCore(boolean b) {
+ this.core = b;
+ return this;
+ }
+
+ public PluginInfo setImplementationBuild(@Nullable String implementationBuild) {
+ this.implementationBuild = implementationBuild;
+ return this;
+ }
+
+ public PluginInfo addRequiredPlugin(RequiredPlugin p) {
+ this.requiredPlugins.add(p);
+ return this;
+ }
+
+ /**
+ * Find out if this plugin is compatible with a given version of SonarQube.
+ * The version of SQ must be greater than or equal to the minimal version
+ * needed by the plugin.
+ */
+ public boolean isCompatibleWith(String sqVersion) {
+ if (null == this.minimalSqVersion) {
+ // no constraint defined on the plugin
+ return true;
+ }
+
+ Version effectiveMin = Version.create(minimalSqVersion.getName()).removeQualifier();
+ Version actualVersion = Version.create(sqVersion).removeQualifier();
+ return actualVersion.compareTo(effectiveMin) >= 0;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%s]", Joiner.on(" / ").skipNulls().join(key, version, implementationBuild));
+ }
+
+ @Override
+ public int compareTo(PluginInfo other) {
+ int cmp = name.compareTo(other.name);
+ if (cmp != 0) {
+ return cmp;
+ }
+ return version.compareTo(other.version);
+ }
+
+ public static PluginInfo create(File jarFile) {
+ try {
+ PluginManifest manifest = new PluginManifest(jarFile);
+ return create(jarFile, manifest);
+
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to extract plugin metadata from file: " + jarFile, e);
+ }
+ }
+
+ @VisibleForTesting
+ static PluginInfo create(File jarFile, PluginManifest manifest) {
+ PluginInfo info = new PluginInfo();
+
+ // required fields
+ info.setKey(manifest.getKey());
+ info.setFile(jarFile);
+ info.setName(manifest.getName());
+ info.setMainClass(manifest.getMainClass());
+ info.setVersion(Version.create(manifest.getVersion()));
+
+ // optional fields
+ info.setDescription(manifest.getDescription());
+ info.setLicense(manifest.getLicense());
+ info.setOrganizationName(manifest.getOrganization());
+ info.setOrganizationUrl(manifest.getOrganizationUrl());
+ String minSqVersion = manifest.getSonarVersion();
+ if (minSqVersion != null) {
+ info.setMinimalSqVersion(Version.create(minSqVersion));
+ }
+ info.setHomepageUrl(manifest.getHomepage());
+ info.setIssueTrackerUrl(manifest.getIssueTrackerUrl());
+ info.setUseChildFirstClassLoader(manifest.isUseChildFirstClassLoader());
+ info.setBasePlugin(manifest.getBasePlugin());
+ info.setImplementationBuild(manifest.getImplementationBuild());
+ String[] requiredPlugins = manifest.getRequirePlugins();
+ if (requiredPlugins != null) {
+ for (String s : requiredPlugins) {
+ info.addRequiredPlugin(RequiredPlugin.parse(s));
+ }
+ }
+ return info;
+ }
+
+ public enum JarToPluginInfo implements Function<File, PluginInfo> {
+ INSTANCE;
+
+ @Override
+ public PluginInfo apply(@Nonnull File jarFile) {
+ return create(jarFile);
+ }
+ };
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/PluginLoader.java b/sonar-core/src/main/java/org/sonar/core/platform/PluginLoader.java
new file mode 100644
index 00000000000..336c4904bcf
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/platform/PluginLoader.java
@@ -0,0 +1,199 @@
+/*
+ * 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.base.Strings;
+import org.apache.commons.lang.SystemUtils;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.Plugin;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.classloader.ClassloaderBuilder;
+import org.sonar.classloader.ClassloaderBuilder.LoadingOrder;
+import org.sonar.classloader.Mask;
+
+import java.io.Closeable;
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.sonar.classloader.ClassloaderBuilder.LoadingOrder.SELF_FIRST;
+
+/**
+ * Loads the plugin JAR files by creating the appropriate classloaders and by instantiating
+ * the entry point classes as defined in manifests. It assumes that JAR files are compatible with current
+ * environment (minimal sonarqube version, compatibility between plugins, ...).
+ * <p/>
+ * Standard plugins have their own isolated classloader. Some others can extend a "base" plugin.
+ * In this case they share the same classloader then the base plugin.
+ * <p/>
+ * This class is stateless. It does not keep classloaders and {@link Plugin} in memory.
+ */
+public class PluginLoader implements BatchComponent, ServerComponent {
+
+ private static final String[] DEFAULT_SHARED_RESOURCES = {"org/sonar/plugins/", "com/sonar/plugins/", "com/sonarsource/plugins/"};
+
+ /**
+ * Information about the classloader to be created for a set of plugins.
+ */
+ static class ClassloaderDef {
+ final String basePluginKey;
+ final Map<String, String> mainClassesByPluginKey = new HashMap<>();
+ final List<File> files = new ArrayList<>();
+ final Mask mask = new Mask();
+ boolean selfFirstStrategy = false;
+ ClassLoader classloader = null;
+
+ public ClassloaderDef(String basePluginKey) {
+ this.basePluginKey = basePluginKey;
+ }
+ }
+
+ private final PluginUnzipper unzipper;
+
+ public PluginLoader(PluginUnzipper unzipper) {
+ this.unzipper = unzipper;
+ }
+
+ public Map<String, Plugin> load(Map<String, PluginInfo> infoByKeys) {
+ Collection<ClassloaderDef> defs = defineClassloaders(infoByKeys).values();
+ buildClassloaders(defs);
+ return instantiatePluginInstances(defs);
+ }
+
+ /**
+ * Step 1 - define the different classloaders to be created. Number of classloaders can be
+ * different than number of plugins.
+ */
+ Map<String, ClassloaderDef> defineClassloaders(Map<String, PluginInfo> infoByKeys) {
+ Map<String, ClassloaderDef> classloadersByBasePlugin = new HashMap<>();
+
+ for (PluginInfo info : infoByKeys.values()) {
+ String baseKey = basePluginKey(info, infoByKeys);
+ ClassloaderDef def = classloadersByBasePlugin.get(baseKey);
+ if (def == null) {
+ def = new ClassloaderDef(baseKey);
+ classloadersByBasePlugin.put(baseKey, def);
+ }
+ UnzippedPlugin unzippedPlugin = unzipper.unzip(info);
+ def.files.add(unzippedPlugin.getMain());
+ def.files.addAll(unzippedPlugin.getLibs());
+ def.mainClassesByPluginKey.put(info.getKey(), info.getMainClass());
+ for (String defaultSharedResource : DEFAULT_SHARED_RESOURCES) {
+ def.mask.addInclusion(defaultSharedResource + info.getKey() + "/");
+ }
+ if (Strings.isNullOrEmpty(info.getBasePlugin())) {
+ // The plugins that extend other plugins can only add some files to classloader.
+ // They can't change ordering strategy.
+ def.selfFirstStrategy = info.isUseChildFirstClassLoader();
+ }
+ }
+ return classloadersByBasePlugin;
+ }
+
+ /**
+ * Step 2 - create classloaders with appropriate constituents and metadata
+ */
+ void buildClassloaders(Collection<ClassloaderDef> defs) {
+ ClassloaderBuilder builder = new ClassloaderBuilder();
+ for (ClassloaderDef def : defs) {
+ builder
+ .newClassloader(def.basePluginKey, getClass().getClassLoader())
+ .setExportMask(def.basePluginKey, def.mask)
+ .setLoadingOrder(def.basePluginKey, def.selfFirstStrategy ? SELF_FIRST : LoadingOrder.PARENT_FIRST);
+ for (File file : def.files) {
+ builder.addURL(def.basePluginKey, fileToUrl(file));
+ }
+ }
+ Map<String, ClassLoader> classloadersByBasePluginKey = builder.build();
+ for (ClassloaderDef def : defs) {
+ def.classloader = classloadersByBasePluginKey.get(def.basePluginKey);
+ }
+ }
+
+ /**
+ * Step 3 - instantiate plugin instances ({@link Plugin}
+ *
+ * @return the instances grouped by plugin key
+ * @throws IllegalStateException if at least one plugin can't be correctly loaded
+ */
+ Map<String, Plugin> instantiatePluginInstances(Collection<ClassloaderDef> defs) {
+ // instantiate plugins
+ Map<String, Plugin> instancesByPluginKey = new HashMap<>();
+ for (ClassloaderDef def : defs) {
+ // the same classloader can be used by multiple plugins
+ for (Map.Entry<String, String> entry : def.mainClassesByPluginKey.entrySet()) {
+ String pluginKey = entry.getKey();
+ String mainClass = entry.getValue();
+ try {
+ instancesByPluginKey.put(pluginKey, (Plugin) def.classloader.loadClass(mainClass).newInstance());
+ } catch (UnsupportedClassVersionError e) {
+ throw new IllegalStateException(String.format("The plugin [%s] does not support Java %s",
+ pluginKey, SystemUtils.JAVA_VERSION_TRIMMED), e);
+ } catch (Exception e) {
+ throw new IllegalStateException(String.format(
+ "Fail to instantiate class [%s] of plugin [%s]", mainClass, pluginKey), e);
+ }
+ }
+ }
+ return instancesByPluginKey;
+ }
+
+ public void unload(Collection<Plugin> plugins) {
+ for (Plugin plugin : plugins) {
+ ClassLoader classLoader = plugin.getClass().getClassLoader();
+ if (classLoader instanceof Closeable && classLoader != getClass().getClassLoader()) {
+ try {
+ ((Closeable) classLoader).close();
+ } catch (Exception e) {
+ Loggers.get(getClass()).error("Fail to close classloader " + classLoader.toString(), e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the root key of a tree of plugins. For example if plugin C depends on B, which depends on A, then
+ * B and C must be attached to the classloader of A. The method returns A in the three cases.
+ */
+ static String basePluginKey(PluginInfo plugin, Map<String, PluginInfo> allPluginsPerKey) {
+ String base = plugin.getKey();
+ String parentKey = plugin.getBasePlugin();
+ while (!Strings.isNullOrEmpty(parentKey)) {
+ PluginInfo parentPlugin = allPluginsPerKey.get(parentKey);
+ base = parentPlugin.getKey();
+ parentKey = parentPlugin.getBasePlugin();
+ }
+ return base;
+ }
+
+ private URL fileToUrl(File file) {
+ try {
+ return file.toURI().toURL();
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginRepository.java b/sonar-core/src/main/java/org/sonar/core/platform/PluginRepository.java
index ad26ec2dae3..1b3b170a938 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginRepository.java
+++ b/sonar-core/src/main/java/org/sonar/core/platform/PluginRepository.java
@@ -17,32 +17,27 @@
* 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.platform;
+package org.sonar.core.platform;
import org.sonar.api.BatchComponent;
import org.sonar.api.Plugin;
import org.sonar.api.ServerComponent;
-import javax.annotation.CheckForNull;
import java.util.Collection;
+/**
+ * Provides information about the plugins installed in the dependency injection container
+ */
public interface PluginRepository extends BatchComponent, ServerComponent {
- @CheckForNull
- Plugin getPlugin(String key);
- /**
- * Metadata of installed plugins. Metadata includes all the fields available in update center
- * (plugin key, name, version, description, license, ...) and some technical information like
- * list of embedded libraries and classloader strategy.
- *
- * @since 2.9
- */
- Collection<PluginMetadata> getMetadata();
+ Collection<PluginInfo> getPluginInfos();
+
+ PluginInfo getPluginInfo(String key);
/**
- * Search for an installed plugin. Returns null if the plugin is not installed.
- * @since 2.9
+ * @return the instance of {@link Plugin} for the given plugin key. Never return null.
*/
- @CheckForNull
- PluginMetadata getMetadata(String pluginKey);
+ Plugin getPluginInstance(String key);
+
+ boolean hasPlugin(String key);
}
diff --git a/sonar-core/src/test/java/org/sonar/core/plugins/ResourcesClassloaderTest.java b/sonar-core/src/main/java/org/sonar/core/platform/PluginUnzipper.java
index e2f6dadd7a0..5ce1ca08da7 100644
--- a/sonar-core/src/test/java/org/sonar/core/plugins/ResourcesClassloaderTest.java
+++ b/sonar-core/src/main/java/org/sonar/core/platform/PluginUnzipper.java
@@ -17,24 +17,24 @@
* 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;
-package org.sonar.core.plugins;
+import org.sonar.api.utils.ZipUtils;
-import org.junit.Test;
+import java.util.zip.ZipEntry;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.List;
+public abstract class PluginUnzipper {
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.notNullValue;
+ protected static final String LIB_RELATIVE_PATH_IN_JAR = "META-INF/lib";
-public class ResourcesClassloaderTest {
+ public abstract UnzippedPlugin unzip(PluginInfo info);
- @Test
- public void test() throws Exception {
- List<URL> urls = Arrays.asList(new URL("http://localhost:9000/deploy/plugins/checkstyle/extension.xml"));
- ResourcesClassloader classLoader = new ResourcesClassloader(urls, null);
- assertThat(classLoader.findResource("extension.xml"), notNullValue());
+ protected ZipUtils.ZipEntryFilter newLibFilter() {
+ return new ZipUtils.ZipEntryFilter() {
+ @Override
+ public boolean accept(ZipEntry entry) {
+ return entry.getName().startsWith(LIB_RELATIVE_PATH_IN_JAR);
+ }
+ };
}
}
diff --git a/sonar-core/src/main/java/org/sonar/core/platform/UnzippedPlugin.java b/sonar-core/src/main/java/org/sonar/core/platform/UnzippedPlugin.java
new file mode 100644
index 00000000000..3c73b8d658b
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/platform/UnzippedPlugin.java
@@ -0,0 +1,62 @@
+/*
+ * 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 java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.apache.commons.io.FileUtils.listFiles;
+
+public class UnzippedPlugin {
+
+ private final String key;
+ private final File main;
+ private final Collection<File> libs;
+
+ public UnzippedPlugin(String key, File main, Collection<File> libs) {
+ this.key = key;
+ this.main = main;
+ this.libs = libs;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public File getMain() {
+ return main;
+ }
+
+ public Collection<File> getLibs() {
+ return libs;
+ }
+
+ public static UnzippedPlugin createFromUnzippedDir(String pluginKey, File jarFile, File unzippedDir) {
+ File libDir = new File(unzippedDir, PluginUnzipper.LIB_RELATIVE_PATH_IN_JAR);
+ Collection<File> libs;
+ if (libDir.isDirectory() && libDir.exists()) {
+ libs = listFiles(libDir, null, false);
+ } else {
+ libs = Collections.emptyList();
+ }
+ return new UnzippedPlugin(pluginKey, jarFile, libs);
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/SonarHomeTest.java b/sonar-core/src/main/java/org/sonar/core/platform/package-info.java
index 66a4069fba1..d93af63a5ba 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/SonarHomeTest.java
+++ b/sonar-core/src/main/java/org/sonar/core/platform/package-info.java
@@ -17,13 +17,11 @@
* 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.server.platform;
-import org.junit.Test;
-
-public class SonarHomeTest {
- @Test
- public void iDontKnowHowToSimplyTestThisClass() {
+/**
+ * Provides support of DI (Dependency Injection) container and management of plugins.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.core.platform;
- }
-}
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java b/sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java
deleted file mode 100644
index a65036b7d94..00000000000
--- a/sonar-core/src/main/java/org/sonar/core/plugins/DefaultPluginMetadata.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * 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.plugins;
-
-import com.google.common.collect.ImmutableList;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.updatecenter.common.Version;
-
-import java.io.File;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class DefaultPluginMetadata implements PluginMetadata, Comparable<PluginMetadata> {
- private File file;
- private List<File> deployedFiles;
- private List<String> pathsToInternalDeps;
- private String key;
- private String version;
- private String sonarVersion;
- private String name;
- private String mainClass;
- private String description;
- private String organization;
- private String organizationUrl;
- private String license;
- private String homepage;
- private String issueTrackerUrl;
- private boolean useChildFirstClassLoader;
- private String basePlugin;
- private boolean core;
- private String implementationBuild;
- private List<String> requiredPlugins;
-
- private DefaultPluginMetadata() {
- deployedFiles = newArrayList();
- pathsToInternalDeps = newArrayList();
- requiredPlugins = newArrayList();
- }
-
- public static DefaultPluginMetadata create(File file) {
- return new DefaultPluginMetadata().setFile(file);
- }
-
- public static DefaultPluginMetadata create(String key) {
- return new DefaultPluginMetadata().setKey(key);
- }
-
- @Override
- public File getFile() {
- return file;
- }
-
- public DefaultPluginMetadata setFile(File file) {
- this.file = file;
- return this;
- }
-
- @Override
- public List<File> getDeployedFiles() {
- return deployedFiles;
- }
-
- public DefaultPluginMetadata addDeployedFile(File f) {
- this.deployedFiles.add(f);
- return this;
- }
-
- public List<String> getPathsToInternalDeps() {
- return ImmutableList.copyOf(pathsToInternalDeps);
- }
-
- public DefaultPluginMetadata setPathsToInternalDeps(List<String> pathsToInternalDeps) {
- this.pathsToInternalDeps = ImmutableList.copyOf(pathsToInternalDeps);
- return this;
- }
-
- @Override
- public String getKey() {
- return key;
- }
-
- public DefaultPluginMetadata setKey(String key) {
- this.key = key;
- return this;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- public DefaultPluginMetadata setName(String name) {
- this.name = name;
- return this;
- }
-
- @Override
- public String getMainClass() {
- return mainClass;
- }
-
- public DefaultPluginMetadata setMainClass(String mainClass) {
- this.mainClass = mainClass;
- return this;
- }
-
- @Override
- public String getDescription() {
- return description;
- }
-
- public DefaultPluginMetadata setDescription(String description) {
- this.description = description;
- return this;
- }
-
- @Override
- public String getOrganization() {
- return organization;
- }
-
- public DefaultPluginMetadata setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- @Override
- public String getOrganizationUrl() {
- return organizationUrl;
- }
-
- public DefaultPluginMetadata setOrganizationUrl(String organizationUrl) {
- this.organizationUrl = organizationUrl;
- return this;
- }
-
- @Override
- public String getLicense() {
- return license;
- }
-
- public DefaultPluginMetadata setLicense(String license) {
- this.license = license;
- return this;
- }
-
- @Override
- public String getVersion() {
- return version;
- }
-
- public DefaultPluginMetadata setVersion(String version) {
- this.version = version;
- return this;
- }
-
- public String getSonarVersion() {
- return sonarVersion;
- }
-
- public DefaultPluginMetadata setSonarVersion(String sonarVersion) {
- this.sonarVersion = sonarVersion;
- return this;
- }
-
- @Override
- public List<String> getRequiredPlugins() {
- return ImmutableList.copyOf(requiredPlugins);
- }
-
- public DefaultPluginMetadata setRequiredPlugins(List<String> requiredPlugins) {
- this.requiredPlugins = ImmutableList.copyOf(requiredPlugins);
- return this;
- }
-
- /**
- * Find out if this plugin is compatible with a given version of Sonar.
- * The version of sonar must be greater than or equal to the minimal version
- * needed by the plugin.
- *
- * @param sonarVersion
- * @return <code>true</code> if the plugin is compatible
- */
- public boolean isCompatibleWith(String sonarVersion) {
- if (null == this.sonarVersion) {
- // Plugins without sonar version are so old, they are compatible with a version containing this code
- return true;
- }
-
- Version minimumVersion = Version.create(this.sonarVersion).removeQualifier();
- Version actualVersion = Version.create(sonarVersion).removeQualifier();
- return actualVersion.compareTo(minimumVersion) >= 0;
- }
-
- @Override
- public String getHomepage() {
- return homepage;
- }
-
- public DefaultPluginMetadata setHomepage(String homepage) {
- this.homepage = homepage;
- return this;
- }
-
- @Override
- public String getIssueTrackerUrl() {
- return issueTrackerUrl;
- }
-
- public DefaultPluginMetadata setIssueTrackerUrl(String issueTrackerUrl) {
- this.issueTrackerUrl = issueTrackerUrl;
- return this;
- }
-
- public DefaultPluginMetadata setUseChildFirstClassLoader(boolean use) {
- this.useChildFirstClassLoader = use;
- return this;
- }
-
- @Override
- public boolean isUseChildFirstClassLoader() {
- return useChildFirstClassLoader;
- }
-
- public DefaultPluginMetadata setBasePlugin(String key) {
- this.basePlugin = key;
- return this;
- }
-
- @Override
- public String getBasePlugin() {
- return basePlugin;
- }
-
- @Override
- public boolean isCore() {
- return core;
- }
-
- public DefaultPluginMetadata setCore(boolean b) {
- this.core = b;
- return this;
- }
-
- @Override
- public String getImplementationBuild() {
- return implementationBuild;
- }
-
- public DefaultPluginMetadata setImplementationBuild(String implementationBuild) {
- this.implementationBuild = implementationBuild;
- return this;
- }
-
- @Override
- public String getParent() {
- return null;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- DefaultPluginMetadata that = (DefaultPluginMetadata) o;
- return key == null ? that.key == null : key.equals(that.key);
- }
-
- @Override
- public int hashCode() {
- return key != null ? key.hashCode() : 0;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
- .append("key", key)
- .append("version", StringUtils.defaultIfEmpty(version, "-"))
- .toString();
- }
-
- @Override
- public int compareTo(PluginMetadata other) {
- return name.compareTo(other.getName());
- }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/plugins/PluginClassloaders.java b/sonar-core/src/main/java/org/sonar/core/plugins/PluginClassloaders.java
deleted file mode 100644
index 8a6b4b88ef1..00000000000
--- a/sonar-core/src/main/java/org/sonar/core/plugins/PluginClassloaders.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * 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.plugins;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.SystemUtils;
-import org.codehaus.plexus.classworlds.ClassWorld;
-import org.codehaus.plexus.classworlds.realm.ClassRealm;
-import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.Plugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.utils.SonarException;
-
-import java.io.File;
-import java.net.URL;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Encapsulates manipulations with ClassLoaders, such as creation and establishing dependencies. Current implementation based on
- * {@link ClassWorld}.
- * <p/>
- * <h3>IMPORTANT</h3>
- * <p>
- * If we have pluginA , then all classes and resources from package and subpackages of <b>org.sonar.plugins.pluginA.api</b> will be visible
- * for all other plugins even if they are located in dependent library.
- * </p>
- * <p/>
- * <h4>Search order for {@link ClassRealm} :</h4>
- * <ul>
- * <li>parent class loader (passed via the constructor) if there is one</li>
- * <li>imports</li>
- * <li>realm's constituents</li>
- * <li>parent realm</li>
- * </ul>
- */
-public class PluginClassloaders {
-
- private static final String[] PREFIXES_TO_EXPORT = {"org.sonar.plugins.", "com.sonar.plugins.", "com.sonarsource.plugins."};
- private static final Logger LOG = LoggerFactory.getLogger(PluginClassloaders.class);
-
- private ClassWorld world;
- private ClassLoader baseClassloader;
- private boolean done = false;
-
- public PluginClassloaders(ClassLoader baseClassloader) {
- this(baseClassloader, new ClassWorld());
- }
-
- @VisibleForTesting
- PluginClassloaders(ClassLoader baseClassloader, ClassWorld world) {
- this.baseClassloader = baseClassloader;
- this.world = world;
- }
-
- public Map<String, Plugin> init(Collection<PluginMetadata> plugins) {
- List<PluginMetadata> children = Lists.newArrayList();
- for (PluginMetadata plugin : plugins) {
- if (StringUtils.isBlank(plugin.getBasePlugin())) {
- add(plugin);
- } else {
- children.add(plugin);
- }
- }
-
- for (PluginMetadata child : children) {
- extend(child);
- }
-
- done();
-
- Map<String, Plugin> pluginsByKey = Maps.newHashMap();
- for (PluginMetadata metadata : plugins) {
- pluginsByKey.put(metadata.getKey(), instantiatePlugin(metadata));
- }
- return pluginsByKey;
- }
-
- public ClassLoader add(PluginMetadata plugin) {
- if (done) {
- throw new IllegalStateException("Plugin classloaders are already initialized");
- }
- try {
- List<URL> resources = Lists.newArrayList();
- List<URL> others = Lists.newArrayList();
- for (File file : plugin.getDeployedFiles()) {
- if (isResource(file)) {
- resources.add(file.toURI().toURL());
- } else {
- others.add(file.toURI().toURL());
- }
- }
- ClassLoader parent;
- if (resources.isEmpty()) {
- parent = baseClassloader;
- } else {
- parent = new ResourcesClassloader(resources, baseClassloader);
- }
- ClassRealm realm;
- if (plugin.isUseChildFirstClassLoader()) {
- ClassRealm parentRealm = world.newRealm(plugin.getKey() + "-parent", parent);
- realm = parentRealm.createChildRealm(plugin.getKey());
- } else {
- realm = world.newRealm(plugin.getKey(), parent);
- }
- for (URL url : others) {
- realm.addURL(url);
- }
- return realm;
- } catch (UnsupportedClassVersionError e) {
- throw new SonarException(String.format("The plugin %s is not supported with Java %s", plugin.getKey(),
- SystemUtils.JAVA_VERSION_TRIMMED), e);
-
- } catch (Exception e) {
- throw new SonarException(String.format("Fail to build the classloader of %s", plugin.getKey()), e);
- }
- }
-
- public boolean extend(PluginMetadata plugin) {
- if (done) {
- throw new IllegalStateException("Plugin classloaders are already initialized");
- }
- try {
- ClassRealm base = world.getRealm(plugin.getBasePlugin());
- if (base == null) {
- // Ignored, because base plugin is not installed
- LOG.warn(String.format("Plugin %s is ignored because base plugin is not installed: %s",
- plugin.getKey(), plugin.getBasePlugin()));
- return false;
- }
- // we create new realm to be able to return it by key without conversion to baseKey
- base.createChildRealm(plugin.getKey());
- for (File file : plugin.getDeployedFiles()) {
- base.addURL(file.toURI().toURL());
- }
- return true;
- } catch (UnsupportedClassVersionError e) {
- throw new SonarException(String.format("The plugin %s is not supported with Java %s",
- plugin.getKey(), SystemUtils.JAVA_VERSION_TRIMMED), e);
-
- } catch (Exception e) {
- throw new SonarException(String.format("Fail to extend the plugin %s for %s",
- plugin.getBasePlugin(), plugin.getKey()), e);
- }
- }
-
- /**
- * Establishes dependencies among ClassLoaders.
- */
- public void done() {
- if (done) {
- throw new IllegalStateException("Plugin classloaders are already initialized");
- }
- for (Object o : world.getRealms()) {
- ClassRealm realm = (ClassRealm) o;
- if (!StringUtils.endsWith(realm.getId(), "-parent")) {
- String[] packagesToExport = new String[PREFIXES_TO_EXPORT.length];
- for (int i = 0; i < PREFIXES_TO_EXPORT.length; i++) {
- // important to have dot at the end of package name only for classworlds 1.1
- packagesToExport[i] = String.format("%s%s.api", PREFIXES_TO_EXPORT[i], realm.getId());
- }
- export(realm, packagesToExport);
- }
- }
- done = true;
- }
-
- /**
- * Exports specified packages from given ClassRealm to all others.
- */
- private void export(ClassRealm realm, String... packages) {
- for (Object o : world.getRealms()) {
- ClassRealm dep = (ClassRealm) o;
- if (!StringUtils.equals(dep.getId(), realm.getId())) {
- try {
- for (String packageName : packages) {
- dep.importFrom(realm.getId(), packageName);
- }
- } catch (NoSuchRealmException e) {
- // should never happen
- throw new SonarException(e);
- }
- }
- }
- }
-
- /**
- * Note that this method should be called only after creation of all ClassLoaders - see {@link #done()}.
- */
- public ClassLoader get(String key) {
- if (!done) {
- throw new IllegalStateException("Plugin classloaders are not initialized");
- }
- try {
- return world.getRealm(key);
- } catch (NoSuchRealmException e) {
- return null;
- }
- }
-
- public Plugin instantiatePlugin(PluginMetadata plugin) {
- try {
- Class clazz = get(plugin.getKey()).loadClass(plugin.getMainClass());
- return (Plugin) clazz.newInstance();
-
- } catch (UnsupportedClassVersionError e) {
- throw new SonarException(String.format("The plugin %s is not supported with Java %s",
- plugin.getKey(), SystemUtils.JAVA_VERSION_TRIMMED), e);
-
- } catch (Exception e) {
- throw new SonarException(String.format("Fail to load plugin %s", plugin.getKey()), e);
- }
- }
-
- private boolean isResource(File file) {
- return !StringUtils.endsWithIgnoreCase(file.getName(), ".jar") && !file.isDirectory();
- }
-
- public void clean() {
- for (ClassRealm realm : world.getRealms()) {
- try {
- world.disposeRealm(realm.getId());
- } catch (Exception e) {
- // Ignore
- }
- }
- world = null;
- baseClassloader=null;
- }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/plugins/PluginJarInstaller.java b/sonar-core/src/main/java/org/sonar/core/plugins/PluginJarInstaller.java
deleted file mode 100644
index 7c5114a323b..00000000000
--- a/sonar-core/src/main/java/org/sonar/core/plugins/PluginJarInstaller.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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.plugins;
-
-import com.google.common.base.Function;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.ServerComponent;
-import org.sonar.api.utils.SonarException;
-import org.sonar.updatecenter.common.PluginManifest;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-
-public abstract class PluginJarInstaller implements BatchComponent, ServerComponent {
-
- protected static final String FAIL_TO_INSTALL_PLUGIN = "Fail to install plugin: ";
-
- protected void install(DefaultPluginMetadata metadata, @Nullable File pluginBasedir, File deployedPlugin) {
- try {
- metadata.addDeployedFile(deployedPlugin);
- copyDependencies(metadata, deployedPlugin, pluginBasedir);
- } catch (IOException e) {
- throw new SonarException(FAIL_TO_INSTALL_PLUGIN + metadata, e);
- }
- }
-
- private void copyDependencies(DefaultPluginMetadata metadata, File pluginFile, @Nullable File pluginBasedir) throws IOException {
- if (!metadata.getPathsToInternalDeps().isEmpty()) {
- // needs to unzip the jar
- File baseDir = extractPluginDependencies(pluginFile, pluginBasedir);
- for (String depPath : metadata.getPathsToInternalDeps()) {
- File dependency = new File(baseDir, depPath);
- if (!dependency.isFile() || !dependency.exists()) {
- throw new IllegalArgumentException("Dependency " + depPath + " can not be found in " + pluginFile.getName());
- }
- metadata.addDeployedFile(dependency);
- }
- }
- }
-
- protected abstract File extractPluginDependencies(File pluginFile, @Nullable File pluginBasedir) throws IOException;
-
- public DefaultPluginMetadata extractMetadata(File file, boolean isCore) {
- try {
- PluginManifest manifest = new PluginManifest(file);
- DefaultPluginMetadata metadata = DefaultPluginMetadata.create(file);
- metadata.setKey(manifest.getKey());
- metadata.setName(manifest.getName());
- metadata.setDescription(manifest.getDescription());
- metadata.setLicense(manifest.getLicense());
- metadata.setOrganization(manifest.getOrganization());
- metadata.setOrganizationUrl(manifest.getOrganizationUrl());
- metadata.setMainClass(manifest.getMainClass());
- metadata.setVersion(manifest.getVersion());
- metadata.setSonarVersion(manifest.getSonarVersion());
- metadata.setHomepage(manifest.getHomepage());
- metadata.setIssueTrackerUrl(manifest.getIssueTrackerUrl());
- metadata.setPathsToInternalDeps(Arrays.asList(manifest.getDependencies()));
- metadata.setUseChildFirstClassLoader(manifest.isUseChildFirstClassLoader());
- metadata.setBasePlugin(manifest.getBasePlugin());
- metadata.setImplementationBuild(manifest.getImplementationBuild());
- metadata.setRequiredPlugins(Arrays.asList(manifest.getRequirePlugins()));
- metadata.setCore(isCore);
- return metadata;
-
- } catch (IOException e) {
- throw new IllegalStateException("Fail to extract plugin metadata from file: " + file, e);
- }
- }
-
- public Function<File, DefaultPluginMetadata> fileToPlugin() {
- return jarFileToPlugin;
- }
-
- public Function<File, DefaultPluginMetadata> fileToCorePlugin() {
- return jarFileToCorePlugin;
- }
-
- private final Function<File, DefaultPluginMetadata> jarFileToCorePlugin = new Function<File, DefaultPluginMetadata>() {
- @Override
- public DefaultPluginMetadata apply(@Nonnull File file) {
- return extractMetadata(file, true);
- }
- };
- private final Function<File, DefaultPluginMetadata> jarFileToPlugin = new Function<File, DefaultPluginMetadata>() {
- @Override
- public DefaultPluginMetadata apply(@Nonnull File file) {
- return extractMetadata(file, false);
- }
- };
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/plugins/RemotePlugin.java b/sonar-core/src/main/java/org/sonar/core/plugins/RemotePlugin.java
index 3bc254a3ff1..6fecfe0ae91 100644
--- a/sonar-core/src/main/java/org/sonar/core/plugins/RemotePlugin.java
+++ b/sonar-core/src/main/java/org/sonar/core/plugins/RemotePlugin.java
@@ -20,6 +20,7 @@
package org.sonar.core.plugins;
import org.apache.commons.lang.StringUtils;
+import org.sonar.core.platform.PluginInfo;
import org.sonar.home.cache.FileHashes;
import java.io.File;
@@ -34,7 +35,7 @@ public class RemotePlugin {
this.core = core;
}
- public static RemotePlugin create(DefaultPluginMetadata metadata) {
+ public static RemotePlugin create(PluginInfo metadata) {
RemotePlugin result = new RemotePlugin(metadata.getKey(), metadata.isCore());
result.setFile(metadata.getFile());
return result;
diff --git a/sonar-core/src/main/java/org/sonar/core/plugins/package-info.java b/sonar-core/src/main/java/org/sonar/core/plugins/package-info.java
index d3208e7de69..e95a48da83b 100644
--- a/sonar-core/src/main/java/org/sonar/core/plugins/package-info.java
+++ b/sonar-core/src/main/java/org/sonar/core/plugins/package-info.java
@@ -17,9 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
+
@ParametersAreNonnullByDefault
package org.sonar.core.plugins;
diff --git a/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java b/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java
index b3acbde594a..110694aff65 100644
--- a/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java
@@ -24,10 +24,10 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
import java.net.URL;
import java.net.URLClassLoader;
@@ -51,8 +51,8 @@ public class DefaultI18nTest {
@Before
public void before() {
PluginRepository pluginRepository = mock(PluginRepository.class);
- List<PluginMetadata> plugins = Arrays.asList(newPlugin("core"), newPlugin("sqale"), newPlugin("frpack"), newPlugin("checkstyle"), newPlugin("other"));
- when(pluginRepository.getMetadata()).thenReturn(plugins);
+ List<PluginInfo> plugins = Arrays.asList(newPlugin("core"), newPlugin("sqale"), newPlugin("frpack"), newPlugin("checkstyle"), newPlugin("other"));
+ when(pluginRepository.getPluginInfos()).thenReturn(plugins);
manager = new DefaultI18n(pluginRepository, system2);
manager.doStart(getClass().getClassLoader());
@@ -222,8 +222,8 @@ public class DefaultI18nTest {
return new URLClassLoader(urls);
}
- private PluginMetadata newPlugin(String key) {
- PluginMetadata plugin = mock(PluginMetadata.class);
+ private PluginInfo newPlugin(String key) {
+ PluginInfo plugin = mock(PluginInfo.class);
when(plugin.getKey()).thenReturn(key);
return plugin;
}
diff --git a/sonar-core/src/test/java/org/sonar/core/i18n/I18nClassloaderTest.java b/sonar-core/src/test/java/org/sonar/core/i18n/I18nClassloaderTest.java
index 971a7573965..19f9add77cc 100644
--- a/sonar-core/src/test/java/org/sonar/core/i18n/I18nClassloaderTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/i18n/I18nClassloaderTest.java
@@ -24,7 +24,7 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.platform.PluginRepository;
+import org.sonar.core.platform.PluginRepository;
import java.net.URL;
import java.net.URLClassLoader;
@@ -80,7 +80,7 @@ public class I18nClassloaderTest {
private static URLClassLoader newClassLoader(String... resourcePaths) {
URL[] urls = new URL[resourcePaths.length];
for (int index = 0; index < resourcePaths.length; index++) {
- urls[index] = DefaultI18nTest.class.getResource(resourcePaths[index]);
+ urls[index] = I18nClassloaderTest.class.getResource(resourcePaths[index]);
}
return new URLClassLoader(urls);
}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java b/sonar-core/src/test/java/org/sonar/core/platform/ComponentContainerTest.java
index 8cbe1f5d3b4..5d7923d23bd 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentContainerTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/platform/ComponentContainerTest.java
@@ -17,7 +17,7 @@
* 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.platform;
+package org.sonar.core.platform;
import org.junit.Rule;
import org.junit.Test;
@@ -31,7 +31,9 @@ import java.util.Arrays;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
public class ComponentContainerTest {
@@ -165,7 +167,7 @@ public class ComponentContainerTest {
@Test
public void shouldDeclareExtensionWithoutAddingIt() {
ComponentContainer container = new ComponentContainer();
- PluginMetadata plugin = mock(PluginMetadata.class);
+ PluginInfo plugin = mock(PluginInfo.class);
container.declareExtension(plugin, ComponentWithProperty.class);
PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
@@ -176,7 +178,7 @@ public class ComponentContainerTest {
@Test
public void shouldDeclareExtensionWhenAdding() {
ComponentContainer container = new ComponentContainer();
- PluginMetadata plugin = mock(PluginMetadata.class);
+ PluginInfo plugin = mock(PluginInfo.class);
container.addExtension(plugin, ComponentWithProperty.class);
PropertyDefinitions propertyDefinitions = container.getComponentByType(PropertyDefinitions.class);
@@ -221,12 +223,12 @@ public class ComponentContainerTest {
@Test
public void display_plugin_name_when_failing_to_add_extension() {
ComponentContainer container = new ComponentContainer();
- PluginMetadata plugin = mock(PluginMetadata.class);
+ PluginInfo plugin = mock(PluginInfo.class);
container.startComponents();
thrown.expect(IllegalStateException.class);
- thrown.expectMessage("Unable to register extension org.sonar.api.platform.ComponentContainerTest$UnstartableComponent");
+ thrown.expectMessage("Unable to register extension org.sonar.core.platform.ComponentContainerTest$UnstartableComponent");
container.addExtension(plugin, UnstartableComponent.class);
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentKeysTest.java b/sonar-core/src/test/java/org/sonar/core/platform/ComponentKeysTest.java
index f2b36a677fe..431890bc012 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/platform/ComponentKeysTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/platform/ComponentKeysTest.java
@@ -17,13 +17,16 @@
* 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.platform;
+package org.sonar.core.platform;
import org.junit.Test;
import org.sonar.api.utils.log.Logger;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.*;
+import static org.mockito.Matchers.startsWith;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
public class ComponentKeysTest {
@@ -35,8 +38,8 @@ public class ComponentKeysTest {
}
@Test
- public void generate_key_of_object() {
- assertThat(keys.of(new FakeComponent())).isEqualTo("org.sonar.api.platform.ComponentKeysTest.FakeComponent-fake");
+ public void generate_key_of_object() throws Exception {
+ assertThat(keys.of(new FakeComponent())).isEqualTo("org.sonar.core.platform.ComponentKeysTest.FakeComponent-fake");
}
@Test
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/platform/PicoUtilsTest.java b/sonar-core/src/test/java/org/sonar/core/platform/PicoUtilsTest.java
index d5b74341b8b..67b488584a9 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/platform/PicoUtilsTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/platform/PicoUtilsTest.java
@@ -17,7 +17,7 @@
* 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.platform;
+package org.sonar.core.platform;
import org.junit.Test;
import org.picocontainer.Characteristics;
@@ -29,8 +29,8 @@ import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
-
public class PicoUtilsTest {
+
@Test
public void shouldSanitizePicoLifecycleException() {
Throwable th = PicoUtils.sanitize(newPicoLifecycleException(false));
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/PluginInfoTest.java b/sonar-core/src/test/java/org/sonar/core/platform/PluginInfoTest.java
new file mode 100644
index 00000000000..2b702748c4b
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/platform/PluginInfoTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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 org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.ManifestUtils;
+import org.sonar.updatecenter.common.PluginManifest;
+import org.sonar.updatecenter.common.Version;
+
+import javax.annotation.Nullable;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.jar.Manifest;
+
+import static com.google.common.collect.Ordering.natural;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+public class PluginInfoTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void test_RequiredPlugin() throws Exception {
+ PluginInfo.RequiredPlugin plugin = PluginInfo.RequiredPlugin.parse("java:1.1");
+ assertThat(plugin.getKey()).isEqualTo("java");
+ assertThat(plugin.getMinimalVersion().getName()).isEqualTo("1.1");
+
+ try {
+ PluginInfo.RequiredPlugin.parse("java");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ // ok
+ }
+ }
+
+ @Test
+ public void test_compare() {
+ PluginInfo java1 = new PluginInfo("java").setName("Java").setVersion(Version.create("1.0"));
+ PluginInfo java2 = new PluginInfo("java").setName("Java").setVersion(Version.create("2.0"));
+ PluginInfo cobol = new PluginInfo("cobol").setName("Cobol").setVersion(Version.create("1.0"));
+ List<PluginInfo> plugins = Arrays.asList(java1, java2, cobol);
+ Collections.shuffle(plugins);
+
+ List<PluginInfo> ordered = natural().sortedCopy(plugins);
+ assertThat(ordered.get(0)).isSameAs(cobol);
+ assertThat(ordered.get(1)).isSameAs(java1);
+ assertThat(ordered.get(2)).isSameAs(java2);
+ }
+
+ @Test
+ public void test_compatibility_with_sq_version() {
+ assertThat(withMinSqVersion("1.1").isCompatibleWith("1.1")).isTrue();
+ assertThat(withMinSqVersion("1.1").isCompatibleWith("1.1.0")).isTrue();
+ assertThat(withMinSqVersion("1.0").isCompatibleWith("1.0.0")).isTrue();
+
+ assertThat(withMinSqVersion("1.0").isCompatibleWith("1.1")).isTrue();
+ assertThat(withMinSqVersion("1.1.1").isCompatibleWith("1.1.2")).isTrue();
+ assertThat(withMinSqVersion("2.0").isCompatibleWith("2.1.0")).isTrue();
+ assertThat(withMinSqVersion("3.2").isCompatibleWith("3.2-RC1")).isTrue();
+ assertThat(withMinSqVersion("3.2").isCompatibleWith("3.2-RC2")).isTrue();
+ assertThat(withMinSqVersion("3.2").isCompatibleWith("3.1-RC2")).isFalse();
+
+ assertThat(withMinSqVersion("1.1").isCompatibleWith("1.0")).isFalse();
+ assertThat(withMinSqVersion("2.0.1").isCompatibleWith("2.0.0")).isFalse();
+ assertThat(withMinSqVersion("2.10").isCompatibleWith("2.1")).isFalse();
+ assertThat(withMinSqVersion("10.10").isCompatibleWith("2.2")).isFalse();
+
+ assertThat(withMinSqVersion("1.1-SNAPSHOT").isCompatibleWith("1.0")).isFalse();
+ assertThat(withMinSqVersion("1.1-SNAPSHOT").isCompatibleWith("1.1")).isTrue();
+ assertThat(withMinSqVersion("1.1-SNAPSHOT").isCompatibleWith("1.2")).isTrue();
+ assertThat(withMinSqVersion("1.0.1-SNAPSHOT").isCompatibleWith("1.0")).isFalse();
+
+ assertThat(withMinSqVersion("3.1-RC2").isCompatibleWith("3.2-SNAPSHOT")).isTrue();
+ assertThat(withMinSqVersion("3.1-RC1").isCompatibleWith("3.2-RC2")).isTrue();
+ assertThat(withMinSqVersion("3.1-RC1").isCompatibleWith("3.1-RC2")).isTrue();
+
+ assertThat(withMinSqVersion(null).isCompatibleWith("0")).isTrue();
+ assertThat(withMinSqVersion(null).isCompatibleWith("3.1")).isTrue();
+ }
+
+ @Test
+ public void create_from_minimal_manifest() throws Exception {
+ PluginManifest manifest = new PluginManifest();
+ manifest.setKey("java");
+ manifest.setVersion("1.0");
+ manifest.setName("Java");
+ manifest.setMainClass("org.foo.FooPlugin");
+
+ File jarFile = temp.newFile();
+ PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest);
+
+ assertThat(pluginInfo.getKey()).isEqualTo("java");
+ assertThat(pluginInfo.getName()).isEqualTo("Java");
+ assertThat(pluginInfo.getVersion().getName()).isEqualTo("1.0");
+ assertThat(pluginInfo.getFile()).isSameAs(jarFile);
+ assertThat(pluginInfo.getMainClass()).isEqualTo("org.foo.FooPlugin");
+
+ // optional fields
+ assertThat(pluginInfo.getBasePlugin()).isNull();
+ assertThat(pluginInfo.getDescription()).isNull();
+ assertThat(pluginInfo.getHomepageUrl()).isNull();
+ assertThat(pluginInfo.getImplementationBuild()).isNull();
+ assertThat(pluginInfo.getIssueTrackerUrl()).isNull();
+ assertThat(pluginInfo.getLicense()).isNull();
+ assertThat(pluginInfo.getOrganizationName()).isNull();
+ assertThat(pluginInfo.getOrganizationUrl()).isNull();
+ assertThat(pluginInfo.getMinimalSqVersion()).isNull();
+ assertThat(pluginInfo.getRequiredPlugins()).isEmpty();
+ }
+
+ @Test
+ public void create_from_complete_manifest() throws Exception {
+ PluginManifest manifest = new PluginManifest();
+ manifest.setKey("fbcontrib");
+ manifest.setVersion("2.0");
+ manifest.setName("Java");
+ manifest.setMainClass("org.fb.FindbugsPlugin");
+ manifest.setBasePlugin("findbugs");
+ manifest.setSonarVersion("4.5.1");
+ manifest.setDescription("the desc");
+ manifest.setHomepage("http://fbcontrib.org");
+ manifest.setImplementationBuild("SHA1");
+ manifest.setLicense("LGPL");
+ manifest.setOrganization("SonarSource");
+ manifest.setOrganizationUrl("http://sonarsource.com");
+ manifest.setIssueTrackerUrl("http://jira.com");
+ manifest.setRequirePlugins(new String[]{"java:2.0", "pmd:1.3"});
+
+ File jarFile = temp.newFile();
+ PluginInfo pluginInfo = PluginInfo.create(jarFile, manifest);
+
+ assertThat(pluginInfo.getBasePlugin()).isEqualTo("findbugs");
+ assertThat(pluginInfo.getDescription()).isEqualTo("the desc");
+ assertThat(pluginInfo.getHomepageUrl()).isEqualTo("http://fbcontrib.org");
+ assertThat(pluginInfo.getImplementationBuild()).isEqualTo("SHA1");
+ assertThat(pluginInfo.getIssueTrackerUrl()).isEqualTo("http://jira.com");
+ assertThat(pluginInfo.getLicense()).isEqualTo("LGPL");
+ assertThat(pluginInfo.getOrganizationName()).isEqualTo("SonarSource");
+ assertThat(pluginInfo.getOrganizationUrl()).isEqualTo("http://sonarsource.com");
+ assertThat(pluginInfo.getMinimalSqVersion().getName()).isEqualTo("4.5.1");
+ assertThat(pluginInfo.getRequiredPlugins()).extracting("key").containsExactly("java", "pmd");
+ }
+
+ @Test
+ public void create_from_file() throws Exception {
+ File checkstyleJar = FileUtils.toFile(getClass().getResource("/org/sonar/core/plugins/sonar-checkstyle-plugin-2.8.jar"));
+ PluginInfo checkstyleInfo = PluginInfo.create(checkstyleJar);
+
+ assertThat(checkstyleInfo.getName()).isEqualTo("Checkstyle");
+ assertThat(checkstyleInfo.getMinimalSqVersion()).isEqualTo(Version.create("2.8"));
+ }
+
+ @Test
+ public void test_toString() throws Exception {
+ PluginInfo pluginInfo = new PluginInfo().setKey("java").setVersion(Version.create("1.1"));
+ assertThat(pluginInfo.toString()).isEqualTo("[java / 1.1]");
+
+ pluginInfo.setImplementationBuild("SHA1");
+ assertThat(pluginInfo.toString()).isEqualTo("[java / 1.1 / SHA1]");
+ }
+
+ @Test
+ public void isCore() throws Exception {
+ PluginInfo pluginInfo = new PluginInfo();
+ assertThat(pluginInfo.isCore()).isFalse();
+
+ pluginInfo.setCore(true);
+ assertThat(pluginInfo.isCore()).isTrue();
+ }
+
+ static PluginInfo withMinSqVersion(@Nullable String version) {
+ PluginInfo pluginInfo = new PluginInfo("foo");
+ if (version != null) {
+ pluginInfo.setMinimalSqVersion(Version.create(version));
+ }
+ return pluginInfo;
+ }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/PluginLoaderTest.java b/sonar-core/src/test/java/org/sonar/core/platform/PluginLoaderTest.java
new file mode 100644
index 00000000000..7cb984b1bda
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/platform/PluginLoaderTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.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 complete_test() throws Exception {
+ 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 TempPluginUnzipper());
+ 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());
+ // should test that classloaders are closed
+ }
+
+ @Test
+ public void define_plugin_classloader__nominal() throws Exception {
+ PluginInfo info = new PluginInfo("foo")
+ .setName("Foo")
+ .setMainClass("org.foo.FooPlugin");
+ File jarFile = temp.newFile();
+ info.setFile(jarFile);
+
+ PluginLoader loader = new PluginLoader(new BasicPluginUnzipper());
+ Map<String, PluginLoader.ClassloaderDef> defs = loader.defineClassloaders(ImmutableMap.of("foo", info));
+
+ assertThat(defs).containsOnlyKeys("foo");
+ PluginLoader.ClassloaderDef def = defs.get("foo");
+ assertThat(def.basePluginKey).isEqualTo("foo");
+ assertThat(def.selfFirstStrategy).isFalse();
+ assertThat(def.files).containsOnly(jarFile);
+ assertThat(def.mainClassesByPluginKey).containsOnly(MapEntry.entry("foo", "org.foo.FooPlugin"));
+ // TODO test mask - require change in sonar-classloader
+ }
+
+ @Test
+ public void define_plugin_classloader__extend_base_plugin() throws Exception {
+ File baseJarFile = temp.newFile(), extensionJarFile = temp.newFile();
+ PluginInfo base = new PluginInfo("foo")
+ .setName("Foo")
+ .setMainClass("org.foo.FooPlugin")
+ .setFile(baseJarFile);
+ PluginInfo extension = new PluginInfo("fooContrib")
+ .setName("Foo Contrib")
+ .setMainClass("org.foo.ContribPlugin")
+ .setFile(extensionJarFile)
+ .setBasePlugin("foo")
+
+ // not a base plugin, can't override base metadata -> will be ignored
+ .setUseChildFirstClassLoader(true);
+
+ PluginLoader loader = new PluginLoader(new BasicPluginUnzipper());
+ Map<String, PluginLoader.ClassloaderDef> defs = loader.defineClassloaders(ImmutableMap.of("foo", base, "fooContrib", extension));
+
+ assertThat(defs).containsOnlyKeys("foo");
+ PluginLoader.ClassloaderDef def = defs.get("foo");
+ assertThat(def.basePluginKey).isEqualTo("foo");
+ assertThat(def.selfFirstStrategy).isFalse();
+ assertThat(def.files).containsOnly(baseJarFile, extensionJarFile);
+ assertThat(def.mainClassesByPluginKey).containsOnly(MapEntry.entry("foo", "org.foo.FooPlugin"), entry("fooContrib", "org.foo.ContribPlugin"));
+ // TODO test mask - require change in sonar-classloader
+ }
+
+ /**
+ * Does not unzip jar file.
+ */
+ private class BasicPluginUnzipper extends PluginUnzipper {
+ @Override
+ public UnzippedPlugin unzip(PluginInfo info) {
+ return new UnzippedPlugin(info.getKey(), info.getFile(), Collections.<File>emptyList());
+ }
+ }
+
+ private class TempPluginUnzipper extends PluginUnzipper {
+ @Override
+ public UnzippedPlugin unzip(PluginInfo info) {
+ try {
+ File tempDir = temp.newFolder();
+ ZipUtils.unzip(info.getFile(), tempDir, newLibFilter());
+ return UnzippedPlugin.createFromUnzippedDir(info.getKey(), info.getFile(), tempDir);
+
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/platform/PluginUnzipperTest.java b/sonar-core/src/test/java/org/sonar/core/platform/PluginUnzipperTest.java
new file mode 100644
index 00000000000..cbdd9c23356
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/platform/PluginUnzipperTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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 org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.ZipUtils;
+
+import java.io.File;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class PluginUnzipperTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Test
+ public void unzip_plugin_with_libs() throws Exception {
+ final File jarFile = getFile("sonar-checkstyle-plugin-2.8.jar");
+ final File toDir = temp.newFolder();
+ PluginInfo pluginInfo = new PluginInfo().setKey("checkstyle").setFile(jarFile);
+
+ PluginUnzipper unzipper = new PluginUnzipper() {
+ @Override
+ public UnzippedPlugin unzip(PluginInfo info) {
+ try {
+ ZipUtils.unzip(jarFile, toDir, newLibFilter());
+ return UnzippedPlugin.createFromUnzippedDir(info.getKey(), info.getFile(), toDir);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ };
+ UnzippedPlugin unzipped = unzipper.unzip(pluginInfo);
+ assertThat(unzipped.getKey()).isEqualTo("checkstyle");
+ assertThat(unzipped.getLibs()).extracting("name").containsOnly("antlr-2.7.6.jar", "checkstyle-5.1.jar", "commons-cli-1.0.jar");
+ assertThat(unzipped.getMain()).isSameAs(jarFile);
+ }
+
+ @Test
+ public void unzip_plugin_without_libs() throws Exception {
+ File jarFile = temp.newFile();
+ final File toDir = temp.newFolder();
+ PluginInfo pluginInfo = new PluginInfo().setFile(jarFile);
+
+ PluginUnzipper unzipper = new PluginUnzipper() {
+ @Override
+ public UnzippedPlugin unzip(PluginInfo info) {
+ return UnzippedPlugin.createFromUnzippedDir("foo", info.getFile(), toDir);
+ }
+ };
+ UnzippedPlugin unzipped = unzipper.unzip(pluginInfo);
+ assertThat(unzipped.getKey()).isEqualTo("foo");
+ assertThat(unzipped.getLibs()).isEmpty();
+ assertThat(unzipped.getMain()).isSameAs(jarFile);
+ }
+
+ private File getFile(String filename) {
+ return FileUtils.toFile(getClass().getResource("/org/sonar/core/plugins/" + filename));
+ }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/plugins/DefaultPluginMetadataTest.java b/sonar-core/src/test/java/org/sonar/core/plugins/DefaultPluginMetadataTest.java
deleted file mode 100644
index 98cdf2698b6..00000000000
--- a/sonar-core/src/test/java/org/sonar/core/plugins/DefaultPluginMetadataTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.plugins;
-
-import org.junit.Test;
-import org.sonar.api.platform.PluginMetadata;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Ordering.natural;
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DefaultPluginMetadataTest {
-
- @Test
- public void testGettersAndSetters() {
- DefaultPluginMetadata metadata = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar"));
- metadata.setKey("checkstyle")
- .setLicense("LGPL")
- .setDescription("description")
- .setHomepage("http://home")
- .setIssueTrackerUrl("http://jira.codehuas.org")
- .setMainClass("org.Main")
- .setOrganization("SonarSource")
- .setOrganizationUrl("http://sonarsource.org")
- .setVersion("1.1")
- .setSonarVersion("3.0")
- .setUseChildFirstClassLoader(true)
- .setCore(false)
- .setImplementationBuild("abcdef");
-
- assertThat(metadata.getKey()).isEqualTo("checkstyle");
- assertThat(metadata.getParent()).isNull();
- assertThat(metadata.getLicense()).isEqualTo("LGPL");
- assertThat(metadata.getDescription()).isEqualTo("description");
- assertThat(metadata.getHomepage()).isEqualTo("http://home");
- assertThat(metadata.getIssueTrackerUrl()).isEqualTo("http://jira.codehuas.org");
- assertThat(metadata.getMainClass()).isEqualTo("org.Main");
- assertThat(metadata.getOrganization()).isEqualTo("SonarSource");
- assertThat(metadata.getOrganizationUrl()).isEqualTo("http://sonarsource.org");
- assertThat(metadata.getVersion()).isEqualTo("1.1");
- assertThat(metadata.getSonarVersion()).isEqualTo("3.0");
- assertThat(metadata.isUseChildFirstClassLoader()).isTrue();
- assertThat(metadata.isCore()).isFalse();
- assertThat(metadata.getBasePlugin()).isNull();
- assertThat(metadata.getFile()).isNotNull();
- assertThat(metadata.getDeployedFiles()).isEmpty();
- assertThat(metadata.getImplementationBuild()).isEqualTo("abcdef");
- }
-
- @Test
- public void testDeployedFiles() {
- DefaultPluginMetadata metadata = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar"))
- .addDeployedFile(new File("foo.jar"))
- .addDeployedFile(new File("bar.jar"));
-
- assertThat(metadata.getDeployedFiles()).hasSize(2);
- }
-
- @Test
- public void testInternalPathToDependencies() {
- DefaultPluginMetadata metadata = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar"))
- .setPathsToInternalDeps(newArrayList("META-INF/lib/commons-lang.jar", "META-INF/lib/commons-io.jar"));
-
- assertThat(metadata.getPathsToInternalDeps()).containsOnly("META-INF/lib/commons-lang.jar", "META-INF/lib/commons-io.jar");
- }
-
- @Test
- public void shouldEquals() {
- DefaultPluginMetadata checkstyle = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar")).setKey("checkstyle");
- PluginMetadata pmd = DefaultPluginMetadata.create(new File("sonar-pmd-plugin.jar")).setKey("pmd");
-
- assertThat(checkstyle).isEqualTo(checkstyle);
- assertThat(checkstyle).isEqualTo(DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar")).setKey("checkstyle"));
- assertThat(checkstyle).isNotEqualTo(pmd);
- }
-
- @Test
- public void shouldCompare() {
- DefaultPluginMetadata checkstyle = DefaultPluginMetadata.create(new File("sonar-checkstyle-plugin.jar"))
- .setKey("checkstyle")
- .setName("Checkstyle");
- DefaultPluginMetadata pmd = DefaultPluginMetadata.create(new File("sonar-pmd-plugin.jar"))
- .setKey("pmd")
- .setName("PMD");
- List<DefaultPluginMetadata> plugins = Arrays.asList(pmd, checkstyle);
-
- assertThat(natural().sortedCopy(plugins)).extracting("key").containsExactly("checkstyle", "pmd");
- }
-
- @Test
- public void should_check_compatibility_with_sonar_version() {
- assertThat(pluginWithVersion("1.1").isCompatibleWith("1.1")).isTrue();
- assertThat(pluginWithVersion("1.1").isCompatibleWith("1.1.0")).isTrue();
- assertThat(pluginWithVersion("1.0").isCompatibleWith("1.0.0")).isTrue();
-
- assertThat(pluginWithVersion("1.0").isCompatibleWith("1.1")).isTrue();
- assertThat(pluginWithVersion("1.1.1").isCompatibleWith("1.1.2")).isTrue();
- assertThat(pluginWithVersion("2.0").isCompatibleWith("2.1.0")).isTrue();
- assertThat(pluginWithVersion("3.2").isCompatibleWith("3.2-RC1")).isTrue();
- assertThat(pluginWithVersion("3.2").isCompatibleWith("3.2-RC2")).isTrue();
- assertThat(pluginWithVersion("3.2").isCompatibleWith("3.1-RC2")).isFalse();
-
- assertThat(pluginWithVersion("1.1").isCompatibleWith("1.0")).isFalse();
- assertThat(pluginWithVersion("2.0.1").isCompatibleWith("2.0.0")).isFalse();
- assertThat(pluginWithVersion("2.10").isCompatibleWith("2.1")).isFalse();
- assertThat(pluginWithVersion("10.10").isCompatibleWith("2.2")).isFalse();
-
- assertThat(pluginWithVersion("1.1-SNAPSHOT").isCompatibleWith("1.0")).isFalse();
- assertThat(pluginWithVersion("1.1-SNAPSHOT").isCompatibleWith("1.1")).isTrue();
- assertThat(pluginWithVersion("1.1-SNAPSHOT").isCompatibleWith("1.2")).isTrue();
- assertThat(pluginWithVersion("1.0.1-SNAPSHOT").isCompatibleWith("1.0")).isFalse();
-
- assertThat(pluginWithVersion("3.1-RC2").isCompatibleWith("3.2-SNAPSHOT")).isTrue();
- assertThat(pluginWithVersion("3.1-RC1").isCompatibleWith("3.2-RC2")).isTrue();
- assertThat(pluginWithVersion("3.1-RC1").isCompatibleWith("3.1-RC2")).isTrue();
-
- assertThat(pluginWithVersion(null).isCompatibleWith("0")).isTrue();
- assertThat(pluginWithVersion(null).isCompatibleWith("3.1")).isTrue();
- }
-
- static DefaultPluginMetadata pluginWithVersion(String version) {
- return DefaultPluginMetadata.create("foo").setSonarVersion(version);
- }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/plugins/PluginClassloadersTest.java b/sonar-core/src/test/java/org/sonar/core/plugins/PluginClassloadersTest.java
deleted file mode 100644
index d9b3ada4254..00000000000
--- a/sonar-core/src/test/java/org/sonar/core/plugins/PluginClassloadersTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.plugins;
-
-import org.apache.commons.io.FileUtils;
-import org.codehaus.plexus.classworlds.ClassWorld;
-import org.codehaus.plexus.classworlds.realm.ClassRealm;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.Plugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.utils.SonarException;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Map;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class PluginClassloadersTest {
-
- private PluginClassloaders classloaders;
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Before
- public void before() {
- classloaders = new PluginClassloaders(getClass().getClassLoader());
- }
-
- @After
- public void clean() {
- if (classloaders != null) {
- classloaders.clean();
- }
- }
-
- @Test
- public void shouldImport() {
- classloaders.add(DefaultPluginMetadata.create("foo").addDeployedFile(getFile("PluginClassloadersTest/foo.jar")));
- classloaders.add(DefaultPluginMetadata.create("bar").addDeployedFile(getFile("PluginClassloadersTest/bar.jar")));
- classloaders.done();
-
- String resourceName = "org/sonar/plugins/bar/api/resource.txt";
- assertThat(classloaders.get("bar").getResourceAsStream(resourceName)).isNotNull();
- assertThat(classloaders.get("foo").getResourceAsStream(resourceName)).isNotNull();
- }
-
- @Test
- public void shouldCreateBaseClassloader() {
- classloaders = new PluginClassloaders(getClass().getClassLoader());
- DefaultPluginMetadata checkstyle = DefaultPluginMetadata.create("checkstyle")
- .setMainClass("org.sonar.plugins.checkstyle.CheckstylePlugin")
- .addDeployedFile(getFile("sonar-checkstyle-plugin-2.8.jar"));
-
- Map<String, Plugin> map = classloaders.init(Arrays.<PluginMetadata>asList(checkstyle));
-
- Plugin checkstyleEntryPoint = map.get("checkstyle");
- ClassRealm checkstyleRealm = (ClassRealm) checkstyleEntryPoint.getClass().getClassLoader();
- assertThat(checkstyleRealm.getId()).isEqualTo("checkstyle");
- }
-
- @Test
- public void shouldExtendPlugin() {
- classloaders = new PluginClassloaders(getClass().getClassLoader());
-
- DefaultPluginMetadata checkstyle = DefaultPluginMetadata.create("checkstyle")
- .setMainClass("org.sonar.plugins.checkstyle.CheckstylePlugin")
- .addDeployedFile(getFile("sonar-checkstyle-plugin-2.8.jar"));
-
- DefaultPluginMetadata checkstyleExt = DefaultPluginMetadata.create("checkstyle-ext")
- .setBasePlugin("checkstyle")
- .setMainClass("com.mycompany.sonar.checkstyle.CheckstyleExtensionsPlugin")
- .addDeployedFile(getFile("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar"));
-
- Map<String, Plugin> map = classloaders.init(Arrays.<PluginMetadata>asList(checkstyle, checkstyleExt));
-
- Plugin checkstyleEntryPoint = map.get("checkstyle");
- Plugin checkstyleExtEntryPoint = map.get("checkstyle-ext");
-
- assertThat(checkstyleEntryPoint.getClass().getClassLoader().equals(checkstyleExtEntryPoint.getClass().getClassLoader())).isTrue();
- }
-
- @Test
- public void detect_plugins_compiled_for_bad_java_version() throws Exception {
- thrown.expect(SonarException.class);
- thrown.expectMessage("The plugin checkstyle is not supported with Java 1.");
-
- ClassWorld world = mock(ClassWorld.class);
- when(world.newRealm(anyString(), any(ClassLoader.class))).thenThrow(new UnsupportedClassVersionError());
-
- classloaders = new PluginClassloaders(getClass().getClassLoader(), world);
-
- DefaultPluginMetadata checkstyle = DefaultPluginMetadata.create("checkstyle")
- .setMainClass("org.sonar.plugins.checkstyle.CheckstylePlugin")
- .addDeployedFile(getFile("sonar-checkstyle-plugin-2.8.jar"));
-
- classloaders.init(Arrays.<PluginMetadata>asList(checkstyle));
- }
-
- private File getFile(String filename) {
- return FileUtils.toFile(getClass().getResource("/org/sonar/core/plugins/" + filename));
- }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/plugins/PluginJarInstallerTest.java b/sonar-core/src/test/java/org/sonar/core/plugins/PluginJarInstallerTest.java
deleted file mode 100644
index b66bf864085..00000000000
--- a/sonar-core/src/test/java/org/sonar/core/plugins/PluginJarInstallerTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.plugins;
-
-import org.apache.commons.io.FileUtils;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-import java.io.IOException;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PluginJarInstallerTest {
-
- private PluginJarInstaller extractor;
-
- @ClassRule
- public static TemporaryFolder temporaryFolder = new TemporaryFolder();
-
- private File userHome;
-
- @Before
- public void setUp() throws IOException {
- userHome = temporaryFolder.newFolder();
- extractor = new PluginJarInstaller() {
- @Override
- protected File extractPluginDependencies(File pluginFile, File pluginBasedir) throws IOException {
- return null;
- }
- };
- }
-
- @Test
- public void should_extract_metadata() throws IOException {
- DefaultPluginMetadata metadata = extractor.extractMetadata(getFileFromCache("sonar-cobertura-plugin-3.1.1.jar"), true);
-
- assertThat(metadata.getKey()).isEqualTo("cobertura");
- assertThat(metadata.getBasePlugin()).isNull();
- assertThat(metadata.getName()).isEqualTo("Cobertura");
- assertThat(metadata.isCore()).isEqualTo(true);
- assertThat(metadata.getFile().getName()).isEqualTo("sonar-cobertura-plugin-3.1.1.jar");
- assertThat(metadata.getVersion()).isEqualTo("3.1.1");
- assertThat(metadata.getImplementationBuild()).isEqualTo("b9283404030db9ce1529b1fadfb98331686b116d");
- assertThat(metadata.getHomepage()).isEqualTo("http://www.sonarsource.org/plugins/sonar-cobertura-plugin");
- assertThat(metadata.getIssueTrackerUrl()).isEqualTo("http://jira.codehaus.org/browse/SONAR");
- }
-
- @Test
- public void should_read_sonar_version() throws IOException {
- DefaultPluginMetadata metadata = extractor.extractMetadata(getFileFromCache("sonar-switch-off-violations-plugin-1.1.jar"), false);
-
- assertThat(metadata.getVersion()).isEqualTo("1.1");
- assertThat(metadata.getSonarVersion()).isEqualTo("2.5");
- }
-
- @Test
- public void should_extract_extension_metadata() throws IOException {
- DefaultPluginMetadata metadata = extractor.extractMetadata(getFileFromCache("sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar"), true);
-
- assertThat(metadata.getKey()).isEqualTo("checkstyleextensions");
- assertThat(metadata.getBasePlugin()).isEqualTo("checkstyle");
- }
-
- @Test
- public void should_extract_requires_plugin_information() throws IOException {
- DefaultPluginMetadata metadata = extractor.extractMetadata(getFileFromCache("fake2-plugin-1.1.jar"), true);
-
- assertThat(metadata.getKey()).isEqualTo("fake2");
- assertThat(metadata.getRequiredPlugins().get(0)).isEqualTo("fake1:1.1");
- }
-
- File getFileFromCache(String filename) throws IOException {
- File src = FileUtils.toFile(PluginJarInstallerTest.class.getResource("/org/sonar/core/plugins/" + filename));
- File destFile = new File(new File(userHome, "" + filename.hashCode()), filename);
- FileUtils.copyFile(src, destFile);
- return destFile;
- }
-
-}
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/PluginClassloadersTest/bar.jar b/sonar-core/src/test/resources/org/sonar/core/plugins/PluginClassloadersTest/bar.jar
deleted file mode 100644
index 343ad65f133..00000000000
--- a/sonar-core/src/test/resources/org/sonar/core/plugins/PluginClassloadersTest/bar.jar
+++ /dev/null
Binary files differ
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/PluginClassloadersTest/foo.jar b/sonar-core/src/test/resources/org/sonar/core/plugins/PluginClassloadersTest/foo.jar
deleted file mode 100644
index 505311c008b..00000000000
--- a/sonar-core/src/test/resources/org/sonar/core/plugins/PluginClassloadersTest/foo.jar
+++ /dev/null
Binary files differ
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/checkstyle-extension.xml b/sonar-core/src/test/resources/org/sonar/core/plugins/checkstyle-extension.xml
deleted file mode 100644
index 75a263db3c3..00000000000
--- a/sonar-core/src/test/resources/org/sonar/core/plugins/checkstyle-extension.xml
+++ /dev/null
@@ -1 +0,0 @@
-<fake/> \ No newline at end of file
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/fake2-plugin-1.1.jar b/sonar-core/src/test/resources/org/sonar/core/plugins/fake2-plugin-1.1.jar
deleted file mode 100644
index f4b8b79b776..00000000000
--- a/sonar-core/src/test/resources/org/sonar/core/plugins/fake2-plugin-1.1.jar
+++ /dev/null
Binary files differ
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar b/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar
deleted file mode 100644
index 4ae5393cee5..00000000000
--- a/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-checkstyle-extensions-plugin-0.1-SNAPSHOT.jar
+++ /dev/null
Binary files differ
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-cobertura-plugin-3.1.1.jar b/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-cobertura-plugin-3.1.1.jar
deleted file mode 100644
index 6a74b55d02c..00000000000
--- a/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-cobertura-plugin-3.1.1.jar
+++ /dev/null
Binary files differ
diff --git a/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-switch-off-violations-plugin-1.1.jar b/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-switch-off-violations-plugin-1.1.jar
deleted file mode 100644
index 8044dff8988..00000000000
--- a/sonar-core/src/test/resources/org/sonar/core/plugins/sonar-switch-off-violations-plugin-1.1.jar
+++ /dev/null
Binary files differ
diff --git a/sonar-deprecated/src/main/java/org/sonar/api/charts/package-info.java b/sonar-deprecated/src/main/java/org/sonar/api/charts/package-info.java
index e5922bf75f0..358d4bbef40 100644
--- a/sonar-deprecated/src/main/java/org/sonar/api/charts/package-info.java
+++ b/sonar-deprecated/src/main/java/org/sonar/api/charts/package-info.java
@@ -17,9 +17,6 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-/**
- * Deprecated in 4.5.1. JFreechart charts are replaced by Javascript charts.
- */
@ParametersAreNonnullByDefault
package org.sonar.api.charts;
diff --git a/sonar-home/src/main/java/org/sonar/home/cache/FileCache.java b/sonar-home/src/main/java/org/sonar/home/cache/FileCache.java
index 3588a908b4b..63a1168639d 100644
--- a/sonar-home/src/main/java/org/sonar/home/cache/FileCache.java
+++ b/sonar-home/src/main/java/org/sonar/home/cache/FileCache.java
@@ -20,15 +20,12 @@
package org.sonar.home.cache;
import org.apache.commons.io.FileUtils;
-import org.sonar.api.utils.ZipUtils;
import org.sonar.home.log.Log;
import javax.annotation.CheckForNull;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.util.zip.ZipEntry;
/**
* This class is responsible for managing Sonar batch file cache. You can put file into cache and
@@ -138,7 +135,7 @@ public class FileCache {
}
}
- private File createTempDir() {
+ public File createTempDir() {
String baseName = System.currentTimeMillis() + "-";
for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
@@ -161,43 +158,4 @@ public class FileCache {
}
return dir;
}
-
- /**
- * Unzip a cached file. Unzip is done only the first time.
- * @param cachedFile
- * @return directory where cachedFile was unzipped
- * @throws IOException
- */
- public File unzip(File cachedFile) throws IOException {
- String filename = cachedFile.getName();
- File destDir = new File(cachedFile.getParentFile(), filename + "_unzip");
- File lockFile = new File(cachedFile.getParentFile(), filename + "_unzip.lock");
- if (!destDir.exists()) {
- FileOutputStream out = new FileOutputStream(lockFile);
- try {
- java.nio.channels.FileLock lock = out.getChannel().lock();
- try {
- // Recheck in case of concurrent processes
- if (!destDir.exists()) {
- File tempDir = createTempDir();
- ZipUtils.unzip(cachedFile, tempDir, new LibFilter());
- FileUtils.moveDirectory(tempDir, destDir);
- }
- } finally {
- lock.release();
- }
- } finally {
- out.close();
- FileUtils.deleteQuietly(lockFile);
- }
- }
- return destDir;
- }
-
- private static final class LibFilter implements ZipUtils.ZipEntryFilter {
- @Override
- public boolean accept(ZipEntry entry) {
- return entry.getName().startsWith("META-INF/lib");
- }
- }
}
diff --git a/sonar-home/src/test/java/org/sonar/home/cache/FileCacheTest.java b/sonar-home/src/test/java/org/sonar/home/cache/FileCacheTest.java
index be82711e85e..2d90503598d 100644
--- a/sonar-home/src/test/java/org/sonar/home/cache/FileCacheTest.java
+++ b/sonar-home/src/test/java/org/sonar/home/cache/FileCacheTest.java
@@ -28,7 +28,6 @@ import org.sonar.home.log.Slf4jLog;
import java.io.File;
import java.io.IOException;
-import java.net.URISyntaxException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
@@ -120,32 +119,4 @@ public class FileCacheTest {
assertThat(FileUtils.readFileToString(cachedFile)).contains("downloaded by");
}
- @Test
- public void unzip_from_cache() throws IOException, URISyntaxException {
- final File samplePlugin = new File(this.getClass().getResource("/sonar-checkstyle-plugin-2.8.jar").toURI());
- FileHashes hashes = mock(FileHashes.class);
- final FileCache cache = new FileCache(tempFolder.newFolder(), log, hashes);
- when(hashes.of(any(File.class))).thenReturn("ABCDE");
-
- FileCache.Downloader downloader = new FileCache.Downloader() {
- public void download(String filename, File toFile) throws IOException {
- FileUtils.copyFile(samplePlugin, toFile);
- }
- };
- final File cachedFile = cache.get("sonar-checkstyle-plugin-2.8.jar", "ABCDE", downloader);
- assertThat(cachedFile).isNotNull().exists().isFile();
- assertThat(cachedFile.getName()).isEqualTo("sonar-checkstyle-plugin-2.8.jar");
-
- File pluginDepsDir = cache.unzip(cachedFile);
-
- assertThat(pluginDepsDir.listFiles()).hasSize(1);
- File metaDir = new File(pluginDepsDir, "META-INF");
- assertThat(metaDir.listFiles()).hasSize(1);
- File libDir = new File(metaDir, "lib");
- assertThat(libDir.listFiles()).hasSize(3);
- assertThat(libDir.listFiles()).containsOnly(new File(libDir, "antlr-2.7.6.jar"), new File(libDir, "checkstyle-5.1.jar"), new File(libDir, "commons-cli-1.0.jar"));
-
- // Unzip again should not do anything as it is already unzipped
- cache.unzip(cachedFile);
- }
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java b/sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java
index ea7bbc755e9..23f5021d3fb 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/Plugin.java
@@ -24,9 +24,9 @@ import java.util.List;
/**
* A plugin is a group of extensions. See <code>org.sonar.api.Extension</code> interface to browse
* available extension points.
- * <p/>
* <p>The manifest property <code>Plugin-Class</code> must declare the name of the implementation class.
* It is automatically set by sonar-packaging-maven-plugin when building plugins.</p>
+ * <p>Implementation must declare a public constructor with no-parameters.</p>
*
* @see org.sonar.api.Extension
* @since 1.10
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginMetadata.java b/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginMetadata.java
deleted file mode 100644
index 97ab71bcfc1..00000000000
--- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginMetadata.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.api.platform;
-
-import javax.annotation.CheckForNull;
-import java.io.File;
-import java.util.List;
-
-/**
- * @since 2.8
- */
-public interface PluginMetadata {
- File getFile();
-
- List<File> getDeployedFiles();
-
- String getKey();
-
- String getName();
-
- String getMainClass();
-
- String getDescription();
-
- String getOrganization();
-
- String getOrganizationUrl();
-
- String getLicense();
-
- String getVersion();
-
- String getHomepage();
-
- /**
- * @since 3.6
- */
- String getIssueTrackerUrl();
-
- boolean isUseChildFirstClassLoader();
-
- String getBasePlugin();
-
- /**
- * Always return <code>null</code> since version 5.2
- * @deprecated in 5.2. Concept of parent relationship is removed. See https://jira.codehaus.org/browse/SONAR-6433
- */
- @Deprecated
- @CheckForNull
- String getParent();
-
- List<String> getRequiredPlugins();
-
- boolean isCore();
-
- String getImplementationBuild();
-}