RMI nachträglich in Programm einbinden - Problem

jimb0p

Erfahrenes Mitglied
Hallo Zusammen,

so mein Hauptprogramm läuft nun fehlerfrei und jetzt möchte ich dass man auch über das Netzwerk Zugriff darauf hat. Also habe ich mir überlegt RMI zu verwenden. 1. Frage wäre ob das die richtige Entscheidung ist und 2. da ich davon ausgehe dass es die richtige Entscheidung ist, habe ich bereits damit angefangen :), nur leider bekomme ich beim Clienten immer eine Exception. Beim Server habe ich es wie folgt implementiert:

Code:
public class Model extends UnicastRemoteObject implements ServerRemoteInterface{


	protected Model() throws RemoteException {
		super();
		// TODO Auto-generated constructor stub
	}

        ...

        public ArrayList<String> getModules() throws RemoteException {
		return appNames;
	 }

         ...
}

class addServerStartListener implements ActionListener{ //ActionListener für den StartButton des Servers

	StarterView view;
	settings config;
	Model model;
	
	addServerStartListener(StarterView view, settings config, Model model) throws IOException{ //erhalte view und config
		this.view = view;
		this.config = config;
		this.model = model;
	}
	
	public void actionPerformed(ActionEvent arg0) {
		try{
			LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
		}
		catch(RemoteException ex){
			System.out.println(ex.getMessage());
		}
		
		try{
			Naming.rebind("Server", model);
		}
		catch(MalformedURLException ex){
			System.out.println(ex.getMessage());
		}
		catch(RemoteException ex){
			System.out.println(ex.getMessage());
		}
		System.out.println("Server laeuft...");
	}
	
}


Interface sieht wie folgt aus:

Code:
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.ArrayList;

public interface ServerRemoteInterface extends Remote{
	public ArrayList<String> getModules() throws RemoteException;
}

Client ruft wie folgt externe Funktion auf:

Code:
        public void connect() throws Exception{
		ServerRemoteInterface remote = (ServerRemoteInterface) Naming.lookup("rmi://localhost/Server");
		ArrayList<String> tmpList = remote.getModules();
		for(String tmp : tmpList){
			System.out.println(tmp);
		}
	}
	
	class ServerStartListener implements ActionListener{

		ExpClientView view;
		
		ServerStartListener(ExpClientView view){
			this.view = view;
		}
		@Override
		public void actionPerformed(ActionEvent arg0) {
			//Wenn Verbinden Button geklickt wird, soll connect durchgeführt werden
			try {
				connect();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

Exceptions die ich beim Clienten bekomme wenn ich mich verbinden will:

Code:
java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
	java.lang.ClassNotFoundException: includes.ServerRemoteInterface (no security manager: RMI class loader disabled)
	at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
	at java.rmi.Naming.lookup(Unknown Source)
	at ExpClientModel.connect(ExpClientModel.java:31)
	at ExpClientModel$ServerStartListener.actionPerformed(ExpClientModel.java:49)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.awt.EventQueue.access$200(Unknown Source)
	at java.awt.EventQueue$3.run(Unknown Source)
	at java.awt.EventQueue$3.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue$4.run(Unknown Source)
	at java.awt.EventQueue$4.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: includes.ServerRemoteInterface (no security manager: RMI class loader disabled)
	at sun.rmi.server.LoaderHandler.loadProxyClass(Unknown Source)
	at java.rmi.server.RMIClassLoader$2.loadProxyClass(Unknown Source)
	at java.rmi.server.RMIClassLoader.loadProxyClass(Unknown Source)
	at sun.rmi.server.MarshalInputStream.resolveProxyClass(Unknown Source)
	at java.io.ObjectInputStream.readProxyDesc(Unknown Source)
	at java.io.ObjectInputStream.readClassDesc(Unknown Source)
	at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	... 40 more

Ist mal wieder sehr viel, freue mich aber riesig über jede Hilfe, bin im Moment nämlich vorerst am Ende mit meinen Ideen.

Gruß, jimb0p
 
Zuletzt bearbeitet:
Hi
Was mir spontan gleich auffällt ist das der Konstruktor in der Model class public sein muss da es sonst auch Exceptions gibt.
Zusätzlich hast du bei deinem Server nirgendwo ein Main und du weißt niemandem dem ActionListener zu.

Eine sauberere Fehlerbehandlung wäre auch nicht schlecht da du den Server nicht binden kannst wenn die Registry nicht läuft.
Java:
try{
            LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
            Naming.rebind("Server", model);
            System.out.println("Server laeuft...");
        catch(Exception ex){
            System.out.println(ex.getMessage());
        }

Lg hendl
 
Hi hendl,

habe nur die Ausschnitte gepostet die denke ich relevant sind. Der Actionlistener wird einfach einem Button zugewiesen und das funktioniert auch fehlerfrei. Habe den Konstruktor jetzt public gesetzt & die Fehlerbehandlung entsprechend wie dein Vorschlag angepasst. Ich denke das irgendwo der Fehler beim Client liegt. Weil der Server wird korrekt gestartet und der Port wird abgehört. Vielen Dank schonmal für deine Hinweise.

LG
 
Hmm
Ich sehe im Code keine Fehler.
Das einzige was mir jetzt noch einfällt ist, dass villeicht die Projektstruktur fehlerhaft ist oder ein Import fehlt.

Lg hendl
 
Hmm ... ich rate mal mit: In der Dokumentation zu Naming.rebind steht, dass der "Name", also der erste Parameter in URL Format sein muss. "Server" sieht aber nicht so aus wie ein URL Format.
 
Hmm ... ich rate mal mit: In der Dokumentation zu Naming.rebind steht, dass der "Name", also der erste Parameter in URL Format sein muss. "Server" sieht aber nicht so aus wie ein URL Format.

Ne, das ist schon ok so, das ist richtig.


Ok, dann eine Zeile mehr:

Objekt für RMI bekannt machen ...
Java:
Naming.rebind("Server", model);

Objekt per RMI holen ...
Java:
ServerRemoteInterface remote = (ServerRemoteInterface) Naming.lookup("rmi://localhost/Server");

Jetzt müsstest du eigentlich selbst drauf kommen, das springt einem ja förmlich ins Auge ;)
 
Meinst du weil es der localhost ist? Denn aktuell läuft es auf ein und dem selben Rechner zum Testen.
 
Ich denke mal, wie ich bereits oben geraten habe, dass du bei dem Naming.rebind auch so etwas wie

Java:
Naming.rebind("rmi://localhost/Server", model);

schreiben musst, statt als Paramter einfach "Server" zu übergeben. Wie bereits geschrieben, besagt die Dokumentation, dass der erste Parameter in URL Format übergeben wird.

Gruß,
Wolf
 
Zurück