diff --git a/README.md b/README.md index 61401d3..9844800 100644 --- a/README.md +++ b/README.md @@ -421,6 +421,23 @@ $ dcm -p 12345 getNegativePolicy $ dcm -p 12345 setNegativePolicy 0 ``` +### Load Cache Entries from File + +```bash +$ dcm -p 12345 load /foo/bar/my-cache.properties +``` + +### Manipulate cache with a command line option at JVM startup + +To manipulate dns entries at jvm startup, add the following jvm-options: + +```bash +# Set individual entry +java -javaagent:="set foo.com 1.1.1.1" --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/sun.net=ALL-UNNAMED ... +# Load entries from file +java -javaagent:="load my-cache.properties" --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/sun.net=ALL-UNNAMED ... +``` + ## 📚 Related information * [Java Agent Specification](http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html) diff --git a/library/pom.xml b/library/pom.xml index 4eded6b..f4c2819 100644 --- a/library/pom.xml +++ b/library/pom.xml @@ -77,6 +77,7 @@ + com.alibaba.dcm.agent.DcmAgent com.alibaba.dcm.agent.DcmAgent false false diff --git a/library/src/main/java/com/alibaba/dcm/DnsCacheManipulator.java b/library/src/main/java/com/alibaba/dcm/DnsCacheManipulator.java index 2e992d1..8f400bf 100644 --- a/library/src/main/java/com/alibaba/dcm/DnsCacheManipulator.java +++ b/library/src/main/java/com/alibaba/dcm/DnsCacheManipulator.java @@ -8,6 +8,7 @@ import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import java.io.FileInputStream; import java.io.InputStream; import java.util.Arrays; import java.util.List; @@ -144,6 +145,27 @@ public static void loadDnsCacheConfig(String propertiesFileName) { } } + /** + * Load dns config from the specified properties file in filesystem, then set dns cache. + * + * @param propertiesFileName specified properties file name in filesystem. + * @throws DnsCacheManipulatorException Operation fail + * @see DnsCacheManipulator#setDnsCache(java.util.Properties) + */ + public static void loadDnsCacheConfigFromFileSystem(String propertiesFileName) { + try { + InputStream inputStream = new FileInputStream(propertiesFileName); + Properties properties = new Properties(); + properties.load(inputStream); + inputStream.close(); + setDnsCache(properties); + } catch (Exception e) { + final String message = String.format("Fail to loadDnsCacheConfig from %s, cause: %s", + propertiesFileName, e); + throw new DnsCacheManipulatorException(message, e); + } + } + /** * Get a dns cache entry by {@code host}. * diff --git a/library/src/main/java/com/alibaba/dcm/agent/DcmAgent.java b/library/src/main/java/com/alibaba/dcm/agent/DcmAgent.java index f1a5fcb..f0cbb23 100644 --- a/library/src/main/java/com/alibaba/dcm/agent/DcmAgent.java +++ b/library/src/main/java/com/alibaba/dcm/agent/DcmAgent.java @@ -38,7 +38,14 @@ public class DcmAgent { static final String DCM_AGENT_SUCCESS_MARK_LINE = "!!DCM SUCCESS!!"; /** - * Entrance method of DCM Java Agent. + * Entrance method of DCM Java Agent when used through a jvm command line option. + */ + public static void premain(@Nonnull String agentArgument) throws Exception { + agentmain(agentArgument); + } + + /** + * Entrance method of DCM Java Agent when connecting to a running jvm. */ @SuppressFBWarnings("THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION") public static void agentmain(@Nonnull String agentArgument) throws Exception { @@ -264,6 +271,8 @@ private static synchronized void initAction2Method() throws NoSuchMethodExceptio map.put("ls", DnsCacheManipulator.class.getMethod("getWholeDnsCache")); map.put("clear", DnsCacheManipulator.class.getMethod("clearDnsCache")); + map.put("load", DnsCacheManipulator.class.getMethod("loadDnsCacheConfigFromFileSystem", String.class)); + map.put("setPolicy", DnsCacheManipulator.class.getMethod("setDnsCachePolicy", int.class)); map.put("getPolicy", DnsCacheManipulator.class.getMethod("getDnsCachePolicy")); map.put("setNegativePolicy", DnsCacheManipulator.class.getMethod("setDnsNegativeCachePolicy", int.class)); diff --git a/library/src/test/java/com/alibaba/dcm/DnsCacheManipulatorTests.kt b/library/src/test/java/com/alibaba/dcm/DnsCacheManipulatorTests.kt index d3671d6..cfa58e6 100644 --- a/library/src/test/java/com/alibaba/dcm/DnsCacheManipulatorTests.kt +++ b/library/src/test/java/com/alibaba/dcm/DnsCacheManipulatorTests.kt @@ -3,15 +3,12 @@ package com.alibaba.dcm import com.alibaba.dcm.internal.InetAddressCacheUtilCommons.isNewInetAddressImpl import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.AnnotationSpec -import io.kotest.matchers.collections.shouldBeEmpty -import io.kotest.matchers.collections.shouldContainExactly -import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder -import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.collections.* import io.kotest.matchers.longs.shouldBeBetween import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldNotBeSameInstanceAs - +import kotlin.io.path.writeText private const val IP1 = "42.42.42.1" private const val IP2 = "42.42.42.2" @@ -276,13 +273,13 @@ class DnsCacheManipulatorTests : AnnotationSpec() { } @Test - fun test_loadDnsCacheConfig_fromMyConfig() { + fun test_loadDnsCacheConfig_fromMyConfigClassPath() { DnsCacheManipulator.loadDnsCacheConfig("my-dns-cache.properties") "www.hello2.com".lookupIpByName() shouldBe IP2 } @Test - fun test_multi_ips_in_config_file() { + fun test_multi_ips_in_config_file_classpath() { DnsCacheManipulator.loadDnsCacheConfig("dns-cache-multi-ips.properties") val host = "www.hello-multi-ips.com" @@ -299,11 +296,32 @@ class DnsCacheManipulatorTests : AnnotationSpec() { } @Test - fun test_configNotFound() { + fun test_configNotFound_classpath() { val ex = shouldThrow { DnsCacheManipulator.loadDnsCacheConfig("not-existed.properties") } ex.message shouldBe "Fail to find not-existed.properties on classpath!" } + + @Test + fun test_loadDnsCacheConfig_fromMyConfigFileSystem() { + val tempFile = kotlin.io.path.createTempFile("dns-cache-test", ".properties") + tempFile.writeText("www.hello2.com $IP2") + tempFile.toFile().deleteOnExit() + + DnsCacheManipulator.loadDnsCacheConfigFromFileSystem(tempFile.toAbsolutePath().toString()) + "www.hello2.com".lookupIpByName() shouldBe IP2 + } + + @Test + fun test_configNotFound_fileSystem() { + val ex = shouldThrow { + DnsCacheManipulator.loadDnsCacheConfigFromFileSystem("not-existed.properties") + } + + ex.message shouldBeIn arrayOf( + "Fail to loadDnsCacheConfig from not-existed.properties, cause: java.io.FileNotFoundException: not-existed.properties (No such file or directory)", + "Fail to loadDnsCacheConfig from not-existed.properties, cause: java.io.FileNotFoundException: not-existed.properties (The system cannot find the file specified)") + } }