From 4f99a3441d5b5856a9c8b1e928047092c3b0daa0 Mon Sep 17 00:00:00 2001 From: Ian <52504170+ibacher@users.noreply.github.com> Date: Wed, 6 Mar 2024 12:09:43 -0500 Subject: [PATCH] TRUNK-6224: Update replace ClassLoaderFileOpener with modern API (#4574) --- .../OpenmrsClassLoaderResourceAccessor.java | 47 +++++++++++++ .../openmrs/util/ClassLoaderFileOpener.java | 69 ------------------- .../org/openmrs/util/DatabaseUpdater.java | 3 +- .../databasechange/SourceMySqldiffFile.java | 6 +- ...penmrsClassLoaderResourceAccessorTest.java | 60 ++++++++++++++++ .../ClassLoaderFileOpenerTest.java | 56 --------------- 6 files changed, 111 insertions(+), 130 deletions(-) create mode 100644 api/src/main/java/org/openmrs/liquibase/OpenmrsClassLoaderResourceAccessor.java delete mode 100644 api/src/main/java/org/openmrs/util/ClassLoaderFileOpener.java create mode 100644 api/src/test/java/org/openmrs/liquibase/OpenmrsClassLoaderResourceAccessorTest.java delete mode 100644 api/src/test/java/org/openmrs/util/databasechange/ClassLoaderFileOpenerTest.java diff --git a/api/src/main/java/org/openmrs/liquibase/OpenmrsClassLoaderResourceAccessor.java b/api/src/main/java/org/openmrs/liquibase/OpenmrsClassLoaderResourceAccessor.java new file mode 100644 index 000000000000..dd859362de9c --- /dev/null +++ b/api/src/main/java/org/openmrs/liquibase/OpenmrsClassLoaderResourceAccessor.java @@ -0,0 +1,47 @@ +/** + * 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.liquibase; + +import liquibase.resource.ClassLoaderResourceAccessor; +import liquibase.resource.InputStreamList; +import org.openmrs.util.OpenmrsClassLoader; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; + +/** + * A customization of Liquibase's {@link ClassLoaderResourceAccessor} which defaults to the OpenMRS ClassLoader and has + * special handling for our liquibase.xml files, which occur multiple times on the classpath. + */ +public class OpenmrsClassLoaderResourceAccessor extends ClassLoaderResourceAccessor { + + public OpenmrsClassLoaderResourceAccessor() { + super(OpenmrsClassLoader.getInstance()); + } + + public OpenmrsClassLoaderResourceAccessor(ClassLoader classLoader) { + super(classLoader); + } + + @Override + public InputStreamList openStreams(String relativeTo, String streamPath) throws IOException { + InputStreamList result = super.openStreams(relativeTo, streamPath); + if (result != null && !result.isEmpty() && result.size() > 1) { + try (InputStreamList oldResult = result) { + URI uri = oldResult.getURIs().get(0); + result = new InputStreamList(uri, uri.toURL().openStream()); + } + + } + + return result; + } +} diff --git a/api/src/main/java/org/openmrs/util/ClassLoaderFileOpener.java b/api/src/main/java/org/openmrs/util/ClassLoaderFileOpener.java deleted file mode 100644 index 60c040ead9f3..000000000000 --- a/api/src/main/java/org/openmrs/util/ClassLoaderFileOpener.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * 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.util; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.SortedSet; - -import liquibase.resource.AbstractResourceAccessor; -import liquibase.resource.InputStreamList; - -/** - * Implementation of liquibase FileOpener interface so that the {@link OpenmrsClassLoader} will be - * used to find files (or any other classloader that is passed into the constructor). This allows - * liquibase xml files in modules to be found. - */ -public class ClassLoaderFileOpener extends AbstractResourceAccessor { - - /** - * The classloader to read from - */ - private final ClassLoader cl; - - /** - * @param cl the {@link ClassLoader} to use for finding files. - */ - public ClassLoaderFileOpener(ClassLoader cl) { - this.cl = cl; - } - - @Override - public InputStreamList openStreams(String context, String path) throws IOException { - InputStreamList result = new InputStreamList(); - - if (path.isEmpty()) { - return result; - } - - URL url = cl.getResource(path); - if (url != null) { - try { - result.add(url.toURI(), url.openStream()); - } - catch (URISyntaxException e) { - throw new IOException(e); - } - } - - return result; - } - - @Override - public SortedSet list(String s, String s1, boolean b, boolean b1, boolean b2) throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public SortedSet describeLocations() { - return null; - } -} diff --git a/api/src/main/java/org/openmrs/util/DatabaseUpdater.java b/api/src/main/java/org/openmrs/util/DatabaseUpdater.java index 790405427bae..b7a6dcb7009e 100644 --- a/api/src/main/java/org/openmrs/util/DatabaseUpdater.java +++ b/api/src/main/java/org/openmrs/util/DatabaseUpdater.java @@ -40,6 +40,7 @@ import org.openmrs.liquibase.ChangeLogVersionFinder; import org.openmrs.liquibase.ChangeSetExecutorCallback; import org.openmrs.liquibase.LiquibaseProvider; +import org.openmrs.liquibase.OpenmrsClassLoaderResourceAccessor; import org.openmrs.module.ModuleClassLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -879,7 +880,7 @@ private static CompositeResourceAccessor getCompositeResourceAccessor(ClassLoade } } - ResourceAccessor openmrsFO = new ClassLoaderFileOpener(classLoader); + ResourceAccessor openmrsFO = new OpenmrsClassLoaderResourceAccessor(classLoader); ResourceAccessor fsFO = new FileSystemResourceAccessor(OpenmrsUtil.getApplicationDataDirectoryAsFile()); return new CompositeResourceAccessor(openmrsFO, fsFO); } diff --git a/api/src/main/java/org/openmrs/util/databasechange/SourceMySqldiffFile.java b/api/src/main/java/org/openmrs/util/databasechange/SourceMySqldiffFile.java index 84d68067db53..5b086f0aa3a0 100644 --- a/api/src/main/java/org/openmrs/util/databasechange/SourceMySqldiffFile.java +++ b/api/src/main/java/org/openmrs/util/databasechange/SourceMySqldiffFile.java @@ -19,7 +19,7 @@ import liquibase.resource.InputStreamList; import liquibase.resource.ResourceAccessor; import org.openmrs.api.context.Context; -import org.openmrs.util.ClassLoaderFileOpener; +import org.openmrs.liquibase.OpenmrsClassLoaderResourceAccessor; import org.openmrs.util.OpenmrsClassLoader; import org.openmrs.util.OpenmrsConstants; import org.openmrs.util.OpenmrsUtil; @@ -30,7 +30,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; @@ -40,7 +39,6 @@ import java.util.Collections; import java.util.List; import java.util.Properties; -import java.util.Set; /** * Executes (aka "source"s) the given file on the current database.
@@ -94,7 +92,7 @@ public void execute(Database database) throws CustomChangeException { try { tmpOutputFile = File.createTempFile(sqlFile, "tmp"); - fileOpener = new ClassLoaderFileOpener(OpenmrsClassLoader.getInstance()); + fileOpener = new OpenmrsClassLoaderResourceAccessor(OpenmrsClassLoader.getInstance()); try (InputStreamList sqlFileInputStream = fileOpener.openStreams(null, sqlFile); OutputStream outputStream = new FileOutputStream(tmpOutputFile)) { if (sqlFileInputStream != null && !sqlFileInputStream.isEmpty()) { diff --git a/api/src/test/java/org/openmrs/liquibase/OpenmrsClassLoaderResourceAccessorTest.java b/api/src/test/java/org/openmrs/liquibase/OpenmrsClassLoaderResourceAccessorTest.java new file mode 100644 index 000000000000..43dac8341292 --- /dev/null +++ b/api/src/test/java/org/openmrs/liquibase/OpenmrsClassLoaderResourceAccessorTest.java @@ -0,0 +1,60 @@ +/** + * 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.liquibase; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.util.Collections; + +import liquibase.resource.InputStreamList; +import org.junit.jupiter.api.Test; +import org.openmrs.liquibase.OpenmrsClassLoaderResourceAccessor; +import org.openmrs.util.OpenmrsClassLoader; + +public class OpenmrsClassLoaderResourceAccessorTest { + + @Test + public void shouldGetSingleResourceAsStream() throws Exception { + ClassLoader classLoader = mock(ClassLoader.class); + + when(classLoader.getResources(any())) + .thenReturn(OpenmrsClassLoader.getSystemClassLoader().getResources("TestingApplicationContext.xml")); + + + OpenmrsClassLoaderResourceAccessor classLoaderFileOpener = new OpenmrsClassLoaderResourceAccessor(classLoader); + try (InputStreamList inputStreamSet = classLoaderFileOpener.openStreams(null, "some path")) { + assertEquals(1, inputStreamSet.size()); + } + } + + @Test + public void shouldGetNoResourceAsStream() throws Exception { + ClassLoader classLoader = mock(ClassLoader.class); + + when(classLoader.getResources(any())) + .thenReturn(Collections.emptyEnumeration()); + + + try (OpenmrsClassLoaderResourceAccessor classLoaderFileOpener = new OpenmrsClassLoaderResourceAccessor(classLoader); + InputStreamList inputStreamSet = classLoaderFileOpener.openStreams(null, "")){ + assertThat(inputStreamSet.size(), is(0)); + } + } +} diff --git a/api/src/test/java/org/openmrs/util/databasechange/ClassLoaderFileOpenerTest.java b/api/src/test/java/org/openmrs/util/databasechange/ClassLoaderFileOpenerTest.java deleted file mode 100644 index c85631f9b299..000000000000 --- a/api/src/test/java/org/openmrs/util/databasechange/ClassLoaderFileOpenerTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - * 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.util.databasechange; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; - -import liquibase.resource.InputStreamList; -import org.junit.jupiter.api.Test; -import org.openmrs.util.ClassLoaderFileOpener; - -public class ClassLoaderFileOpenerTest { - - @Test - public void shouldGetSingleResourceAsStream() throws IOException { - ClassLoader classLoader = mock(ClassLoader.class); - - when(classLoader.getResource(any())) - .thenReturn(getClass().getClassLoader().getResource("TestingApplicationContext.xml")); - - ClassLoaderFileOpener classLoaderFileOpener = new ClassLoaderFileOpener(classLoader); - InputStreamList inputStreamSet = classLoaderFileOpener.openStreams(null, "some path"); - - assertEquals(1, inputStreamSet.size()); - } - - @Test - public void shouldGetNoResourceAsStream() throws IOException { - ClassLoader classLoader = mock(ClassLoader.class); - - ClassLoaderFileOpener classLoaderFileOpener = new ClassLoaderFileOpener(classLoader); - InputStreamList inputStreamSet = classLoaderFileOpener.openStreams(null, ""); - - assertEquals(0, inputStreamSet.size()); - } - - @Test - public void shouldIndicateThatListIsNotSupported() throws IOException { - ClassLoader classLoader = mock(ClassLoader.class); - - ClassLoaderFileOpener classLoaderFileOpener = new ClassLoaderFileOpener(classLoader); - assertThrows(UnsupportedOperationException.class, () -> classLoaderFileOpener.list("", "", false, false, false)); - } -}