diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/util/MBeans.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/util/MBeans.java index ded49d6a6ef..4c7516052e4 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/util/MBeans.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/util/MBeans.java @@ -18,13 +18,17 @@ package org.apache.hadoop.metrics2.util; import java.lang.management.ManagementFactory; +import java.util.HashMap; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanServer; import javax.management.ObjectName; +import com.google.common.annotations.VisibleForTesting; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; @@ -60,8 +64,25 @@ public class MBeans { */ static public ObjectName register(String serviceName, String nameName, Object theMbean) { + return register(serviceName, nameName, new HashMap(), theMbean); + } + + /** + * Register the MBean using our standard MBeanName format + * "hadoop:service=,name=" + * Where the and are the supplied parameters + * + * @param serviceName + * @param nameName + * @param properties - Key value pairs to define additional JMX ObjectName properties. + * @param theMbean - the MBean to register + * @return the named used to register the MBean + */ + static public ObjectName register(String serviceName, String nameName, + Map properties, + Object theMbean) { final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - ObjectName name = getMBeanName(serviceName, nameName); + ObjectName name = getMBeanName(serviceName, nameName, properties); if (name != null) { try { mbs.registerMBean(theMbean, name); @@ -116,9 +137,17 @@ public class MBeans { DefaultMetricsSystem.removeMBeanName(mbeanName); } - static private ObjectName getMBeanName(String serviceName, String nameName) { + @VisibleForTesting + static ObjectName getMBeanName(String serviceName, String nameName, + Map additionalParameters) { + + String additionalKeys = additionalParameters.entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(Collectors.joining(",")); + String nameStr = DOMAIN_PREFIX + SERVICE_PREFIX + serviceName + "," + - NAME_PREFIX + nameName; + NAME_PREFIX + nameName + (additionalKeys.isEmpty() ? "" : "," + additionalKeys); try { return DefaultMetricsSystem.newMBeanName(nameStr); } catch (Exception e) { diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/DummyMXBean.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/DummyMXBean.java new file mode 100644 index 00000000000..4cf14a37fe9 --- /dev/null +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/DummyMXBean.java @@ -0,0 +1,23 @@ +/** + * 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.hadoop.metrics2.util; + +public interface DummyMXBean { + + int getCounter(); +} diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/TestMBeans.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/TestMBeans.java new file mode 100644 index 00000000000..212351b3119 --- /dev/null +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/metrics2/util/TestMBeans.java @@ -0,0 +1,101 @@ +/** + * 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.hadoop.metrics2.util; + +import org.junit.Assert; +import org.junit.Test; + +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.lang.management.ManagementFactory; +import java.util.HashMap; +import java.util.Map; + +public class TestMBeans implements DummyMXBean { + + public int counter = 1; + + @Test + public void testRegister() throws Exception { + ObjectName objectName = null; + try { + counter = 23; + objectName = MBeans.register("UnitTest", + "RegisterTest", this); + + MBeanServer platformMBeanServer = + ManagementFactory.getPlatformMBeanServer(); + + int jmxCounter = (int) platformMBeanServer + .getAttribute(objectName, "Counter"); + Assert.assertEquals(counter, jmxCounter); + } finally { + if (objectName != null) { + MBeans.unregister(objectName); + } + } + } + + + @Test + public void testRegisterWithAdditionalProperties() throws Exception { + ObjectName objectName = null; + try { + counter = 42; + + Map properties = new HashMap(); + properties.put("flavour", "server"); + objectName = MBeans.register("UnitTest", "RegisterTest", properties, this); + + MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); + int jmxCounter = (int) platformMBeanServer.getAttribute(objectName, "Counter"); + Assert.assertEquals(counter, jmxCounter); + } finally { + if (objectName != null) { + MBeans.unregister(objectName); + } + } + } + + @Test + public void testGetMbeanNameName() { + HashMap properties = new HashMap<>(); + + ObjectName mBeanName = MBeans.getMBeanName("Service", + "Name", properties); + + Assert.assertEquals("Service", + MBeans.getMbeanNameService(mBeanName)); + + properties.put("key", "value"); + mBeanName = MBeans.getMBeanName( + "Service", + "Name", + properties); + + Assert.assertEquals("Service", + MBeans.getMbeanNameService(mBeanName)); + + } + + @Override + public int getCounter() { + return counter; + } + +} \ No newline at end of file