Can't start JMXConnectorServer
Asked Answered
S

3

5

I would like to connect to my application via JMX remotely, so I've created following configuration in main method:

MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:7890/jmxrmi");
Map<String, Object> envConf = new HashMap<>();
//My custom authenticator
envConf.put(JMXConnectorServer.AUTHENTICATOR, new MyAuthenticator(jmxUsername, jmxPassword));
JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, envConf, mbs);
cs.start();

Here is how I start my application:

java -Dcom.sun.management.jmxremote 
     -Dcom.sun.management.jmxremote.port=7890
     -Dcom.sun.management.jmxremote.authenticate=false 
     -Dcom.sun.management.jmxremote.ssl=false 
     Main

But it seems that something is missing and I get following exception:

Cannot bind to URL [rmi://localhost:7890/jmxrmi]: javax.naming.NoPermissionException [Root exception is java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.AccessException: Cannot modify this registry]
java.io.IOException: Cannot bind to URL [rmi://localhost:7890/jmxrmi]: javax.naming.NoPermissionException [Root exception is java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.AccessException: Cannot modify this registry]
    at javax.management.remote.rmi.RMIConnectorServer.newIOException(RMIConnectorServer.java:827)
    at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:432)
    at test.jms.Main.start(JmxModule.java:35)
Caused by: javax.naming.NoPermissionException [Root exception is java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.AccessException: Cannot modify this registry]
    at com.sun.jndi.rmi.registry.RegistryContext.bind(RegistryContext.java:147)
    at com.sun.jndi.toolkit.url.GenericURLContext.bind(GenericURLContext.java:228)
    at javax.naming.InitialContext.bind(InitialContext.java:425)
    at javax.management.remote.rmi.RMIConnectorServer.bind(RMIConnectorServer.java:644)
    at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:427)
    ... 4 more
Caused by: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
    java.rmi.AccessException: Cannot modify this registry
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:420)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:268)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$254(TCPTransport.java:683)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$13/8098086.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:379)
    at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
    at com.sun.jndi.rmi.registry.RegistryContext.bind(RegistryContext.java:141)
    ... 8 more
Caused by: java.rmi.AccessException: Cannot modify this registry
    at sun.management.jmxremote.SingleEntryRegistry.bind(SingleEntryRegistry.java:76)
    at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
    at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:410)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:268)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$254(TCPTransport.java:683)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$13/8098086.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Could you please point me where am I wrong?

Seymour answered 17/7, 2015 at 8:30 Comment(0)
S
6

The problem was that I didn't have RMI registry running, so simply running this command in console:

rmiregistry

or adding this line of code before start of server:

LocateRegistry.createRegistry(1099);

solves an issue.

Seymour answered 23/7, 2015 at 13:41 Comment(1)
how to run rmiregistry or where did you add that line of code?Chrissa
M
4

By the launching the application using java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=7890 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false Main

you are starting the default RMI JMX connector on port 7890. And you are trying to start the custom connector on the same port and it fails.

If you are going to use your own connector instance you can safely omit all the -Dcom.sun.management.jmxremote.* properties.

Margaret answered 21/7, 2015 at 16:3 Comment(2)
In this case I have another exception: Cannot bind to URL [rmi://localhost:7890/jmxrmi]: javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException: Connection refused to host: localhost; nested exception is: java.net.ConnectException: Connection refused: connect] . Port is not closed and not blocked by firewallSeymour
Generally people should use this solution. You shouldn't start up the JMX server yourself. However, if you need some sort of customization and need to start it yourself, check out Oleskii's or my answer.Nummulite
N
0

Below is a minimal working example for JDK 1.8 extended from https://docs.oracle.com/cd/E19698-01/816-7609/6mdjrf86t/index.html#security-ex-37 and https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/tutorial/security.html#wp997065

The key missing steps from the code in the links and the accepted answers are:

  1. LocateReigstry.createRegistry(port)
  2. Thread.sleep() loop to ensure that the application doesn't shutdown.
  3. Answer does not describe MyAuthenticator. My answer uses the default authenticator that expects paths to the access and password files.

Working code Main.java:

import javax.management.MBeanServer;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.util.*;

public class Main {

    public static void main(String[] args) throws Exception {
        if(args.length != 2) {
            throw new IllegalArgumentException("Main <port> <path suffix>"
                            + "\nservice:jmx:rmi:///jndi/rmi://localhost:<port>/<pathsuffix>"
                            );
        }

        int port = Integer.parseInt(args[0]);
        String pathSuffix = args[1];

        LocateRegistry.createRegistry(port);

        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://0.0.0.0:" + port + "/" + pathSuffix);

        Map<String, Object> envConf = new HashMap<>();
        envConf.put("jmx.remote.x.password.file", "password.properties");
        envConf.put("jmx.remote.x.access.file", "access.properties");

        JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, envConf, mbs);
        cs.start();

        while(true) {
            Thread.sleep(1000);
        }
    }

}

Contents of jmx.remote.x.access.file:

admin readwrite

Contents of jmx.remote.x.password.file:

admin password

I executed the code from maven using (assuming 8474 is available):

javac Main.java
java Main  8474 jmxrmi   
Nummulite answered 11/12, 2017 at 22:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.