简体   繁体   中英

How to use a JMX RMI agent in a WebStart process?

I am trying to implement a monitoring control based on an RMI connector for JMX, for an application launcher via WebStart.

The connectors work fine no matter how I start them when the application is started from the command-line or IDE. However, everything goes south when I try to inspect it when it's been launched by invoking the JNLP file with javaws.

I have tried several approaches:

  • using the built-in JMX features, by specifying the following variables in JAVAWS_VM_ARGS (docs say it should work in 1.6, but people report it doesn't; they don't appear to be set at all in the resulting process, if I inspect it using the Attach API):

     -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=true -Dcom.sun.management.jmxremote.port=SOME_PORT_HERE -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false 
  • using the built-in JMX features, by specifying the following variables in the JNLP file (some say this shouldn't work, and indeed they don't seem to be set when I inspect with the Attach API; the JNLP is set with all-permissions as well):

     <property name="com.sun.management.jmxremote.local.only" value="true" /> <property name="com.sun.management.jmxremote.port" value="SOME_PORT_HERE" /> <property name="com.sun.management.jmxremote.authenticate" value="false" /> <property name="com.sun.management.jmxremote.ssl" value="false" /> 
  • using the built-in JMX features, by specifying the following variables using -J options to the calling javaws program (they don't appear to be set at all in the resulting process, if I inspect it using the Attach API):

     -J-Dcom.sun.management.jmxremote -J-Dcom.sun.management.jmxremote.local.only=true -J-Dcom.sun.management.jmxremote.port=SOME_PORT_HERE -J-Dcom.sun.management.jmxremote.authenticate=false -J-Dcom.sun.management.jmxremote.ssl=false 
  • using a custom JMXConnectorServer with the following code (connection is still refused as with the previous attempts, with "Connection Failed. Retry? The connection did not succeed."):

      try { final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); final String jmxPort = System.getProperty("jmx.port"); if (jmxPort != null) { final int port = Integer.parseInt(jmxPort); System.out.println("settings JMX properties"); System.setProperty("java.rmi.server.randomIDs", "true"); Map<String, String> env = new HashMap<String, String>(); env.put("com.sun.management.jmxremote.ssl", "false"); env.put("com.sun.management.jmxremote.authenticate", "false"); env.put("com.sun.management.jmxremote.local.only", "true"); System.out.println("Creating Locate Registry"); LocateRegistry.createRegistry(port); System.out.println("Creating JMX Service URL"); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/server"); System.out.println("Creating new JMX Connector Server"); JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); cs.start(); } } catch (final RemoteException e) { e.printStackTrace(); } catch (final MalformedURLException e) { e.printStackTrace(); } catch (final IOException e) { e.printStackTrace(); } 

I try to connect with JConsole (ultimately, this will be done from another program, but I try from JConsole to verify the JMX service is running correctly) with this JMXServiceURL:

    service:jmx:rmi:///jndi/rmi://localhost:SOME_PORT_HERE/jmxrmi

Does anyone have any idea how to do this, either programmatically or how to get these properties passed to the WebStart-ed process?

Thanks in advance.

Additional Notes

  • this is for Java 1.6+ (not 1.5).
  • these options do work when I invoke my program directly and pass them via the command-line.
  • Some mentioned specifying the IP directly, using java.rmi.server.hostname=YOUR_IP. However, this doesn't seem require when the process is started normally, so I don't think it would be relevant to the WebStart scenario.
  • I can use a connection with the Attach API to connect to a process by PID with JConsole or JVisualVM, but ultimately the product cannot rely on this, as it requires a JDK or to bundle the tools.jar, and I don't think there are open alternatives to this. If there is, that would actually be a lot easier so let me know if you know one.

Update:

Actually, when using my last example with an explicit JMXConnectorServer , I get an NPE at the launch-time of the WebStart process, with:

12:39:28,743 WARN  [App] [trce] java.lang.NullPointerException
 at org.jboss.security.jndi.LoginInitialContextFactory.getInitialContext(LoginInitialContextFactory.java:81)
 at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
 at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
 at javax.naming.InitialContext.init(InitialContext.java:223)
 at javax.naming.InitialContext.<init>(InitialContext.java:197)
 at javax.management.remote.rmi.RMIConnectorServer.bind(RMIConnectorServer.java:619)
 at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:412)
 // line invoking .start() on the JMXConnectorServer's instance

As discussed with jtahlborn in the question's comment, we worked out that this was really specific to the application's setup.

There are some pitfalls to address to make JMX work for WebStart-ed applications, and there's also some implications to the use of multiple JNDI context factories.

In this particular case, the application had a jndi.properties read on startup and populating configuration settings, so a JBoss JNDI context factory was already even at the call point of the static block of the WebStart-ed application's entry-point / main-class.

As these JNDI properties were necessary for the rest of the program, the solution is simply to override these properties when creating the JMXServerConnector programmatically.

Here's an example:

    @SuppressWarnings("serial")
    private static Properties   initProperties() {
        return (new Properties() {{
            // overrides for the JNDI factory
            // mostly changing the INITIAL_CONTEXT_FACTORY from:
            //   "org.jboss.security.jndi.JndiLoginInitialContextFactory"
            // to:
            put(Context.INITIAL_CONTEXT_FACTORY,
                "org.jnp.interfaces.NamingContextFactory");
            put(Context.PROVIDER_URL, "jnp://localhost/");

            // Required JMX properties and other things ...
            //  YMMV of course, these were for my current settings
            put("java.rmi.server.randomIDs", "true");
            put("java.rmi.server.hostname", host); // host needs to be an IP
            put("com.sun.management.jmxremote.ssl", "false");
            put("com.sun.management.jmxremote.authenticate", "false");
            put("com.sun.management.jmxremote.local.only", "true");
            put("com.sun.management.jmxremote.port", String.valueOf(port));
        }});
    }

and:

    // error handling left out for clarity
    private static void startJMXAgent() throws TheWorld {
        Registry           reg  = LocateRegistry.createRegistry(port);
        JMXConnectorServer cs   =
            JMXConnectorServerFactory.newJMXConnectorServer(
                new JMXServiceURL(
                    "service:jmx:rmi://" + host + ":" + port + "/" +
                    "jndi/rmi://" + host + ":" + port + "/" +
                    servicename
                ),
                initProperties(),
                ManagementFactory.getPlatformMBeanServer()
            );
        cs.start();
    }

Note: I assume you could probably do it the other way around and override these properties on the command-line or in the JNLP file, and then reset them to whatever is needed for later contexts. However, this didn't fit the use case here so I didn't really look into it.

try setting following argument from command line on windows

set JAVAWS_VM_ARGS=-Dcom.sun.management.jmxremote.port=9400 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

and then start the jnlp file from that same command prompt. It worked for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM