Index: hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMasterCommandLine.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMasterCommandLine.java (revision 1561480) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMasterCommandLine.java (working copy) @@ -41,6 +41,7 @@ import org.apache.hadoop.hbase.util.ServerCommandLine; import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster; import org.apache.hadoop.hbase.zookeeper.ZKUtil; +import org.apache.hadoop.hbase.jmx.JMXServer; import org.apache.zookeeper.KeeperException; @InterfaceAudience.Private @@ -61,6 +62,8 @@ private final Class masterClass; + private JMXServer jmxServer = null; + public HMasterCommandLine(Class masterClass) { this.masterClass = masterClass; } @@ -186,6 +189,8 @@ LOG.info("Won't bring the Master up as a shutdown is requested"); return 1; } + jmxServer = new JMXServer(conf, "hbase.master"); + jmxServer.start(); master.start(); master.join(); if(master.isAborted()) @@ -193,6 +198,7 @@ } } catch (Throwable t) { LOG.error("Master exiting", t); + stopJMXServer(); return 1; } return 0; @@ -221,6 +227,9 @@ LOG.error("Failed to stop master", t); return 1; } + finally { + stopJMXServer(); + } return 0; } @@ -272,4 +281,16 @@ this.zkcluster = zkcluster; } } + + private void stopJMXServer() { + if (jmxServer != null) { + try { + jmxServer.stop(); + } catch (IOException e) { + LOG.warn("Exception during JMX server stop.", e); + } finally { + jmxServer = null; + } + } + } } Index: hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision 1561480) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (working copy) @@ -240,6 +240,7 @@ import com.google.protobuf.ServiceException; import com.google.protobuf.TextFormat; import com.google.protobuf.ZeroCopyLiteralByteString; +import org.apache.hadoop.hbase.jmx.JMXServer; /** * HRegionServer makes a set of HRegions available to clients. It checks in with @@ -520,6 +521,8 @@ private UserProvider userProvider; + private JMXServer jmxServer = null; + /** * Starts a HRegionServer at the default location * @@ -628,6 +631,7 @@ // that port is occupied. Adjust serverInfo if this is the case. this.rsInfo.setInfoPort(putUpWebUI()); this.distributedLogReplay = HLogSplitter.isDistributedLogReplay(this.conf); + jmxServer = new JMXServer(conf, "hbase.regionserver"); } /** @@ -835,7 +839,6 @@ } catch (Throwable e) { abort("Fatal exception during initialization", e); } - try { // Set our ephemeral znode up in zookeeper now we have a name. createMyEphemeralNode(); @@ -907,6 +910,9 @@ abort(prefix + t.getMessage(), t); } } + finally { + stopJMXServer(); + } // Run shutdown. if (mxBean != null) { MBeanUtil.unregisterMBean(mxBean); @@ -1643,6 +1649,7 @@ sinkConf.setInt("hbase.client.serverside.retries.multiplier", 1); this.splitLogWorker = new SplitLogWorker(this.zooKeeper, sinkConf, this, this); splitLogWorker.start(); + if (jmxServer != null) jmxServer.start(); } /** @@ -4573,4 +4580,15 @@ respBuilder.setResponse(openInfoList.size()); return respBuilder.build(); } + private void stopJMXServer() { + if (jmxServer != null) { + try { + jmxServer.stop(); + } catch (IOException e) { + LOG.warn("Exception during JMX server stop.", e); + } finally { + jmxServer = null; + } + } + } } Index: hbase-server/src/test/java/org/apache/hadoop/hbase/jmx/TestJMXServer.java =================================================================== --- hbase-server/src/test/java/org/apache/hadoop/hbase/jmx/TestJMXServer.java (revision 0) +++ hbase-server/src/test/java/org/apache/hadoop/hbase/jmx/TestJMXServer.java (working copy) @@ -0,0 +1,112 @@ +/** + * 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.hbase.jmx; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.net.Inet4Address; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.metrics2.annotation.Metric; +import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem; +import org.apache.hadoop.metrics2.util.MBeans; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class TestJMXServer { + + private Configuration conf; + private JMXServer server; + + @Before + public void setup() { + conf = new Configuration(); + conf.set("jmxtest.rmi.registry.port","2356"); + conf.set("jmxtest.rmi.registry.port","2356"); + } + + @After + public void tearDown() throws IOException { + if (server != null) { + server.stop(); + } + } + + public static interface TestJMXMBean { + String getName(); + } + + public static class TestJMX implements TestJMXMBean { + + @Metric({ "name", "Name of MBean" }) + public String getName() { + return "Hbase"; + } + } + + @Test + public void testJMXStart() throws Exception { + conf.set("jmxtest.rmi.registry.ip",Inet4Address.getLocalHost().getHostAddress().toString()); + System.out.println("TestJMXServer.testJMXStart()"); + server = new JMXServer(conf, "jmxtest"); + server.start(); + + // Initialize metric system + TestJMXMBean mbean = new TestJMX(); + MBeans.register("TestJMX", "TestJMXInfo", mbean); + DefaultMetricsSystem.instance().register("TestJMX", "Test JMX", mbean); + + JMXServiceURL jmxUrl = server.getUrl(); + JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxUrl, null); + MBeanServerConnection mbeansServerConnection = jmxConnector.getMBeanServerConnection(); + ObjectName objectName = new ObjectName("Hadoop:service=TestJMX,name=TestJMXInfo"); + + MBeanInfo mBeanInfo = mbeansServerConnection.getMBeanInfo(objectName); + MBeanAttributeInfo[] attributes = mBeanInfo.getAttributes(); + + Object attribute = mbeansServerConnection.getAttribute(objectName, attributes[0].getName()); + + assertTrue("Mbean not registered with JMX Server", + attribute.toString().equalsIgnoreCase("Hbase")); + } + + @Test + public void testPortValidation() throws Exception { + conf.set("jmxtest.rmi.registry.port","1023"); + server = new JMXServer(conf, "jmxtest"); + try { + server.start(); + fail("Port not validated"); + } catch (IllegalArgumentException e) { + // success + } + } + +} \ No newline at end of file