This is an automated email from the ASF dual-hosted git repository.
szetszwo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ratis.git
The following commit(s) were added to refs/heads/master by this push:
new 862684066 RATIS-2561. Refactor MetricRegistriesLoader. (#1483)
862684066 is described below
commit 862684066a5b6ac5ba49e3a10c0b0f01e488b775
Author: Tsz-Wo Nicholas Sze <[email protected]>
AuthorDate: Mon Jun 15 13:31:59 2026 -0700
RATIS-2561. Refactor MetricRegistriesLoader. (#1483)
---
.../java/org/apache/ratis/util/ServiceUtils.java | 74 ++++++++++++++++++
.../org/apache/ratis/metrics/MetricRegistries.java | 4 +-
.../ratis/metrics/MetricRegistriesLoader.java | 90 ----------------------
.../dropwizard3/TestLoadDm3MetricRegistries.java | 5 +-
.../apache/ratis/metrics/TestMetricRegistries.java | 36 +++++----
5 files changed, 101 insertions(+), 108 deletions(-)
diff --git a/ratis-common/src/main/java/org/apache/ratis/util/ServiceUtils.java
b/ratis-common/src/main/java/org/apache/ratis/util/ServiceUtils.java
new file mode 100644
index 000000000..bb772b516
--- /dev/null
+++ b/ratis-common/src/main/java/org/apache/ratis/util/ServiceUtils.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.ratis.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ServiceLoader;
+import java.util.function.Supplier;
+
+/** Utility methods for {@link ServiceLoader}. */
+public final class ServiceUtils {
+ private static final Logger LOG =
LoggerFactory.getLogger(ServiceUtils.class);
+
+ public static <T> T load(Class<T> serviceInterface, String defaultClass) {
+ final Supplier<T> defaultInstance = () -> {
+ try {
+ return
ReflectionUtils.newInstance(Class.forName(defaultClass).asSubclass(serviceInterface));
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Failed to load " + defaultClass, e);
+ }
+ };
+ final List<T> providers = loadServiceProviders(serviceInterface);
+ return load(serviceInterface, defaultInstance, providers);
+ }
+
+ public static <T> T load(Class<T> serviceInterface, Supplier<T>
defaultInstance, List<T> loaded) {
+ if (loaded.isEmpty()) {
+ return defaultInstance.get();
+ }
+
+ final T first = loaded.get(0);
+ if (loaded.size() == 1) {
+ LOG.debug("Loaded {}", first.getClass());
+ } else {
+ // Warn that there are more than one services configured.
+ final String classes = loaded.stream()
+ .map(Object::getClass)
+ .map(Class::getName)
+ .reduce((a, b) -> a + ", " + b).orElse("");
+ LOG.warn("Loaded {} duplicated services of {}: {}", loaded.size(),
serviceInterface.getSimpleName(), classes);
+ LOG.warn("Using the first: {}", first.getClass());
+ }
+ return first;
+ }
+
+ private static <T> List<T> loadServiceProviders(Class<T> serviceInterface) {
+ final ServiceLoader<T> loader = ServiceLoader.load(serviceInterface,
serviceInterface.getClassLoader());
+ final List<T> loaded = new ArrayList<>();
+ for (T impl : loader) {
+ loaded.add(impl);
+ }
+ return loaded;
+ }
+
+ private ServiceUtils() {}
+}
diff --git
a/ratis-metrics-api/src/main/java/org/apache/ratis/metrics/MetricRegistries.java
b/ratis-metrics-api/src/main/java/org/apache/ratis/metrics/MetricRegistries.java
index 3a11213bb..b05afe7cc 100644
---
a/ratis-metrics-api/src/main/java/org/apache/ratis/metrics/MetricRegistries.java
+++
b/ratis-metrics-api/src/main/java/org/apache/ratis/metrics/MetricRegistries.java
@@ -18,6 +18,7 @@
package org.apache.ratis.metrics;
+import org.apache.ratis.util.ServiceUtils;
import org.apache.ratis.util.TimeDuration;
import java.util.Collection;
@@ -30,9 +31,10 @@ import java.util.function.Consumer;
* ref-counting of MetricRegistry's via create() and remove() methods.
*/
public abstract class MetricRegistries {
+ static final String DEFAULT_CLASS =
"org.apache.ratis.metrics.impl.MetricRegistriesImpl";
private static final class LazyHolder {
- private static final MetricRegistries GLOBAL =
MetricRegistriesLoader.load();
+ private static final MetricRegistries GLOBAL =
ServiceUtils.load(MetricRegistries.class, DEFAULT_CLASS);
}
/**
diff --git
a/ratis-metrics-api/src/main/java/org/apache/ratis/metrics/MetricRegistriesLoader.java
b/ratis-metrics-api/src/main/java/org/apache/ratis/metrics/MetricRegistriesLoader.java
deleted file mode 100644
index 8baac7a46..000000000
---
a/ratis-metrics-api/src/main/java/org/apache/ratis/metrics/MetricRegistriesLoader.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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
- *
- * http://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.apache.ratis.metrics;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.ServiceLoader;
-import java.util.stream.Collectors;
-
-import
org.apache.ratis.thirdparty.com.google.common.annotations.VisibleForTesting;
-import org.apache.ratis.util.ReflectionUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-public final class MetricRegistriesLoader {
- private static final Logger LOG =
LoggerFactory.getLogger(MetricRegistriesLoader.class);
-
- static final String DEFAULT_CLASS =
"org.apache.ratis.metrics.impl.MetricRegistriesImpl";
-
- private MetricRegistriesLoader() {
- }
-
- /**
- * Creates a {@link MetricRegistries} instance using the corresponding
{@link MetricRegistries}
- * available to {@link ServiceLoader} on the classpath. If no instance is
found, then default
- * implementation will be loaded.
- * @return A {@link MetricRegistries} implementation.
- */
- public static MetricRegistries load() {
- List<MetricRegistries> availableImplementations =
getDefinedImplementations();
- return load(availableImplementations);
- }
-
- /**
- * Creates a {@link MetricRegistries} instance using the corresponding
{@link MetricRegistries}
- * available to {@link ServiceLoader} on the classpath. If no instance is
found, then default
- * implementation will be loaded.
- * @return A {@link MetricRegistries} implementation.
- */
- @VisibleForTesting
- static MetricRegistries load(List<MetricRegistries> registries) {
- if (registries.isEmpty()) {
- try {
- return
ReflectionUtils.newInstance(Class.forName(DEFAULT_CLASS).asSubclass(MetricRegistries.class));
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException("Failed to load default
MetricRegistries " + DEFAULT_CLASS, e);
- }
- }
-
- final MetricRegistries first = registries.get(0);
- if (registries.size() == 1) {
- // One and only one instance -- what we want/expect
- LOG.debug("Loaded {}", first.getClass());
- } else {
- // Tell the user they're doing something wrong, and choose the first
impl.
- final List<? extends Class<?>> classes =
registries.stream().map(Object::getClass).collect(Collectors.toList());
- LOG.warn("Found multiple MetricRegistries: {}. Using the first: {}",
classes, first.getClass());
- }
- return first;
- }
-
- private static List<MetricRegistries> getDefinedImplementations() {
- ServiceLoader<MetricRegistries> loader = ServiceLoader.load(
- MetricRegistries.class,
- MetricRegistries.class.getClassLoader());
- List<MetricRegistries> availableFactories = new ArrayList<>();
- for (MetricRegistries impl : loader) {
- availableFactories.add(impl);
- }
- return availableFactories;
- }
-}
diff --git
a/ratis-metrics-dropwizard3/src/test/java/org/apache/ratis/metrics/dropwizard3/TestLoadDm3MetricRegistries.java
b/ratis-metrics-dropwizard3/src/test/java/org/apache/ratis/metrics/dropwizard3/TestLoadDm3MetricRegistries.java
index 5b3897ffd..4bae01738 100644
---
a/ratis-metrics-dropwizard3/src/test/java/org/apache/ratis/metrics/dropwizard3/TestLoadDm3MetricRegistries.java
+++
b/ratis-metrics-dropwizard3/src/test/java/org/apache/ratis/metrics/dropwizard3/TestLoadDm3MetricRegistries.java
@@ -20,19 +20,18 @@ package org.apache.ratis.metrics.dropwizard3;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import org.apache.ratis.metrics.MetricRegistries;
-import org.apache.ratis.metrics.MetricRegistriesLoader;
import org.apache.ratis.metrics.MetricRegistryInfo;
import org.apache.ratis.metrics.RatisMetricRegistry;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
- * Test class for {@link MetricRegistriesLoader}.
+ * Test class for loading {@link Dm3MetricRegistriesImpl}.
*/
public class TestLoadDm3MetricRegistries {
@Test
public void testLoadDm3() {
- final MetricRegistries r = MetricRegistriesLoader.load();
+ final MetricRegistries r = MetricRegistries.global();
Assertions.assertSame(Dm3MetricRegistriesImpl.class, r.getClass());
}
diff --git
a/ratis-metrics-default/src/test/java/org/apache/ratis/metrics/TestMetricRegistriesLoader.java
b/ratis-test/src/test/java/org/apache/ratis/metrics/TestMetricRegistries.java
similarity index 67%
rename from
ratis-metrics-default/src/test/java/org/apache/ratis/metrics/TestMetricRegistriesLoader.java
rename to
ratis-test/src/test/java/org/apache/ratis/metrics/TestMetricRegistries.java
index 9816cc99c..f58480bc9 100644
---
a/ratis-metrics-default/src/test/java/org/apache/ratis/metrics/TestMetricRegistriesLoader.java
+++
b/ratis-test/src/test/java/org/apache/ratis/metrics/TestMetricRegistries.java
@@ -17,13 +17,17 @@
*/
package org.apache.ratis.metrics;
+import static org.apache.ratis.metrics.MetricRegistries.DEFAULT_CLASS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.mock;
+import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import org.apache.ratis.metrics.impl.MetricRegistriesImpl;
+import org.apache.ratis.util.ServiceUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -31,39 +35,43 @@ import java.util.Arrays;
import java.util.Collections;
/**
- * Test class for {@link MetricRegistriesLoader}.
+ * Test class for loading {@link MetricRegistries} using {@link ServiceUtils}.
*/
-public class TestMetricRegistriesLoader {
+public class TestMetricRegistries {
+ static MetricRegistries load(List<MetricRegistries> loaded) {
+ return ServiceUtils.load(MetricRegistries.class, MetricRegistries::global,
loaded);
+ }
+
@Test
public void testLoadEmptyInstance() {
- MetricRegistries instance =
MetricRegistriesLoader.load(Collections.emptyList());
- assertEquals(MetricRegistriesLoader.DEFAULT_CLASS,
instance.getClass().getName());
+ MetricRegistries instance = load(Collections.emptyList());
+ assertEquals(DEFAULT_CLASS, instance.getClass().getName());
+ assertSame(MetricRegistries.global(), instance);
}
@Test
public void testLoadSingleInstance() {
MetricRegistries loader = mock(MetricRegistries.class);
- MetricRegistries instance =
MetricRegistriesLoader.load(Collections.singletonList(loader));
+ MetricRegistries instance = load(Collections.singletonList(loader));
assertEquals(loader, instance);
}
@Test
public void testLoadMultipleInstances() {
- MetricRegistries loader1 = mock(MetricRegistries.class);
- MetricRegistries loader2 = mock(MetricRegistries.class);
- MetricRegistries loader3 = mock(MetricRegistries.class);
- MetricRegistries instance =
MetricRegistriesLoader.load(Arrays.asList(loader1, loader2, loader3));
+ final MetricRegistries first = mock(MetricRegistries.class);
+ final MetricRegistries second = MetricRegistries.global();
+ final MetricRegistries instance = load(Arrays.asList(first, second));
// the load() returns the first instance
- assertEquals(loader1, instance);
- assertNotEquals(loader2, instance);
- assertNotEquals(loader3, instance);
+ assertEquals(first, instance);
+ assertNotEquals(second, instance);
}
@Test
public void testLoadDefault() {
- final MetricRegistries r = MetricRegistriesLoader.load();
- Assertions.assertSame(MetricRegistriesImpl.class, r.getClass());
+ final MetricRegistries loaded = MetricRegistries.global();
+ Assertions.assertSame(MetricRegistriesImpl.class, loaded.getClass());
+ Assertions.assertSame(MetricRegistries.global(), loaded);
}
@Test