Introduce mechanism to overload Gerrit core modules

CacheImpl [1] introduced the possibility to overload core Gerrit
module with one that is provided by library. This change
generalizes it so that any Gerrit core module can be overloaded.

How to overload Gerrit core module:
* identify module that needs to be overloaded and mark it with
@ModuleImpl(name="moduleX") annotation; note that circular dependencies
from different module qualifies particular instance as non-candidate
* build lib module that provides alternative implementation
to the module in question and mark it with the same
annotation
* place implementation jar under GERRIT_SITE/lib dir and add
gerrit.installModule entry with your.package.Module path to
gerrit.config.

[1] https://gerrit-review.googlesource.com/c/gerrit/+/173162

Change-Id: Ic6dac8d1cc558abdcfd7a1cc257dbd7f8924ff9b
Signed-off-by: Jacek Centkowski <jcentkowski@collab.net>
This commit is contained in:
Jacek Centkowski 2018-05-08 21:48:02 +02:00 committed by David Pursehouse
parent a3cc510fc1
commit b6e94a00a0
7 changed files with 32 additions and 22 deletions

View File

@ -15,10 +15,11 @@
package com.google.gerrit.server.cache.h2;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.cache.CacheImpl;
import com.google.gerrit.server.ModuleImpl;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.cache.PersistentCacheFactory;
@CacheImpl(type = CacheImpl.Type.PERSISTENT)
@ModuleImpl(name = CacheModule.PERSISTENT_MODULE)
public class H2CacheModule extends LifecycleModule {
@Override
protected void configure() {

View File

@ -15,11 +15,12 @@
package com.google.gerrit.server.cache.mem;
import com.google.gerrit.extensions.config.FactoryModule;
import com.google.gerrit.server.cache.CacheImpl;
import com.google.gerrit.server.ModuleImpl;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.cache.ForwardingRemovalListener;
import com.google.gerrit.server.cache.MemoryCacheFactory;
@CacheImpl(type = CacheImpl.Type.MEMORY)
@ModuleImpl(name = CacheModule.MEMORY_MODULE)
public class DefaultMemoryCacheModule extends FactoryModule {
@Override
protected void configure() {

View File

@ -48,9 +48,9 @@ import com.google.gerrit.pgm.util.LogFileCompressor;
import com.google.gerrit.pgm.util.RuntimeShutdown;
import com.google.gerrit.pgm.util.SiteProgram;
import com.google.gerrit.server.LibModuleLoader;
import com.google.gerrit.server.ModuleOverloader;
import com.google.gerrit.server.StartupChecks;
import com.google.gerrit.server.account.InternalAccountDirectory;
import com.google.gerrit.server.cache.CacheOverrides;
import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
import com.google.gerrit.server.change.ChangeCleanupRunner;
@ -441,7 +441,7 @@ public class Daemon extends SiteProgram {
modules.add(new ChangeCleanupRunner.Module());
}
return cfgInjector.createChildInjector(
CacheOverrides.override(modules, LibModuleLoader.loadModules(cfgInjector)));
ModuleOverloader.override(modules, LibModuleLoader.loadModules(cfgInjector)));
}
private Module createIndexModule() {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.cache;
package com.google.gerrit.server;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@ -24,11 +24,11 @@ import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(TYPE)
@Inherited
public @interface CacheImpl {
enum Type {
MEMORY,
PERSISTENT
}
Type type();
/**
* Use this annotation to mark module as being swappable with implementation from {@code
* gerrit.installModule}. Note that module with this annotation shouldn't be part of circular
* dependency with any existing module.
*/
public @interface ModuleImpl {
String name();
}

View File

@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.cache;
package com.google.gerrit.server;
import com.google.inject.Module;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CacheOverrides {
public class ModuleOverloader {
public static List<Module> override(List<Module> modules, List<Module> overrideCandidates) {
if (overrideCandidates == null || overrideCandidates.isEmpty()) {
return modules;
@ -30,7 +30,7 @@ public class CacheOverrides {
overrideCandidates
.stream()
.collect(
Collectors.groupingBy(m -> m.getClass().getAnnotation(CacheImpl.class) != null));
Collectors.groupingBy(m -> m.getClass().getAnnotation(ModuleImpl.class) != null));
// add all non annotated libs to modules list
List<Module> libs = grouped.get(Boolean.FALSE);
@ -48,18 +48,23 @@ public class CacheOverrides {
.stream()
.map(
m -> {
CacheImpl a = m.getClass().getAnnotation(CacheImpl.class);
ModuleImpl a = m.getClass().getAnnotation(ModuleImpl.class);
if (a == null) {
return m;
}
return overrides
.stream()
.filter(o -> o.getClass().getAnnotation(CacheImpl.class).type() == a.type())
.filter(
o ->
o.getClass()
.getAnnotation(ModuleImpl.class)
.name()
.equalsIgnoreCase(a.name()))
.findFirst()
.orElse(m);
})
.collect(Collectors.toList());
}
private CacheOverrides() {}
private ModuleOverloader() {}
}

View File

@ -31,6 +31,9 @@ import java.lang.reflect.Type;
/** Miniature DSL to support binding {@link Cache} instances in Guice. */
public abstract class CacheModule extends FactoryModule {
public static final String MEMORY_MODULE = "cache-memory";
public static final String PERSISTENT_MODULE = "cache-persistent";
private static final TypeLiteral<Cache<?, ?>> ANY_CACHE = new TypeLiteral<Cache<?, ?>>() {};
/**

View File

@ -32,9 +32,9 @@ import com.google.gerrit.lucene.LuceneIndexModule;
import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker;
import com.google.gerrit.pgm.util.LogFileCompressor;
import com.google.gerrit.server.LibModuleLoader;
import com.google.gerrit.server.ModuleOverloader;
import com.google.gerrit.server.StartupChecks;
import com.google.gerrit.server.account.InternalAccountDirectory;
import com.google.gerrit.server.cache.CacheOverrides;
import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
import com.google.gerrit.server.change.ChangeCleanupRunner;
@ -367,7 +367,7 @@ public class WebAppInitializer extends GuiceServletContextListener implements Fi
modules.add(new GarbageCollectionModule());
modules.add(new ChangeCleanupRunner.Module());
return cfgInjector.createChildInjector(
CacheOverrides.override(modules, LibModuleLoader.loadModules(cfgInjector)));
ModuleOverloader.override(modules, LibModuleLoader.loadModules(cfgInjector)));
}
private Module createIndexModule() {