From d29fa32c8e9fcf514dbae2dcb817999d5b5785b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 9 May 2019 10:36:27 +0200 Subject: [PATCH] First steps to create a bootstrap module for data migration --- .../scm/repository/RepositoryPermission.java | 2 +- scm-webapp/pom.xml | 6 ++ .../main/java/sonia/scm/BootstrapModule.java | 102 ++++++++++++++++++ .../java/sonia/scm/ScmContextListener.java | 11 +- .../main/java/sonia/scm/ScmServletModule.java | 20 ++-- .../scm/boot/BootstrapContextListener.java | 70 ++++++++---- 6 files changed, 176 insertions(+), 35 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/BootstrapModule.java diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java index 4a458a6e6a..79236ab679 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryPermission.java @@ -132,7 +132,7 @@ public class RepositoryPermission implements PermissionObject, Serializable { // Normally we do not have a log of repository permissions having the same size of verbs, but different content. // Therefore we do not use the verbs themselves for the hash code but only the number of verbs. - return Objects.hashCode(name, verbs.size(), groupPermission); + return Objects.hashCode(name, verbs == null? -1: verbs.size(), groupPermission); } diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml index e6a784ddfe..f3c96af5fc 100644 --- a/scm-webapp/pom.xml +++ b/scm-webapp/pom.xml @@ -184,6 +184,12 @@ ${guice.version} + + com.google.inject.extensions + guice-assistedinject + ${guice.version} + + diff --git a/scm-webapp/src/main/java/sonia/scm/BootstrapModule.java b/scm-webapp/src/main/java/sonia/scm/BootstrapModule.java new file mode 100644 index 0000000000..dcb1fe90cf --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/BootstrapModule.java @@ -0,0 +1,102 @@ +package sonia.scm; + +import com.google.inject.AbstractModule; +import com.google.inject.throwingproviders.ThrowingProviderBinder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.config.ScmConfiguration; +import sonia.scm.io.DefaultFileSystem; +import sonia.scm.io.FileSystem; +import sonia.scm.plugin.DefaultPluginLoader; +import sonia.scm.repository.RepositoryDAO; +import sonia.scm.repository.xml.XmlRepositoryDAO; +import sonia.scm.security.CipherUtil; +import sonia.scm.security.DefaultKeyGenerator; +import sonia.scm.security.KeyGenerator; +import sonia.scm.store.BlobStoreFactory; +import sonia.scm.store.ConfigurationEntryStoreFactory; +import sonia.scm.store.ConfigurationStoreFactory; +import sonia.scm.store.DataStoreFactory; +import sonia.scm.store.FileBlobStoreFactory; +import sonia.scm.store.JAXBConfigurationEntryStoreFactory; +import sonia.scm.store.JAXBConfigurationStoreFactory; +import sonia.scm.store.JAXBDataStoreFactory; +import sonia.scm.util.ScmConfigurationUtil; + +public class BootstrapModule extends AbstractModule { + + private static final Logger LOG = LoggerFactory.getLogger(BootstrapModule.class); + + private final ClassOverrides overrides; + private final DefaultPluginLoader pluginLoader; + + public BootstrapModule(ClassOverrides overrides, DefaultPluginLoader pluginLoader) { + this.overrides = overrides; + this.pluginLoader = pluginLoader; + } + + @Override + protected void configure() { + install(ThrowingProviderBinder.forModule(this)); + + ScmConfiguration config = getScmConfiguration(); + + CipherUtil cu = CipherUtil.getInstance(); + + SCMContextProvider context = SCMContext.getContext(); + + bind(SCMContextProvider.class).toInstance(context); + + bind(KeyGenerator.class).to(DefaultKeyGenerator.class); + + bind(RepositoryDAO.class, XmlRepositoryDAO.class); + + bind(FileSystem.class, DefaultFileSystem.class); + + + // bind core + bind(ConfigurationStoreFactory.class, JAXBConfigurationStoreFactory.class); + bind(ConfigurationEntryStoreFactory.class, JAXBConfigurationEntryStoreFactory.class); + bind(DataStoreFactory.class, JAXBDataStoreFactory.class); + bind(BlobStoreFactory.class, FileBlobStoreFactory.class); + + // bind(ScmConfiguration.class).toInstance(config); +// bind(PluginLoader.class).toInstance(pluginLoader); +// bind(PluginManager.class, DefaultPluginManager.class); + + // note CipherUtil uses an other generator +// bind(KeyGenerator.class).to(DefaultKeyGenerator.class); +// bind(CipherHandler.class).toInstance(cu.getCipherHandler()); +// bind(FileSystem.class, DefaultFileSystem.class); + } + + private void bind(Class clazz, Class defaultImplementation) { + Class implementation = find(clazz, defaultImplementation); + LOG.debug("bind {} to {}", clazz, implementation); + bind(clazz).to(implementation); + } + + private Class find(Class clazz, Class defaultImplementation) { + Class implementation = overrides.getOverride(clazz); + + if (implementation != null) { + LOG.info("found override {} for {}", implementation, clazz); + } else { + implementation = defaultImplementation; + + LOG.trace( + "no override available for {}, using default implementation {}", + clazz, implementation); + } + + return implementation; + } + + private ScmConfiguration getScmConfiguration() { + ScmConfiguration configuration = new ScmConfiguration(); + + ScmConfigurationUtil.getInstance().load(configuration); + + return configuration; + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java index 8ae005e826..6dbc33af03 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java @@ -37,6 +37,7 @@ import com.google.common.base.Throwables; import com.google.common.collect.Lists; import com.google.inject.Injector; import com.google.inject.Module; +import com.google.inject.assistedinject.Assisted; import org.apache.shiro.guice.web.ShiroWebModule; import org.jboss.resteasy.plugins.guice.GuiceResteasyBootstrapServletContextListener; import org.slf4j.Logger; @@ -55,6 +56,7 @@ import sonia.scm.upgrade.UpgradeManager; import sonia.scm.user.UserManager; import sonia.scm.util.IOUtil; +import javax.inject.Inject; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import java.util.Collections; @@ -77,9 +79,12 @@ public class ScmContextListener extends GuiceResteasyBootstrapServletContextList private final Set plugins; private Injector injector; - //~--- constructors --------------------------------------------------------- - - public ScmContextListener(ClassLoader parent, Set plugins) + public interface Factory { + ScmContextListener create(ClassLoader parent, Set plugins); + } + + @Inject + public ScmContextListener(@Assisted ClassLoader parent, @Assisted Set plugins) { this.parent = parent; this.plugins = plugins; diff --git a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java index a3661a25f0..fb65b15236 100644 --- a/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java +++ b/scm-webapp/src/main/java/sonia/scm/ScmServletModule.java @@ -208,9 +208,9 @@ public class ScmServletModule extends ServletModule { install(ThrowingProviderBinder.forModule(this)); - SCMContextProvider context = SCMContext.getContext(); - - bind(SCMContextProvider.class).toInstance(context); +// SCMContextProvider context = SCMContext.getContext(); +// +// bind(SCMContextProvider.class).toInstance(context); ScmConfiguration config = getScmConfiguration(); CipherUtil cu = CipherUtil.getInstance(); @@ -230,10 +230,10 @@ public class ScmServletModule extends ServletModule bind(ScmEventBus.class).toInstance(ScmEventBus.getInstance()); // bind core - bind(ConfigurationStoreFactory.class, JAXBConfigurationStoreFactory.class); - bind(ConfigurationEntryStoreFactory.class, JAXBConfigurationEntryStoreFactory.class); - bind(DataStoreFactory.class, JAXBDataStoreFactory.class); - bind(BlobStoreFactory.class, FileBlobStoreFactory.class); +// bind(ConfigurationStoreFactory.class, JAXBConfigurationStoreFactory.class); +// bind(ConfigurationEntryStoreFactory.class, JAXBConfigurationEntryStoreFactory.class); +// bind(DataStoreFactory.class, JAXBDataStoreFactory.class); +// bind(BlobStoreFactory.class, FileBlobStoreFactory.class); bind(ScmConfiguration.class).toInstance(config); bind(PluginLoader.class).toInstance(pluginLoader); bind(PluginManager.class, DefaultPluginManager.class); @@ -242,9 +242,9 @@ public class ScmServletModule extends ServletModule bind(Scheduler.class).to(QuartzScheduler.class); // note CipherUtil uses an other generator - bind(KeyGenerator.class).to(DefaultKeyGenerator.class); +// bind(KeyGenerator.class).to(DefaultKeyGenerator.class); bind(CipherHandler.class).toInstance(cu.getCipherHandler()); - bind(FileSystem.class, DefaultFileSystem.class); +// bind(FileSystem.class, DefaultFileSystem.class); // bind health check stuff bind(HealthCheckContextListener.class); @@ -266,7 +266,7 @@ public class ScmServletModule extends ServletModule // bind dao bind(GroupDAO.class, XmlGroupDAO.class); bind(UserDAO.class, XmlUserDAO.class); - bind(RepositoryDAO.class, XmlRepositoryDAO.class); +// bind(RepositoryDAO.class, XmlRepositoryDAO.class); bindDecorated(RepositoryManager.class, DefaultRepositoryManager.class, RepositoryManagerProvider.class); diff --git a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java index be5a1e7ac2..766024158a 100644 --- a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java +++ b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java @@ -28,22 +28,25 @@ */ - package sonia.scm.boot; -//~--- non-JDK imports -------------------------------------------------------- - import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; import com.google.common.io.Files; - +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.assistedinject.FactoryModuleBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - +import sonia.scm.BootstrapModule; +import sonia.scm.ClassOverrides; import sonia.scm.SCMContext; import sonia.scm.ScmContextListener; import sonia.scm.Stage; import sonia.scm.event.ScmEventBus; +import sonia.scm.plugin.DefaultPluginLoader; import sonia.scm.plugin.Plugin; import sonia.scm.plugin.PluginException; import sonia.scm.plugin.PluginLoadException; @@ -53,29 +56,23 @@ import sonia.scm.plugin.SmpArchive; import sonia.scm.util.ClassLoaders; import sonia.scm.util.IOUtil; -//~--- JDK imports ------------------------------------------------------------ - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; - -import java.net.MalformedURLException; -import java.net.URL; - -import java.util.Iterator; -import java.util.List; -import java.util.Set; - import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; - import javax.xml.bind.DataBindingException; import javax.xml.bind.JAXB; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Iterator; +import java.util.List; +import java.util.Set; /** * @@ -161,7 +158,38 @@ public class BootstrapContextListener implements ServletContextListener Set plugins = PluginsInternal.collectPlugins(cl, pluginDirectory.toPath()); - contextListener = new ScmContextListener(cl, plugins); + + Module scmContextListenerModule = new AbstractModule() { + @Override + protected void configure() { + + install(new FactoryModuleBuilder().build(ScmContextListener.Factory.class)); + } + }; + + + + DefaultPluginLoader pluginLoader = new DefaultPluginLoader(context, cl, plugins); + + Injector bootstrapInjector = Guice.createInjector(new BootstrapModule( + ClassOverrides.findOverrides(pluginLoader.getUberClassLoader()), + pluginLoader + ), + scmContextListenerModule + ); + + + + + contextListener = bootstrapInjector.getInstance(ScmContextListener.Factory.class).create(cl, plugins); + + +// Set steps = bootstrapInjector.getInstance(....); + // migrate + + + +// contextListener = new ScmContextListener(cl, plugins); } catch (IOException ex) { @@ -169,7 +197,7 @@ public class BootstrapContextListener implements ServletContextListener } contextListener.contextInitialized(sce); - + // register for restart events if (!registered && (SCMContext.getContext().getStage() == Stage.DEVELOPMENT))