2

I've rubberduck debugged every line of code along with multiple working examples but for some reason my java application just closes when I start an RMI server.

I expect the java application to keep running because I have started a Registry and I have rebound an object that implements java.rmi.Remote.

But what happens is that the application stops right after it's created everything.

Here's my Main.java:

package com.distribridge.servercomponent;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

    private static Logger logger = Logger.getLogger(Main.class.getName());
    private static int portNumber = 1099;

    private Main() {
        logger.log(Level.INFO, "Starting component");

        Server server;
        try {

            server = new Server();
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Could not create server.");
            System.exit(1);
            return;
        }

        logger.log(Level.FINE, "Server created.");

        Registry registry;
        try {
            registry = LocateRegistry.createRegistry(portNumber);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Could not create registry");
            System.exit(1);
            return;
        }

        logger.log(Level.FINE, "Registry created.");

        try {
            registry.rebind("server", server);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Could not bind server.");
            System.exit(1);
            return;
        }

        logger.log(Level.FINE, "Server bound.");
        logger.log(Level.INFO, "Component started.");
    }

    public static void main(String[] args) {
        System.out.println("Start");
        Main main = new Main();
    }
}

And my Server.java looks like this:

public class Server implements IServerForClientLogin, IServerForClient, IServerForTable, Remote {
    Server() {
        System.out.println("Server Constructor");
    }

    //Some methods that don't get called yet.
}

The interfaces the server extends are in a "Shared" module. I started the project with that module and added modules like the server.

Here's what my console output is:

Start 
Jan 03, 2018 1:10:05 PM com.distribridge.servercomponent.Main <init>
INFO: Starting component
Server Constructor 
Jan 03, 2018 1:10:05 PM com.distribridge.servercomponent.Main <init>
INFO: Component started.

Process finished with exit code 0

As you can see, the process just closes immediately while the registry has a remote object bound.

user207421
  • 305,947
  • 44
  • 307
  • 483
Tvde1
  • 1,246
  • 3
  • 21
  • 41
  • Why should the Java application keep running? Is there any blocking code being run inside the registry or the server which is executed? – Dominik Sandjaja Jan 03 '18 at 12:20
  • Yes the registry should keep the application alive. See https://stackoverflow.com/questions/7446035/what-make-rmi-server-keep-running. – Tvde1 Jan 03 '18 at 12:26
  • It works if you have a stub exported, e.g.: `IServerForClient stub = UnicastRemoteObject.exportObject(server, 0);` – Dominik Sandjaja Jan 03 '18 at 12:48
  • Woah that keeps the application running. Let's see if that will also work with the clients. – Tvde1 Jan 03 '18 at 12:56
  • If I export the object as a remote (`Remote stub = Unicast...`), the client can't cast it to a server, and if I use `Server stub = (Server) UnicastRemoteObject.exportObject(server, 0); registry.rebind("server", stub);` It also stops the program. – Tvde1 Jan 03 '18 at 13:03
  • But shouldn't the client only cast it to your interfaces (`IServerForClientLogin`, etc.)? There shouldn't be a direct casting to the actual implementation class (`Server`). – Dominik Sandjaja Jan 03 '18 at 15:53
  • Also can't cast to that @DominikSandjaja – Tvde1 Jan 03 '18 at 16:05

1 Answers1

4

The Registry that you store the result of LocateRegistry.createRegistry() into needs to be static.

Otherwise it can be garbage-collected, which unexports it, which allows all the stubs in it to be GC'd, which allows the remote objects they refer to to be DGC'd, which unexports them, which allows the RMI accept threads to exit, which allows the JVM to exit.

However you have another problem. Your Server isn't a remote object yet. You need to export it, either by extending UnicastRemoteObject or calling UnicastRemoteObject.exportObject() on it. At present it is just a mobile agent that is carted bodily to the client and executes there.

Server doesn't need to implement Remote directly. It needs to implement interfaces that extend Remote.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Even though this wasn't needed in many examples I read, it solved my problem and I understand why. Thanks! – Tvde1 Jan 04 '18 at 11:32
  • It certainly is needed. This may come as a shock, but not all example code out there actually works. – user207421 Jan 05 '18 at 01:27
  • I had an example project downloaded and that worked. Anyhow I'm glad it's fixed. – Tvde1 Jan 05 '18 at 06:31