From 824638594ba5dcb18b53f2689888f600e237ab42 Mon Sep 17 00:00:00 2001 From: elcallio Date: Tue, 11 Oct 2016 14:13:18 +0200 Subject: [PATCH] Clean up and simplify Main startup --- src/main/java/com/scylladb/jmx/main/Main.java | 124 +++++++++++++++--- .../jmx/utils/APIMBeanIntrospector.java | 103 --------------- .../jmx/utils/RMIServerSocketFactoryImpl.java | 121 ----------------- 3 files changed, 107 insertions(+), 241 deletions(-) delete mode 100644 src/main/java/com/scylladb/jmx/utils/APIMBeanIntrospector.java delete mode 100644 src/main/java/com/scylladb/jmx/utils/RMIServerSocketFactoryImpl.java diff --git a/src/main/java/com/scylladb/jmx/main/Main.java b/src/main/java/com/scylladb/jmx/main/Main.java index 414aeac..6a8dfd3 100644 --- a/src/main/java/com/scylladb/jmx/main/Main.java +++ b/src/main/java/com/scylladb/jmx/main/Main.java @@ -3,38 +3,128 @@ */ package com.scylladb.jmx.main; -import com.scylladb.jmx.api.APIConfig; -import com.scylladb.jmx.utils.RMIServerSocketFactoryImpl; +import static java.lang.management.ManagementFactory.getPlatformMBeanServer; +import static java.rmi.registry.LocateRegistry.createRegistry; +import static java.util.Arrays.asList; +import static javax.net.ServerSocketFactory.getDefault; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.rmi.server.RMIServerSocketFactory; +import java.util.HashMap; +import java.util.Map; + +import javax.management.MBeanServer; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnectorServer; import org.apache.cassandra.db.commitlog.CommitLog; import org.apache.cassandra.db.compaction.CompactionManager; -import org.apache.cassandra.gms.Gossiper; import org.apache.cassandra.gms.FailureDetector; +import org.apache.cassandra.gms.Gossiper; import org.apache.cassandra.locator.EndpointSnitchInfo; import org.apache.cassandra.net.MessagingService; import org.apache.cassandra.service.CacheService; import org.apache.cassandra.service.GCInspector; import org.apache.cassandra.service.StorageProxy; import org.apache.cassandra.service.StorageService; +import org.apache.cassandra.streaming.StreamManager; + +import com.scylladb.jmx.api.APIClient; +import com.scylladb.jmx.api.APIConfig; +import com.scylladb.jmx.metrics.APIMBean; public class Main { + // todo: command line options. Make us an agent class (also) + private static final APIConfig config = new APIConfig(); + public static final APIClient client = new APIClient(config); + + private static JMXConnectorServer jmxServer = null; + + private static void setupJmx() { + System.setProperty("javax.management.builder.initial", "com.scylladb.jmx.utils.APIBuilder"); + String jmxPort = System.getProperty("com.sun.management.jmxremote.port"); + + if (jmxPort == null) { + System.out.println("JMX is not enabled to receive remote connections."); + + jmxPort = System.getProperty("cassandra.jmx.local.port", "7199"); + String address = System.getProperty("jmx.address", "localhost"); + if (address.equals("localhost")) { + System.setProperty("java.rmi.server.hostname", InetAddress.getLoopbackAddress().getHostAddress()); + } else { + try { + System.setProperty("java.rmi.server.hostname", InetAddress.getByName(address).getHostAddress()); + } catch (UnknownHostException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + try { + RMIServerSocketFactory serverFactory = pPort -> getDefault().createServerSocket(pPort, 0, + InetAddress.getLoopbackAddress()); + createRegistry(Integer.valueOf(jmxPort), null, serverFactory); + + StringBuffer url = new StringBuffer(); + url.append("service:jmx:"); + url.append("rmi://").append(address).append("/jndi/"); + url.append("rmi://").append(address).append(":").append(jmxPort).append("/jmxrmi"); + System.out.println(url); + Map env = new HashMap<>(); + env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverFactory); + + jmxServer = new RMIConnectorServer(new JMXServiceURL(url.toString()), env, getPlatformMBeanServer()); + + jmxServer.start(); + } catch (IOException e) { + System.out.println("Error starting local jmx server: " + e.toString()); + } + + } else { + System.out.println("JMX is enabled to receive remote connections on port: " + jmxPort); + } + + } public static void main(String[] args) throws Exception { - APIConfig.setConfig(); - System.out.println("Connecting to " + APIConfig.getBaseUrl()); + System.out.println("Connecting to " + config.getBaseUrl()); System.out.println("Starting the JMX server"); - RMIServerSocketFactoryImpl.maybeInitJmx(); - StorageService.getInstance(); - StorageProxy.getInstance(); - MessagingService.getInstance(); - CommitLog.getInstance(); - Gossiper.getInstance(); - EndpointSnitchInfo.getInstance(); - FailureDetector.getInstance(); - CacheService.getInstance(); - CompactionManager.getInstance(); - GCInspector.register(); - Thread.sleep(Long.MAX_VALUE); + + setupJmx(); + + try { + MBeanServer server = getPlatformMBeanServer(); + for (Class clazz : asList(StorageService.class, StorageProxy.class, + MessagingService.class, CommitLog.class, Gossiper.class, EndpointSnitchInfo.class, + FailureDetector.class, CacheService.class, CompactionManager.class, GCInspector.class, + StreamManager.class)) { + Constructor c = clazz.getDeclaredConstructor(APIClient.class); + APIMBean m = c.newInstance(client); + server.registerMBean(m, null); + } + + try { + // forces check for dynamically created mbeans + server.queryNames(null, null); + } catch (IllegalStateException e) { + // ignore this. Just means we started before scylla. + } + + for (;;) { + Thread.sleep(Long.MAX_VALUE); + } + } finally { + // make sure to kill the server otherwise we can hang. Not an issue + // when killed perhaps, but any exception above etc would leave a + // zombie. + if (jmxServer != null) { + jmxServer.stop(); + } + } } } diff --git a/src/main/java/com/scylladb/jmx/utils/APIMBeanIntrospector.java b/src/main/java/com/scylladb/jmx/utils/APIMBeanIntrospector.java deleted file mode 100644 index 738b2c8..0000000 --- a/src/main/java/com/scylladb/jmx/utils/APIMBeanIntrospector.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.scylladb.jmx.utils; -/** - * Copyright (C) The MX4J Contributors. - * All rights reserved. - * - * This software is distributed under the terms of the MX4J License version 1.0. - * See the terms of the MX4J License in the documentation provided with this software. - */ - -/** - * Modified by ScyllaDB - * Copyright 2016 ScyllaDB - */ -/* -* This file is part of Scylla. -* -* Scylla is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* Scylla is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with Scylla. If not, see . -*/ - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.management.MBeanInfo; - -import mx4j.server.MBeanIntrospector; -import mx4j.server.MBeanMetaData; - -public class APIMBeanIntrospector extends MBeanIntrospector { - private static final java.util.logging.Logger logger = java.util.logging.Logger - .getLogger(APIMBeanIntrospector.class.getName()); - - public boolean isMBeanCompliant(MBeanMetaData metadata) { - Class info = metadata.getMBeanInterface(); - if (info != null) { - String cn = info.getName(); - if (cn != null) { - if (cn.endsWith("MXBean")) { - return true; - } - } - } - return super.isMBeanCompliant(metadata); - } - - public void apiIntrospectStandardMBean(MBeanMetaData metadata) { - try { - Class[] cArg = new Class[1]; - cArg[0] = MBeanMetaData.class; - Method met = MBeanIntrospector.class - .getDeclaredMethod("introspectStandardMBean", cArg); - met.setAccessible(true); - met.invoke((MBeanIntrospector) this, metadata); - } catch (NoSuchMethodException | SecurityException - | IllegalAccessException | IllegalArgumentException - | InvocationTargetException e) { - logger.warning("Failed setting mbean info " + e.getMessage()); - } - } - - public void apiIntrospect(MBeanMetaData metadata) { - apiIntrospectStandardMBean(metadata); - Class[] cArg = new Class[1]; - cArg[0] = MBeanMetaData.class; - try { - Method met = MBeanIntrospector.class - .getDeclaredMethod("createStandardMBeanInfo", cArg); - met.setAccessible(true); - Object info = met.invoke((MBeanIntrospector) this, metadata); - metadata.setMBeanInfo((MBeanInfo) info); - } catch (IllegalAccessException | NoSuchMethodException - | SecurityException | IllegalArgumentException - | InvocationTargetException e) { - logger.warning("Failed setting mbean info" + e.getMessage()); - } - } - - public void introspect(MBeanMetaData metadata) { - Class mx_mbean = null; - for (Class it : metadata.getMBean().getClass().getInterfaces()) { - if (it.getName().endsWith("MXBean")) { - mx_mbean = it; - break; - } - } - if (mx_mbean != null) { - metadata.setMBeanInterface(mx_mbean); - apiIntrospect(metadata); - return; - } - super.introspect(metadata); - } -} diff --git a/src/main/java/com/scylladb/jmx/utils/RMIServerSocketFactoryImpl.java b/src/main/java/com/scylladb/jmx/utils/RMIServerSocketFactoryImpl.java deleted file mode 100644 index a234e56..0000000 --- a/src/main/java/com/scylladb/jmx/utils/RMIServerSocketFactoryImpl.java +++ /dev/null @@ -1,121 +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. - */ - -/* - * Copyright 2016 ScyllaDB - * - * Modified by ScyllaDB - */ - -package com.scylladb.jmx.utils; - -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.net.*; -import java.rmi.registry.LocateRegistry; -import java.rmi.server.RMIServerSocketFactory; -import java.util.HashMap; -import java.util.Map; - -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.rmi.RMIConnectorServer; -import javax.net.ServerSocketFactory; - -public class RMIServerSocketFactoryImpl implements RMIServerSocketFactory { - public static JMXConnectorServer jmxServer = null; - - public static void maybeInitJmx() { - System.setProperty("javax.management.builder.initial", "com.scylladb.jmx.utils.APIBuilder"); - System.setProperty("mx4j.strict.mbean.interface", "no"); - - String jmxPort = System - .getProperty("com.sun.management.jmxremote.port"); - - if (jmxPort == null) { - System.out.println( - "JMX is not enabled to receive remote connections."); - - jmxPort = System.getProperty("cassandra.jmx.local.port", "7199"); - String address = System.getProperty("jmx.address", "localhost"); - if (address.equals("localhost")) { - System.setProperty("java.rmi.server.hostname", - InetAddress.getLoopbackAddress().getHostAddress()); - } else { - try { - System.setProperty("java.rmi.server.hostname", - InetAddress.getByName(address).getHostAddress()); - } catch (UnknownHostException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - try { - RMIServerSocketFactory serverFactory = new RMIServerSocketFactoryImpl(); - LocateRegistry.createRegistry(Integer.valueOf(jmxPort), null, - serverFactory); - - StringBuffer url = new StringBuffer(); - url.append("service:jmx:"); - url.append("rmi://").append(address).append("/jndi/"); - url.append("rmi://").append(address).append(":").append(jmxPort) - .append("/jmxrmi"); - System.out.println(url); - Map env = new HashMap(); - env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, - serverFactory); - - jmxServer = new RMIConnectorServer( - new JMXServiceURL(url.toString()), env, - ManagementFactory.getPlatformMBeanServer()); - - jmxServer.start(); - } catch (IOException e) { - System.out.println( - "Error starting local jmx server: " + e.toString()); - } - - } else { - System.out.println( - "JMX is enabled to receive remote connections on port: " - + jmxPort); - } - } - - public ServerSocket createServerSocket(final int pPort) throws IOException { - return ServerSocketFactory.getDefault().createServerSocket(pPort, 0, - InetAddress.getLoopbackAddress()); - } - - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - - return obj.getClass().equals(getClass()); - } - - public int hashCode() { - return RMIServerSocketFactoryImpl.class.hashCode(); - } - -}