Returning class instance via RMI call - java

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!

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

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.

The IllegalAccessError reason is simple: GameState is NOT public
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.

Related

Best way to check internet connection in whole app

I want to check internet connection in whole app. I've googled for it, but the result was everyone creates an instance method in each class and tries to check the internet connection. My plan is to create a class with static method and check it without instantiating my class. Is it good idea to do that? Or should I try another way? My plan is to do something like this:
public class CheckInternetConnecting {
public static boolean isOnline(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null &&
cm.getActiveNetworkInfo().isConnectedOrConnecting();
}
}
You can also check the internet connectivity in the following way..
public boolean testConnection() {
try {
boolean connectionStatus=false;
InetAddress addr=InetAddress.getByName("8.8.8.8");//google dns 8.8.8.8
connectionStatus=addr.isReachable(1000); // 1second time for response
}
catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
}
return connectionStatus;
}
Your approach is totally fine. I would recommend to add a package Utils to your project and put Helper-Classes in there. So instead of a class CheckInternetConnecting, create a class NetworkHelper and put your static method in there.
Adding a package:
On the left side of eclipse, in your package explorer right click your src folder and add a new package. It's important to include your package name, e.g when your package name is com.my.project than add a package called com.my.project.utils... Then you can add your NetworkHelper class to the new package by e.g right clicking and adding a new file. Copy your static code into the NetworkHelper and then you're all set...
Perhaps you can consider registering a broadcast receiver and listening out for connectivity changes as explained here.

get a thread from another class

I have a java class:
public class httpd implements Runnable
{
public void createHttpdStatistics
{
httpdStatistics stats = new httpdStastics(this);
}
}
Now I would get in another class the object stats created inside httpd. When httpd object starts, it execute in the jvm. I tought to build get method inside httpd class but when I'm in the other class how I get the exact httpd object to call get method to retrieve stats object?
EDIT
public class httpd implements Runnable
{
public static void main(String[] args)
{
httpd server = new httpd();
OtherClass oc = new OtherClass(server);
}
{
MY OWN MAIN
public class myownmain
{
public static void main(String[] args)
{
//Here I need OtherClass object created in httpd class
}
}
What's the problem in passing the passing the stats object to the other class you need inside a CTOR, by providing a getter to the stats object in class httpd -
this is only of course if the createHttpdStatistics method is not executed in the code of the run method (I suggest your pvovide it).
If the createHttpdStatistics method is executed within the run method (in a different thread) you should consider having a shared data structure between the threads (for example - shared Singletone that can be used as a shared data structure), if you want to create the HttpdStatistics object within a thread.
In this case the code will look like:
public class httpd implements Runnable
{
public void createHttpdStatistics()
{
httpdStatistics stats = new httpdStastics(this);
StatsManager.getInstance().putStats(stats);
}
public void run() {
//I assume the creation is done at the run method. Maybe I'm wrong here.
createHttpdStatistics();
}
}
And then use this somewhere in your code -
HttpdStatistics stats = StatsManager.getInstance().getStats();
MyClass stats = new MyClass(stats); //passing stats to another object.
You should of course make sure that getStats either blocks under the stats object is set to the singletone, or to check if getStats() returns null.
Given the code posted here:
In your other class, say OtherClass for example, you should have setter for httpd object or provide the httpd instance in the OtherClass constructor. This way OtherClass will have a reference to httpd
public class OtherClass{
httpd httpd_ = null;
public OtherClass(httpd httpd_){
this.httpd_ = httpd_;
}
// Access and use stats from httpd
public void useStats(){
httpdStatistics stats = httpd_.getStatistics()
if(stats != null){
// Do something here
}else{
// stats not set yet, the thread did probably not start yet
}
}
}
In your application's main you can have the following:
httpd h = new httpd();
OtherClass otherClass = new OtherClass(h);
EDIT As mentioned in one of the comments, the stats variable is shared among two threads so you will have to synchronize on it and make sure it is updated in a exclusive way.

How to use methods from two classes in eachother in Java?

I've been looking around and I only found one answer which wasn't clear enough, to me at least.
I am building a very basic chat application with a GUI and I have separated the GUI from the connection stuff. Now I need to call one method from GUI in server class and vice versa. But I don't quite understand how to do it (even with "this"). Here's what a part of code looks like (this is a class named server_frame):
textField.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
srv.sendData(arg0.getActionCommand());
} catch (Exception e) {
e.printStackTrace();
}
textField.setText("");
}
}
);
This is a code from server_frame, srv is an object from the other class (server) which contains sendData method, and I probably didn't define it correctly so hopefully someone could make a definition of it.
On the other side class server from which object srv was made contains method using JTextArea displayArea from server_frame in this code:
private void displayMessage(final String message){
sf = new server_frame();
SwingUtilities.invokeLater(new Runnable(){
public void run(){
sf.displayArea.append(message);
}
}
);
}
Yet again sf is an object made of server_frame and yet again probably missdefined :)
Hopefully that was clear enough, sadly I tried the searching but it just didn't give me the results I was looking for, if you need any more info I will gladly add it!
Thanks for reading,
Mr.P.
P.S. Please don't mind if I made terminology mishaps, I am still quite new to java and open to any corrections!
Some class must be building both of these objects--the GUI and the server--and it should make each aware of the other. For example, say the main class is ServerApplication. I'll use standard Java convention of starting class names with an uppercase letter for clarity.
class ServerApplication {
Server server;
ServerFrame gui;
public static void main(String []) {
server = new Server(...);
gui = new ServerFrame(server);
server.setGui(gui);
}
}
Each class should store the reference to the other as well.
class Server {
ServerFrame gui;
public void setGui(ServerFrame gui) {
this.gui = gui;
}
...
}
class ServerFrame extends JFrame {
Server server;
public ServerFrame(Server server) {
this.server = server;
}
...
}
I think you may be looking for the ClassName.this.methodName syntax. this in those actionlisteners refer to the anonymous class you created. If you used the above syntax you would be referencing the class that contains the anonymous class.
Or if you are looking for a private field in the class, you would do ClassName.this.privateField

Do I need all classes on the client, server and registry for RMI to work?

I'm doing my first steps with RMI, and I have a simple question.
I have a .jar file which has the implementation of several methods from a library.
I want to call this methods in the .jar file using RMI.
What I'm trying is to create a kind of a wrapper to do it.
So, I'm working on something like this:
Interface class: This interface has the methods to be implemented by the remote object.
Implementation class: This class, has the implementation of the interface methods, each implementation calls the corresponding method in the .jar file. E.g., the jar file has a method called getDetails(), and it returns a "ResponseDetail" object. ResponseDetail is a response class I have in the .jar.
Server class: it binds the methods to the rmiregistry
Client class: it will consume the methods implemented in implementation.
So far so good? :)
Now, I have a lib folder where resides the .jar file.
In the server machine I have deployed the Interface, Implementation and Server classes. I've generated the stub, and I ran the rmiregistry successfully, but, with these details:
To start the rmiregistry, I had to set the classpath in the command line to reference the .jar files, otherwise I get the java.lang.NoClassDefFoundError. I did it with this .sh file:
THE_CLASSPATH=
for i in `ls ./lib/*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
rmiregistry -J-classpath -J".:${THE_CLASSPATH}"
To start the server, I had to set the classpath as well to reference the .jar files, otherwise, I get the java.lang.NoClassDefFoundError. I've used something like this:
THE_CLASSPATH=
for i in `ls ./lib/*.jar` do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
java -classpath ".:${THE_CLASSPATH}" Server
Client machine:
To run the Client.class file from the client machine, I had to copy the .jar files to it, and make reference to them in the classpath, because otherwise, it does not run and I get the java.lang.NoClassDefFoundError. I had to use this on the client machine:
THE_CLASSPATH=
for i in `ls ./lib/*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
java -classpath ".:${THE_CLASSPATH}" HelloClient
Is this ok? I mean, do I have to copy the .jar files to the client machine to execute methods through RMI?
Prior to JDK v5 one had to generate the RMI stubc using the rmic (RMI Compiler). This is done automatically from JDK v5 on. Moreover, you can start the RMI Registry from within the Java code as well. To start with a simple RMI application you may want to follow the following steps:
Create the interface:
import java.rmi.*;
public interface SomeInterface extends Remote {
public String someMethod1() throws RemoteException;
public int someMethod2(float someParameter) throws RemoteException;
public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException;
}
Implement the interface:
import java.rmi.*;
import java.rmi.server.*;
public class SomeImpl extends UnicastRemoteObject implements SomeInterface {
public SomeImpl() throws RemoteException {
super();
}
public String someMethod1() throws RemoteException {
return "Hello World!";
}
public int someMethod2( float f ) throws RemoteException {
return (int)f + 1;
}
public SomeStruct someStructTest(SomeStruct someStruct) throws RemoteException {
int i = someStruct.getInt();
float f = someStruct.getFloat();
someStruct.setInt(i + 1);
someStruct.setFloat(f + 1.0F);
return someStruct;
}
}
Implement a non-primitive serializable object that is to be passed between a client and the server:
import java.io.*;
public class SomeStruct implements Serializable {
private int i = 0;
private float f = 0.0F;
public SomeStruct(int i, float f) {
this.i = i;
this.f = f;
}
public int getInt() {
return i;
}
public float getFloat() {
return f;
}
public void setInt(int i) {
this.i = i;
}
public void setFloat(float f) {
this.f = f;
}
}
Implement the server:
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.net.*;
import java.io.*;
public class SomeServer {
public static void main(String args[]) {
String portNum = "1234", registryURL;
try{
SomeImpl exportedObj = new SomeImpl();
startRegistry( Integer.parseInt(portNum) );
// register the object under the name "some"
registryURL = "rmi://localhost:" + portNum + "/some";
Naming.rebind(registryURL, exportedObj);
System.out.println("Some Server ready.");
} catch (Exception re) {
System.out.println("Exception in SomeServer.main: " + re);
}
}
// This method starts a RMI registry on the local host, if it
// does not already exist at the specified port number.
private static void startRegistry(int rmiPortNum) throws RemoteException{
try {
Registry registry = LocateRegistry.getRegistry(rmiPortNum);
registry.list( );
// The above call will throw an exception
// if the registry does not already exist
} catch (RemoteException ex) {
// No valid registry at that port.
System.out.println("RMI registry is not located at port " + rmiPortNum);
Registry registry = LocateRegistry.createRegistry(rmiPortNum);
System.out.println("RMI registry created at port " + rmiPortNum);
}
}
}
Implement the client:
import java.io.*;
import java.rmi.*;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
public class SomeClient {
public static void main(String args[]) {
try {
String hostName;
String portNum = "1234";
String registryURL = "rmi://localhost:" + portNum + "/some";
SomeInterface h = (SomeInterface)Naming.lookup(registryURL);
// invoke the remote method(s)
String message = h.someMethod1();
System.out.println(message);
int i = h.someMethod2(12344);
System.out.println(i);
SomeStruct someStructOut = new SomeStruct(10, 100.0F);
SomeStruct someStructIn = new SomeStruct(0, 0.0F);
someStructIn = h.someStructTest(someStructOut);
System.out.println( someStructIn.getInt() );
System.out.println( someStructIn.getFloat() );
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
A larger client-server application should be divided into three modules:client, server, and common (for classes shared between the server and client code, i.e. the remote interface and the non-primitive object in this example). The client application will then be created from client + common modules on the classpath and the server from server + common modules on the classpath.
I used this example many years ago to learn basics of RMI and it still works. However it is far from being perfect (default Java package used, incorrect exception handling, hostname and port parameters are hard-coded and not configurable, etc.)
Nevertheless, it is good for starters. All the files can be placed in one directory and compiled using the simple javac *.java command. The server application can then be started using the java SomeServer and the client one by launching the java SomeClient command.
I hope this helps to understand the Java RMI which is, in fact, far more complicated than just this.
You shouldn't be generating stubs (if you are following a tutorial, it is way old). you can run the client without necessarily having the jars locally (using remote classloading), but it's way easier to do it this with the jars available locally (i've personally done a fair bit of RMI and never actually deployed a system with remote classloading). typically, you want 2 jars, a "client" jar with just the remote interfaces (and any Serializable classes used by those interfaces) and a "server" jar which includes the implementation classes. you would then run the server with the server jar, and the rmiregistry/client with the client jars.
This is a pretty good (up to date and simple) getting started guide.
To say it in short what the other answers elaborated:
The client needs only the common interfaces (and the client classes), not the server implementation.
The server needs interfaces and implementation (and your server main class).
The rmiregistry needs only the interfaces.
(Actually, you can start your own registry inside the server process - then you don't need the rmiregistry at all. Have a look at the createRegistry methods in the java.rmi.registry.LocateRegistry class.)
"Interfaces" here means both the remote interfaces and any (serializable) classes used by these as parameter or argument types.
How you distribute these classes to jar files is independent of this.

Problem with Apache's Java XMLRPC library

So i'm trying to get my Apache xmlrpc client/server implementation to play ball. Everything works fine except for one crucial issue:
my handler class (mapped through the properties file org.apache.xmlrpc.webserver.XmlRpcServlet.properties) reacts as it should but it's constructor is called at every method invocation. It would seem that the handler class is instantiated at each call which is bad because I have data stored in instance variables that I need to save between calls.
How do I save a reference to the instantiated handler so that I can access it's instance variables?
So, for anyone else who still wants to use XMLRPC here's how I fixed this issue:
http://xmlrpc.sourceforge.net/
far superior to apache xmlrpc, in my opinion.
This is standard behaviour of Apache XMLRPC 3.x. http://ws.apache.org/xmlrpc/handlerCreation.html:
By default, Apache XML-RPC creates a new object for processing each
request received at the server side.
However, you can emulate the behaviour of XMLRPC 2.x, where you registered handler objects instead of handler classes, using a RequestProcessorFactoryFactory. I have written a custom RequestProcessorFactoryFactory that you can use:
public class CustomHandler implements RequestProcessorFactoryFactory {
Map<Class<?>, RequestProcessorFactory> handlers =
Collections.synchronizedMap(
new HashMap<Class<?>, RequestProcessorFactory>());
#Override
public RequestProcessorFactory getRequestProcessorFactory(Class pClass)
throws XmlRpcException {
return handlers.get(pClass);
}
public void addHandler(final Object handler) {
handlers.put(handler.getClass(), new RequestProcessorFactory() {
#Override
public Object getRequestProcessor(XmlRpcRequest pRequest)
throws XmlRpcException {
return handler;
}
});
}
}
This can then be used with e.g. a XMLRPC WebServer like this
WebServer server = ...
PropertyHandlerMapping phm = new PropertyHandlerMapping();
server.getXmlRpcServer().setHandlerMapping(phm);
Custom sh = new CustomHandler();
phm.setRequestProcessorFactoryFactory(sh);
Object handler = ... /** The object you want to expose via XMLRPC */
sh.addHandler(handler);
phm.addHandler(serverName, handler.getClass());
Maybe something to do with javax.xml.rpc.session.maintain set to true?
I know this is a really old post but I managed to solve the problem with Apache's Java XML-RPC.
First, I thought this could be solved with singleton class in Java but it doesn't work and throws "illegal access exception".
These are what I have done:
public class XmlRpcServer {
private static JFrame frame = new JFrame();
private static JPanel pane = new JPanel();
public static XmlRpcServer singleton_inst = new XmlRpcServer();
public XmlRpcServer() {
// I kept the constructor empty.
}
public static void main(String[] args) throws XmlRpcException, IOException {
// In my case, I put the constructor code here.
// Then stuff for XML-RPC server
// Server Part
WebServer ws = new WebServer(8741);
PropertyHandlerMapping mapping = new PropertyHandlerMapping();
mapping.addHandler("SERVER", singleton_inst.getClass());
ws.getXmlRpcServer().setHandlerMapping(mapping);
ws.start();
////
}
// I called doTheJob() from python via XML-RPC
public String doTheJob(String s) throws XmlRpcException {
loop();
return s;
}
// It executed loop() forever
private static void loop() throws XmlRpcException {
// Actual work is here
}
But metaspace increases gradually:
I worked too much on this metaspace issue when looping forever in Java but I couldn't figure out a solution.

Categories