diff --git a/agrona/src/main/java/org/agrona/PropertyAction.java b/agrona/src/main/java/org/agrona/PropertyAction.java new file mode 100644 index 000000000..4d5f05139 --- /dev/null +++ b/agrona/src/main/java/org/agrona/PropertyAction.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014-2020 Real Logic Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.agrona; + +/** + * Action to be taken for each property loaded into system properties. + */ +public enum PropertyAction +{ + /** + * Replace existing property value if one exists. + */ + REPLACE, + + /** + * Preserve existing property value if one exists. + */ + PRESERVE +} diff --git a/agrona/src/main/java/org/agrona/SystemUtil.java b/agrona/src/main/java/org/agrona/SystemUtil.java index ff1756619..4c50bba85 100644 --- a/agrona/src/main/java/org/agrona/SystemUtil.java +++ b/agrona/src/main/java/org/agrona/SystemUtil.java @@ -15,9 +15,7 @@ */ package org.agrona; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; +import java.io.*; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.management.ThreadInfo; @@ -193,7 +191,7 @@ public static String threadDump() } /** - * Load system properties from a given filename or url. + * Load system properties from a given filename or url with default to {@link PropertyAction#REPLACE}. *
* File is first searched for in resources using the system {@link ClassLoader}, * then file system, then URL. All are loaded if multiples found. @@ -202,15 +200,26 @@ public static String threadDump() */ public static void loadPropertiesFile(final String filenameOrUrl) { - final Properties properties = new Properties(System.getProperties()); - System.getProperties().forEach(properties::put); + loadPropertiesFile(PropertyAction.REPLACE, filenameOrUrl); + } + /** + * Load system properties from a given filename or url. + *
+ * File is first searched for in resources using the system {@link ClassLoader}, + * then file system, then URL. All are loaded if multiples found. + * + * @param propertyAction to take with each loaded property. + * @param filenameOrUrl that holds properties. + */ + public static void loadPropertiesFile(final PropertyAction propertyAction, final String filenameOrUrl) + { final URL resource = ClassLoader.getSystemClassLoader().getResource(filenameOrUrl); if (null != resource) { try (InputStream in = resource.openStream()) { - properties.load(in); + loadProperties(propertyAction, in); } catch (final Exception ignore) { @@ -220,9 +229,9 @@ public static void loadPropertiesFile(final String filenameOrUrl) final File file = new File(filenameOrUrl); if (file.exists()) { - try (FileInputStream in = new FileInputStream(file)) + try (InputStream in = new FileInputStream(file)) { - properties.load(in); + loadProperties(propertyAction, in); } catch (final Exception ignore) { @@ -231,26 +240,36 @@ public static void loadPropertiesFile(final String filenameOrUrl) try (InputStream in = new URL(filenameOrUrl).openStream()) { - properties.load(in); + loadProperties(propertyAction, in); } catch (final Exception ignore) { } + } - System.setProperties(properties); + /** + * Load system properties from a given set of filenames or URLs with default to {@link PropertyAction#REPLACE}. + * + * @param filenamesOrUrls that holds properties. + * @see #loadPropertiesFile(String) + */ + public static void loadPropertiesFiles(final String... filenamesOrUrls) + { + loadPropertiesFiles(PropertyAction.REPLACE, filenamesOrUrls); } /** * Load system properties from a given set of filenames or URLs. * + * @param propertyAction to take with each loaded property. * @param filenamesOrUrls that holds properties. * @see #loadPropertiesFile(String) */ - public static void loadPropertiesFiles(final String... filenamesOrUrls) + public static void loadPropertiesFiles(final PropertyAction propertyAction, final String... filenamesOrUrls) { for (final String filenameOrUrl : filenamesOrUrls) { - loadPropertiesFile(filenameOrUrl); + loadPropertiesFile(propertyAction, filenameOrUrl); } } @@ -440,4 +459,30 @@ public static long parseDuration(final String propertyName, final String propert propertyName + ": " + propertyValue + " should end with: s, ms, us, or ns."); } } + + private static void loadProperties(final PropertyAction propertyAction, final InputStream in) throws IOException + { + final Properties systemProperties = System.getProperties(); + final Properties properties = new Properties(); + + properties.load(in); + properties.forEach( + (k, v) -> + { + switch (propertyAction) + { + case PRESERVE: + if (!systemProperties.containsKey(k)) + { + systemProperties.setProperty((String)k, (String)v); + } + break; + + default: + case REPLACE: + systemProperties.setProperty((String)k, (String)v); + break; + } + }); + } } diff --git a/agrona/src/test/java/org/agrona/SystemUtilTest.java b/agrona/src/test/java/org/agrona/SystemUtilTest.java index 0c0e674a1..5f2332e0f 100644 --- a/agrona/src/test/java/org/agrona/SystemUtilTest.java +++ b/agrona/src/test/java/org/agrona/SystemUtilTest.java @@ -21,36 +21,35 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.core.Is.is; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; public class SystemUtilTest { @Test public void shouldParseSizesWithSuffix() { - assertThat(parseSize("", "1"), is(1L)); - assertThat(parseSize("", "1k"), is(1024L)); - assertThat(parseSize("", "1K"), is(1024L)); - assertThat(parseSize("", "1m"), is(1024L * 1024)); - assertThat(parseSize("", "1M"), is(1024L * 1024)); - assertThat(parseSize("", "1g"), is(1024L * 1024 * 1024)); - assertThat(parseSize("", "1G"), is(1024L * 1024 * 1024)); + assertEquals(1L, parseSize("", "1")); + assertEquals(1024L, parseSize("", "1k")); + assertEquals(1024L, parseSize("", "1K")); + assertEquals(1024L * 1024L, parseSize("", "1m")); + assertEquals(1024L * 1024L, parseSize("", "1M")); + assertEquals(1024L * 1024L * 1024L, parseSize("", "1g")); + assertEquals(1024L * 1024L * 1024L, parseSize("", "1G")); } @Test public void shouldParseTimesWithSuffix() { - assertThat(parseDuration("", "1"), is(1L)); - assertThat(parseDuration("", "1ns"), is(1L)); - assertThat(parseDuration("", "1NS"), is(1L)); - assertThat(parseDuration("", "1us"), is(1000L)); - assertThat(parseDuration("", "1US"), is(1000L)); - assertThat(parseDuration("", "1ms"), is(1000L * 1000)); - assertThat(parseDuration("", "1MS"), is(1000L * 1000)); - assertThat(parseDuration("", "1s"), is(1000L * 1000 * 1000)); - assertThat(parseDuration("", "1S"), is(1000L * 1000 * 1000)); - assertThat(parseDuration("", "12s"), is(12L * 1000 * 1000 * 1000)); + assertEquals(1L, parseDuration("", "1")); + assertEquals(1L, parseDuration("", "1ns")); + assertEquals(1L, parseDuration("", "1NS")); + assertEquals(1000L, parseDuration("", "1us")); + assertEquals(1000L, parseDuration("", "1US")); + assertEquals(1000L * 1000, parseDuration("", "1ms")); + assertEquals(1000L * 1000, parseDuration("", "1MS")); + assertEquals(1000L * 1000 * 1000, parseDuration("", "1s")); + assertEquals(1000L * 1000 * 1000, parseDuration("", "1S")); + assertEquals(12L * 1000 * 1000 * 1000, parseDuration("", "12S")); } @Test @@ -78,7 +77,7 @@ public void shouldDoNothingToSystemPropsWhenLoadingFileWhichDoesNotExist() loadPropertiesFile("$unknown-file$"); - assertThat(originalSystemPropSize, is(System.getProperties().size())); + assertEquals(originalSystemPropSize, System.getProperties().size()); } @Test @@ -89,19 +88,31 @@ public void shouldMergeMultiplePropFilesTogether() loadPropertiesFiles("TestFileA.properties", "TestFileB.properties"); - assertThat(System.getProperty("TestFileA.foo"), is("AAA")); - assertThat(System.getProperty("TestFileB.foo"), is("BBB")); + assertEquals("AAA", System.getProperty("TestFileA.foo")); + assertEquals("BBB", System.getProperty("TestFileB.foo")); } @Test public void shouldOverrideSystemPropertiesWithConfigFromPropFile() { System.setProperty("TestFileA.foo", "ToBeOverridden"); - assertThat(System.getProperty("TestFileA.foo"), is("ToBeOverridden")); + assertEquals("ToBeOverridden", System.getProperty("TestFileA.foo")); loadPropertiesFile("TestFileA.properties"); - assertThat(System.getProperty("TestFileA.foo"), is("AAA")); + assertEquals("AAA", System.getProperty("TestFileA.foo")); + + System.clearProperty("TestFileA.foo"); + } + + @Test + public void shouldNotOverrideSystemPropertiesWithConfigFromPropFile() + { + System.setProperty("TestFileA.foo", "ToBeNotOverridden"); + assertEquals("ToBeNotOverridden", System.getProperty("TestFileA.foo")); + + loadPropertiesFile(PropertyAction.PRESERVE, "TestFileA.properties"); + assertEquals("ToBeNotOverridden", System.getProperty("TestFileA.foo")); System.clearProperty("TestFileA.foo"); }