Add DynamicItem for extension points with one implementation

Some extension points should only have one implementation provided,
such as a provider of avatar images.  In this case it doesn't make
sense to have multiple providers.  For this use-case we need
DynamicItem.

Change-Id: If5166c3f42c5619daea56d79dea8feb70f9ee084
This commit is contained in:
Brad Larson
2012-12-12 14:09:24 -06:00
committed by Shawn Pearce
parent 095a25143c
commit ae984a98e2
5 changed files with 388 additions and 1 deletions

View File

@@ -13,6 +13,8 @@
// limitations under the License.
package com.google.gerrit.server.plugins;
import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicItemsOf;
import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicMapsOf;
import static com.google.gerrit.extensions.registration.PrivateInternals_DynamicTypes.dynamicSetsOf;
@@ -22,6 +24,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.registration.PrivateInternals_DynamicMapImpl;
@@ -74,6 +77,8 @@ public class PluginGuiceEnvironment {
private Provider<ModuleGenerator> sshGen;
private Provider<ModuleGenerator> httpGen;
private Map<TypeLiteral<?>, DynamicItem<?>> sysItems;
private Map<TypeLiteral<?>, DynamicSet<?>> sysSets;
private Map<TypeLiteral<?>, DynamicSet<?>> sshSets;
private Map<TypeLiteral<?>, DynamicSet<?>> httpSets;
@@ -98,6 +103,7 @@ public class PluginGuiceEnvironment {
onReload = new CopyOnWriteArrayList<ReloadPluginListener>();
onReload.addAll(listeners(sysInjector, ReloadPluginListener.class));
sysItems = dynamicItemsOf(sysInjector);
sysSets = dynamicSetsOf(sysInjector);
sysMaps = dynamicMapsOf(sysInjector);
}
@@ -106,6 +112,10 @@ public class PluginGuiceEnvironment {
return srvInfo;
}
boolean hasDynamicItem(TypeLiteral<?> type) {
return sysItems.containsKey(type);
}
boolean hasDynamicSet(TypeLiteral<?> type) {
return sysSets.containsKey(type)
|| (sshSets != null && sshSets.containsKey(type))
@@ -182,6 +192,8 @@ public class PluginGuiceEnvironment {
l.onStartPlugin(plugin);
}
attachItem(sysItems, plugin.getSysInjector(), plugin);
attachSet(sysSets, plugin.getSysInjector(), plugin);
attachSet(sshSets, plugin.getSshInjector(), plugin);
attachSet(httpSets, plugin.getHttpInjector(), plugin);
@@ -191,6 +203,15 @@ public class PluginGuiceEnvironment {
attachMap(httpMaps, plugin.getHttpInjector(), plugin);
}
private void attachItem(Map<TypeLiteral<?>, DynamicItem<?>> items,
@Nullable Injector src,
Plugin plugin) {
for (RegistrationHandle h : PrivateInternals_DynamicTypes
.attachItems(src, items, plugin.getName())) {
plugin.add(h);
}
}
private void attachSet(Map<TypeLiteral<?>, DynamicSet<?>> sets,
@Nullable Injector src,
Plugin plugin) {
@@ -230,6 +251,8 @@ public class PluginGuiceEnvironment {
reattachSet(old, sysSets, newPlugin.getSysInjector(), newPlugin);
reattachSet(old, sshSets, newPlugin.getSshInjector(), newPlugin);
reattachSet(old, httpSets, newPlugin.getHttpInjector(), newPlugin);
reattachItem(old, sysItems, newPlugin.getSysInjector(), newPlugin);
}
private void reattachMap(
@@ -350,6 +373,41 @@ public class PluginGuiceEnvironment {
}
}
}
private void reattachItem(
ListMultimap<TypeLiteral<?>, ReloadableRegistrationHandle<?>> oldHandles,
Map<TypeLiteral<?>, DynamicItem<?>> items,
@Nullable Injector src,
Plugin newPlugin) {
if (src == null || items == null || items.isEmpty()) {
return;
}
for (Map.Entry<TypeLiteral<?>, DynamicItem<?>> e : items.entrySet()) {
@SuppressWarnings("unchecked")
TypeLiteral<Object> type = (TypeLiteral<Object>) e.getKey();
@SuppressWarnings("unchecked")
DynamicItem<Object> item = (DynamicItem<Object>) e.getValue();
Iterator<ReloadableRegistrationHandle<?>> oi =
oldHandles.get(type).iterator();
for (Binding<?> binding : bindings(src, type)) {
@SuppressWarnings("unchecked")
Binding<Object> b = (Binding<Object>) binding;
if (oi.hasNext()) {
@SuppressWarnings("unchecked")
ReloadableRegistrationHandle<Object> h =
(ReloadableRegistrationHandle<Object>) oi.next();
oi.remove();
replace(newPlugin, h, b);
} else {
newPlugin.add(item.set(b.getKey(), b.getProvider(),
newPlugin.getName()));
}
}
}
}
private static <T> void replace(Plugin newPlugin,
ReloadableRegistrationHandle<T> h, Binding<T> b) {