An apache karaf feature for the liquibase RDMBS schema management, including slf4j logging.
|
1 week ago | |
---|---|---|
.github | 2 months ago | |
liquibase-bom | 2 months ago | |
liquibase-core-karaf | 1 week ago | |
liquibase-integration-test | 2 months ago | |
liquibase-libraries | 2 months ago | |
.editorconfig | 5 years ago | |
.gitignore | 2 years ago | |
LICENSE | 7 years ago | |
README.org | 2 months ago | |
pom.xml | 1 week ago |
NOTE! Version 4.15.0 is the first release of the liquibase karaf feature in nearly three years See Using liquibase from OSGi bundles if you come from version 3.8.0 of this feature, for changes that need to be made.
This project contains a karaf feature for easily using Liquibase from OSGi-based applications running in apache karaf.
If you haven't yet encountered it: liquibase is a really smooth solution for handling your RDBMS schemas. Smooth initial startup, and smooth evolution of schemas (adding columns, adding tables, dropping columns and dropping tables).
Liquibase does the same job as ad-hoc delta script solutions, but liquibase does the job in a clean and robust way, tested and refined over the 11 years of its existence.
Liquibase does pretty much the same thing as flyway but in a different way that fits my programmer's mind better. And liquibase is cross-database capable, i.e. done right it's possible to write schema migrations in ways that will make them work on all databases with a JDBC driver.
file:https://maven-badges.herokuapp.com/maven-central/no.priv.bang.karaf/liquibase-core-karaf/badge.svg file:https://github.com/steinarb/liquibase-karaf-feature/actions/workflows/liquibase-karaf-feature-maven-ci-build.yml/badge.svg
Date | Version | Liquibase version | Liquibase slf4j version | Comment |
---|---|---|---|---|
<2024-12-10 Tue 20:31> | 4.30.0 | 4.30.0 | ||
<2024-07-31 Wed 18:13> | 4.29.0 | 4.29.0 | ||
<2024-07-03 Wed 22:07> | 4.28.0.1 | 4.28.0 | Bugfix for 4.28.0 release | |
<2024-07-03 Wed 21:33> | 4.28.0 | 4.28.0 | Adds new liquibase-runner library | |
<2024-04-05 Fri 22:27> | 4.27.0 | 4.27.0 | ||
<2023-12-11 Mon 22:33> | 4.24.0 | 4.24.0 | ||
<2023-12-12 Tue 22:33> | 4.23.2 | 4.23.2 | ||
<2023-12-11 Mon 21:07> | 4.25.0 | 4.23.1 | Mistaken release! Sorry! | |
<2023-12-11 Mon 20:44> | 4.23.1 | 4.23.1 | Integration test had to replace derby with h2 | |
<2023-06-28 Wed 23:53> | 4.23.0 | 4.23.0 | First OSGi compatible version since 4.19.0 | |
<2023-03-05 Sun 21:10> | 4.19.0 | 4.19.0 | ||
<2022-10-30 Sun 15:48> | 4.17.1 | 4.17.1 | ||
<2022-08-20 Sat 19:27> | 4.15.0 | 4.15.0 | First liquibase 4.x release of the feature | |
<2019-11-18 Mon 21:25> | 3.8.0 | 3.8.0 | 2.0.0 | |
<2019-11-18 Mon 20:42> | 3.7.0 | 3.7.0 | 2.0.0 | Use snakeyaml 1.23 |
<2019-11-18 Mon 19:33> | 3.6.3 | 3.6.3 | 2.0.0 | |
<2019-11-17 Sun 22:58> | 3.6.2 | 3.6.2 | 2.0.0 | |
<2019-11-17 Sun 22:09> | 3.6.1.1 | 3.6.1 | 2.0.0 | Loads snakeyaml 1.18 instead of 1.17 |
<2019-11-17 Sun 17:35> | 3.6.1 | 3.6.1 | 2.0.0 | Broken because of wrong snakeyaml version |
<2019-11-17 Sun 21:27> | 3.6.0.1 | 3.6.0 | 2.0.0 | Loads snakeyaml 1.18 instead of 1.17 |
<2019-11-17 Sun 16:01> | 3.6.0 | 3.6.0 | 2.0.0 | Broken because of wrong snakeyaml version |
<2019-11-16 Sat 23:09> | 3.5.5 | 3.5.5 | 2.0.0 | Use version 3.5.1 of maven-bundle-plugin |
<2019-11-16 Sat 11:28> | 3.5.4 | 3.5.4 | 2.0.0 | Updated pom.xml release config, update karaf to 4.2.7 |
<2017-08-06 Sun 18:48> | 3.5.3 | 3.5.3 | 2.0.0 | First release with the same version as the liquibase version |
<2017-08-06 Sun 15:18> | 1.0.2 | 3.5.3 | 2.0.0 | First successful release |
<2017-08-06 Sun 12:03> | 1.0.1 | 3.5.3 | 2.0.0 | Failed release |
<2017-08-05 Sat 21:37> | 1.0.0 | 3.5.3 | 2.0.0 | Failed release |
After this, the liquibase Java API is available to your OSGi applications and the liquibase logging will go to the karaf log.
To use liquibase from your own, manually edited, karaf feature, include the feature's feature repository and depend on the liquibase-core feature:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="ukelonn.bundle.db.liquibase">
<repository>mvn:no.priv.bang.karaf/liquibase-core-karaf/4.30.0/xml/features</repository>
<feature name="ukelonn-db-liquibase">
<feature>liquibase-core</feature>
</feature>
</features>
If you generate your karaf feature repository using the karaf-maven-plugin, you can include the liquibase-core feature into your generated feature repository, by adding this dependency to the maven project building the feature repository:
<dependency>
<groupId>no.priv.bang.karaf</groupId>
<artifactId>liquibase-core-karaf</artifactId>
<version>4.30.0</version>
<type>xml</type>
<classifier>features</classifier>
</dependency>
The version number of this karaf feature is intended to be the same as the Liquibase version it is a feature for.
This makes it simple for me to roll and release a new version of the feature when a new version of Liquibase is out.
I have created the project liquibase-sample to test new versions of this karaf feature.
The liquibase-sample has a minimal OSGi component that loads and creates a schema in a derby in-memory database from a liquibase changelog file.
The liquibase-sample application can also be used to verify that the liquibase logs are redirected to the karaf logs.
Liquibase 4 is built internally with an inversion-of-control architecture, and uses java.util.ServiceLoader to find the implementations of its services.
The ServiceLoader doesn't work well with OSGi. The ServiceLoader expects a single, flat, classloader, and a single thread, and this is not what OSGi has.
It is possible to make the ServiceLoader work in OSGi, using the Service Loader Mediator.
A single implementation of the service loader mediator exists: Apache Aries SPI Fly.
The liquibase karaf feature created from this project will load SPI Fly at the same start-level as the liquibase-core bundle.
The Require-Capability header of OSGi bundle manifests can be used to start available SPI services, and once started they will behave as regular OSGi services.
The liquibase-core bundle will start all SPI services it requires in the maniest, so you, as a user, don't have to think about SPI or Apache Aries SPI Fly (but it can be helpful to know what's going on).
Note! One thing you will need to think about is if you use XML formatted Liquibase change logs: Liquibase will need to find the XSD schema files when parsing the change logs.
The XSD files are provideded as classpath resources in the liquibase-core OSGi bundle.
But these resources aren't available to other OSGi bundles (classpath resources are local to the bundle they reside in).
This means that all OSGi bundles that parse XML liquibase change logs needs to copy the XSD schemas of liquibase-core into its own classpath.
The of the maven-bundle-plugin config below will copy the XSD schemas into the place where liquibase will look for them.
Copy this config into all OSGi bundles that load liquibase XML change logs.
org.apache.felix maven-bundle-plugin 5.1.9 =target/classes, /www.liquibase.org/=target/dependency/www.liquibase.org/ org.apache.maven.plugins maven-dependency-plugin copy-liquibase-xsd validate unpack org.liquibase liquibase-core **/dbchangelog-3.5.xsd
In the above example only dbchangelog-3.5 is copied. If a different schema version is used, that version must be copied instead.
To copy all schemas, change includes to this (Disclaimer: not tested):
*/.xsd
private Bundle bundle;
@Activate public void activate(BundleContext bundlecontext) { this.bundle = bundlecontext.getBundle(); }
@Override public void prepare(DataSource datasource) throws SQLException { try (Connection connection = datasource.getConnection()) { applyLiquibaseChangelist(connection, "sample-db-changelog/db-changelog-1.0.0.xml"); } catch (LiquibaseException e) { throw new RuntimeException("Error creating sampleapp test database schema", e); } }
private void applyLiquibaseChangelist(Connection connection, String changelistClasspathResource) throws LiquibaseException { try(Liquibase liquibase = createLiquibaseInstance(connection, changelistClasspathResource)) { liquibase.update(""); } }
private Liquibase createLiquibaseInstance(Connection connection, String changelistClasspathResource) throws LiquibaseException { DatabaseConnection databaseConnection = new JdbcConnection(connection); var resourceAccessor = new OSGiResourceAccessor(bundle); return new Liquibase(changelistClasspathResource, resourceAccessor, databaseConnection); }
} #+end_src has to be replaced with something like this: #+begin_src java @Component(immediate=true, property = "name=sampledb") public class SampleDbLiquibaseRunner implements PreHook {
@Activate public void activate(BundleContext bundlecontext) { Scope.setScopeManager(new ThreadLocalScopeManager()); }
@Override public void prepare(DataSource datasource) throws SQLException { try (var connection = datasource.getConnection()) { applyLiquibaseChangelist(connection, "sample-db-changelog/db-changelog-1.0.0.xml"); } catch (Exception e) { throw new RuntimeException("Error creating sampleapp test database schema", e); } }
private void applyLiquibaseChangelist(Connection connect, String liquibaseChangeLogClassPathResource) throws Exception, DatabaseException { applyLiquibaseChangelist(connect, liquibaseChangeLogClassPathResource, getClass().getClassLoader()); }
public void applyLiquibaseChangelist(Connection connect, String liquibaseChangeLogClassPathResource, ClassLoader classLoader) throws Exception { try (var database = findCorrectDatabaseImplementation(connect)) { Scope.child(scopeObjectsWithClassPathResourceAccessor(classLoader), () -> new CommandScope(UPDATE) .addArgumentValue(DATABASE_ARG, database) .addArgumentValue(CHANGELOG_FILE_ARG, liquibaseChangeLogClassPathResource) .execute()); } }
private Database findCorrectDatabaseImplementation(Connection connect) throws DatabaseException { return DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connect)); }
private Map scopeObjectsWithClassPathResourceAccessor(ClassLoader classLoader) { return Map.of(resourceAccessor.name(), new ClassLoaderResourceAccessor(classLoader)); }
} #+end_src If the integration test fails in the schema setup, I haven't yet found a way to debug in the integration test itself.
But it is possible to start a karaf process locally, attach an IDE to that karaf process for remote debugging, and then load the same feature as the integration tests.
This maven project is licensed with the Apache v 2.0 license.
The details of the license can be found in the LICENSE file.
The liquibase-slf4j jar is covered with the MIT license, copyright 2012-2015 Matt Bertolini. This license and copyright also covers the rebundled version of the jar that results from the "com.mattbertolini.liquibase-slf4j-osgi" maven module.