Search code examples
javarmi

Java RMI issue: Can't solve Exception in thread "main" java.rmi.NotBoundException: Server


I am getting the following error:

Exception in thread "main" java.rmi.NotBoundException: Server
at java.rmi/sun.rmi.registry.RegistryImpl.lookup(RegistryImpl.java:234)
at java.rmi/sun.rmi.registry.RegistryImpl_Skel.dispatch(RegistryImpl_Skel.java:133)
at java.rmi/sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:468)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:298)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:562)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:796)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:677)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:676)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
at java.rmi/sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:303)
at java.rmi/sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:279)
at java.rmi/sun.rmi.server.UnicastRef.invoke(UnicastRef.java:380)
at java.rmi/sun.rmi.registry.RegistryImpl_Stub.lookup(RegistryImpl_Stub.java:123)
at client.RMIClient.startClient(RMIClient.java:17)
at client.FahrradClient.main(FahrradClient.java:12)

Can anybody look at my code and tell me where I went wrong? I'd be more than grateful. Would even send a small tip or something lmao I am that desperate.

package server;
import shared.RMI_Interface;

import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class FahrradServer {
    public static void main(String[] args) throws IOException, AlreadyBoundException {
        RMI_Interface server = new ConfigImpl();
        Registry registry = LocateRegistry.createRegistry(1099);
        Runtime.getRuntime().exec("rmiregistry 1099");
        registry.bind("Server", server);
        System.out.println("Server started");
    }
}

package client;
import shared.Fahrrad;
import shared.RMI_Interface;

import java.rmi.*;
import java.rmi.registry.*;

public class RMIClient {
    private RMI_Interface server;

    public RMIClient() {}

    public void startClient() throws RemoteException, NotBoundException {
        Registry registry = LocateRegistry.getRegistry("localhost", 1099);
        server = (RMI_Interface)registry.lookup("Server");
    }

    public Fahrrad configureFahrrad(String lenkertyp,  String material, String schaltung, String griff ) {
        Fahrrad result = null;
        try {
            result = server.configureFahrrad(lenkertyp, material, schaltung, griff);
        } catch (RemoteException e) {
            e.printStackTrace();
            throw new RuntimeException("Could not contact server");
        }
        return result;
    }
}

package server;

import shared.Fahrrad;
import shared.RMI_Interface;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class ConfigImpl implements RMI_Interface {

    public void ConfigImpl() throws RemoteException {
        UnicastRemoteObject.exportObject(this, 0);
    }

    @Override
    public Fahrrad configureFahrrad(String lenkertyp,  String material, String schaltung, String griff ) throws RemoteException {
        Fahrrad f = new Fahrrad();
        f.setLenkertyp(lenkertyp);
        f.setGriff(griff);
        f.setMaterial(material);
        f.setSchaltung(schaltung);

        if (!lenkertyp.equals( "Faltbarlenker")  && !lenkertyp.equals( "Rennradlenker") && !lenkertyp.equals( "Bullhornlenker")) {
            throw new IllegalArgumentException("Ungültiger Lenktypinput");
        }

        if (!material.equals( "Aluminium") && !material.equals( "Stahl") && !material.equals( "Kunststoff")){
            throw new IllegalArgumentException("Ungültiges Material!");
        }

        if (!schaltung.equals("Kettenschaltung") && !schaltung.equals( "Tretlagerschaltung") && !lenkertyp.equals( "Nebenschaltung")) {
            throw new IllegalArgumentException("Ungültige Schaltung!");
        }

        if (!griff.equals( "Kunststoffgriff") && !griff.equals( "Ledergriff") && !lenkertyp.equals( "Schaumstoffgriff")) {
            throw new IllegalArgumentException("Ungültige Schaltung!");
        }

        if (lenkertyp.equals("Faltbarlenker") || lenkertyp.equals("Rennradlenker")) {
            if (!material.equals( "Aluminium") && !material.equals( "Kunststoff")) {
                throw new IllegalArgumentException(lenkertyp + " kann nur aus Aluminium oder Kunststoff bestehen.");
            }
        }

        if (material.equals("Stahl")) {
            if (!schaltung.equals("Kettenschaltung")) {
                throw new IllegalArgumentException("Materialtyp "+ material + " kann nur Kettenschaltung haben!");
            }
        }

        if (material.equals("Kunststoff")) {
            if (griff.equals("Kunststoffgriff")) {
                throw new IllegalArgumentException("Nur Kunststoffmaterial kann Kunststoffgriff haben!");
            }
        }

        if (lenkertyp.equals( "Bullhornlenker") || lenkertyp.equals("Faltbarlenker")) {
            if (griff.equals("Ledergriff")) {
                throw new IllegalArgumentException("Nur Rennladlenker können Ledergriffe haben!");
            }
        }
        return f;
    }
}

package server;
import shared.RMI_Interface;

import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class FahrradServer{
    public static void main(String[] args) throws IOException, AlreadyBoundException {
        RMI_Interface server = new ConfigImpl();
        Registry registry = LocateRegistry.createRegistry(1099);
        Runtime.getRuntime().exec("rmiregistry 1099");
        registry.bind("Server", server);
        System.out.println("Server started");
    }
}

package shared;

public class Fahrrad {
    public String lenkertyp;
    public String material;
    public String schaltung;
    public String griff;

    public void setLenkertyp(String lenkertyp){
        this.lenkertyp=lenkertyp;
    }

    public String getLenkertyp() {
        return lenkertyp;
    }

    public void setMaterial(String material){
        this.material=material;
    }

    public String getMaterial() {
        return material;
    }

    public void setSchaltung(String schaltung) {
        this.schaltung=schaltung;
    }

    public String getSchaltung() {
        return schaltung;
    }

    public void setGriff(String griff){
        this.griff=griff;
    }

    public String getGriff() {
        return griff;
    }
}

package shared;

import java.rmi.Remote;
import java.rmi.RemoteException;

// Creating Remote interface for our application
public interface RMI_Interface extends Remote {
    public Fahrrad configureFahrrad(String lenkertyp,  String material, String schaltung, String griff ) throws RemoteException;
}

I know the code isn't perfect. I will change it but the most important thing is to get the client and server run independently. My client sadly doesn't run.


Solution

  • The steps to follow when creating a RMI application.

    1. Create the "remote" interface.
      Your interface RMI_Interface is OK. Nothing to do here.
    2. Create a class that implements the remote interface.
      I made the constructor empty. (The rest of the code is unchanged.)
    public ConfigImpl() throws RemoteException {
        // Empty.
    }
    
    1. Create a RMI server. Here I made a few changes.
    package server;
    
    import java.rmi.AlreadyBoundException;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    import java.rmi.server.UnicastRemoteObject;
    
    import shared.RMI_Interface;
    
    public class FahrradServer {
    
        public static void main(String[] args) {
            try {
                ConfigImpl server = new ConfigImpl();
                RMI_Interface stub = (RMI_Interface) UnicastRemoteObject.exportObject(server, 0);
                Registry registry = LocateRegistry.createRegistry(1099);
                registry.bind("Server", stub);
                System.out.println("Server started");
            }
            catch (AlreadyBoundException | RemoteException x) {
                x.printStackTrace();
            }
        }
    }
    

    Note that calling method createRegistry() will launch the rmiregistry so no need for this line of your code:

    Runtime.getRuntime().exec("rmiregistry 1099");
    
    1. Run the server, i.e. java server.FahrradServer
      (I assume you know the correct command that you need to actually launch your server.)
      Note that the server program will run forever – unless you kill it.
    2. Write the client. The client will run in a separate JVM so the client needs a main() method so that you can launch it via the java command.
    package client;
    
    import java.rmi.NotBoundException;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    
    import shared.Fahrrad;
    import shared.RMI_Interface;
    
    public class RMIClient {
        private RMI_Interface server;
    
        public void startClient() throws RemoteException, NotBoundException {
            Registry registry = LocateRegistry.getRegistry(1099);
            server = (RMI_Interface) registry.lookup("Server");
        }
    
        public Fahrrad configureFahrrad(String lenkertyp,
                                        String material,
                                        String schaltung,
                                        String griff) throws RemoteException {
            return server.configureFahrrad(lenkertyp, material, schaltung, griff);
        }
    
        public static void main(String[] args) {
            RMIClient client = new RMIClient();
            try {
                client.startClient();
                Fahrrad f = client.configureFahrrad("Faltbarlenker",
                                                    "Aluminium",
                                                    "Kettenschaltung",
                                                    "Kunststoffgriff");
                System.out.println("Fahrrad: " + f);
            }
            catch (RemoteException | NotBoundException x) {
                x.printStackTrace();
            }
        }
    }
    
    1. Since the return value of the remote interface method is a class that you wrote, that class must implement interface Serializable, i.e.
    public class Fahrrad implements java.io.Serializable
    
    1. Now you can launch your RMI client, e.g. java client.RMIClient

    Refer to the RMI trail of Oracle's java tutorials.