summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsimonbrandhof <simon.brandhof@gmail.com>2010-09-28 15:53:04 +0000
committersimonbrandhof <simon.brandhof@gmail.com>2010-09-28 15:53:04 +0000
commitf25c971275702a3a53195b568fe3c91469076c83 (patch)
tree52764695c638d5905d6116d2bf4d5d4416290ba6
parent5cdbf337fef2559593e53dc7b2a2c68d8e1f992f (diff)
downloadsonarqube-f25c971275702a3a53195b568fe3c91469076c83.tar.gz
sonarqube-f25c971275702a3a53195b568fe3c91469076c83.zip
SONAR-1814 add the method ExtensionProvider.provide() in order to support obfuscated code
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/BatchPluginRepository.java1
-rw-r--r--sonar-core/src/main/java/org/sonar/core/plugin/AbstractPluginRepository.java49
-rw-r--r--sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java34
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/ExtensionProvider.java35
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginRepository.java3
-rw-r--r--sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java1
6 files changed, 73 insertions, 50 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/BatchPluginRepository.java b/sonar-batch/src/main/java/org/sonar/batch/BatchPluginRepository.java
index 5544762ad7a..51a2e095380 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/BatchPluginRepository.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/BatchPluginRepository.java
@@ -105,6 +105,7 @@ public class BatchPluginRepository extends AbstractPluginRepository {
throw new SonarException("Fail to load extensions from plugin " + pluginMetadata.getKey(), e);
}
}
+ invokeExtensionProviders(pico);
}
boolean shouldRegisterCoverageExtension(String pluginKey) {
diff --git a/sonar-core/src/main/java/org/sonar/core/plugin/AbstractPluginRepository.java b/sonar-core/src/main/java/org/sonar/core/plugin/AbstractPluginRepository.java
index b62bf983045..9a15c9e06ba 100644
--- a/sonar-core/src/main/java/org/sonar/core/plugin/AbstractPluginRepository.java
+++ b/sonar-core/src/main/java/org/sonar/core/plugin/AbstractPluginRepository.java
@@ -19,16 +19,18 @@
*/
package org.sonar.core.plugin;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
import com.google.common.collect.Maps;
import org.picocontainer.Characteristics;
import org.picocontainer.MutablePicoContainer;
-import org.picocontainer.injectors.ProviderAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.*;
import org.sonar.api.platform.PluginRepository;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
/**
@@ -38,7 +40,7 @@ public abstract class AbstractPluginRepository implements PluginRepository {
private static final Logger LOG = LoggerFactory.getLogger(AbstractPluginRepository.class);
- private Map<String, Plugin> pluginByKey = Maps.newHashMap();
+ private BiMap<String, Plugin> pluginByKey = HashBiMap.create();
private Map<Object, Plugin> pluginByExtension = Maps.newIdentityHashMap();
protected void registerPlugin(MutablePicoContainer container, Plugin plugin, String pluginKey) {
@@ -49,15 +51,30 @@ public abstract class AbstractPluginRepository implements PluginRepository {
}
}
+ /**
+ * Must be executed by implementations when all plugins are registered.
+ */
+ protected void invokeExtensionProviders(MutablePicoContainer container) {
+ List<ExtensionProvider> providers = container.getComponents(ExtensionProvider.class);
+ for (ExtensionProvider provider : providers) {
+ Plugin plugin = getPluginForExtension(provider);
+ Object obj = provider.provide();
+ if (obj instanceof Iterable) {
+ for (Object elt : (Iterable) obj) {
+ registerExtension(container, plugin, getPluginKey(plugin), elt);
+ }
+ } else {
+ registerExtension(container, plugin, getPluginKey(plugin), obj);
+ }
+ }
+ }
+
private void registerExtension(MutablePicoContainer container, Plugin plugin, String pluginKey, Object extension) {
if (shouldRegisterExtension(pluginKey, extension)) {
LOG.debug("Register the extension: {}", extension);
container.as(Characteristics.CACHE).addComponent(getExtensionKey(extension), extension);
pluginByExtension.put(extension, plugin);
- }
- if (isExtensionProvider(extension)) {
- LOG.debug("Register the extension provider: {}", extension);
- container.as(Characteristics.CACHE).addAdapter(new ExtensionProviderAdapter(extension));
+
}
}
@@ -71,6 +88,10 @@ public abstract class AbstractPluginRepository implements PluginRepository {
return pluginByKey.get(key);
}
+ public String getPluginKey(Plugin plugin) {
+ return pluginByKey.inverse().get(plugin);
+ }
+
/**
* Returns the list of properties of a plugin
*/
@@ -102,15 +123,7 @@ public abstract class AbstractPluginRepository implements PluginRepository {
}
protected static boolean isExtensionProvider(Object extension) {
- boolean is = false;
- if (isType(extension, ExtensionProvider.class)) {
- if (extension instanceof ExtensionProvider) {
- is = true;
- } else {
- LOG.error("The following ExtensionProvider must be registered in Plugin.getExtensions() as an instance but not a class: " + extension);
- }
- }
- return is;
+ return isType(extension, ExtensionProvider.class);
}
protected static Object getExtensionKey(Object component) {
@@ -119,10 +132,4 @@ public abstract class AbstractPluginRepository implements PluginRepository {
}
return component.getClass().getCanonicalName() + "-" + component.toString();
}
-
- public static class ExtensionProviderAdapter extends ProviderAdapter {
- public ExtensionProviderAdapter(Object provider) {
- super(provider);
- }
- }
}
diff --git a/sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java b/sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java
index 319150c5c95..de2343a07f5 100644
--- a/sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/plugin/AbstractPluginRepositoryTest.java
@@ -28,6 +28,7 @@ import org.sonar.api.ServerExtension;
import org.sonar.api.utils.IocContainer;
import java.util.Arrays;
+import java.util.Collection;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.notNullValue;
@@ -61,9 +62,9 @@ public class AbstractPluginRepositoryTest {
}
@Test
- public void extensionProviderIsAnObjectButNotAClass() {
- assertThat(AbstractPluginRepository.isExtensionProvider(BProvider.class), is(false));
- assertThat(AbstractPluginRepository.isExtensionProvider(new BProvider()), is(true));
+ public void shouldBeExtensionProvider() {
+ assertThat(AbstractPluginRepository.isExtensionProvider(BProvider.class), is(true));
+ assertThat(AbstractPluginRepository.isExtensionProvider(new BProvider(new A())), is(true));
}
@Test
@@ -77,20 +78,18 @@ public class AbstractPluginRepositoryTest {
};
Plugin plugin = mock(Plugin.class);
- BProvider bProvider = new BProvider();
- when(plugin.getExtensions()).thenReturn(Arrays.asList(A.class, bProvider, C.class, D.class));
+ when(plugin.getExtensions()).thenReturn(Arrays.asList(A.class, BProvider.class, B.class, C.class, D.class));
repository.registerPlugin(pico, plugin, "foo");
+ repository.invokeExtensionProviders(pico);
pico.start();
assertThat(pico.getComponent(A.class), is(A.class));
assertThat(pico.getComponent(C.class), is(C.class));
assertThat(pico.getComponent(D.class), is(D.class));
- assertThat(pico.getComponent(C.class).getBees().length, is(2));
- assertThat(pico.getComponent(D.class).getBees().length, is(2));
- assertThat(bProvider.calls, is(1)); // do not create B instances two times (C and D dependencies)
-
- // Picocontainer question: why components created by providers are not registered in the container ?
- //assertThat(pico.getComponents(B.class).size(), is(2)); // created by the ExtensionProvider
+ assertThat(pico.getComponent(C.class).getBees().length, is(3));// 1 in plugin.getExtensions() + 2 created by BProvider
+ assertThat(pico.getComponent(D.class).getBees().length, is(3));
+ assertThat(pico.getComponent(BProvider.class).calls, is(1)); // do not create B instances two times (C and D dependencies)
+ assertThat(pico.getComponents(B.class).size(), is(3));
}
public static class FakeServerExtension implements ServerExtension {
@@ -115,6 +114,7 @@ public class AbstractPluginRepositoryTest {
}
}
+
public static class C implements ServerExtension {
private B[] bees;
@@ -139,12 +139,18 @@ public class AbstractPluginRepositoryTest {
}
}
- public static class BProvider extends ExtensionProvider {
+ public static class BProvider extends ExtensionProvider implements ServerExtension {
private int calls = 0;
- public B[] provide(A a) {
+ private A a;
+
+ public BProvider(A a) {
+ this.a = a;
+ }
+
+ public Collection<B> provide() {
calls++;
- return new B[]{new B(a), new B(a)};
+ return Arrays.asList(new B(a), new B(a));
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/ExtensionProvider.java b/sonar-plugin-api/src/main/java/org/sonar/api/ExtensionProvider.java
index 40dcbba5d97..02ad1ff5c05 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/ExtensionProvider.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/ExtensionProvider.java
@@ -19,38 +19,43 @@
*/
package org.sonar.api;
-import org.picocontainer.injectors.Provider;
-
/**
* Factory of extensions. It allows to dynamically create extensions depending upon runtime context. A use-case is
* to create one rule repository by language.
*
- * <p>Constraints are :
+ * <p>Notes :
* <ul>
- * <li>the factory is declared in Plugin.getExtensions() as an instance but not as a class</li>
- * <li>the factory must have a public method named "provide()"</li>
- * <li>the method provide() must return an object or an array of objects. Collections and classes are excluded.</li>
- * <li>the methode provide() can accept parameters. These parameters are IoC dependencies.
+ * <li>the provider is declared in Plugin.getExtensions()</li>
+ * <li>the provider must also implement ServerExtension and/or BatchExtension</li>
+ * <li>the provider can accept dependencies (parameters) in its constructors.</li>
+ * <li>the method provide() is automatically executed once by sonar</li>
+ * <li>the method provide() must return an object or an Iterable of objects. <strong>Arrays are excluded</strong>.</li>
* </ul>
* </p>
*
* <p>Example:
* <pre>
- * public class RuleRepositoryProvider extends ExtensionProvider {
- * public RuleRepository[] provide(Language[] languages) {
- * RuleRepository[] result = new RuleRepository[languages.length];
- * for(int index=0; index &lt; languages.length ; index++) {
- * Language language = languages[index];
- * result[index] = new RuleRepository(...);
+ * public class RuleRepositoryProvider extends ExtensionProvider implements ServerExtension {
+ * private Language[] languages;
+ *
+ * public RuleRepositoryProvider(Language[] languages) {
+ * this.languages = languages;
+ * }
+ *
+ * public List<RuleRepository> provide() {
+ * List<RuleRepository> result = new ArrayList<RuleRepository>();
+ * for(Language language: languages) {
+ * result.add(new RuleRepository(..., language, ...));
* }
* return result;
* }
* }
* </pre>
* </p>
- *
+ *
* @since 2.3
*/
-public abstract class ExtensionProvider implements Extension, Provider {
+public abstract class ExtensionProvider implements Extension {
+ public abstract Object provide();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginRepository.java b/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginRepository.java
index 8529642a9f1..49e42cd4c8c 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginRepository.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/platform/PluginRepository.java
@@ -31,6 +31,9 @@ public interface PluginRepository extends BatchComponent, ServerComponent {
Plugin getPlugin(String key);
+ /**
+ * @deprecated since 2.3
+ */
@Deprecated
Plugin getPluginForExtension(Object extension);
diff --git a/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java b/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java
index cfb1191fc11..318a5ac5769 100644
--- a/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java
+++ b/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java
@@ -60,6 +60,7 @@ public class ServerPluginRepository extends AbstractPluginRepository {
throw new SonarException("Please check the plugin manifest. The main plugin class does not exist: " + jpaPlugin.getPluginClass(), e);
}
}
+ invokeExtensionProviders(pico);
}
@Override