I am new in Java and JavaRMI so a have some doubts about how its works, see below:
public interface Something implements Remote {...}
public SomeStub extends UnicastRemoteObject implements Something {...}
Every time when I create and bind (registry.rebind(...)) one object of SomeStub I am creating a new ServerSocket to listen calls only for this object?
Example:
registry.rebind("...", new obj1);
registry.rebind("...", new obj2);
registry.rebind("...", new obj3).
2) So if the question 1 is true, is better use just only one stub of this object and threads to avoid create lots of serversockets?
PS: I am using the default serversocket and socket factories provided by the JavaRMI.
Every time when I create and bind (registry.rebind(...)) one object of SomeStub I am creating a new ServerSocket to listen calls only for this object?
No. Every time you export a new remote object RMI attempts to do port sharing, and creates a new ServerSocket only if it doesn't already have one it can share with the new object.
Binding has nothing to do with it.
NB This is not a stub. It is a remote object, and it has its own stub created by RMI. Don't misuse standard naming. Call it something else.
So if the question 1 is true
It isn't.
is better use just only one stub of this object and threads to avoid create lots of serversockets
No.
Related
I have a small application containing a number of classes. The application is designed to connect to a server and send / recv binary protocol msgs.
I have this part working using a connection manager class and a message processor class. The connection manager gets instantiated and creates 2 threads one to send and one to recv msgs. On receipt of a message a new message processor object is instantiated to handle the parsing of the message.
I have now created a GUI that has connect, logon etc... buttons.
The gui creates an instance of connection manager and when the connect button is presses it calls connection manager.connect.
When the logon button is pressed it calls connection manager.logon.
the connection manager object has a Boolean called connected.
so the gui can read connection manager.connected and see true/false. now what I need to be able to do is access connection manager.connected from my message processor object which gets created inside connection manager each time a message is received. So if message processor sees a logon ack message it can set connection manager.connected = true and the GUI which created the connection manager object can read the value.
However I cant see how I can access connection manager.connected from the message processor object. I think this is possibly a flaw in my design?
code examples.
GUI creates connection manager object reading in GUI text fields
cm = new ConnectionManager(jTextField1.getText(), jTextField2.getText())
Connection Manager has a Boolean connected. It also creates a read and write from network thread
public boolean connected;
executor.execute(new MessageProcessor(header, message, msgType));
Inside MessageProcessor I want to update cm.connected - is this possible?
Thanks
Did you create the MessageProcessor yourself? If so you could add a parameter in constructor and send a reference to the ConnectionManager:
executor.execute(new MessageProcessor(header, message, msgType, this));
Then the MessageProcessor will be able to access connected through ConnectionManager.
MessageProcessor should hold a reference to its calling ConnectionManager. You can pass the reference in the constructor of MessageProcessor and store it in an instance variable:
public class MessageProcessor {
private ConnectionManager cm;
public MessageProcessor(ConnectionManager cm) {
this.cm = cm;
}
public void process() {
cm.setConnected(false);
}
}
instantiating a MessageProcessor:
public class ConnectionManager {
public void connect() {
MessageProcessor pm = new MessageProcessor(this);
}
public void setConnected(boolean connected) {
this.connected = connected;
}
}
of course you have coupled MessageProcessor and ConnectionManager. There are (rather) complex solutions that allow you to "decide" at run time between implementations of MessageProcessor and ConnectionManager. These include the factory patter and dependency injection.
how are you planning to access cm from your MessageProcessor object? it's also about the communication between objects. If you have only one ConnectionManager for your send/receive threads and if you always have one pair of threads (send/receive), you can simply use public static boolean connected and upon establishing a connection you can set it to true. This is not a good solution of you have multiple thead-couples (for send/receive activities). I almost forgot until someone pointed it out, you can pass on a parameter this - reference to who is calling MessageProcessor constructor. However, this is still not very good as any change in class definition will hurt the implementation in MessageProcessor.
In simple word, yes it is possible to access/mutate connected from your MessageProcessor - you should also consider using synchronized methods to access/mutate connected. But if you need to make the solution better, you need to consider using individual connectionManager objects. #sharonbn has already shown you some examples of how to go about doing this.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
hi i have searched the internet for a long time trying to find some thing that talk about how to start rmi registry in windows 7 using cmd so if any one know how to do that pleas let me to know how to do it or if any one can provide us a good link for that... thx in advance
ok thanx for all how answered my question when i asked the question i was not fully understand the RMI system or how it work but know i have good idea i will summarized this for provide all with an idea for the RMI system and if i have any mistake please correct me
so
Remote Interface:
We need an interface that extends from the Remote class and defined the method that we would like to invoke remotely
note:
Remote is a "marker" interface that identifies interfaces whose methods may be invoked from a non-local virtual machine.
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Calendar;
public interface CalendarTask extends Remote {
Calendar getDate() throws RemoteException;
}
The Remote Object:
We need class that create a Remote object's so we crate class object implement the Remote Interface to make the object's that created by this class object remote object's and we link this object's to the RMI System by extends from this class UnicastRemoteObjec so When a class extends from UnicastRemoteObject, it must provide a constructor declaring this constructor calls super(), it activates code in UnicastRemoteObject, which performs the RMI linking and remote object initialization.
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Calendar;
public class CalendarImpl extends UnicastRemoteObject implements CalendarTask {
private int counter = 1;
public CalendarImpl() throws RemoteException {}
public Calendar getDate() throws RemoteException{
System.out.print("Method called on server:");
System.out.println("counter = " + counter++);
return Calendar.getInstance();
}
}
Writing the Server:
3.1 The server's job is to accept requests from a client, perform some service, and then send the results back to the client.
3.2 The server must specify an interface that defines the methods available to clients as a service. we do that above in the first step (Remote Interface)
3.3 The server creates the remote object, registers it under some arbitrary name, then waits for remote requests
3.4 so for register The remote object we use java.rmi.registry.LocateRegistry class allows the RMI registry service (provided as part of the JVM) to be started within the code by calling its createRegistry() method.
3.5 The java.rmi.registry.Registry class provides two methods for binding objects to the registry.
• Naming.bind("ArbitraryName", remoteObj);
throws an Exception if an object is already bound under the "ArbitrayName".
• Naming.rebind ("ArbitraryName", remoteObj);
binds the object under the "ArbitraryName" if it does not exist or overwrites the object that is bound.
3.6 The example on the following acts as a server that creates a CalendarImpl object and makes it available to clients by binding it under a name of "TheCalendar"
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
public class CalendarServer {
public static void main(String args[]) {
System.out.println("Starting server...");
// Start RMI registry service and bind
// object to the registry
try {
LocateRegistry.createRegistry(1099);
Naming.rebind("TheCalendar",
new CalendarImpl());
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
System.out.println("Server ready");
}
}
Writing the Client:
4.1 An RMI client is a program that accesses the services provided by a remote object
4.2 The java.rmi.registry.LocateRegistry class allows the RMI registry service to be located by a client by its getRegistry() method
4.3 The java.rmi.registry.Registry class provides a lookup() method that takes the "ArbitraryName" the remote object was bound to by the server.
Once the client obtains a reference to a remote object, it invokes methods as if the object were local
import java.rmi.registry.*;
import java.util.Calendar;
public class CalendarClient {
public static void main(String args[]) {
Calendar c = null;
CalendarTask remoteObj;
String host = "localhost";
if(args.length == 1)
host = args[0];
try {
Registry r =
LocateRegistry.getRegistry(host, 1099);
Object o = r.lookup("TheCalendar");
remoteObj = (CalendarTask) o;
c = remoteObj.getDate();
} catch (Exception e) {
e.printStackTrace();
}
System.out.printf("%tc", c);
}
}
The code you have written doesn't start a registry. LocateRegistry.getRegistry() doesn't do that. Check the Javadoc. It assumes the Registry is already running. LocateRegistry.getRegistry() just constructs a Registry stub according to the host and port you provide. It doesn't even do any network operations.
To start a Registry from within your JVM, use LocateRegistry.createRegistry(), as its Javadoc states.
EDIT: There's a lot of misinformation in your edit.
Remote is a "marker" interface that identifies interfaces whose methods may be invoked from a non-local virtual machine.
Only if implemented by an exported remote object whose stub has been transmitted to that VM. The remote interface itself doesn't have any such magical property. All methods defined in a remote interface must be declared to throw RemoteException, although the implementations of these methods generally don't need to be so declared (i.e. unless they perform remote operations themselves: the compiler will tell you).
We need class that create a Remote object's so we crate class object implement the Remote Interface to make the object's that created by this class object
Far too much confusion here. We need a class. The class must implement the remote interface. This is not an 'object' yet: it is a piece of code that must be compiled to a .class file. A class doesn't 'make objects'. An application does that, with the new operator.
we link this object's to the RMI System by extends from this class UnicastRemoteObjec so When a class extends from UnicastRemoteObject, it must provide a constructor declaring this constructor calls super(), it activates code in UnicastRemoteObject, which performs the RMI linking and remote object initialization
There is no 'link' step in RMI. There is an 'export' step. It is performed either by extending UnicastRemoteObject or by calling UnicastRemoteObject.exportObject(). If you don't extend UnicastRemoteObject you don't need the constructor you described.
The server's job is to accept requests from a client, perform some service, and then send the results back to the client.
The server's job is to implement the methods in the remote interface. RMI does all the rest for you.
The server creates the remote object, registers it under some arbitrary name, then waits for remote requests
Or else the server is the remote object and it registers itself.
for register The remote object we use java.rmi.registry.LocateRegistry class allows the RMI registry service (provided as part of the JVM) to be started within the code by calling its createRegistry() method.
Or you can use an external Registry via the rmiregistry command. Or you can use an LDAP server via JNDI.
LocateRegistry.createRegistry(1099);
Naming.rebind("TheCalendar",
new CalendarImpl());
This won't work unless you store the result of createRegistry() into a static variable. And having stored it, you may as well use it to do the bind, instead of using the Naming class. If you don't store it into a static variable it will be garbage-collected and so will the remote object.
The java.rmi.registry.LocateRegistry class allows the RMI registry service to be located by a client by its getRegistry() method
Or you can use the Naming class, see below.
The java.rmi.registry.Registry class provides a lookup() method that takes the "ArbitraryName" the remote object was bound to by the server.
So does the Naming class. It takes an rmi: URL which specifies the host and port and bind-name. You can omit the rmi:// part. If you omit the host it defaults to 'localhost', but this is only useful if the client is running in the same host as the server, which isn't itself very useful. If you omit the port it defaults to 1099.
I have a certain problem: I'm using RMI to communicate between server and client.
public class RemoteMap
extends java.rmi.server.UnicastRemoteObject
implements RemoteMapInterface {
private TreeMap<String, GeneralSprite> sprites;
...
This is my remote object. But I want the client to be able to change this object's content. And after the change the server can execute some operation based on this.
Example at the client side:
map = (RemoteMapInterface) (registry.lookup("map"));
map.getSprites.get("object1").setDx(-1);
I'm using serialiable on the GeneralSprite, but I guess it passed by value. So when I did some changes at the GeneralSprite, it wasn't transported to the server . Do I have to make GeneralSprite to an Remote object too? Or is it even possibly?
Thanks in advance, and sorry for my bad english, I hope you can understand.
Everything which does not implement the Remote interface, whether directly or indirectly, will get serialized for the remote method invocation. So it’s a “call-by-copy” behavior. You can implement a new Map which implements Remote, but you can also add a method like setDx(String spriteName, int value) to your RemoteMapInterface and implement it as sprites.get(spriteName) .setDx(value); on the server side.
Scenario:
Client C connects to Server S via RMI
C asks S to create a handler H, S returns H to C
C then talks to H
Now I could do this in two ways:
Make the handler a Remote and let S return the stub to it, so C can directly talk to that (h.say(String msg);)
Give the handler an ID and return that to C. C will talk to H via S (s.sayToHandler(int id, String msg);)
The first is nicer OO, but what about the performance? Will an extra TCP connection be opened, or is the existing connection between S and H used?
I don't know about the implementation. I don't think a new connection is made. But what I know is the more objects you share remotely the more objects that depends on remote dereference to get garbage collected (so there will be more objects living longer, not good).
Alternative approach
I'll recommend a mixed approach. Use the nice approach for the client but implement it the not-so-nice-way internally:
interface Server {
public Handler getHandler(...);
}
interface Handler extends Serializable {
// it gets copied!
public X doThis(...);
public Y doThat(...);
}
class HandlerImpl implements Handler {
public X doThis(...) {
backDoor.doThis(this, ...);
}
public Y doThat(...) {
backDoor.doThat(this, ...);
}
private BackDoor backDoor;
}
interface BackDoor {
public X doThis(Handler h, ...);
public Y doThat(Handler h, ...);
}
class ServerImpl imlpements Server, BackDoor {
public Handler getHandler(...) {
return /*a handler with a self reference as backdoor, only ONE remote obj shared via TWO interfaces */
}
...
// it does everything
// it receives the handler
}
BackDoor and Handler are sync'ed interfaces. The first has the methods with Handler as argument, the later has the pure methods. I don't think it's a big deal. And the two different interfaces let you work cleanly without the client know nothing and allowing the thin serializable Handler's do the dirty work.
Hope you like it!
The RMI specification does not really say whether there should be a new connection or the existing one reused. The wire protocol allows both, using either multiplexing or one TCP connection per call (which might be reused for following calls to the same sever object, I'm not sure). If you need tunneling through HTTP, than only one message per connection is allowed.
I did not find anything on how to configure which type of protocol to use (other than disabling HTTP tunneling).
If you want to make sure that only one TCP connection is used, use custom client and server socket factories doing the tunneling of multiple connections though one themselves. This will probably be less efficient than what the RMI runtime system would be doing there.
I've created a generic 'SocketServer' class in java which takes the following arguments:
String address, int port, Class socketProtocol, String encryptionType, int backlogSize
Basically, I want other developers to be able to instance this class in their projects and set some simple options for encryption, backlog, address, port.. at which point they have to design the protocol. SocketProtocol is an interface which enables sendMessage and receiveMessage (along with a few others).
At this point, the user of the class should just implement SocketProtocol and pass the class (i.e. MySocketProto.class) to the SocketServer instance, which will in turn instance a copy of the protocol for each incoming connection via .newInstance();
Does this make sense? Is there an easier way to establish this type functionality? I don't like the idea of passing the class type to the server, it just seems odd.
Thanks all,
Chris
I would use the Factory pattern in this situation. The linked Wikipedia example is a bit verbose, but it can be really simple:
public interface ISocketProtocolFactory {
ISocketProtocol buildProtocol();
}
Your SocketServer constructor would then take an instance of something implementing ISocketProtocolFactory, and ask it for new ISocketProtocols as it goes.
This will give your users a lot more flexibility in constructing the ISocketProtocol instances, take care of the 'nastiness' of having a class parameter.
I would assume that each port would have it's own protocol. With that in mind you would specify it for the port.
The way I had done it in the past is to have the implementors pass in a class that inherits from:
public Interface ProtocolInterface
{
public void serve(InputStream in, OutputStream out) throws IOException
...
where the InputStream and OutputStream are the input and outputs to the Socket