Reputation: 442
I'm trying to return a normal class via a RMI call. My server holds a instance of a class called GameState that i want to perform actions on via it's methods, from a client application. So the RMI works fine if a just return a int or something, but when a try to return GameState, which is a class defined inside the GameServer java file, the following error occurs (game state is declared neither public, protected or private):
Exception in thread "main" java.lang.IllegalAccessError: tried to access class GameState from class $Proxy0 at $Proxy0.getGameState(Unknown Source) at GameClient.login(GameClient.java:204) at GameClient.main(GameClient.java:168)
So, i guess the client application knows how GameState looks, but dont have any access to it?
I have tried to make GameState a public class in it's own file, but then the different connecting client applications get each their own GameState, so it's seems like that dont get it from the server.
Here are some code that i think is relevant:
The remote interface:
import java.rmi.*;
public interface ServerInterface extends Remote
{
public GameState getGameState() throws RemoteException;
}
Some if the server code:
public class GameServer extends UnicastRemoteObject implements ServerInterface {
/**
*
*/
private static final long serialVersionUID = -6633456258968168102L;
private final static int DEFAULT_NAMING_PORT = 9955; // TODO: IMPORTANT - change this to a group-specific number,
// e.g., 2000 + group number. The number should be the same
// as in GameClient.java.
private final GameState m_state;
public static void main(String[] args) {
//the variables: port and host etc it configurated here, but has nothing to do with the RMI problem.
try {
GameServer instance = new GameServer(players);
System.out.print("Setting up registry on "+host+":"+port+" ... ");
//Set up an unrestricted security manager.
if (System.getSecurityManager() == null) {
// Set security manager to an instance of a dynamically created
// subclass of RMISecurityManager with the checkPermission() method overloaded
System.setSecurityManager(
new RMISecurityManager() {
@Override
public void checkPermission(Permission permission) {
}
}
);
}
// Create a registry for binding names (name server)
Registry naming = LocateRegistry.createRegistry(port);
System.out.println("done.");
String rmiObjectName = "GeschenktServer";
System.out.print("Binding name "+rmiObjectName+" ... ");
naming.rebind(rmiObjectName, instance);
System.out.println("done.");
} catch(RemoteException e) {
System.err.println("Could not start server: "+e);
System.exit(-1);
}
}
//the rest of the server code....
//the GameState declared in the same file
class GameState implements java.io.Serializable {
private static final long serialVersionUID = 545671487061859760L;
//the rest of the Game state code.
Here is some of the client code:
private void login() {
try {
System.out.println("Connecting to server on host "+m_host+".");
// Set up an unrestricted security manager. In the server we trust.
// See GameServer.java for code explanation.
if (System.getSecurityManager() == null) {
System.setSecurityManager(
new RMISecurityManager() {
@Override
public void checkPermission(Permission permission) {
}
}
);
}
System.out.print("Locating registry on "+m_host+":"+m_port+" ... ");
Registry naming = LocateRegistry.getRegistry(m_host, m_port);
System.out.println("done.");
String name = "GeschenktServer";
System.out.print("Looking up name "+name+" ... ");
m_server = (ServerInterface) naming.lookup(name);
System.out.println("done.");
// TODO: Connect the player, i.e., register the player with the server.
// Make sure that the player cannot register if there are already enough players.
m_Id = m_server.getGameState().loginPlayer(m_name); //this line is causing the error...
if(m_Id < 0)
System.exit(0);
System.out.println("Server connection successful.");
m_window = new GameWindow(m_server, m_name, m_Id);
m_window.run();
} catch (Exception e) {
System.out.println("Connection failed - "+e);
System.exit(1);
}
}
}
I am using eclipse to do all this, and based on what i have red about RMI in eclipse, rmic and that stuff is not needed anymore, i'm i right?
So anyone with any idea?
Thanks in advance!
Upvotes: 1
Views: 1860
Reputation: 12066
The IllegalAccessError
reason is simple:
However, there is a larger issue:
you do understand that loginPlayer
will not do what you like it to... The GameState is a copy of the original state. You want GameState to be Remote
not serializable, so you can execute the operation on the server, not each client to get a useless copy of.
Upvotes: 0
Reputation: 311039
try to return GameState, which is a class defined inside the GameServer java file, the following error occurs (game state is declared neither public, protected or private)
This is the problem. Only the GameServer class and classes in the same package can create instances of GameState. Your RMI proxy object (stub) Make it a public class in its own file.
I have tried to make GameState a public class in it's own file, but then the different connecting client applications get each their own GameState, so it's seems like that dont get it from the server
That's correct. It is serialized to each client. If you want to share a single GameState and have it remain at the server, it has to be an exported remote object itself, with a remote interface called GameState.
Upvotes: 0
Reputation: 2866
I don't think this is a permission problem. I cannot tell for sure from the code above, but I would assume it is a codebase problem. Did you configure the codebase also on client-side?
To deserialize the GameState
class, the client needs to be able to load the class definition. This definition is located in the Server implementation and not the interface. Normally, the Server implementation should not be compiled to the client's classpath, only the interface should. I am not entirely sure, as in your solution the interface seems to have a dependency on the implementation due to the GameState
which is not a good idea btw. Anyways, try adding a codebase configuration to your VM-args. Assuming you execute everything on localhost, it should look like this:
-Djava.rmi.server.codebase=file:${workspace_loc}/PROJECT-NAME/bin/
Where ${workspace_loc}
is the absolute path to your workspace and PROJECT-NAME
is the name of the server project. Eclipse will resolve ${workspace_loc}
automatically, so you only need to set your PROJECT-NAME
As a side note: If you implement it that way, the GameState
object is transmitted to the client-side and is executed on the client, having no effect whatsoever on the execution of the server. Is this really what you want? If you want the GameState
instance to execute on the server-side, GameState
also needs to implement Remote
, not Serializable
, and you need to export it when transmitting its stub to the client.
Finally, as you correctly stated, you do not need to use rmic since Java 1.5
Upvotes: 0