Donnerstag, 2. Februar 2012

Firewall Friendly RMI Port Fixing

Although it probably makes little difference its often required to keep the number of ports allowed by a firewall as small as possible. By default RMI determines dynamically which port to use for communication. One way to define the port that shall be used for communication is to define it when exporting the remote object. Another less invasive way is to set a custom RMISocketFactory like the following one:

public class CustomRmiSocketFactory extends RMISocketFactory {
  private static RMISocketFactory delegate = RMISocketFactory.getDefaultSocketFactory();
  public static void register(int customPort) throws IOException {
     RMISocketFactory.setSocketFactory(new CustomRmiSocketFactory(customPort));
  }
  private final int customPort; 
  private CustomRmiSocketFactory(int customPort) {
    this.customPort = customPort;
  }
  public Socket createSocket(String host, int port) throws IOException {
    return delegate.createSocket(host, port);
  }
  public ServerSocket createServerSocket(int port) throws IOException { // 0 means arbitrary port
    return delegate.createServerSocket(port!=0 ? port : customPort); 
  }
  public int hashCode() {
    return customServerSocketPort;
  }
  public boolean equals(Object obj) {
    return (getClass() == obj.getClass() && customPort == ((CustomRmiSocketFactory) obj).customPort);
  }
}


As fas as you ensure the register method is calles as early as possible in your application (e.g. in an static initializer in your main class) this works quite well. All RMI communication uses the predefined (server) port.

One unexpected and nasty thing happens when you use this in connection with JMX. If you start your application with the usual JMX options the JMX agent already initializes RMI and chooses a port befor any class of your application is loaded. In order to keep RMI only taking the defined port you either have to provice jour own JMX agent (wich first sets the factory) or start the JMX agent programatically in jour application (after setting the RMISocketFactory).

Keine Kommentare:

Kommentar veröffentlichen