diff --git a/README.md b/README.md
index f312c1ae..5c3c0b71 100644
--- a/README.md
+++ b/README.md
@@ -197,6 +197,7 @@ See the [documentation on Initializer's logging properties](readme/rtprops.md#lo
#### Version 2.7.0
* Added support for 'queues' domain.
* Added support for 'addresshierarchy' domain.
+* Fix for Liquibase Loader to ensure compatibility with OpenMRS versions 2.5.5+
#### Version 2.6.0
* Added support for 'cohorttypes' and 'cohortattributetypes' domains.
diff --git a/api-2.5/pom.xml b/api-2.5/pom.xml
new file mode 100644
index 00000000..be0f4ebf
--- /dev/null
+++ b/api-2.5/pom.xml
@@ -0,0 +1,106 @@
+
+
+
+ initializer
+ org.openmrs.module
+ 2.7.0-SNAPSHOT
+
+ 4.0.0
+
+ initializer-api-2.5
+ jar
+ Initializer API 2.5
+ API 2.5 project for Initializer
+
+
+ ${openmrsVersion2.5}
+ 2.2.0
+
+
+
+
+
+ org.openmrs.test
+ openmrs-test
+ pom
+ ${openmrsPlatformVersion}
+ test
+
+
+ org.powermock
+ powermock-api-mockito2
+
+
+
+
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api
+ ${project.parent.version}
+ provided
+
+
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api
+ ${project.parent.version}
+ test
+ test-jar
+
+
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api-2.4
+ ${project.parent.version}
+ provided
+
+
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api-2.3
+ ${project.parent.version}
+ provided
+
+
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api-2.3
+ ${project.parent.version}
+ test
+ test-jar
+
+
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api-2.2
+ ${project.parent.version}
+ provided
+
+
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api-2.2
+ ${project.parent.version}
+ test
+ test-jar
+
+
+
+ org.openmrs.module
+ fhir2-api-2.5
+ ${fhir2Version}
+ provided
+
+
+
+ org.openmrs.module
+ datafilter-api
+ ${datafilterVersion}
+ provided
+
+
+
+
+
diff --git a/api-2.5/src/main/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader2_5.java b/api-2.5/src/main/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader2_5.java
new file mode 100644
index 00000000..7e4c9526
--- /dev/null
+++ b/api-2.5/src/main/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader2_5.java
@@ -0,0 +1,96 @@
+package org.openmrs.module.initializer.api.loaders;
+
+import org.openmrs.annotation.OpenmrsProfile;
+import org.openmrs.api.context.Context;
+import org.openmrs.liquibase.ChangeSetExecutorCallback;
+import org.openmrs.module.initializer.Domain;
+import org.openmrs.module.initializer.api.ConfigDirUtil;
+import org.openmrs.util.DatabaseUpdater;
+import org.openmrs.util.OpenmrsUtil;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+@OpenmrsProfile(openmrsPlatformVersion = "2.5.5")
+public class LiquibaseLoader2_5 extends BaseFileLoader {
+
+ public static final String LIQUIBASE_FILE_NAME = "liquibase";
+
+ @Override
+ protected Domain getDomain() {
+ return Domain.LIQUIBASE;
+ }
+
+ @Override
+ protected String getFileExtension() {
+ return "xml";
+ }
+
+ @Override
+ protected void load(File file) throws Exception {
+ if (file.getName().equalsIgnoreCase(LIQUIBASE_FILE_NAME + "." + getFileExtension())) {
+ // Because liquibase uses the path provided as an identifier of the changeset, we need to relativize it
+ // This ensures that liquibase changesets are not re-executed if the absolute path on the server changes
+ String absolutePath = file.getAbsolutePath();
+ String relativePath = getPathRelativeToApplicationDataDirectory(file);
+ updateExistingLiquibaseChangeLogPathsIfNeeded(absolutePath, relativePath);
+ try {
+ DatabaseUpdater.executeChangelog(relativePath, (ChangeSetExecutorCallback) null);
+ }
+ catch (Exception e) {
+ log.error("An error occurred executing liquibase file: " + file, e);
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * If a particular changeset file is being executed, and this is referenced by the given oldPath,
+ * then update that changeset to reference the given newPath
+ */
+ protected void updateExistingLiquibaseChangeLogPathsIfNeeded(String oldPath, String newPath) {
+ log.debug("Checking if liquibase filenames need to be updated for " + oldPath);
+ int numRows = sqlCount("select count(*) from liquibasechangelog where filename = '" + oldPath + "'");
+ if (numRows > 0) {
+ log.warn("Liquibase filename update is needed for " + oldPath + ". Updating to " + newPath);
+ sqlUpdate("update liquibasechangelog set filename = '" + newPath + "' where filename = '" + oldPath + "'");
+ } else {
+ log.debug("Liquibase filename update is not required");
+ }
+ }
+
+ /**
+ * @param file the file to relativize
+ * @return the path of the given file, relativized to the OpenMRS application data directory
+ */
+ protected String getPathRelativeToApplicationDataDirectory(File file) {
+ Path appDataDirPath = Paths.get(OpenmrsUtil.getApplicationDataDirectory());
+ Path liquibaseFilePath = file.toPath();
+ return appDataDirPath.relativize(liquibaseFilePath).toString();
+ }
+
+ /**
+ * @param sql the sql to execute
+ * @return the results of that execution, where the first column of the first row is returned as an
+ * integer count
+ */
+ private int sqlCount(String sql) {
+ List> results = Context.getAdministrationService().executeSQL(sql, true);
+ Object singleResult = results.get(0).get(0);
+ return Integer.parseInt(singleResult.toString());
+ }
+
+ /**
+ * @param sql the sql to execute as a database update operation
+ */
+ private void sqlUpdate(String sql) {
+ Context.getAdministrationService().executeSQL(sql, false);
+ }
+
+ @Override
+ public ConfigDirUtil getDirUtil() {
+ return new ConfigDirUtil(iniz.getConfigDirPath(), iniz.getChecksumsDirPath(), getDomainName(), true);
+ }
+}
diff --git a/api-2.5/src/test/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader25IntegrationTest.java b/api-2.5/src/test/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader25IntegrationTest.java
new file mode 100644
index 00000000..390974ab
--- /dev/null
+++ b/api-2.5/src/test/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader25IntegrationTest.java
@@ -0,0 +1,110 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public License,
+ * v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
+ * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
+ *
+ * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
+ * graphic logo is a trademark of OpenMRS Inc.
+ */
+package org.openmrs.module.initializer.api.loaders;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.openmrs.api.AdministrationService;
+import org.openmrs.module.initializer.DomainBaseModuleContextSensitiveTest;
+import org.openmrs.util.OpenmrsClassLoader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+public class LiquibaseLoader25IntegrationTest extends DomainBaseModuleContextSensitiveTest {
+
+ @Autowired
+ private LiquibaseLoader2_5 loader;
+
+ @Autowired
+ @Qualifier("adminService")
+ private AdministrationService adminService;
+
+ @Before
+ public void setup() throws Exception {
+ System.setProperty("useInMemoryDatabase", "true");
+ ClassLoader cl = OpenmrsClassLoader.getInstance();
+ String schemaSql = IOUtils.resourceToString("liquibase-schema.sql", StandardCharsets.UTF_8, cl);
+ adminService.executeSQL(schemaSql, false);
+ }
+
+ @After
+ public void teardown() {
+ adminService.executeSQL("drop table LIQUIBASECHANGELOG", false);
+ adminService.executeSQL("drop table LIQUIBASECHANGELOGLOCK", false);
+ }
+
+ @Test
+ public void load_shouldExecuteNewChangeSet() {
+ String relativePath = "configuration/liquibase/liquibase.xml";
+ String absolutePath = getAppDataDirPath() + relativePath;
+ Assert.assertEquals(0, numChangeLogEntries(absolutePath));
+ Assert.assertEquals(0, numChangeLogEntries(relativePath));
+ Assert.assertNull(adminService.getGlobalProperty("test_changes_1"));
+ Assert.assertNull(adminService.getGlobalProperty("test_changes_2"));
+ loader.load();
+ Assert.assertEquals(0, numChangeLogEntries(absolutePath));
+ Assert.assertEquals(2, numChangeLogEntries(relativePath));
+ Assert.assertEquals("true", adminService.getGlobalProperty("test_changes_1"));
+ Assert.assertEquals("true", adminService.getGlobalProperty("test_changes_2"));
+ }
+
+ @Test
+ public void load_shouldUpdateAbsolutePathToRelativePathIfNeeded() {
+ String relativePath = "configuration/liquibase/liquibase.xml";
+ String absolutePath = getAppDataDirPath() + relativePath;
+ insertExistingChangeLogEntry(absolutePath);
+ Assert.assertEquals(1, numChangeLogEntries(absolutePath));
+ Assert.assertEquals(0, numChangeLogEntries(relativePath));
+ loader.updateExistingLiquibaseChangeLogPathsIfNeeded(absolutePath, relativePath);
+ Assert.assertEquals(0, numChangeLogEntries(absolutePath));
+ Assert.assertEquals(1, numChangeLogEntries(relativePath));
+ }
+
+ private int numChangeLogEntries(String filename) {
+ List> ret = adminService
+ .executeSQL("select count(*) from liquibasechangelog where filename = '" + filename + "'", true);
+ return Integer.parseInt(ret.get(0).get(0).toString());
+ }
+
+ private void insertExistingChangeLogEntry(String filename) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("INSERT INTO LIQUIBASECHANGELOG (");
+ sb.append(" ID, ");
+ sb.append(" AUTHOR, ");
+ sb.append(" FILENAME, ");
+ sb.append(" DATEEXECUTED, ");
+ sb.append(" ORDEREXECUTED, ");
+ sb.append(" EXECTYPE, ");
+ sb.append(" MD5SUM, ");
+ sb.append(" DESCRIPTION, ");
+ sb.append(" COMMENTS, ");
+ sb.append(" LIQUIBASE ");
+ sb.append(") ");
+ sb.append("values (");
+ sb.append(" 'previousSqlFileChangeset', ");
+ sb.append(" 'iniz', ");
+ sb.append(" '").append(filename).append("', ");
+ sb.append(" '2023-11-01 00:00:00', ");
+ sb.append(" 1, ");
+ sb.append(" 'EXECUTED', ");
+ sb.append(" '8:4019e34234869ff55c81acf9d779f2a7', ");
+ sb.append(" 'sqlFile', ");
+ sb.append(" '', ");
+ sb.append(" '4.4.1'");
+ sb.append(")");
+ adminService.executeSQL(sb.toString(), false);
+ }
+}
diff --git a/api-2.5/src/test/resources/liquibase-schema.sql b/api-2.5/src/test/resources/liquibase-schema.sql
new file mode 100644
index 00000000..037113bd
--- /dev/null
+++ b/api-2.5/src/test/resources/liquibase-schema.sql
@@ -0,0 +1,27 @@
+CREATE TABLE LIQUIBASECHANGELOG
+(
+ ID varchar(255) NOT NULL,
+ AUTHOR varchar(255) NOT NULL,
+ FILENAME varchar(255) NOT NULL,
+ DATEEXECUTED datetime NOT NULL,
+ ORDEREXECUTED int(11) NOT NULL,
+ EXECTYPE varchar(10) NOT NULL,
+ MD5SUM varchar(35),
+ DESCRIPTION varchar(255),
+ COMMENTS varchar(255),
+ TAG varchar(255),
+ LIQUIBASE varchar(20),
+ CONTEXTS varchar(255),
+ LABELS varchar(255),
+ DEPLOYMENT_ID varchar(10),
+ PRIMARY KEY (ID, AUTHOR, FILENAME)
+);
+
+CREATE TABLE LIQUIBASECHANGELOGLOCK
+(
+ ID int(11) NOT NULL,
+ LOCKED tinyint(1) NOT NULL,
+ LOCKGRANTED datetime,
+ LOCKEDBY varchar(255),
+ PRIMARY KEY (ID)
+);
\ No newline at end of file
diff --git a/api-2.5/src/test/resources/log4j2.xml b/api-2.5/src/test/resources/log4j2.xml
new file mode 100644
index 00000000..478cf73e
--- /dev/null
+++ b/api-2.5/src/test/resources/log4j2.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+ %p - %C{1}.%M(%L) |%d{ISO8601}| %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/liquibase.xml b/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/liquibase.xml
new file mode 100644
index 00000000..d745b27f
--- /dev/null
+++ b/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/liquibase.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/sql/test_changes_1.sql b/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/sql/test_changes_1.sql
new file mode 100644
index 00000000..b16ce7d8
--- /dev/null
+++ b/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/sql/test_changes_1.sql
@@ -0,0 +1 @@
+insert into global_property (uuid, property, property_value) values (uuid(), 'test_changes_1', 'true');
\ No newline at end of file
diff --git a/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/sql/test_changes_2.sql b/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/sql/test_changes_2.sql
new file mode 100644
index 00000000..86ec7db6
--- /dev/null
+++ b/api-2.5/src/test/resources/testAppDataDir/configuration/liquibase/sql/test_changes_2.sql
@@ -0,0 +1 @@
+insert into global_property (uuid, property, property_value) values (uuid(), 'test_changes_2', 'true');
\ No newline at end of file
diff --git a/api/src/main/java/org/openmrs/module/initializer/api/OrderedFile.java b/api/src/main/java/org/openmrs/module/initializer/api/OrderedFile.java
index 4f542846..bb7381ab 100644
--- a/api/src/main/java/org/openmrs/module/initializer/api/OrderedFile.java
+++ b/api/src/main/java/org/openmrs/module/initializer/api/OrderedFile.java
@@ -24,7 +24,7 @@ public OrderedFile(String pathname) {
order = fetchOrder(this);
}
catch (UnsupportedOperationException e) {
- log.warn(e.getMessage());
+ log.debug(e.getMessage());
}
catch (Exception e) {
log.error("There was an error while attempting to read the loading order of a configuration file: "
diff --git a/api/src/main/java/org/openmrs/module/initializer/api/loaders/AddressHierarchyLoader.java b/api/src/main/java/org/openmrs/module/initializer/api/loaders/AddressHierarchyLoader.java
index 7a7705c7..3e294fe0 100644
--- a/api/src/main/java/org/openmrs/module/initializer/api/loaders/AddressHierarchyLoader.java
+++ b/api/src/main/java/org/openmrs/module/initializer/api/loaders/AddressHierarchyLoader.java
@@ -29,7 +29,8 @@ public ConfigDirUtil getDirUtil() {
public void loadUnsafe(List wildcardExclusions, boolean doThrow) throws Exception {
try {
- AddressConfigurationLoader.loadAddressConfiguration(Paths.get(iniz.getConfigDirPath()), Paths.get(iniz.getChecksumsDirPath()));
+ AddressConfigurationLoader.loadAddressConfiguration(Paths.get(iniz.getConfigDirPath()),
+ Paths.get(iniz.getChecksumsDirPath()));
}
catch (Exception e) {
log.error(e.getMessage());
diff --git a/api/src/main/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader.java b/api/src/main/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader.java
index b9b66503..5e9a1049 100644
--- a/api/src/main/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader.java
+++ b/api/src/main/java/org/openmrs/module/initializer/api/loaders/LiquibaseLoader.java
@@ -1,12 +1,13 @@
package org.openmrs.module.initializer.api.loaders;
-import java.io.File;
+import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.module.initializer.Domain;
import org.openmrs.module.initializer.api.ConfigDirUtil;
import org.openmrs.util.DatabaseUpdater;
-import org.springframework.stereotype.Component;
-@Component
+import java.io.File;
+
+@OpenmrsProfile(openmrsPlatformVersion = "2.1.1 - 2.5.4")
public class LiquibaseLoader extends BaseFileLoader {
public static final String LIQUIBASE_FILE_NAME = "liquibase";
diff --git a/omod/pom.xml b/omod/pom.xml
index c1aa6a99..f9441c25 100644
--- a/omod/pom.xml
+++ b/omod/pom.xml
@@ -36,6 +36,12 @@
${project.parent.artifactId}-api-2.4
${project.parent.version}
+
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api-2.5
+ ${project.parent.version}
+
${project.parent.groupId}
diff --git a/omod/src/main/resources/config.xml b/omod/src/main/resources/config.xml
index 072737df..24e0e669 100644
--- a/omod/src/main/resources/config.xml
+++ b/omod/src/main/resources/config.xml
@@ -17,7 +17,11 @@
/lib/initializer-api-2.4-${project.version}.jar
- 2.4.* - 2.*
+ 2.4.* - 9.*
+
+
+ /lib/initializer-api-2.5-${project.version}.jar
+ 2.5.* - 9.*
diff --git a/pom.xml b/pom.xml
index 0e077899..ec860eeb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,6 +36,7 @@
api-2.2
api-2.3
api-2.4
+ api-2.5
omod
@@ -54,6 +55,7 @@
2.2.0
2.3.6
2.4.0
+ 2.5.5
${openmrsVersion2.1}
diff --git a/validator/pom.xml b/validator/pom.xml
index 8ba3b202..324a224e 100644
--- a/validator/pom.xml
+++ b/validator/pom.xml
@@ -133,6 +133,13 @@
jar
+
+ ${project.parent.groupId}
+ ${project.parent.artifactId}-api-2.5
+ ${project.parent.version}
+ jar
+
+
org.openmrs.api
openmrs-api