p.purr p.purr - 1 month ago 20
Java Question

Use of Flyway with RCP built from Eclipse plugins

We have an RCP application built from many individual plug-ins that save and restore application data to a single, user-selectable database made up of several tables. Over time the database format changes and we want to be able to manage these changes by using Flyway database migration.

One solution would be to have each plugin performing its own migration (i.e. call Flyway.migrate in each plugin) however this has the disadvantage that if tables in the database are shared by more than one plugin then ordering the execution order of the migrate calls between plug-ins becomes key and problematic.

A better solution would be to have a single Migrate call but the problem then becomes how to feed the classpaths of the Java migration scripts to the Flyway instance especially given that due to the lazy loading of the Eclipse plug-ins classes with the migration code required may not yet have been loaded. This is not a problem for SQL based migration scripts as the API supports this - it does not support it for classpath based searching.

The question then is there a way to ensure that when Flyway.migrate() is called from a single plug-in all the classpaths of migration scripts are discoverable by the flyway scanner classes?

Any suggestions greatly appreciated ...

Answer Source

The kind of problem is usually solved with extension points and extensions in RCP/plug-in based applications.

For example, the migration plug-in could define an extension point migrationScript that is able to specify the SQL code to migrate the database schema. Then individual plug-ins are free to contribute migrations scripts to this extension.

<extension point="org.example.migrationScript">
  <script sql="alter table ..." />
</extension>

At runtime, the migration plug-in can use the IExtensionRegistry to read all migrationScript extensions. The RCP runtime ensures that extensions from all installed plug-ins are read and activates contributing plugins as necessary (e.g. if their code is invoked).

If the migration requires Java code to be contributed, the migration plug-in can define an interface or abstract class for which the contributing plug-ins can provide concrete implementations.

For example, the migration plugin defines this interface:

interface ScriptProvider {
  String sql();
}

... and individual plug-ins contribute their share to the migration

<extension point="org.example.migrationScript">
  <script class="org.example.MyScriptProvider" />
</extension>

public class MyScriptProvider {
  public String sql() { return "alter table ..."; }
}

The classpath and activation of necessary plug-ins are managed by the RCP runtime and OSGi respectively.