Merge
authorjprovino
Fri, 01 Jan 2016 17:08:24 +0000 (2016-01-01)
changeset 35266 e18371fa3e76
parent 35250 abe1866e51e3 (current diff)
parent 35265 87b434f45259 (diff)
child 35267 8f0a2a0b4d96
Merge
jdk/make/lib/LibCommon.gmk
--- a/jdk/make/gensrc/Gensrc-jdk.jdi.gmk	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/make/gensrc/Gensrc-jdk.jdi.gmk	Fri Jan 01 17:08:24 2016 +0000
@@ -70,7 +70,7 @@
 # Filter com.sun.jdi.connect.Connector
 $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector: \
     $(JDK_TOPDIR)/src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.Connector \
-    $(HOTSPOT_TOPDIR)/agent/src/share/classes/META-INF/services/com.sun.jdi.connect.Connector
+    $(HOTSPOT_TOPDIR)/src/jdk.hotspot.agent/share/classes/META-INF/services/com.sun.jdi.connect.Connector
 	$(process-provider)
 
 # Copy the same service file into jdk.hotspot.agent so that they are kept the same.
--- a/jdk/make/lib/CoreLibraries.gmk	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/make/lib/CoreLibraries.gmk	Fri Jan 01 17:08:24 2016 +0000
@@ -25,6 +25,10 @@
 
 WIN_VERIFY_LIB := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libverify/verify.lib
 
+# Hook to include the corresponding custom file, if present.
+$(eval $(call IncludeCustomExtension, jdk, lib/CoreLibraries.gmk))
+
+
 ##########################################################################################
 # libfdlibm is statically linked with libjava below and not delivered into the
 # product on its own.
@@ -119,6 +123,9 @@
     -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
     -DARCHPROPNAME='"$(OPENJDK_TARGET_CPU_OSARCH)"'
 
+# Make it possible to override this variable
+LIBJAVA_MAPFILE ?= $(JDK_TOPDIR)/make/mapfiles/libjava/mapfile-vers
+
 ifeq ($(OPENJDK_TARGET_OS), macosx)
   BUILD_LIBJAVA_java_props_md.c_CFLAGS := -x objective-c
   BUILD_LIBJAVA_java_props_macosx.c_CFLAGS := -x objective-c
@@ -146,7 +153,7 @@
     System.c_CFLAGS := $(VERSION_CFLAGS), \
     jdk_util.c_CFLAGS := $(VERSION_CFLAGS), \
     DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
-    MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjava/mapfile-vers, \
+    MAPFILE := $(LIBJAVA_MAPFILE), \
     LDFLAGS := $(LDFLAGS_JDKLIB) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LDFLAGS_macosx := -L$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/, \
--- a/jdk/make/lib/LibCommon.gmk	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/make/lib/LibCommon.gmk	Fri Jan 01 17:08:24 2016 +0000
@@ -27,6 +27,11 @@
 include MakeBase.gmk
 include NativeCompilation.gmk
 
+# Hook to include the corresponding custom file, if present.
+$(eval $(call IncludeCustomExtension, jdk, lib/LibCommon.gmk))
+
+################################################################################
+
 GLOBAL_VERSION_INFO_RESOURCE := $(JDK_TOPDIR)/src/java.base/windows/native/common/version.rc
 
 # Absolute paths to lib files on windows for use in LDFLAGS. Should figure out a more
@@ -56,7 +61,7 @@
 # Find the default set of src dirs for a native library.
 # Param 1 - module name
 # Param 2 - library name
-FindSrcDirsForLib = \
+FindSrcDirsForLib += \
   $(call uniq, $(wildcard \
       $(JDK_TOPDIR)/src/$(strip $1)/$(OPENJDK_TARGET_OS)/native/lib$(strip $2) \
       $(JDK_TOPDIR)/src/$(strip $1)/$(OPENJDK_TARGET_OS_TYPE)/native/lib$(strip $2) \
--- a/jdk/src/java.base/share/classes/java/lang/ref/PhantomReference.java	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/ref/PhantomReference.java	Fri Jan 01 17:08:24 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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
@@ -29,23 +29,20 @@
 /**
  * Phantom reference objects, which are enqueued after the collector
  * determines that their referents may otherwise be reclaimed.  Phantom
- * references are most often used for scheduling pre-mortem cleanup actions in
- * a more flexible way than is possible with the Java finalization mechanism.
+ * references are most often used to schedule post-mortem cleanup actions.
  *
- * <p> If the garbage collector determines at a certain point in time that the
- * referent of a phantom reference is <a
- * href="package-summary.html#reachability">phantom reachable</a>, then at that
- * time or at some later time it will enqueue the reference.
+ * <p> Suppose the garbage collector determines at a certain point in time
+ * that an object is <a href="package-summary.html#reachability">
+ * phantom reachable</a>.  At that time it will atomically clear
+ * all phantom references to that object and all phantom references to
+ * any other phantom-reachable objects from which that object is reachable.
+ * At the same time or at some later time it will enqueue those newly-cleared
+ * phantom references that are registered with reference queues.
  *
  * <p> In order to ensure that a reclaimable object remains so, the referent of
  * a phantom reference may not be retrieved: The {@code get} method of a
  * phantom reference always returns {@code null}.
  *
- * <p> Unlike soft and weak references, phantom references are not
- * automatically cleared by the garbage collector as they are enqueued.  An
- * object that is reachable via phantom references will remain so until all
- * such references are cleared or themselves become unreachable.
- *
  * @author   Mark Reinhold
  * @since    1.2
  */
@@ -69,8 +66,8 @@
      *
      * <p> It is possible to create a phantom reference with a {@code null}
      * queue, but such a reference is completely useless: Its {@code get}
-     * method will always return null and, since it does not have a queue, it
-     * will never be enqueued.
+     * method will always return {@code null} and, since it does not have a queue,
+     * it will never be enqueued.
      *
      * @param referent the object the new phantom reference will refer to
      * @param q the queue with which the reference is to be registered,
--- a/jdk/src/java.base/share/classes/java/lang/ref/package-info.java	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/ref/package-info.java	Fri Jan 01 17:08:24 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. 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
@@ -43,8 +43,7 @@
  * implementing memory-sensitive caches, weak references are for
  * implementing canonicalizing mappings that do not prevent their keys
  * (or values) from being reclaimed, and phantom references are for
- * scheduling pre-mortem cleanup actions in a more flexible way than
- * is possible with the Java finalization mechanism.
+ * scheduling post-mortem cleanup actions.
  *
  * <p> Each reference-object type is implemented by a subclass of the
  * abstract base {@link java.lang.ref.Reference} class.
@@ -64,9 +63,9 @@
  * object with a <em>reference queue</em> at the time the reference
  * object is created.  Some time after the garbage collector
  * determines that the reachability of the referent has changed to the
- * value corresponding to the type of the reference, it will add the
- * reference to the associated queue.  At this point, the reference is
- * considered to be <em>enqueued</em>.  The program may remove
+ * value corresponding to the type of the reference, it will clear the
+ * reference and add it to the associated queue.  At this point, the
+ * reference is considered to be <em>enqueued</em>.  The program may remove
  * references from a queue either by polling or by blocking until a
  * reference becomes available.  Reference queues are implemented by
  * the {@link java.lang.ref.ReferenceQueue} class.
@@ -92,16 +91,6 @@
  * structure, this check will add little overhead to the hashtable
  * access methods.
  *
- * <h3>Automatically-cleared references</h3>
- *
- * Soft and weak references are automatically cleared by the collector
- * before being added to the queues with which they are registered, if
- * any.  Therefore soft and weak references need not be registered
- * with a queue in order to be useful, while phantom references do.
- * An object that is reachable via phantom references will remain so
- * until all such references are cleared or themselves become
- * unreachable.
- *
  * <a name="reachability"></a>
  * <h3>Reachability</h3>
  *
--- a/jdk/src/java.base/share/native/include/jvm.h	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/src/java.base/share/native/include/jvm.h	Fri Jan 01 17:08:24 2016 +0000
@@ -208,6 +208,9 @@
 JNIEXPORT void JNICALL
 JVM_SetMethodInfo(JNIEnv* env, jobject frame);
 
+JNIEXPORT jobjectArray JNICALL
+JVM_GetVmArguments(JNIEnv *env);
+
 /*
  * java.lang.Thread
  */
--- a/jdk/src/java.base/share/native/libjava/jni_util.c	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/src/java.base/share/native/libjava/jni_util.c	Fri Jan 01 17:08:24 2016 +0000
@@ -660,7 +660,8 @@
             */
                     if ((strcmp(encname, "8859_1") == 0) ||
                         (strcmp(encname, "ISO8859-1") == 0) ||
-                        (strcmp(encname, "ISO8859_1") == 0))
+                        (strcmp(encname, "ISO8859_1") == 0) ||
+                        (strcmp(encname, "ISO-8859-1") == 0))
                         fastEncoding = FAST_8859_1;
                     else if (strcmp(encname, "ISO646-US") == 0)
                         fastEncoding = FAST_646_US;
--- a/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java	Fri Jan 01 17:08:24 2016 +0000
@@ -30,9 +30,12 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.Serializable;
 import java.lang.management.ManagementFactory;
 import java.net.InetAddress;
 import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.ServerSocket;
 import java.net.UnknownHostException;
 import java.rmi.NoSuchObjectException;
 import java.rmi.Remote;
@@ -40,6 +43,7 @@
 import java.rmi.registry.Registry;
 import java.rmi.server.RMIClientSocketFactory;
 import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RMISocketFactory;
 import java.rmi.server.RemoteObject;
 import java.rmi.server.UnicastRemoteObject;
 import java.security.KeyStore;
@@ -60,6 +64,8 @@
 import javax.management.remote.rmi.RMIConnectorServer;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManagerFactory;
 import javax.rmi.ssl.SslRMIClientSocketFactory;
 import javax.rmi.ssl.SslRMIServerSocketFactory;
@@ -107,6 +113,8 @@
 
         public static final String PORT =
                 "com.sun.management.jmxremote.port";
+        public static final String HOST =
+                "com.sun.management.jmxremote.host";
         public static final String RMI_PORT =
                 "com.sun.management.jmxremote.rmi.port";
         public static final String CONFIG_FILE_NAME =
@@ -424,10 +432,14 @@
             checkAccessFile(accessFileName);
         }
 
+        final String bindAddress =
+                props.getProperty(PropertyNames.HOST);
+
         if (log.debugOn()) {
             log.debug("startRemoteConnectorServer",
                     Agent.getText("jmxremote.ConnectorBootstrap.starting") +
                     "\n\t" + PropertyNames.PORT + "=" + port +
+                    (bindAddress == null ? "" : "\n\t" + PropertyNames.HOST + "=" + bindAddress) +
                     "\n\t" + PropertyNames.RMI_PORT + "=" + rmiPort +
                     "\n\t" + PropertyNames.USE_SSL + "=" + useSsl +
                     "\n\t" + PropertyNames.USE_REGISTRY_SSL + "=" + useRegistrySsl +
@@ -458,7 +470,7 @@
                     sslConfigFileName, enabledCipherSuitesList,
                     enabledProtocolsList, sslNeedClientAuth,
                     useAuthentication, loginConfigName,
-                    passwordFileName, accessFileName);
+                    passwordFileName, accessFileName, bindAddress);
             cs = data.jmxConnectorServer;
             url = data.jmxRemoteURL;
             log.config("startRemoteConnectorServer",
@@ -628,12 +640,13 @@
             String sslConfigFileName,
             String[] enabledCipherSuites,
             String[] enabledProtocols,
-            boolean sslNeedClientAuth) {
+            boolean sslNeedClientAuth,
+            String bindAddress) {
         if (sslConfigFileName == null) {
-            return new SslRMIServerSocketFactory(
+            return new HostAwareSslSocketFactory(
                     enabledCipherSuites,
                     enabledProtocols,
-                    sslNeedClientAuth);
+                    sslNeedClientAuth, bindAddress);
         } else {
             checkRestrictedFile(sslConfigFileName);
             try {
@@ -687,11 +700,11 @@
                 SSLContext ctx = SSLContext.getInstance("SSL");
                 ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 
-                return new SslRMIServerSocketFactory(
+                return new HostAwareSslSocketFactory(
                         ctx,
                         enabledCipherSuites,
                         enabledProtocols,
-                        sslNeedClientAuth);
+                        sslNeedClientAuth, bindAddress);
             } catch (Exception e) {
                 throw new AgentConfigurationError(AGENT_EXCEPTION, e, e.toString());
             }
@@ -711,7 +724,8 @@
             boolean useAuthentication,
             String loginConfigName,
             String passwordFileName,
-            String accessFileName)
+            String accessFileName,
+            String bindAddress)
             throws IOException, MalformedURLException {
 
         /* Make sure we use non-guessable RMI object IDs.  Otherwise
@@ -719,7 +733,7 @@
          * IDs.  */
         System.setProperty("java.rmi.server.randomIDs", "true");
 
-        JMXServiceURL url = new JMXServiceURL("rmi", null, rmiPort);
+        JMXServiceURL url = new JMXServiceURL("rmi", bindAddress, rmiPort);
 
         Map<String, Object> env = new HashMap<>();
 
@@ -727,6 +741,8 @@
 
         env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
 
+        boolean useSocketFactory = bindAddress != null && !useSsl;
+
         if (useAuthentication) {
             if (loginConfigName != null) {
                 env.put("jmx.remote.x.login.config", loginConfigName);
@@ -751,7 +767,7 @@
             csf = new SslRMIClientSocketFactory();
             ssf = createSslRMIServerSocketFactory(
                     sslConfigFileName, enabledCipherSuites,
-                    enabledProtocols, sslNeedClientAuth);
+                    enabledProtocols, sslNeedClientAuth, bindAddress);
         }
 
         if (useSsl) {
@@ -761,6 +777,12 @@
                     ssf);
         }
 
+        if (useSocketFactory) {
+            ssf = new HostAwareSocketFactory(bindAddress);
+            env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE,
+                    ssf);
+        }
+
         JMXConnectorServer connServer = null;
         try {
             connServer =
@@ -780,6 +802,10 @@
             registry =
                     new SingleEntryRegistry(port, csf, ssf,
                     "jmxrmi", exporter.firstExported);
+        } else if (useSocketFactory) {
+            registry =
+                    new SingleEntryRegistry(port, csf, ssf,
+                    "jmxrmi", exporter.firstExported);
         } else {
             registry =
                     new SingleEntryRegistry(port,
@@ -813,4 +839,172 @@
     private static final ClassLogger log =
         new ClassLogger(ConnectorBootstrap.class.getPackage().getName(),
                         "ConnectorBootstrap");
+
+    private static class HostAwareSocketFactory implements RMIServerSocketFactory {
+
+        private final String bindAddress;
+
+        private HostAwareSocketFactory(String bindAddress) {
+             this.bindAddress = bindAddress;
+        }
+
+        @Override
+        public ServerSocket createServerSocket(int port) throws IOException {
+            if (bindAddress == null) {
+                return new ServerSocket(port);
+            } else {
+                try {
+                    InetAddress addr = InetAddress.getByName(bindAddress);
+                    return new ServerSocket(port, 0, addr);
+                } catch (UnknownHostException e) {
+                    return new ServerSocket(port);
+                }
+            }
+        }
+    }
+
+    private static class HostAwareSslSocketFactory extends SslRMIServerSocketFactory {
+
+        private final String bindAddress;
+        private final String[] enabledCipherSuites;
+        private final String[] enabledProtocols;
+        private final boolean needClientAuth;
+        private final SSLContext context;
+
+        private HostAwareSslSocketFactory(String[] enabledCipherSuites,
+                                          String[] enabledProtocols,
+                                          boolean sslNeedClientAuth,
+                                          String bindAddress) throws IllegalArgumentException {
+            this(null, enabledCipherSuites, enabledProtocols, sslNeedClientAuth, bindAddress);
+        }
+
+        private HostAwareSslSocketFactory(SSLContext ctx,
+                                          String[] enabledCipherSuites,
+                                          String[] enabledProtocols,
+                                          boolean sslNeedClientAuth,
+                                          String bindAddress) throws IllegalArgumentException {
+            this.context = ctx;
+            this.bindAddress = bindAddress;
+            this.enabledProtocols = enabledProtocols;
+            this.enabledCipherSuites = enabledCipherSuites;
+            this.needClientAuth = sslNeedClientAuth;
+            checkValues(ctx, enabledCipherSuites, enabledProtocols);
+        }
+
+        @Override
+        public ServerSocket createServerSocket(int port) throws IOException {
+            if (bindAddress != null) {
+                try {
+                    InetAddress addr = InetAddress.getByName(bindAddress);
+                    return new SslServerSocket(port, 0, addr, context,
+                                               enabledCipherSuites, enabledProtocols, needClientAuth);
+                } catch (UnknownHostException e) {
+                    return new SslServerSocket(port, context,
+                                               enabledCipherSuites, enabledProtocols, needClientAuth);
+                }
+            } else {
+                return new SslServerSocket(port, context,
+                                           enabledCipherSuites, enabledProtocols, needClientAuth);
+            }
+        }
+
+        private static void checkValues(SSLContext context,
+                                        String[] enabledCipherSuites,
+                                        String[] enabledProtocols) throws IllegalArgumentException {
+            // Force the initialization of the default at construction time,
+            // rather than delaying it to the first time createServerSocket()
+            // is called.
+            //
+            final SSLSocketFactory sslSocketFactory =
+                    context == null ?
+                        (SSLSocketFactory)SSLSocketFactory.getDefault() : context.getSocketFactory();
+            SSLSocket sslSocket = null;
+            if (enabledCipherSuites != null || enabledProtocols != null) {
+                try {
+                    sslSocket = (SSLSocket) sslSocketFactory.createSocket();
+                } catch (Exception e) {
+                    final String msg = "Unable to check if the cipher suites " +
+                            "and protocols to enable are supported";
+                    throw (IllegalArgumentException)
+                    new IllegalArgumentException(msg).initCause(e);
+                }
+            }
+
+            // Check if all the cipher suites and protocol versions to enable
+            // are supported by the underlying SSL/TLS implementation and if
+            // true create lists from arrays.
+            //
+            if (enabledCipherSuites != null) {
+                sslSocket.setEnabledCipherSuites(enabledCipherSuites);
+            }
+            if (enabledProtocols != null) {
+                sslSocket.setEnabledProtocols(enabledProtocols);
+            }
+        }
+    }
+
+    private static class SslServerSocket extends ServerSocket {
+
+        private static SSLSocketFactory defaultSSLSocketFactory;
+        private final String[] enabledCipherSuites;
+        private final String[] enabledProtocols;
+        private final boolean needClientAuth;
+        private final SSLContext context;
+
+        private SslServerSocket(int port,
+                                SSLContext ctx,
+                                String[] enabledCipherSuites,
+                                String[] enabledProtocols,
+                                boolean needClientAuth) throws IOException {
+            super(port);
+            this.enabledProtocols = enabledProtocols;
+            this.enabledCipherSuites = enabledCipherSuites;
+            this.needClientAuth = needClientAuth;
+            this.context = ctx;
+        }
+
+        private SslServerSocket(int port,
+                                int backlog,
+                                InetAddress bindAddr,
+                                SSLContext ctx,
+                                String[] enabledCipherSuites,
+                                String[] enabledProtocols,
+                                boolean needClientAuth) throws IOException {
+            super(port, backlog, bindAddr);
+            this.enabledProtocols = enabledProtocols;
+            this.enabledCipherSuites = enabledCipherSuites;
+            this.needClientAuth = needClientAuth;
+            this.context = ctx;
+        }
+
+        @Override
+        public Socket accept() throws IOException {
+            final SSLSocketFactory sslSocketFactory =
+                    context == null ?
+                        getDefaultSSLSocketFactory() : context.getSocketFactory();
+            Socket socket = super.accept();
+            SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
+                    socket, socket.getInetAddress().getHostName(),
+                    socket.getPort(), true);
+            sslSocket.setUseClientMode(false);
+            if (enabledCipherSuites != null) {
+                sslSocket.setEnabledCipherSuites(enabledCipherSuites);
+            }
+            if (enabledProtocols != null) {
+                sslSocket.setEnabledProtocols(enabledProtocols);
+            }
+            sslSocket.setNeedClientAuth(needClientAuth);
+            return sslSocket;
+        }
+
+        private static synchronized SSLSocketFactory getDefaultSSLSocketFactory() {
+            if (defaultSSLSocketFactory == null) {
+                defaultSSLSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
+                return defaultSSLSocketFactory;
+            } else {
+                return defaultSSLSocketFactory;
+            }
+        }
+
+    }
 }
--- a/jdk/src/java.management/share/conf/management.properties	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/src/java.management/share/conf/management.properties	Fri Jan 01 17:08:24 2016 +0000
@@ -316,3 +316,16 @@
 
 # For a non-default password file location use the following line
 # com.sun.management.jmxremote.access.file=filepath
+#
+
+# ################ Management agent listen interface #########################
+#
+# com.sun.management.jmxremote.host=<host-or-interface-name>
+#      Specifies the local interface on which the JMX RMI agent will bind.
+#      This is useful when running on machines which have several
+#      interfaces defined. It makes it possible to listen to a specific
+#      subnet accessible through that interface.
+#
+#      The format of the value for that property is any string accepted
+#      by java.net.InetAddress.getByName(String).
+#
--- a/jdk/src/java.management/share/native/include/jmm.h	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/src/java.management/share/native/include/jmm.h	Fri Jan 01 17:08:24 2016 +0000
@@ -227,16 +227,10 @@
   jint         (JNICALL *GetOptionalSupport)     (JNIEnv *env,
                                                   jmmOptionalSupport* support_ptr);
 
-  /* This is used by JDK 6 and earlier.
-   * For JDK 7 and after, use GetInputArgumentArray.
-   */
-  jobject      (JNICALL *GetInputArguments)      (JNIEnv *env);
-
   jint         (JNICALL *GetThreadInfo)          (JNIEnv *env,
                                                   jlongArray ids,
                                                   jint maxDepth,
                                                   jobjectArray infoArray);
-  jobjectArray (JNICALL *GetInputArgumentArray)  (JNIEnv *env);
 
   jobjectArray (JNICALL *GetMemoryPools)         (JNIEnv* env, jobject mgr);
 
--- a/jdk/src/java.management/share/native/libmanagement/VMManagementImpl.c	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/src/java.management/share/native/libmanagement/VMManagementImpl.c	Fri Jan 01 17:08:24 2016 +0000
@@ -112,7 +112,7 @@
 Java_sun_management_VMManagementImpl_getVmArguments0
   (JNIEnv *env, jobject dummy)
 {
-    return jmm_interface->GetInputArgumentArray(env);
+    return JVM_GetVmArguments(env);
 }
 
 JNIEXPORT jlong JNICALL
--- a/jdk/test/com/sun/jdi/BreakpointWithFullGC.sh	Fri Dec 18 09:37:18 2015 -0800
+++ b/jdk/test/com/sun/jdi/BreakpointWithFullGC.sh	Fri Jan 01 17:08:24 2016 +0000
@@ -121,7 +121,8 @@
 jdbFailIfNotPresent 'System\..*end of test'
 
 # make sure we had at least one full GC
-debuggeeFailIfNotPresent 'Full GC'
+# Prior to JDK9-B95, the pattern was 'Full GC'
+debuggeeMatchRegexp '^.*?\bPause Full\b\(System.gc\(\)\)\b.*?$'
 
 # check for error message due to thread ID change
 debuggeeFailIfPresent \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ref/PhantomReferentClearing.java	Fri Jan 01 17:08:24 2016 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8071507
+ * @summary Test that PhantomReferences are cleared when notified.
+ * @run main/othervm PhantomReferentClearing
+ */
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PhantomReferentClearing {
+
+    private static final long ENQUEUE_TIMEOUT = 1000;   // 1 sec, in millis
+
+    // P1 & P2 are PhantomReference objects
+    // O1 & O2 are objects
+    //
+    // -> is a strong reference
+    // => is a referent reference
+    //
+    //   root -> P1
+    //   root -> P2
+    //   root -> O1
+    //   root -> O2
+    //   O1 -> O2
+    //   P1 => O1
+    //   P2 => O2
+    //
+    // (1) Remove root -> O1 and collect.  P1 notified, P2 !notified.
+    // (2) Remove root -> O2 and collect.
+    //
+    // If phantom references are cleared when notified, as proposed by
+    // 8071507, then P2 should be notified, and the test passes.
+    //
+    // Otherwise, P2 does not get notified because it remains reachable
+    // from O1, which is being retained by P1.  This fails the test.
+
+    private static final ReferenceQueue<Object> Q1 = new ReferenceQueue<>();
+    private static final ReferenceQueue<Object> Q2 = new ReferenceQueue<>();
+
+    private static volatile Object O2 = new Object();
+    private static volatile List<Object> O1 = new ArrayList<>();
+    static {
+        O1.add(O2);
+    }
+
+    private static final PhantomReference<Object> P1 = new PhantomReference<>(O1, Q1);
+    private static final PhantomReference<Object> P2 = new PhantomReference<>(O2, Q2);
+
+    public static void main(String[] args) throws InterruptedException {
+
+        // Collect, and verify neither P1 or P2 notified.
+        System.gc();
+        if (Q1.remove(ENQUEUE_TIMEOUT) != null) {
+            throw new RuntimeException("P1 already notified");
+        } else if (Q2.poll() != null) {
+            throw new RuntimeException("P2 already notified");
+        }
+
+        // Delete root -> O1, collect, verify P1 notified, P2 not notified.
+        O1 = null;
+        System.gc();
+        if (Q1.remove(ENQUEUE_TIMEOUT) == null) {
+            throw new RuntimeException("P1 not notified by O1 deletion");
+        } else if (Q2.remove(ENQUEUE_TIMEOUT) != null) {
+            throw new RuntimeException("P2 notified by O1 deletion.");
+        }
+
+        // Delete root -> O2, collect. P2 should be notified.
+        O2 = null;
+        System.gc();
+        if (Q2.remove(ENQUEUE_TIMEOUT) == null) {
+            throw new RuntimeException("P2 not notified by O2 deletion");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/management/jmxremote/bootstrap/JMXAgentInterfaceBinding.java	Fri Jan 01 17:08:24 2016 +0000
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2015, Red Hat Inc
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+
+/**
+ * Tests client connections to the JDK's built-in JMX agent server on the given
+ * ports/interface combinations.
+ *
+ * @see JMXInterfaceBindingTest
+ *
+ * @author Severin Gehwolf <sgehwolf@redhat.com>
+ *
+ * Usage:
+ *
+ * SSL:
+ *        java -Dcom.sun.management.jmxremote.ssl.need.client.auth=true \
+ *             -Dcom.sun.management.jmxremote.host=127.0.0.1 \
+ *             -Dcom.sun.management.jmxremote.port=9111 \
+ *             -Dcom.sun.management.jmxremote.rmi.port=9112 \
+ *             -Dcom.sun.management.jmxremote.authenticate=false \
+ *             -Dcom.sun.management.jmxremote.ssl=true \
+ *             -Dcom.sun.management.jmxremote.registry.ssl=true
+ *             -Djavax.net.ssl.keyStore=... \
+ *             -Djavax.net.ssl.keyStorePassword=... \
+ *             JMXAgentInterfaceBinding 127.0.0.1 9111 9112 true
+ *
+ * Non-SSL:
+ *        java -Dcom.sun.management.jmxremote.host=127.0.0.1 \
+ *             -Dcom.sun.management.jmxremote.port=9111 \
+ *             -Dcom.sun.management.jmxremote.rmi.port=9112 \
+ *             -Dcom.sun.management.jmxremote.authenticate=false \
+ *             -Dcom.sun.management.jmxremote.ssl=false \
+ *             JMXAgentInterfaceBinding 127.0.0.1 9111 9112 false
+ *
+ */
+public class JMXAgentInterfaceBinding {
+
+    private final MainThread mainThread;
+
+    public JMXAgentInterfaceBinding(InetAddress bindAddress,
+                                   int jmxPort,
+                                   int rmiPort,
+                                   boolean useSSL) {
+        this.mainThread = new MainThread(bindAddress, jmxPort, rmiPort, useSSL);
+    }
+
+    public void startEndpoint() {
+        mainThread.start();
+        try {
+            mainThread.join();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Test failed", e);
+        }
+        if (mainThread.isFailed()) {
+            mainThread.rethrowException();
+        }
+    }
+
+    public static void main(String[] args) {
+        if (args.length != 4) {
+            throw new RuntimeException(
+                    "Test failed. usage: java JMXInterfaceBindingTest <BIND_ADDRESS> <JMX_PORT> <RMI_PORT> {true|false}");
+        }
+        int jmxPort = parsePortFromString(args[1]);
+        int rmiPort = parsePortFromString(args[2]);
+        boolean useSSL = Boolean.parseBoolean(args[3]);
+        String strBindAddr = args[0];
+        System.out.println(
+                "DEBUG: Running test for triplet (hostname,jmxPort,rmiPort) = ("
+                        + strBindAddr + "," + jmxPort + "," + rmiPort + "), useSSL = " + useSSL);
+        InetAddress bindAddress;
+        try {
+            bindAddress = InetAddress.getByName(args[0]);
+        } catch (UnknownHostException e) {
+            throw new RuntimeException("Test failed. Unknown ip: " + args[0]);
+        }
+        JMXAgentInterfaceBinding test = new JMXAgentInterfaceBinding(bindAddress,
+                jmxPort, rmiPort, useSSL);
+        test.startEndpoint(); // Expect for main test to terminate process
+    }
+
+    private static int parsePortFromString(String port) {
+        try {
+            return Integer.parseInt(port);
+        } catch (NumberFormatException e) {
+            throw new RuntimeException(
+                    "Invalid port specified. Not an integer! Value was: "
+                            + port);
+        }
+    }
+
+    private static class JMXConnectorThread extends Thread {
+
+        private final InetAddress addr;
+        private final int jmxPort;
+        private final int rmiPort;
+        private final boolean useSSL;
+        private final CountDownLatch latch;
+        private boolean failed;
+        private boolean jmxConnectWorked;
+        private boolean rmiConnectWorked;
+
+        private JMXConnectorThread(InetAddress addr,
+                                   int jmxPort,
+                                   int rmiPort,
+                                   boolean useSSL,
+                                   CountDownLatch latch) {
+            this.addr = addr;
+            this.jmxPort = jmxPort;
+            this.rmiPort = rmiPort;
+            this.latch = latch;
+            this.useSSL = useSSL;
+        }
+
+        @Override
+        public void run() {
+            try {
+                connect();
+            } catch (IOException e) {
+                failed = true;
+            }
+        }
+
+        private void connect() throws IOException {
+            System.out.println(
+                    "JMXConnectorThread: Attempting JMX connection on: "
+                            + addr.getHostAddress() + " on port " + jmxPort);
+            JMXServiceURL url;
+            try {
+                url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"
+                        + addr.getHostAddress() + ":" + jmxPort + "/jmxrmi");
+            } catch (MalformedURLException e) {
+                throw new RuntimeException("Test failed.", e);
+            }
+            Map<String, Object> env = new HashMap<>();
+            if (useSSL) {
+                SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
+                env.put("com.sun.jndi.rmi.factory.socket", csf);
+                env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
+            }
+            // connect and immediately close
+            JMXConnector c = JMXConnectorFactory.connect(url, env);
+            c.close();
+            System.out.println("JMXConnectorThread: connection to JMX worked");
+            jmxConnectWorked = true;
+            checkRmiSocket();
+            latch.countDown(); // signal we are done.
+        }
+
+        private void checkRmiSocket() throws IOException {
+            Socket rmiConnection;
+            if (useSSL) {
+                rmiConnection = SSLSocketFactory.getDefault().createSocket();
+            } else {
+                rmiConnection = new Socket();
+            }
+            SocketAddress target = new InetSocketAddress(addr, rmiPort);
+            rmiConnection.connect(target);
+            if (useSSL) {
+                ((SSLSocket)rmiConnection).startHandshake();
+            }
+            System.out.println(
+                    "JMXConnectorThread: connection to rmi socket worked host/port = "
+                            + addr.getHostAddress() + "/" + rmiPort);
+            rmiConnectWorked = true;
+            // Closing the channel without sending any data will cause an
+            // java.io.EOFException on the server endpoint. We don't care about this
+            // though, since we only want to test if we can connect.
+            rmiConnection.close();
+        }
+
+        public boolean isFailed() {
+            return failed;
+        }
+
+        public boolean jmxConnectionWorked() {
+            return jmxConnectWorked;
+        }
+
+        public boolean rmiConnectionWorked() {
+            return rmiConnectWorked;
+        }
+    }
+
+    private static class MainThread extends Thread {
+
+        private static final int WAIT_FOR_JMX_AGENT_TIMEOUT_MS = 500;
+        private final InetAddress bindAddress;
+        private final int jmxPort;
+        private final int rmiPort;
+        private final boolean useSSL;
+        private boolean terminated = false;
+        private boolean jmxAgentStarted = false;
+        private Exception excptn;
+
+        private MainThread(InetAddress bindAddress, int jmxPort, int rmiPort, boolean useSSL) {
+            this.bindAddress = bindAddress;
+            this.jmxPort = jmxPort;
+            this.rmiPort = rmiPort;
+            this.useSSL = useSSL;
+        }
+
+        @Override
+        public void run() {
+            try {
+                waitUntilReadyForConnections();
+                // Do nothing, but wait for termination.
+                try {
+                    while (!terminated) {
+                        Thread.sleep(100);
+                    }
+                } catch (InterruptedException e) { // ignore
+                }
+                System.out.println("MainThread: Thread stopped.");
+            } catch (Exception e) {
+                this.excptn = e;
+            }
+        }
+
+        private void waitUntilReadyForConnections() {
+            CountDownLatch latch = new CountDownLatch(1);
+            JMXConnectorThread connectionTester = new JMXConnectorThread(
+                    bindAddress, jmxPort, rmiPort, useSSL, latch);
+            connectionTester.start();
+            boolean expired = false;
+            try {
+                expired = !latch.await(WAIT_FOR_JMX_AGENT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+                System.out.println(
+                        "MainThread: Finished waiting for JMX agent to become available: expired == "
+                                + expired);
+                jmxAgentStarted = !expired;
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Test failed", e);
+            }
+            if (!jmxAgentStarted) {
+                throw new RuntimeException(
+                        "Test failed. JMX server agents not becoming available.");
+            }
+            if (connectionTester.isFailed()
+                    || !connectionTester.jmxConnectionWorked()
+                    || !connectionTester.rmiConnectionWorked()) {
+                throw new RuntimeException(
+                        "Test failed. JMX agent does not seem ready. See log output for details.");
+            }
+            // The main test expects this exact message being printed
+            System.out.println("MainThread: Ready for connections");
+        }
+
+        private boolean isFailed() {
+            return excptn != null;
+        }
+
+        private void rethrowException() throws RuntimeException {
+            throw new RuntimeException(excptn);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/management/jmxremote/bootstrap/JMXInterfaceBindingTest.java	Fri Jan 01 17:08:24 2016 +0000
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2015, Red Hat Inc
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.testlibrary.ProcessThread;
+import jdk.testlibrary.ProcessTools;
+
+/**
+ * NOTE:
+ *    This test requires at least a setup similar to the following in
+ *    /etc/hosts file (or the windows equivalent). I.e. it expects it to
+ *    be multi-homed and not both being the loop-back interface.
+ *    For example:
+ *    ----->8-------- /etc/hosts ----------->8---
+ *    127.0.0.1   localhost
+ *    192.168.0.1 localhost
+ *    ----->8-------- /etc/hosts ----------->8---
+ *
+ * @test
+ * @bug     6425769
+ * @summary Test JMX agent host address binding. Same ports but different
+ *          interfaces to bind to (using plain sockets and SSL sockets).
+ *
+ * @modules java.management/sun.management
+ *          java.management/sun.management.jmxremote
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.* JMXAgentInterfaceBinding
+ * @run main/timeout=5 JMXInterfaceBindingTest
+ */
+public class JMXInterfaceBindingTest {
+
+    public static final int COMMUNICATION_ERROR_EXIT_VAL = 1;
+    public static final int STOP_PROCESS_EXIT_VAL = 143;
+    public static final int JMX_PORT = 9111;
+    public static final int RMI_PORT = 9112;
+    public static final String READY_MSG = "MainThread: Ready for connections";
+    public static final String TEST_CLASS = JMXAgentInterfaceBinding.class.getSimpleName();
+    public static final String KEYSTORE_LOC = System.getProperty("test.src", ".") +
+                                              File.separator +
+                                              "ssl" +
+                                              File.separator +
+                                              "keystore";
+    public static final String TRUSTSTORE_LOC = System.getProperty("test.src", ".") +
+                                                File.separator +
+                                                "ssl" +
+                                                File.separator +
+                                                "truststore";
+    public static final String TEST_CLASSPATH = System.getProperty("test.classes", ".");
+
+    public void run(InetAddress[] addrs) {
+        System.out.println("DEBUG: Running tests with plain sockets.");
+        runTests(addrs, false);
+        System.out.println("DEBUG: Running tests with SSL sockets.");
+        runTests(addrs, true);
+    }
+
+    private void runTests(InetAddress[] addrs, boolean useSSL) {
+        ProcessThread[] jvms = new ProcessThread[addrs.length];
+        for (int i = 0; i < addrs.length; i++) {
+            System.out.println();
+            String msg = String.format("DEBUG: Launching java tester for triplet (HOSTNAME,JMX_PORT,RMI_PORT) == (%s,%d,%d)",
+                    addrs[i].getHostAddress(),
+                    JMX_PORT,
+                    RMI_PORT);
+            System.out.println(msg);
+            jvms[i] = runJMXBindingTest(addrs[i], useSSL);
+            jvms[i].start();
+            System.out.println("DEBUG: Started " + (i + 1) + " Process(es).");
+        }
+        int failedProcesses = 0;
+        for (ProcessThread pt: jvms) {
+            try {
+                pt.stopProcess();
+                pt.join();
+            } catch (InterruptedException e) {
+                System.err.println("Failed to stop process: " + pt.getName());
+                throw new RuntimeException("Test failed", e);
+            }
+            int exitValue = pt.getOutput().getExitValue();
+            // If there is a communication error (the case we care about)
+            // we get a exit code of 1
+            if (exitValue == COMMUNICATION_ERROR_EXIT_VAL) {
+                // Failure case since the java processes should still be
+                // running.
+                System.err.println("Test FAILURE on " + pt.getName());
+                failedProcesses++;
+            } else if (exitValue == STOP_PROCESS_EXIT_VAL) {
+                System.out.println("DEBUG: OK. Spawned java process terminated with expected exit code of " + STOP_PROCESS_EXIT_VAL);
+            } else {
+                System.err.println("Test FAILURE on " + pt.getName() + " reason: Unexpected exit code => " + exitValue);
+                failedProcesses++;
+            }
+        }
+        if (failedProcesses > 0) {
+            throw new RuntimeException("Test FAILED. " + failedProcesses + " out of " + addrs.length + " process(es) failed to start the JMX agent.");
+        }
+    }
+
+    private ProcessThread runJMXBindingTest(InetAddress a, boolean useSSL) {
+        List<String> args = new ArrayList<>();
+        args.add("-classpath");
+        args.add(TEST_CLASSPATH);
+        args.add("-Dcom.sun.management.jmxremote.host=" + a.getHostAddress());
+        args.add("-Dcom.sun.management.jmxremote.port=" + JMX_PORT);
+        args.add("-Dcom.sun.management.jmxremote.rmi.port=" + RMI_PORT);
+        args.add("-Dcom.sun.management.jmxremote.authenticate=false");
+        args.add("-Dcom.sun.management.jmxremote.ssl=" + Boolean.toString(useSSL));
+        if (useSSL) {
+            args.add("-Dcom.sun.management.jmxremote.registry.ssl=true");
+            args.add("-Djavax.net.ssl.keyStore=" + KEYSTORE_LOC);
+            args.add("-Djavax.net.ssl.trustStore=" + TRUSTSTORE_LOC);
+            args.add("-Djavax.net.ssl.keyStorePassword=password");
+            args.add("-Djavax.net.ssl.trustStorePassword=trustword");
+        }
+        args.add(TEST_CLASS);
+        args.add(a.getHostAddress());
+        args.add(Integer.toString(JMX_PORT));
+        args.add(Integer.toString(RMI_PORT));
+        args.add(Boolean.toString(useSSL));
+        try {
+            ProcessBuilder builder = ProcessTools.createJavaProcessBuilder(args.toArray(new String[] {}));
+            System.out.println(ProcessTools.getCommandLine(builder));
+            ProcessThread jvm = new ProcessThread("JMX-Tester-" + a.getHostAddress(), JMXInterfaceBindingTest::isJMXAgentResponseAvailable, builder);
+            return jvm;
+        } catch (Exception e) {
+            throw new RuntimeException("Test failed", e);
+        }
+
+    }
+
+    private static boolean isJMXAgentResponseAvailable(String line) {
+        if (line.equals(READY_MSG)) {
+            System.out.println("DEBUG: Found expected READY_MSG.");
+            return true;
+        } else if (line.startsWith("Error:")) {
+            // Allow for a JVM process that exits with
+            // "Error: JMX connector server communication error: ..."
+            // to continue as well since we handle that case elsewhere.
+            // This has the effect that the test does not timeout and
+            // fails with an exception in the test.
+            System.err.println("PROBLEM: JMX agent of target JVM did not start as it should.");
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static void main(String[] args) {
+        InetAddress[] addrs = getAddressesForLocalHost();
+        if (addrs.length < 2) {
+            System.out.println("Ignoring manual test since no more than one IPs are configured for 'localhost'");
+            System.exit(0);
+        }
+        JMXInterfaceBindingTest test = new JMXInterfaceBindingTest();
+        test.run(addrs);
+        System.out.println("All tests PASSED.");
+    }
+
+    private static InetAddress[] getAddressesForLocalHost() {
+        InetAddress[] addrs;
+        try {
+            addrs = InetAddress.getAllByName("localhost");
+        } catch (UnknownHostException e) {
+            throw new RuntimeException("Test failed", e);
+        }
+        return addrs;
+    }
+}