From be9ce826dce00df63e2640a9f946d1f16def2a95 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Tue, 21 May 2019 09:13:49 +0200
Subject: [PATCH 1/2] Move further listener modules to bootstrap module
---
.../src/main/java/sonia/scm/ScmContextListener.java | 2 --
.../sonia/scm/boot/BootstrapContextListener.java | 13 ++++++++++++-
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java
index 4f61ebaa17..40fb345caa 100644
--- a/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java
+++ b/scm-webapp/src/main/java/sonia/scm/ScmContextListener.java
@@ -132,8 +132,6 @@ public class ScmContextListener extends GuiceResteasyBootstrapServletContextList
List moduleList = Lists.newArrayList();
moduleList.add(new ResteasyModule());
- moduleList.add(new ScmInitializerModule());
- moduleList.add(new EagerSingletonModule());
moduleList.add(ShiroWebModule.guiceFilterModule());
moduleList.add(new WebElementModule(pluginLoader));
moduleList.add(new ScmServletModule(context, pluginLoader, overrides));
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 86e62d8f94..69e70828a2 100644
--- a/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java
+++ b/scm-webapp/src/main/java/sonia/scm/boot/BootstrapContextListener.java
@@ -39,9 +39,11 @@ import com.google.inject.Module;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import sonia.scm.EagerSingletonModule;
import sonia.scm.SCMContext;
import sonia.scm.ScmContextListener;
import sonia.scm.ScmEventBusModule;
+import sonia.scm.ScmInitializerModule;
import sonia.scm.Stage;
import sonia.scm.event.ScmEventBus;
import sonia.scm.plugin.DefaultPluginLoader;
@@ -150,9 +152,18 @@ public class BootstrapContextListener implements ServletContextListener {
Module scmContextListenerModule = new ScmContextListenerModule();
BootstrapModule bootstrapModule = new BootstrapModule(pluginLoader);
+ ScmInitializerModule scmInitializerModule = new ScmInitializerModule();
+ EagerSingletonModule eagerSingletonModule = new EagerSingletonModule();
ScmEventBusModule scmEventBusModule = new ScmEventBusModule();
- Injector bootstrapInjector = Guice.createInjector(bootstrapModule, scmContextListenerModule, scmEventBusModule);
+ Injector bootstrapInjector =
+ Guice.createInjector(
+ bootstrapModule,
+ scmContextListenerModule,
+ scmEventBusModule,
+ scmInitializerModule,
+ eagerSingletonModule
+ );
processUpdates(pluginLoader, bootstrapInjector);
From f3d7727198828ac7427e7550d032441a18a348a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?=
Date: Mon, 20 May 2019 16:34:22 +0200
Subject: [PATCH 2/2] Add documentation
---
.../java/sonia/scm/migration/UpdateStep.java | 69 +++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/scm-core/src/main/java/sonia/scm/migration/UpdateStep.java b/scm-core/src/main/java/sonia/scm/migration/UpdateStep.java
index eaa6d8d549..ed5f60a630 100644
--- a/scm-core/src/main/java/sonia/scm/migration/UpdateStep.java
+++ b/scm-core/src/main/java/sonia/scm/migration/UpdateStep.java
@@ -3,11 +3,80 @@ package sonia.scm.migration;
import sonia.scm.plugin.ExtensionPoint;
import sonia.scm.version.Version;
+/**
+ * This is the main interface for data migration/update. Using this interface, SCM-Manager provides the possibility to
+ * change data structures between versions for a given type of data.
+ * The data type can be an arbitrary string, but it is considered a best practice to use a qualified name, for
+ * example
+ *
+ * com.example.myPlugin.configuration for data in plugins, or
+ * com.cloudogu.scm.repository for core data structures.
+ *
+ *
+ * The version is unrelated to other versions and therefore can be chosen freely, so that a data type can be updated
+ * without in various ways independent of other data types or the official version of the plugin or the core.
+ * A coordination between different data types and their versions is only necessary, when update steps of different data
+ * types rely on each other. If a update step of data type A has to run before another step for data type
+ * B, the version number of the second step has to be greater in regards to {@link Version#compareTo(Version)}.
+ *
+ * The algorithm looks something like this:
+ * Whenever the SCM-Manager starts,
+ *
+ * - it creates a so called bootstrap guice context, that contains
+ *
+ * - a {@link sonia.scm.security.KeyGenerator},
+ * - the {@link sonia.scm.repository.RepositoryLocationResolver},
+ * - the {@link sonia.scm.io.FileSystem},
+ * - the {@link sonia.scm.security.CipherHandler},
+ * - a {@link sonia.scm.store.ConfigurationStoreFactory},
+ * - a {@link sonia.scm.store.ConfigurationEntryStoreFactory},
+ * - a {@link sonia.scm.store.DataStoreFactory},
+ * - a {@link sonia.scm.store.BlobStoreFactory}, and
+ * - the {@link sonia.scm.plugin.PluginLoader}.
+ *
+ * Mind, that there are no DAOs, Managers or the like available at this time!
+ *
+ * - It then checks whether there are instances of this interface that have not run before, that is either
+ *
+ * - their version number given by {@link #getTargetVersion()} is bigger than the last recorded target version of an
+ * executed update step for the data type given by {@link #getAffectedDataType()}, or
+ *
+ * - there is no version number known for the given data type.
+ *
+ *
+ * These are the relevant update steps.
+ *
+ * - These relevant update steps are then sorted ascending by their target version given by
+ * {@link #getTargetVersion()}.
+ *
+ * - Finally, these sorted steps are executed one after another calling {@link #doUpdate()} of each step, updating the
+ * version for the data type accordingly.
+ *
+ * - If all works well, SCM-Manager then creates the runtime guice context by loading all further modules.
+ * - If any of the update steps fails, the whole process is interrupted and SCM-Manager will not start up and will
+ * not record the version number of this update step.
+ *
+ *
+ *
+ */
@ExtensionPoint
public interface UpdateStep {
+ /**
+ * Implement this to update the data to the new version. If any {@link Exception} is thrown, SCM-Manager will not
+ * start up.
+ */
void doUpdate() throws Exception;
+ /**
+ * Declares the new version of the data type given by {@link #getAffectedDataType()}. A update step will only be
+ * executed, when this version is bigger than the last recorded version for its data type according to
+ * {@link Version#compareTo(Version)}
+ */
Version getTargetVersion();
+ /**
+ * Declares the data type this update step will take care of. This should be a qualified name, like
+ * com.example.myPlugin.configuration.
+ */
String getAffectedDataType();
}