4981215: Publishing a port number for management console to access
Reviewed-by: emcmanus, dfuchs
--- a/jdk/src/share/classes/sun/management/ConnectorAddressLink.java Sun Mar 09 21:56:42 2008 -0700
+++ b/jdk/src/share/classes/sun/management/ConnectorAddressLink.java Mon Mar 10 23:13:31 2008 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2004-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,12 +25,13 @@
package sun.management;
+import java.io.IOException;
import java.nio.ByteBuffer;
-import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
-import java.util.Iterator;
-import java.util.Set;
-import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
import sun.misc.Perf;
import sun.management.counter.Units;
@@ -46,36 +47,67 @@
public class ConnectorAddressLink {
private static final String CONNECTOR_ADDRESS_COUNTER =
- "sun.management.JMXConnectorServer.address";
+ "sun.management.JMXConnectorServer.address";
+
+ /*
+ * The format of the jvmstat counters representing the properties of
+ * a given out-of-the-box JMX remote connector will be as follows:
+ *
+ * sun.management.JMXConnectorServer.<counter>.<key>=<value>
+ *
+ * where:
+ *
+ * counter = index computed by this class which uniquely identifies
+ * an out-of-the-box JMX remote connector running in this
+ * Java virtual machine.
+ * key/value = a given key/value pair in the map supplied to the
+ * exportRemote() method.
+ *
+ * For example,
+ *
+ * sun.management.JMXConnectorServer.0.remoteAddress=service:jmx:rmi:///jndi/rmi://myhost:5000/jmxrmi
+ * sun.management.JMXConnectorServer.0.authenticate=false
+ * sun.management.JMXConnectorServer.0.ssl=false
+ * sun.management.JMXConnectorServer.0.sslRegistry=false
+ * sun.management.JMXConnectorServer.0.sslNeedClientAuth=false
+ */
+ private static final String REMOTE_CONNECTOR_COUNTER_PREFIX =
+ "sun.management.JMXConnectorServer.";
+
+ /*
+ * JMX remote connector counter (it will be incremented every
+ * time a new out-of-the-box JMX remote connector is created).
+ */
+ private static AtomicInteger counter = new AtomicInteger();
/**
* Exports the specified connector address to the instrumentation buffer
* so that it can be read by this or other Java virtual machines running
* on the same system.
*
- * @param address The connector address.
+ * @param address The connector address.
*/
public static void export(String address) {
if (address == null || address.length() == 0) {
throw new IllegalArgumentException("address not specified");
}
Perf perf = Perf.getPerf();
- perf.createString(CONNECTOR_ADDRESS_COUNTER, 1, Units.STRING.intValue(), address);
+ perf.createString(
+ CONNECTOR_ADDRESS_COUNTER, 1, Units.STRING.intValue(), address);
}
/**
* Imports the connector address from the instrument buffer
* of the specified Java virtual machine.
*
- * @param vmid an identifier that uniquely identifies a local
- * Java virtual machine, or <code>0</code> to indicate
- * the current Java virtual machine.
+ * @param vmid an identifier that uniquely identifies a local Java virtual
+ * machine, or <code>0</code> to indicate the current Java virtual machine.
*
- * @return the value of the connector address, or <code>null</code>
- * if the target VM has not exported a connector address.
+ * @return the value of the connector address, or <code>null</code> if the
+ * target VM has not exported a connector address.
*
- * @throws IOException An I/O error occurred while trying to acquire
- * the instrumentation buffer.
+ * @throws IOException An I/O error occurred while trying to acquire the
+ * instrumentation buffer.
*/
public static String importFrom(int vmid) throws IOException {
Perf perf = Perf.getPerf();
@@ -85,14 +117,65 @@
} catch (IllegalArgumentException iae) {
throw new IOException(iae.getMessage());
}
- List counters = (new PerfInstrumentation(bb)).findByPattern(CONNECTOR_ADDRESS_COUNTER);
+ List counters =
+ new PerfInstrumentation(bb).findByPattern(CONNECTOR_ADDRESS_COUNTER);
Iterator i = counters.iterator();
if (i.hasNext()) {
- Counter c = (Counter)i.next();
- return (String)c.getValue();
+ Counter c = (Counter) i.next();
+ return (String) c.getValue();
} else {
return null;
}
}
+ /**
+ * Exports the specified remote connector address and associated
+ * configuration properties to the instrumentation buffer so that
+ * it can be read by this or other Java virtual machines running
+ * on the same system.
+ *
+ * @param properties The remote connector address properties.
+ */
+ public static void exportRemote(Map<String, String> properties) {
+ final int index = counter.getAndIncrement();
+ Perf perf = Perf.getPerf();
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+ perf.createString(REMOTE_CONNECTOR_COUNTER_PREFIX + index + "." +
+ entry.getKey(), 1, Units.STRING.intValue(), entry.getValue());
+ }
+ }
+
+ /**
+ * Imports the remote connector address and associated
+ * configuration properties from the instrument buffer
+ * of the specified Java virtual machine.
+ *
+ * @param vmid an identifier that uniquely identifies a local Java virtual
+ * machine, or <code>0</code> to indicate the current Java virtual machine.
+ *
+ * @return a map containing the remote connector's properties, or an empty
+ * map if the target VM has not exported the remote connector's properties.
+ *
+ * @throws IOException An I/O error occurred while trying to acquire the
+ * instrumentation buffer.
+ */
+ public static Map<String, String> importRemoteFrom(int vmid) throws IOException {
+ Perf perf = Perf.getPerf();
+ ByteBuffer bb;
+ try {
+ bb = perf.attach(vmid, "r");
+ } catch (IllegalArgumentException iae) {
+ throw new IOException(iae.getMessage());
+ }
+ List counters = new PerfInstrumentation(bb).getAllCounters();
+ Map<String, String> properties = new HashMap<String, String>();
+ for (Object c : counters) {
+ String name = ((Counter) c).getName();
+ if (name.startsWith(REMOTE_CONNECTOR_COUNTER_PREFIX) &&
+ !name.equals(CONNECTOR_ADDRESS_COUNTER)) {
+ properties.put(name, ((Counter) c).getValue().toString());
+ }
+ }
+ return properties;
+ }
}
--- a/jdk/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java Sun Mar 09 21:56:42 2008 -0700
+++ b/jdk/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java Mon Mar 10 23:13:31 2008 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
+import java.rmi.server.RemoteObject;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
@@ -70,12 +71,14 @@
import javax.security.auth.Subject;
+import sun.rmi.server.UnicastRef;
import sun.rmi.server.UnicastServerRef;
import sun.rmi.server.UnicastServerRef2;
import sun.management.Agent;
import sun.management.AgentConfigurationError;
import static sun.management.AgentConfigurationError.*;
+import sun.management.ConnectorAddressLink;
import sun.management.FileSystem;
import sun.management.snmp.util.MibLogger;
@@ -92,20 +95,22 @@
* Default values for JMX configuration properties.
**/
public static interface DefaultValues {
- public static final String PORT="0";
- public static final String CONFIG_FILE_NAME="management.properties";
- public static final String USE_SSL="true";
- public static final String USE_REGISTRY_SSL="false";
- public static final String USE_AUTHENTICATION="true";
- public static final String PASSWORD_FILE_NAME="jmxremote.password";
- public static final String ACCESS_FILE_NAME="jmxremote.access";
- public static final String SSL_NEED_CLIENT_AUTH="false";
+
+ public static final String PORT = "0";
+ public static final String CONFIG_FILE_NAME = "management.properties";
+ public static final String USE_SSL = "true";
+ public static final String USE_REGISTRY_SSL = "false";
+ public static final String USE_AUTHENTICATION = "true";
+ public static final String PASSWORD_FILE_NAME = "jmxremote.password";
+ public static final String ACCESS_FILE_NAME = "jmxremote.access";
+ public static final String SSL_NEED_CLIENT_AUTH = "false";
}
/**
* Names of JMX configuration properties.
**/
public static interface PropertyNames {
+
public static final String PORT =
"com.sun.management.jmxremote.port";
public static final String CONFIG_FILE_NAME =
@@ -133,6 +138,21 @@
}
/**
+ * JMXConnectorServer associated data.
+ */
+ private static class JMXConnectorServerData {
+
+ public JMXConnectorServerData(
+ JMXConnectorServer jmxConnectorServer,
+ JMXServiceURL jmxRemoteURL) {
+ this.jmxConnectorServer = jmxConnectorServer;
+ this.jmxRemoteURL = jmxRemoteURL;
+ }
+ JMXConnectorServer jmxConnectorServer;
+ JMXServiceURL jmxRemoteURL;
+ }
+
+ /**
* <p>Prevents our RMI server objects from keeping the JVM alive.</p>
*
* <p>We use a private interface in Sun's JMX Remote API implementation
@@ -151,6 +171,7 @@
* works). Hence the somewhat misleading name of this class.</p>
*/
private static class PermanentExporter implements RMIExporter {
+
public Remote exportObject(Remote obj,
int port,
RMIClientSocketFactory csf,
@@ -158,24 +179,25 @@
throws RemoteException {
synchronized (this) {
- if (firstExported == null)
+ if (firstExported == null) {
firstExported = obj;
+ }
}
final UnicastServerRef ref;
- if (csf == null && ssf == null)
+ if (csf == null && ssf == null) {
ref = new UnicastServerRef(port);
- else
+ } else {
ref = new UnicastServerRef2(port, csf, ssf);
+ }
return ref.exportObject(obj, null, true);
}
// Nothing special to be done for this case
public boolean unexportObject(Remote obj, boolean force)
- throws NoSuchObjectException {
+ throws NoSuchObjectException {
return UnicastRemoteObject.unexportObject(obj, force);
}
-
Remote firstExported;
}
@@ -202,19 +224,21 @@
}
private void checkAccessFileEntries(Subject subject) {
- if (subject == null)
+ if (subject == null) {
throw new SecurityException(
"Access denied! No matching entries found in " +
"the access file [" + accessFile + "] as the " +
"authenticated Subject is null");
+ }
final Set principals = subject.getPrincipals();
- for (Iterator i = principals.iterator(); i.hasNext(); ) {
+ for (Iterator i = principals.iterator(); i.hasNext();) {
final Principal p = (Principal) i.next();
- if (properties.containsKey(p.getName()))
+ if (properties.containsKey(p.getName())) {
return;
+ }
}
final Set<String> principalsStr = new HashSet<String>();
- for (Iterator i = principals.iterator(); i.hasNext(); ) {
+ for (Iterator i = principals.iterator(); i.hasNext();) {
final Principal p = (Principal) i.next();
principalsStr.add(p.getName());
}
@@ -225,16 +249,16 @@
}
private static Properties propertiesFromFile(String fname)
- throws IOException {
+ throws IOException {
Properties p = new Properties();
- if (fname == null)
+ if (fname == null) {
return p;
+ }
FileInputStream fin = new FileInputStream(fname);
p.load(fin);
fin.close();
return p;
}
-
private final Map<String, Object> environment;
private final Properties properties;
private final String accessFile;
@@ -251,22 +275,23 @@
// Load a new management properties
final Properties props = Agent.loadManagementProperties();
- if (props == null) return null;
+ if (props == null) {
+ return null;
+ }
final String portStr = props.getProperty(PropertyNames.PORT);
// System.out.println("initializing: {port=" + portStr + ",
// properties="+props+"}");
- return initialize(portStr,props);
+ return initialize(portStr, props);
}
/**
* Initializes and starts a JMX Connector Server for remote
* monitoring and management.
**/
- public static synchronized
- JMXConnectorServer initialize(String portStr, Properties props) {
+ public static synchronized JMXConnectorServer initialize(String portStr, Properties props) {
// Get port number
final int port;
@@ -280,21 +305,21 @@
}
// Do we use authentication?
- final String useAuthenticationStr =
+ final String useAuthenticationStr =
props.getProperty(PropertyNames.USE_AUTHENTICATION,
DefaultValues.USE_AUTHENTICATION);
final boolean useAuthentication =
Boolean.valueOf(useAuthenticationStr).booleanValue();
// Do we use SSL?
- final String useSslStr =
+ final String useSslStr =
props.getProperty(PropertyNames.USE_SSL,
DefaultValues.USE_SSL);
final boolean useSsl =
Boolean.valueOf(useSslStr).booleanValue();
// Do we use RMI Registry SSL?
- final String useRegistrySslStr =
+ final String useRegistrySslStr =
props.getProperty(PropertyNames.USE_REGISTRY_SSL,
DefaultValues.USE_REGISTRY_SSL);
final boolean useRegistrySsl =
@@ -307,7 +332,7 @@
StringTokenizer st = new StringTokenizer(enabledCipherSuites, ",");
int tokens = st.countTokens();
enabledCipherSuitesList = new String[tokens];
- for (int i = 0 ; i < tokens; i++) {
+ for (int i = 0; i < tokens; i++) {
enabledCipherSuitesList[i] = st.nextToken();
}
}
@@ -319,12 +344,12 @@
StringTokenizer st = new StringTokenizer(enabledProtocols, ",");
int tokens = st.countTokens();
enabledProtocolsList = new String[tokens];
- for (int i = 0 ; i < tokens; i++) {
+ for (int i = 0; i < tokens; i++) {
enabledProtocolsList[i] = st.nextToken();
}
}
- final String sslNeedClientAuthStr =
+ final String sslNeedClientAuthStr =
props.getProperty(PropertyNames.SSL_NEED_CLIENT_AUTH,
DefaultValues.SSL_NEED_CLIENT_AUTH);
final boolean sslNeedClientAuth =
@@ -374,39 +399,49 @@
sslNeedClientAuth +
"\n\t" + PropertyNames.USE_AUTHENTICATION + "=" +
useAuthentication +
- (useAuthentication ?
- (loginConfigName == null ?
- ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
- passwordFileName) :
- ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
+ (useAuthentication ? (loginConfigName == null ? ("\n\t" + PropertyNames.PASSWORD_FILE_NAME + "=" +
+ passwordFileName) : ("\n\t" + PropertyNames.LOGIN_CONFIG_NAME + "=" +
loginConfigName)) : "\n\t" +
Agent.getText("jmxremote.ConnectorBootstrap.initialize.noAuthentication")) +
- (useAuthentication ?
- ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
+ (useAuthentication ? ("\n\t" + PropertyNames.ACCESS_FILE_NAME + "=" +
accessFileName) : "") +
"");
}
final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
JMXConnectorServer cs = null;
+ JMXServiceURL url = null;
try {
- cs = exportMBeanServer(mbs, port, useSsl, useRegistrySsl,
+ final JMXConnectorServerData data = exportMBeanServer(
+ mbs, port, useSsl, useRegistrySsl,
sslConfigFileName, enabledCipherSuitesList,
enabledProtocolsList, sslNeedClientAuth,
useAuthentication, loginConfigName,
passwordFileName, accessFileName);
-
- final JMXServiceURL url = cs.getAddress();
+ cs = data.jmxConnectorServer;
+ url = data.jmxRemoteURL;
log.config("initialize",
Agent.getText("jmxremote.ConnectorBootstrap.initialize.ready",
- new JMXServiceURL(url.getProtocol(),
- url.getHost(),
- url.getPort(),
- "/jndi/rmi://"+url.getHost()+":"+port+"/"+
- "jmxrmi").toString()));
+ url.toString()));
} catch (Exception e) {
throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
}
+ try {
+ // Export remote connector address and associated configuration
+ // properties to the instrumentation buffer.
+ Map<String, String> properties = new HashMap<String, String>();
+ properties.put("remoteAddress", url.toString());
+ properties.put("authenticate", useAuthenticationStr);
+ properties.put("ssl", useSslStr);
+ properties.put("sslRegistry", useRegistrySslStr);
+ properties.put("sslNeedClientAuth", sslNeedClientAuthStr);
+ ConnectorAddressLink.exportRemote(properties);
+ } catch (Exception e) {
+ // Remote connector server started but unable to export remote
+ // connector address and associated configuration properties to
+ // the instrumentation buffer - non-fatal error.
+ log.debug("initialize", e);
+ }
return cs;
}
@@ -452,7 +487,7 @@
}
private static void checkPasswordFile(String passwordFileName) {
- if (passwordFileName == null || passwordFileName.length()==0) {
+ if (passwordFileName == null || passwordFileName.length() == 0) {
throw new AgentConfigurationError(PASSWORD_FILE_NOT_SET);
}
File file = new File(passwordFileName);
@@ -468,9 +503,9 @@
try {
if (fs.supportsFileSecurity(file)) {
if (!fs.isAccessUserOnly(file)) {
- final String msg=Agent.getText("jmxremote.ConnectorBootstrap.initialize.password.readonly",
+ final String msg = Agent.getText("jmxremote.ConnectorBootstrap.initialize.password.readonly",
passwordFileName);
- log.config("initialize",msg);
+ log.config("initialize", msg);
throw new AgentConfigurationError(PASSWORD_FILE_ACCESS_NOT_RESTRICTED,
passwordFileName);
}
@@ -482,7 +517,7 @@
}
private static void checkAccessFile(String accessFileName) {
- if (accessFileName == null || accessFileName.length()==0) {
+ if (accessFileName == null || accessFileName.length() == 0) {
throw new AgentConfigurationError(ACCESS_FILE_NOT_SET);
}
File file = new File(accessFileName);
@@ -619,7 +654,7 @@
}
}
- private static JMXConnectorServer exportMBeanServer(
+ private static JMXConnectorServerData exportMBeanServer(
MBeanServer mbs,
int port,
boolean useSsl,
@@ -697,24 +732,30 @@
}
final Registry registry;
- if (useRegistrySsl)
+ if (useRegistrySsl) {
registry =
new SingleEntryRegistry(port, csf, ssf,
"jmxrmi", exporter.firstExported);
- else
+ } else {
registry =
new SingleEntryRegistry(port,
"jmxrmi", exporter.firstExported);
+ }
+
+ JMXServiceURL remoteURL = new JMXServiceURL(
+ "service:jmx:rmi:///jndi/rmi://" + url.getHost() + ":" +
+ ((UnicastRef) ((RemoteObject) registry).getRef()).getLiveRef().getPort() +
+ "/jmxrmi");
/* Our exporter remembers the first object it was asked to
- export, which will be an RMIServerImpl appropriate for
- publication in our special registry. We could
- alternatively have constructed the RMIServerImpl explicitly
- and then constructed an RMIConnectorServer passing it as a
- parameter, but that's quite a bit more verbose and pulls in
- lots of knowledge of the RMI connector. */
+ export, which will be an RMIServerImpl appropriate for
+ publication in our special registry. We could
+ alternatively have constructed the RMIServerImpl explicitly
+ and then constructed an RMIConnectorServer passing it as a
+ parameter, but that's quite a bit more verbose and pulls in
+ lots of knowledge of the RMI connector. */
- return connServer;
+ return new JMXConnectorServerData(connServer, remoteURL);
}
/**
@@ -726,5 +767,4 @@
// XXX Revisit: should probably clone this MibLogger....
private static final MibLogger log =
new MibLogger(ConnectorBootstrap.class);
-
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/management/jmxremote/bootstrap/JvmstatCountersTest.java Mon Mar 10 23:13:31 2008 +0100
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4981215
+ * @summary Tests that the jvmstat counters published by the out-of-the-box
+ * management agent for the JMX connection details are correct.
+ * @author Luis-Miguel Alventosa
+ * @run clean JvmstatCountersTest
+ * @run build JvmstatCountersTest
+ * @run main/othervm JvmstatCountersTest 1
+ * @run main/othervm -Dcom.sun.management.jmxremote JvmstatCountersTest 2
+ * @run main/othervm -Dcom.sun.management.jmxremote.port=0 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false JvmstatCountersTest 3
+ * @run main/othervm JvmstatCountersTest 4
+ */
+
+import java.io.*;
+import java.lang.management.*;
+import java.util.*;
+import javax.management.*;
+import javax.management.remote.*;
+import com.sun.tools.attach.*;
+import sun.management.ConnectorAddressLink;
+
+public class JvmstatCountersTest {
+
+ public static void checkAddress(String address) throws IOException {
+ System.out.println("Address = " + address);
+ JMXServiceURL url = new JMXServiceURL(address);
+ JMXConnector jmxc = JMXConnectorFactory.connect(url);
+ MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
+ System.out.println("MBean Count = " + mbsc.getMBeanCount());
+ }
+
+ public static void checkKey(Map<String, String> data, int index,
+ String key, String expectedValue) throws Exception {
+ String counter = "sun.management.JMXConnectorServer." + index + "." + key;
+ if (!data.containsKey(counter)) {
+ System.out.println("Test FAILED! Missing counter " + counter);
+ throw new IllegalArgumentException("Test case failed");
+ }
+ String value = data.get(counter);
+ if (key.equals("remoteAddress")) {
+ checkAddress(value);
+ } else if (!expectedValue.equals(value)) {
+ System.out.println("Test FAILED! Invalid counter " +
+ counter + "=" + value);
+ throw new IllegalArgumentException("Test case failed");
+ }
+ System.out.println("OK: " + counter + "=" + value);
+ }
+
+ public static void main(String args[]) throws Exception {
+ String localAddress = ConnectorAddressLink.importFrom(0);
+ Map<String, String> remoteData = ConnectorAddressLink.importRemoteFrom(0);
+ final int testCase = Integer.parseInt(args[0]);
+ switch (testCase) {
+ case 1:
+ if (localAddress == null && remoteData.isEmpty()) {
+ System.out.println("Test PASSED! The OOTB management " +
+ "agent didn't publish any jvmstat counter.");
+ } else {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent unexpectedly published jvmstat counters.");
+ throw new IllegalArgumentException("Test case 1 failed");
+ }
+ break;
+ case 2:
+ if (localAddress == null) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent didn't publish the local connector.");
+ throw new IllegalArgumentException("Test case 2 failed");
+ }
+ checkAddress(localAddress);
+ if (!remoteData.isEmpty()) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent shouldn't publish the remote connector.");
+ throw new IllegalArgumentException("Test case 2 failed");
+ }
+ System.out.println("Test PASSED! The OOTB management " +
+ "agent only publishes the local connector through " +
+ "a jvmstat counter.");
+ break;
+ case 3:
+ if (localAddress == null) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent didn't publish the local connector.");
+ throw new IllegalArgumentException("Test case 3 failed");
+ }
+ checkAddress(localAddress);
+ if (remoteData.isEmpty()) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent didnn't publish the remote connector.");
+ throw new IllegalArgumentException("Test case 3 failed");
+ }
+ for (String key : remoteData.keySet()) {
+ if (!key.startsWith("sun.management.JMXConnectorServer.0.")) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent shouldn't publish anything which isn't " +
+ "related to the remote connector.");
+ throw new IllegalArgumentException("Test case 3 failed");
+ }
+ }
+ checkKey(remoteData, 0, "remoteAddress", null);
+ checkKey(remoteData, 0, "authenticate", "false");
+ checkKey(remoteData, 0, "ssl", "false");
+ checkKey(remoteData, 0, "sslRegistry", "false");
+ checkKey(remoteData, 0, "sslNeedClientAuth", "false");
+ System.out.println("Test PASSED! The OOTB management " +
+ "agent publishes both the local and remote " +
+ "connector info through jvmstat counters.");
+ break;
+ case 4:
+ if (localAddress != null || !remoteData.isEmpty()) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent unexpectedly published jvmstat counters.");
+ throw new IllegalArgumentException("Test case 4 failed");
+ }
+ RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
+ String name = rt.getName();
+ System.out.println("name = " + name);
+ String vmid = name.substring(0, name.indexOf("@"));
+ System.out.println("vmid = " + vmid);
+ VirtualMachine vm = VirtualMachine.attach(vmid);
+ String agent = vm.getSystemProperties().getProperty("java.home") +
+ File.separator + "lib" + File.separator + "management-agent.jar";
+ vm.loadAgent(agent, "com.sun.management.jmxremote.port=0,com.sun.management.jmxremote.authenticate=false,com.sun.management.jmxremote.ssl=false");
+ vm.detach();
+ String localAddress2 = ConnectorAddressLink.importFrom(0);
+ if (localAddress2 == null) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent didn't publish the local connector.");
+ throw new IllegalArgumentException("Test case 4 failed");
+ }
+ checkAddress(localAddress2);
+ Map<String, String> remoteData2 = ConnectorAddressLink.importRemoteFrom(0);
+ if (remoteData2.isEmpty()) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent didnn't publish the remote connector.");
+ throw new IllegalArgumentException("Test case 4 failed");
+ }
+ for (String key : remoteData2.keySet()) {
+ if (!key.startsWith("sun.management.JMXConnectorServer.0.")) {
+ System.out.println("Test FAILED! The OOTB management " +
+ "agent shouldn't publish anything which isn't " +
+ "related to the remote connector.");
+ throw new IllegalArgumentException("Test case 4 failed");
+ }
+ }
+ checkKey(remoteData2, 0, "remoteAddress", null);
+ checkKey(remoteData2, 0, "authenticate", "false");
+ checkKey(remoteData2, 0, "ssl", "false");
+ checkKey(remoteData2, 0, "sslRegistry", "false");
+ checkKey(remoteData2, 0, "sslNeedClientAuth", "false");
+ System.out.println("Test PASSED! The OOTB management agent " +
+ "publishes both the local and remote connector " +
+ "info through jvmstat counters when the agent is " +
+ "loaded through the Attach API.");
+ }
+ System.out.println("Bye! Bye!");
+ }
+}