RMI streikt

Status
Nicht offen für weitere Antworten.

JPKI

Top Contributor
Guten Tag. Ich schreibe zur Zeit an einem Kartenspiel mit Mehrspielerfunktion, dazu nutze ich RMI.

Ich habe folgende Schnittstelle deklariert, die von einer Serverklasse implementiert wird:
Code:
package de.jpki.games.nigg.network;

import de.jpki.games.nigg.game.*;
import java.util.List;
import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RuleExecutor extends Remote {

  public boolean executeGameStep(GameStep step) throws RemoteException;
  
  public List<Card> getDealedCards() throws RemoteException;
  
  public GameStep checkForNextGameStep(NetworkID id) throws RemoteException;
}

Hier ein Ausschnitt aus besagter Serverklasse:
Code:
package de.jpki.games.nigg.network;

import de.jpki.games.nigg.control.*;
import de.jpki.games.nigg.game.*;
import de.jpki.games.nigg.exceptions.*;

import java.rmi.*;
import java.net.*;
import java.util.*;

public class Server implements CardConstants, FigureConstants, RuleExecutor {

  private NetworkID ownID;
  private List<GameStep> steps;
  private List<NetworkID> gueltyIDs;
  private List<Card> playedCards;
  
  public Server(NetworkID ownID, NetworkID clientIDs[]) {
  
   this.ownID = ownID;
   steps = new LinkedList<GameStep>();
   gueltyIDs = new ArrayList<NetworkID>();
   playedCards = new ArrayList<Card>();
   gueltyIDs.add(ownID);
   
   for (NetworkID id : clientIDs)
    gueltyIDs.add(id);
 }
  
  public List<Card> getDealedCards() {
  
   return new ArrayList<Card>();
 }

  public GameStep checkForNextGameStep(NetworkID id) throws RemoteException {
  
   if (!gueltyIDs.contains(id))
    throw new RemoteException("you are not allowed to play");
   
   return steps.get(steps.size()-1);
 }
  
  public boolean executeGameStep(GameStep step) throws RemoteException {
  
   if (!gueltyIDs.contains(step.getID()))
    return false;
   
   try {
   
    execute(step);
    steps.add(step);
    return true;
    
  } catch (NotExecutableException ex) {
  
    NiggManager.log(ex);
    return false;
  }
 }
  
  private void execute(GameStep step) throws NotExecutableException {
  
   playedCards.addAll(step.getCardList());
 }
}

In einer anderen Klasse melde ich dann das ganze in der RMI-Registry an:
Code:
   try {
  
    server = new Server(new NetworkID(""),new NetworkID[0]);
    RuleExecutor executor = (RuleExecutor)UnicastRemoteObject.exportObject(server,0);
        
    RemoteServer.setLog(NiggManager.getRemoteLogStream());
        
    Registry registry = LocateRegistry.getRegistry();
    registry.bind("RuleExecutor",executor); //Diese Zeile wirft eine Exception
        
  } catch (Exception ex) {
   
    NiggManager.log(ex);
    throw new Error("Unable to register the RuleExecutor at the RMI Registry: Is the rmiregistry program started?");
  }

Die Fehlerausgabe sieht folgendermaßen aus:
Code:
java.rmi.ServerException occured: Tue Jun 12 19:50:34 CEST 2007
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: 
	java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
	java.lang.ClassNotFoundException: de.jpki.games.nigg.network.RuleExecutor
	at sun.rmi.server.UnicastServerRef.oldDispatch(Unknown Source)
	at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
	at sun.rmi.transport.Transport$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
	at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
	at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
	at sun.rmi.server.UnicastRef.invoke(Unknown Source)
	at sun.rmi.registry.RegistryImpl_Stub.bind(Unknown Source)
	at de.jpki.games.nigg.gui.CardFrame.startGame(CardFrame.java:63)
	at de.jpki.games.nigg.control.NiggManager.main(NiggManager.java:103)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is: 
	java.lang.ClassNotFoundException: de.jpki.games.nigg.network.RuleExecutor
	at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
	at sun.rmi.server.UnicastServerRef.oldDispatch(Unknown Source)
	at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
	at sun.rmi.transport.Transport$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: de.jpki.games.nigg.network.RuleExecutor
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClassInternal(Unknown Source)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Unknown Source)
	at sun.rmi.server.LoaderHandler.loadProxyInterfaces(Unknown Source)
	at sun.rmi.server.LoaderHandler.loadProxyClass(Unknown Source)
	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)
	... 12 more

Der RMI-Log sieht normal aus:
Code:
12.06.2007 19:50:34 sun.rmi.server.UnicastServerRef logCall
FEINER: RMI TCP Connection(1)-127.0.0.1: [127.0.0.1: sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]

Dazu möchte ich noch sagen, dass ich RMIREGISTRY gestartet habe.
Kann wer den Fehler finden? Wär toll...
 
S

SlaterB

Gast
Klasse nicht gefunden, was soll man dazu noch sagen?
Classpath aktualisieren

übrigens testet man sowas mit einem HelloWorld-Minimal-Server + -Client..
 

JPKI

Top Contributor
Klasse nicht gefunden, das dachte ich mir schon :wink: .
Tut mir leid, ich hab mich wohl nicht präzise genug ausgedrückt.

Wo geb ich jetzt die Klasse (besser gesagt: das Interface) "RuleExecutor" an? Im Classpath scheint's ja zu sein -- sonst würden die anderen Klassen ja nicht drauf zugreifen können oder ???:L ?
 
S

SlaterB

Gast
welche anderen Klassen können darauf zugreifen?

jedes für sich gestartete Java-Programm hat einen eigenen Classpath
 

JPKI

Top Contributor
Naja, ich registriere in der Klasse CardFrame mit der bind-Methode das RuleExecutor-Interface. Muss ich dazu der Registry auch noch den Classpath mitgeben?? Wenn ja, wie? Irgendwie peil ich das gerade nicht...
 
S

SlaterB

Gast
CLASSPATH-Fragen kommen hier doch nur wenn man seine ersten Programme kompiliert..

Umgebungsvariable CLASSPATH
oder
java -cp .;source MyClass


wirf
> registry.bind("RuleExecutor",executor); //Diese Zeile wirft eine Exception

raus, sowie alles was je mit RMI oder sonstwas komischen zu tun hat
und starte mit einem HelloWorld-Programm, erweitert um
System.out.println("Interface: "+ RuleExecutor.class.getName());
um zu prüfen, ob die Klasse vorhanden ist
 

JPKI

Top Contributor
Vorhanden ist sie, der Classpath funktioniert auch! Ich hab ja auch von überall aus Zugriff auf die Klasse, nirgendwo wird eine ClassNotFoundException geworfen, lediglich bei bind() von Registry...
 
S

SlaterB

Gast
funktioniert denn nun eine Ausgabe
System.out.println("Interface: "+ RuleExecutor.class.getName());
eine Zeile davor ja oder nein?

aber mag gerne so sein, dass es an ganz was anderem liegt
 

dhachim

Bekanntes Mitglied
Du solltest das Problem im Kleinen realisieren..... Also nen kleines Hello world etc.

RMI ist ne heikle Sache wie ich dieses Semster feststellen musste.

Hast du deinen Classfileserver implementiert ?, Hast du in der Run Configuration deine Policys und eventuell die Codebase angegeben ?

RMI hat so viele Stellen an denen es hängen kann, deshalb macht es echt sinn sich ein kleines Dummy Projekt zu erzeugen, das weniger Codelastig ist, aber vom Prinzip her das selbe machen soll, wie dein Programm.
 

JPKI

Top Contributor
Hab jetzt ein wirklich einfaches Beispielprogramm nach dem selben Muster wie oben erstellt, und es funktioniert. Fragt sich jetzt also, wo der Fehler liegt:

Interface:
Code:
import java.rmi.*;

public interface Rem extends Remote {

  public void printSomething(String toPrint) throws RemoteException;
}

Implementierung:
Code:
import java.rmi.*;

public class Printer implements Rem {

  public void printSomething(String s) throws RemoteException {

   System.out.println("Hallo: " + s);
 }
}

Registrierung:
Code:
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;

public class Register {

  public static void main(String args[]) throws Exception {

   Printer printer = new Printer();
   Rem rem = (Rem)UnicastRemoteObject.exportObject(printer,0);
   Registry registry = LocateRegistry.getRegistry();
   registry.bind("Rem",rem);
 }
}

So, diese drei Programmteile werden kompliliert und dann zusammen mit rmiregistry gestartet.
Jetzt starte ich noch eine JVM mit folgender Klasse in einer anderen Konsole:

Code:
import java.rmi.*;
import java.rmi.registry.*;

public class Test {

  public static void main(String args[]) throws Exception {

   Registry registry = LocateRegistry.getRegistry();
   Rem rem = (Rem)registry.lookup("Rem");

   rem.printSomething(args[0]);
 }
}

Wie gesagt, das funktioniert jetzt. Allerdings gehe ich hier genauso vor wie oben. Was mache ich da oben falsch ???:L ?
 
S

SlaterB

Gast
tja, was kann man dazu sagen?
statt Rem nimm nun RuleExecutor, was ja auch erstmal nur ein Interface ist,
bzw. es liegt wohl an den packages? was ist wen Rem in einem package liegt?

Schritt für Schritt an die Fehlersituation annähern bis entweder diese Situation läuft oder in einem möglichst kleinen Schritt der Fehler dazukommt
 

JPKI

Top Contributor
Oh mann... Ich wollte RMI der Einfachheit halber nutzen, aber wie ich seh' bringt das nix...
Ich nutze wohl lieber die direkte Serialisierung über eine Socketverbindung und ObjectIn/OutputStreams.
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben