Package org.eclipse.emf.cdo.server.db.evolution.phased

# Class PhasedModelEvolutionSupport

java.lang.Object
org.eclipse.net4j.util.event.Notifier
org.eclipse.net4j.util.lifecycle.Lifecycle
org.eclipse.emf.cdo.server.db.evolution.phased.PhasedModelEvolutionSupport

All Implemented Interfaces:
  `IModelEvolutionSupport`, `org.eclipse.net4j.util.event.INotifier`, `org.eclipse.net4j.util.event.INotifier.INotifier2`, `org.eclipse.net4j.util.lifecycle.IDeactivateable`, `org.eclipse.net4j.util.lifecycle.ILifecycle`, `org.eclipse.net4j.util.lifecycle.ILifecycle.DeferrableActivation`

public class PhasedModelEvolutionSupport extends org.eclipse.net4j.util.lifecycle.Lifecycle implements IModelEvolutionSupport
A `phased` implementation of `model evolution support` for DB stores.

Model evolution support is responsible for evolving the models stored in a DB store to match the currently registered EPackages.

This implementation is based on a phased approach. The following phases are supported:

1. Change detection: Detects model changes between the stored models and the currently registered EPackages. If no changes are detected, the model evolution process is aborted.
2. Repository export: Exports the repository data to a temporary location to prepare for schema migration. This phase is optional.
3. Schema migration: Evolves the database schema to match the new models. This includes updating the database schema, changing the container feature IDs in case of shifted features, and adjusting enum literals in case of changed enums. This phase is mandatory and ensures that the database schema is in sync with the new models.
4. Store processing: Performs any necessary post-processing on the DB store after schema migration. This phase is optional.
5. Repository processing: Performs any necessary post-processing on the repository after the DB store has been processed. This phase is optional.

Each phase is handled by a dedicated `phase handler`. Phase handlers can be configured via dependency injection (see `AnnotationFactory`). The Change Detection and Schema Migration phases must have a phase handler configured. If no phase handler is configured for these phases, a default implementation is used:

- Change Detection: `DefaultChangeDetector`
- Schema Migration: `DefaultSchemaMigrator`

The Repository Export, Store Processing, and Repository Processing phases may be skipped if no phase handler is configured for them. The Repository Export phase is the only optional phase for which a default implementation exists: `DefaultRepositoryExporter`.

Each phase is triggered at a specific point during the activation of the DB store and the repository. There are two `triggers`:

- `ActivatingStore`: Triggered when the DB store is being activated by the `IRepository`. This is the main trigger for model evolution. It only occurs when the store is restarted, i.e., not when the store is activated for the first time.
- `ActivatedRepository`: Triggered when the `IRepository` has been fully activated. This trigger exists mainly for special purposes, e.g., to export repository models before the schema is upgraded.

Phases can request a store or repository restart by returning the appropriate `Phase.Transition` from their `transition` method.

The model evolution process can be configured via the `mode` attribute, which can be set to `migrate` (default), `prevent`, or `disabled`. In `migrate` mode, model changes are automatically evolved. In `prevent` mode, an exception is thrown if model changes are detected. In `disabled` mode, model evolution is skipped entirely.

The model evolution process stores its state in a dedicated root folder, which can be configured via the `rootFolder` attribute. The root folder contains an `evolution.properties` file storing the current evolution ID and phase, as well as dedicated evolution folders for each evolution process. Each evolution folder is named after the evolution ID and contains the exported models and an optional evolution log. The `DefaultRepositoryExporter` stores the repository export file in the evolution folder during the Repository Export phase.

The model evolution context, which contains the models to be evolved and other relevant information, is persisted in the evolution folder after the Change Detection phase. If the model evolution process is interrupted, it can be resumed from the persisted context. Manual inspection of the evolution folder may help diagnosing issues during model evolution or recovering from failures. The context is managed by a `context manager`, which can be configured via dependency injection.

The phases and their handlers fire various events during the model evolution process. Clients can register `listeners` with the model evolution support to be notified about these events and to monitor or impact the evolution process. Registering a `LogListener` will log all evolution events to the logging system and helps to understand the evolution process.

Example configuration snippet:

     <store type="db">
       ...
       <modelEvolutionSupport type="phased" rootFolder="@state/evolution" mode="migrate">
         <
         <changeDetector/>
         <repositoryExporter type="default" binary="false"/>
         <schemaMigrator/>
         <storeProcessor type="my-sql-processor" myExtraArg="data"/>
         <repositoryProcessor type="my-eobject-handler" myExtraArg="data"/> -->
         <!-- Optional listeners -->
         <listener type="log"/>
         <listener type="my-extra-checks"/>
       </modelEvolutionSupport>
       ...
     </store>

Since:
  4.14
Author:
  Eike Stepper
No Implement
  This package is currently considered provisional.
No Extend
  This package is currently considered provisional.
No Reference
  This package is currently considered provisional.

## Nested Class Summary

Nested Classes
Modifier and Type
Class
Description
`static enum`
`PhasedModelEvolutionSupport.Mode`
Indicates the model evolution mode.

## Nested classes/interfaces inherited from class org.eclipse.net4j.util.event.Notifier

`org.eclipse.net4j.util.event.Notifier.Cancelation`

## Nested classes/interfaces inherited from interface org.eclipse.net4j.util.lifecycle.ILifecycle

`org.eclipse.net4j.util.lifecycle.ILifecycle.DeferrableActivation`

## Nested classes/interfaces inherited from interface org.eclipse.emf.cdo.server.db.evolution.IModelEvolutionSupport

`IModelEvolutionSupport.Trigger`

## Nested classes/interfaces inherited from interface org.eclipse.net4j.util.event.INotifier

`org.eclipse.net4j.util.event.INotifier.INotifier2`

## Field Summary

Fields
Modifier and Type
Field
Description
`static final String`
`FACTORY_TYPE`
The factory type of the default model evolution support implementation.

### Fields inherited from class org.eclipse.net4j.util.lifecycle.Lifecycle

`USE_LABEL`

### Fields inherited from interface org.eclipse.emf.cdo.server.db.evolution.IModelEvolutionSupport

`PRODUCT_GROUP`

## Constructor Summary

Constructors
Constructor
Description
`PhasedModelEvolutionSupport()`
Creates a model evolution support.

## Method Summary

Modifier and Type
Method
Description
`protected void`
`addedChangeInfo(Context.Model model, Object changeInfo)`
Called after a change info has been added to the evolution context.
`protected Phase`
`determineNextPhase()`
Determines the next phase to execute, skipping any phases without a handler.
`protected void`
`doActivate()`
`protected void`
`doBeforeActivate()`
`protected void`
`doDeactivate()`
`protected void`
`executePhaseHandler(Phase.Handler phaseHandler)`
Executes the given phase handler.
`protected void`
`executePhaseLoop()`
Executes the phase loop until completion or until a restart is requested.
`Context`
`getContext()`
Returns the current evolution context.
`Context.Manager`
`getContextManager()`
Returns the context manager used to create, load, and save evolution contexts.
`protected Phase.Handler`
`getCurrentPhaseHandler()`
Returns the handler for the current phase, throwing an exception if none is set.
`File`
`getEvolutionFolder()`
Returns the evolution folder for the current evolution ID, or `null` if the evolution ID is less than 1.
`int`
`getEvolutionID()`
Returns the current evolution ID.
`File`
`getEvolutionLog()`
`PhasedModelEvolutionSupport.Mode`
`getMode()`
Returns the model evolution mode.
`InternalCDOPackageRegistry`
`getNewPackageRegistry()`
Returns the new package registry used for determining the new EPackages.
`InternalCDOPackageRegistry`
`getOldPackageRegistry()`
Returns the old package registry used for recreating the old EPackages.
`Phase`
`getPhase()`
Returns the current evolution phase.
`Phase.Handler`
`getPhaseHandler(Phase phase)`
Returns the phase handler for the given phase, or `null` if none is set.
`File`
`getRootFolder()`
Returns the root folder where evolution data is stored.
`IDBStore`
`getStore()`
Returns the DB store this model evolution support is associated with.
`boolean`
`isPhaseOngoing()`
Returns whether the current phase is ongoing.
`void`
`log(Object message)`
Logs the given message to the evolution log.
`void`
`setChangeDetector(Phase.Handler changeDetector)`
Sets the change detection phase handler.
`void`
`setContextManager(Context.Manager contextManager)`
Sets the context manager used to create, load, and save evolution contexts.
`void`
`setMode(PhasedModelEvolutionSupport.Mode mode)`
Sets the model evolution mode.
`void`
`setRepositoryExporter(Phase.Handler repositoryExporter)`
Sets the repository export phase handler.
`void`
`setRepositoryPostProcessor(Phase.Handler repositoryProcessor)`
Sets the repository post-processing phase handler.
`void`
`setRootFolder(File rootFolder)`
Sets the root folder where evolution data is stored.
`void`
`setSchemaMigrator(Phase.Handler schemaMigrator)`
Sets the schema migration phase handler.
`void`
`setStore(IDBStore store)`
Sets the DB store this model evolution support is associated with.
`void`
`setStorePostProcessor(Phase.Handler storeProcessor)`
Sets the store post-processing phase handler.
`void`
`trigger(IModelEvolutionSupport.Trigger trigger)`
Evolves the models stored in the given DB store to match the currently registered `EPackages`.

### Methods inherited from class org.eclipse.net4j.util.lifecycle.Lifecycle

`activate, checkActive, checkArg, checkArg, checkInactive, checkNull, checkState, checkState, deactivate, deferredActivate, doAfterActivate, doBeforeDeactivate, dump, getLifecycleState, isActive, isDeferredActivation, toString`

### Methods inherited from class org.eclipse.net4j.util.event.Notifier

`addListener, addUniqueListener, fireEvent, fireEvent, fireEvent, fireThrowable, firstListenerAdded, getListeners, getNotificationService, hasListener, hasListeners, lastListenerRemoved, listenerAdded, listenerRemoved, removeListener`

### Methods inherited from class java.lang.Object

`clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

### Methods inherited from interface org.eclipse.net4j.util.lifecycle.ILifecycle

`activate, deactivate, getLifecycleState, isActive`

### Methods inherited from interface org.eclipse.net4j.util.event.INotifier

`addListener, getListeners, hasListeners, removeListener`

## Field Details

### FACTORY_TYPE

public static final String FACTORY_TYPE
The factory type of the default model evolution support implementation.

See Also:
  - Constant Field Values

## Constructor Details

### PhasedModelEvolutionSupport

public PhasedModelEvolutionSupport()
Creates a model evolution support.

## Method Details

### getRootFolder

public File getRootFolder()
Returns the root folder where evolution data is stored.

The root folder contains the evolution properties file and dedicated evolution folders for each evolution process.

See Also:
  - `getEvolutionFolder()`

### setRootFolder

public void setRootFolder(File rootFolder)
Sets the root folder where evolution data is stored.

### getStore

public IDBStore getStore()
Returns the DB store this model evolution support is associated with.

Specified by:
  `getStore` in interface `IModelEvolutionSupport`

### setStore

public void setStore(IDBStore store)
Sets the DB store this model evolution support is associated with.

Specified by:
  `setStore` in interface `IModelEvolutionSupport`
No Reference
  This method is not intended to be called by clients.

### getMode

public PhasedModelEvolutionSupport.Mode getMode()
Returns the model evolution mode.

### setMode

public void setMode(PhasedModelEvolutionSupport.Mode mode)
Sets the model evolution mode.

### getContextManager

public Context.Manager getContextManager()
Returns the context manager used to create, load, and save evolution contexts.

### setContextManager

public void setContextManager(Context.Manager contextManager)
Sets the context manager used to create, load, and save evolution contexts.

### getPhaseHandler

public Phase.Handler getPhaseHandler(Phase phase)
Returns the phase handler for the given phase, or `null` if none is set.

### setChangeDetector

public void setChangeDetector(Phase.Handler changeDetector)
Sets the change detection phase handler.

### setRepositoryExporter

public void setRepositoryExporter(Phase.Handler repositoryExporter)
Sets the repository export phase handler.

### setSchemaMigrator

public void setSchemaMigrator(Phase.Handler schemaMigrator)
Sets the schema migration phase handler.

### setStorePostProcessor

public void setStorePostProcessor(Phase.Handler storeProcessor)
Sets the store post-processing phase handler.

### setRepositoryPostProcessor

public void setRepositoryPostProcessor(Phase.Handler repositoryProcessor)
Sets the repository post-processing phase handler.

### getPhase

public Phase getPhase()
Returns the current evolution phase.

### isPhaseOngoing

public boolean isPhaseOngoing()
Returns whether the current phase is ongoing.

### getEvolutionID

public int getEvolutionID()
Returns the current evolution ID.

The evolution ID is incremented each time a model evolution process is successfully completed. It starts at 0 for a new repository and is stored in the evolution properties file.

The evolution ID is used to create a dedicated evolution folder under the root folder for each evolution process.

See Also:
  - `getEvolutionFolder()`

### getEvolutionFolder

public File getEvolutionFolder()
Returns the evolution folder for the current evolution ID, or `null` if the evolution ID is less than 1.

The evolution folder is a subfolder of the root folder named after the evolution ID. It contains the models properties file and the exported models for the corresponding evolution process.

See Also:
  - `getRootFolder()`
  - `getEvolutionID()`

### getEvolutionLog

public File getEvolutionLog()

### getContext

public Context getContext()
Returns the current evolution context.

The evolution context contains the models to be evolved and other relevant information for the model evolution process.

### getOldPackageRegistry

public InternalCDOPackageRegistry getOldPackageRegistry()
Returns the old package registry used for recreating the old EPackages.

### getNewPackageRegistry

public InternalCDOPackageRegistry getNewPackageRegistry()
Returns the new package registry used for determining the new EPackages.

### log

public void log(Object message)
Logs the given message to the evolution log.

Can be used by phases and handlers to log messages during model evolution.

The evolution log is typically located in the `evolution folder`.

### trigger

public void trigger(IModelEvolutionSupport.Trigger trigger) throws Exception
Evolves the models stored in the given DB store to match the currently registered `EPackages`.

The evolution process is triggered by the given `trigger`. Depending on the current phase of the evolution process, the appropriate phase handler is executed.

If the evolution mode is set to `PhasedModelEvolutionSupport.Mode.Disabled`, the evolution process is skipped.

If the evolution mode is set to `PhasedModelEvolutionSupport.Mode.Prevent` and model changes are detected, an exception is thrown.

If the evolution mode is set to `PhasedModelEvolutionSupport.Mode.Migrate`, the evolution process is executed phase by phase until completion.

If a phase handler requests a store or repository restart, a `LifecycleUtil.ReactivationTrigger` is thrown to signal the need for a restart.

Specified by:
  `trigger` in interface `IModelEvolutionSupport`
Throws:
  `Exception`

### executePhaseLoop

protected void executePhaseLoop() throws IOException, Exception, org.eclipse.net4j.util.lifecycle.LifecycleUtil.ReactivationTrigger
Executes the phase loop until completion or until a restart is requested.

Throws:
  `IOException`
  `Exception`
  `org.eclipse.net4j.util.lifecycle.LifecycleUtil.ReactivationTrigger`

### executePhaseHandler

protected void executePhaseHandler(Phase.Handler phaseHandler) throws Exception
Executes the given phase handler.

Throws:
  `Exception`

### determineNextPhase

protected Phase determineNextPhase()
Determines the next phase to execute, skipping any phases without a handler.

Returns:
  the next phase to execute, or `null` if there are no more phases left to execute.

### getCurrentPhaseHandler

protected Phase.Handler getCurrentPhaseHandler()
Returns the handler for the current phase, throwing an exception if none is set.

### addedChangeInfo

protected void addedChangeInfo(Context.Model model, Object changeInfo)
Called after a change info has been added to the evolution context.

Can be used by phases and handlers to notify listeners about added change infos.

Subclasses may override.

### doBeforeActivate

protected void doBeforeActivate() throws Exception

Overrides:
  `doBeforeActivate` in class `org.eclipse.net4j.util.lifecycle.Lifecycle`
Throws:
  `Exception`

### doActivate

protected void doActivate() throws Exception

Overrides:
  `doActivate` in class `org.eclipse.net4j.util.lifecycle.Lifecycle`
Throws:
  `Exception`

### doDeactivate

protected void doDeactivate() throws Exception

Overrides:
  `doDeactivate` in class `org.eclipse.net4j.util.lifecycle.Lifecycle`
Throws:
  `Exception`