From ada6a788f907eaa3cd82ecec7e2e65b283caa8aa Mon Sep 17 00:00:00 2001 From: Michael Seaton Date: Mon, 3 Feb 2025 07:36:41 -0500 Subject: [PATCH] #288 - Fix Global Properties loading for OpenMRS 2.7+ (#289) --- README.md | 3 + ...lPropertiesLoaderIntegration_2_7_Test.java | 75 +++++++++++++++++++ .../configuration/globalproperties/gp1.xml | 12 +++ .../configuration/globalproperties/gp2.xml | 8 ++ .../configuration/globalproperties/gp3.xml | 19 +++++ .../api/InitializerSerializer.java | 25 +++++-- 6 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 api-2.7/src/test/java/org/openmrs/module/initializer/api/loaders/GlobalPropertiesLoaderIntegration_2_7_Test.java create mode 100644 api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp1.xml create mode 100644 api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp2.xml create mode 100644 api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp3.xml diff --git a/README.md b/README.md index 079a2c10c..7a354bfb1 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,9 @@ See the [documentation on Initializer's logging properties](readme/rtprops.md#lo ## Releases notes +#### Version 2.9.0 +* Fix for InitializerSerializer to ensure compatibility with OpenMRS version 2.7.0+ + #### Version 2.8.0 * Ampath forms translation files will now generate checksums. * Enhancement to ensure that when an Ampath forms file is loaded, a new resource with the existing Ampath forms translations is created. diff --git a/api-2.7/src/test/java/org/openmrs/module/initializer/api/loaders/GlobalPropertiesLoaderIntegration_2_7_Test.java b/api-2.7/src/test/java/org/openmrs/module/initializer/api/loaders/GlobalPropertiesLoaderIntegration_2_7_Test.java new file mode 100644 index 000000000..3baae432f --- /dev/null +++ b/api-2.7/src/test/java/org/openmrs/module/initializer/api/loaders/GlobalPropertiesLoaderIntegration_2_7_Test.java @@ -0,0 +1,75 @@ +/** + * 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.junit.Assert; +import org.junit.Test; +import org.openmrs.GlobalProperty; +import org.openmrs.api.context.Context; +import org.openmrs.module.initializer.DomainBaseModuleContextSensitive_2_7_Test; +import org.openmrs.module.initializer.api.gp.GlobalPropertiesLoader; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * This test is intended to be a copy of the GlobalPropertiesLoaderIntegrationTest from the api module, + * but included within the api-2.7 module to test that global properties loading from xml works successfully + * in an OpenMRS 2.7 environment + */ +public class GlobalPropertiesLoaderIntegration_2_7_Test extends DomainBaseModuleContextSensitive_2_7_Test { + + @Autowired + private GlobalPropertiesLoader loader; + + @Test + public void loadGlobalProperties_shouldLoadGlobalProperties() { + + // Replay + loader.load(); + + // Verif + Assert.assertEquals("GP one one", Context.getAdministrationService().getGlobalProperty("gp.gp11")); + Assert.assertEquals("GP one two", Context.getAdministrationService().getGlobalProperty("gp.gp12")); + Assert.assertEquals("GP two one", Context.getAdministrationService().getGlobalProperty("gp.gp21")); + Assert.assertEquals("GP three one", Context.getAdministrationService().getGlobalProperty("gp.gp31")); + Assert.assertEquals("GP three two", Context.getAdministrationService().getGlobalProperty("gp.gp32")); + Assert.assertEquals("GP three three", Context.getAdministrationService().getGlobalProperty("gp.gp33")); + } + + @Test + public void load_shouldOverrideGlobalProperties() { + + // Setup + Context.getAdministrationService().saveGlobalProperty(new GlobalProperty("gp.gp11", "foobar")); + Assert.assertEquals("foobar", Context.getAdministrationService().getGlobalProperty("gp.gp11")); + + // Replay + loader.load(); + + // Verif + Assert.assertEquals("GP one one", Context.getAdministrationService().getGlobalProperty("gp.gp11")); + } + + @Test + public void load_shouldNotAffectOtherGlobalProperties() { + + // Setup + Context.getAdministrationService().saveGlobalProperty(new GlobalProperty("gp.foo", "Foo")); + Context.getAdministrationService().saveGlobalProperty(new GlobalProperty("gp.bar", "Bar")); + Context.getAdministrationService().saveGlobalProperty(new GlobalProperty("gp.baz", "Baz")); + + // Replay + loader.load(); + + // Verif + Assert.assertEquals("Foo", Context.getAdministrationService().getGlobalProperty("gp.foo")); + Assert.assertEquals("Bar", Context.getAdministrationService().getGlobalProperty("gp.bar")); + Assert.assertEquals("Baz", Context.getAdministrationService().getGlobalProperty("gp.baz")); + } +} diff --git a/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp1.xml b/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp1.xml new file mode 100644 index 000000000..0026f22bf --- /dev/null +++ b/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp1.xml @@ -0,0 +1,12 @@ + + + + gp.gp11 + GP one one + + + gp.gp12 + GP one two + + + \ No newline at end of file diff --git a/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp2.xml b/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp2.xml new file mode 100644 index 000000000..ebc58a459 --- /dev/null +++ b/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp2.xml @@ -0,0 +1,8 @@ + + + + gp.gp21 + GP two one + + + \ No newline at end of file diff --git a/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp3.xml b/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp3.xml new file mode 100644 index 000000000..c1fefc0b2 --- /dev/null +++ b/api-2.7/src/test/resources/testAppDataDir/configuration/globalproperties/gp3.xml @@ -0,0 +1,19 @@ + + + It should be ok to just add some comments like this. + + + + gp.gp31 + GP three one + + + gp.gp32 + GP three two + + + gp.gp33 + GP three three + + + \ No newline at end of file diff --git a/api/src/main/java/org/openmrs/module/initializer/api/InitializerSerializer.java b/api/src/main/java/org/openmrs/module/initializer/api/InitializerSerializer.java index c2b1140f1..dcf2139cb 100644 --- a/api/src/main/java/org/openmrs/module/initializer/api/InitializerSerializer.java +++ b/api/src/main/java/org/openmrs/module/initializer/api/InitializerSerializer.java @@ -1,11 +1,5 @@ package org.openmrs.module.initializer.api; -import java.io.InputStream; - -import org.openmrs.GlobalProperty; -import org.openmrs.module.idgen.IdentifierSource; -import org.openmrs.module.initializer.api.gp.GlobalPropertiesConfig; - import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.reflection.ReflectionConverter; @@ -14,12 +8,22 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.mapper.Mapper; import com.thoughtworks.xstream.mapper.MapperWrapper; +import org.openmrs.GlobalProperty; +import org.openmrs.module.idgen.IdentifierSource; +import org.openmrs.module.initializer.api.gp.GlobalPropertiesConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.lang.reflect.Method; /** * Use this serializer instead of a bare {@link XStream} if you want to ignore unmapped fields. */ public class InitializerSerializer extends XStream { + private static final Logger log = LoggerFactory.getLogger(InitializerSerializer.class); + public InitializerSerializer() { super(); } @@ -53,6 +57,15 @@ public static XStream getGlobalPropertiesConfigSerializer() { xs.alias("config", GlobalPropertiesConfig.class); xs.alias("globalProperty", GlobalProperty.class); xs.aliasField("value", GlobalProperty.class, "propertyValue"); + try { + Method allowTypeHierarchy = XStream.class.getMethod("allowTypeHierarchy", Class.class); + allowTypeHierarchy.invoke(xs, GlobalPropertiesConfig.class); + allowTypeHierarchy.invoke(xs, GlobalProperty.class); + log.debug("Successfully configured global properties config serializer with allowed types"); + } + catch (Exception e) { + log.debug("Error configuring global properties config serializer with allowed types", e); + } return xs; }