RMI - create thread on server to serve client - java

I'm developing a application using rmi which allow client to login, perform some task and logout. I know that each client is considered as one thread when it call a method on server, however, all clients' threads call to the same object created on server. So now, I want to for each client login successfully, a new thread is created (and a new object, which is used by only one client, is binded, too), a thread terminates when client logout. Hence, each client has its own server's object to work with.
Thank you very much.
Cheers

I know that each client is considered
as one thread when it call a method on
server
That's not correct. The relationship between clients and server threads is undefined in RMI.
In any case you don't need a thread per client. You need a remote object per client. This is a job for the Session pattern:
public interface Login extends Remote
{
Session login(String credentials) throws RemoteException;
}
public interface Session extends Remote
{
// Your API here
}
Have your Login implementation object return a new Session implementation object for every client.

Related

Tomcat Websockets Across Multiple Servers

Current Solution
I have a Java server (Tomcat) setup issue that I'm hoping someone can provide some guidance on. Currently my web application is a single-server that has a Java backend running on Tomcat 8.5. To handle Websocket connections, I keep a Map of all the javax.websocket.Session passed in the onOpen() method.
#ServerEndpoint("/status")
public class StatusMessenger
{
private static ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap();
#OnOpen
public void onOpen(Session session) throws Exception
{
String sessionId = session.getRequestParameterMap().get("sessionId").get(0);
sessions.put(session.getId(), session);
}
My application only broadcasts messages to all users, so the broadcast() in my code simply loops through sessions.values() and sends the message through each javax.websocket.Session.
public static void broadcast(String event, String message)
{
for (Session session: sessions.values())
{
// send the message
}
}
I'm not even sure that's the correct way to handle Websockets in Tomcat, but it's worked for me for years, so I assume it's acceptable.
The Problem
I want to now horizontally scale out my application on AWS to multiple servers. For the most part my application is stateless and I store the regular HTTP session information in the database. My problem is this static Map of javax.websocket.Session - it's not stateless, and there's a different Map on each server, each with their own list of javax.websocket.Sessions.
In my application, the server code in certain situations will need to broadcast out a message to all the users. These events may happen on any server in this multi-server setup. The event will trigger the broadcast() method which loops through the javax.websocket.Sessions. However, it will only loop through the sessions in it's own Map.
How do I get the multi-server application to broadcast this message to all websocket connections stored across all the servers in the setup? The application works fine on a single-server (obviously) because there's only 1 list of websocket sessions. In other words, how do I write a stateless application that needs to store the websocket connections so it can communicate with them later?
I found 2 alternative solutions for this...
In my load balancer I put a rule to route all paths with /{my websocket server path} to 1 server so that all the Sessions were on the same server.
Use a 3rd party web push library like Pusher (http://pusher.com)

Understanding java RMI exportObject method

I'm very new to RMI and I just decided to give it a try. I got confused by the exportObject(Object, int) method. The documentation says:
Exports the remote object to make it available to receive incoming
calls, using the particular supplied port. The object is exported with
a server socket created using the RMISocketFactory class.
Consider the following simple example:
public interface Client extends Remote {
void clientMethod() throws RemoteException;
}
public class ClientImpl implements Client {
public clientMethod() throws RemoteException {
System.out.println("clientMethod invoked");
}
}
Client stub = (Client) UnicastRemoteObject
.exportObject(new ClientImpl(), 56789); //<------ HERE
So we create a stub and will transfer it to another VM either manually or through RmiRegistry, doesn't matter here.
I'm confused by "[...] the object is exported with a server socket [...]"
What do they mean by that?
A ServerSocket is created to listen for incoming connections at the port you specified when exporting. This port can be shared between multiple remote objects.
The statement about the RMISocketFactory is incorrect. Where did you read that? This class has been obsolete since 1998.
The stub contains the server's hostname or IP address and port number, and some internal data to identify the remote object it belongs to.
TCP connections between the stub and the remote object are created on demand when you call remote methods, via a connection pool.
So, when we transfer the stub to another VM (VM 0), the stub will hold a socket connection to the VM (VM 2) it was originally created on.
No, see above.
The VM 2 in turn will maintain a server socket to accept incoming method invocations.
Correct.

Webservice client creation approach

I am using following approaches to create web service client. I could likte to know if connection between client and server is established after creating stub instance like followings.
Otherwise Is connection between client and server established after invoking Remote method calling such as stub.xxxmethod(), myervicePort.xxxMetho()
RPC/Encoded
stub = new MyWsRPCPortStub(new URL(), new MyWsRPCLocator());
stub.setTimeout(pdbTimeout);
Document/Literal
MyServicePort myervicePort = service.getMyServicePort();
After learning the above question I am going to decide when stub instance will be created? I mean there will be two ways:
1- create only one stub instance in application ,I mean I will use singleton pattern
2- create stub instance before invoking a method call each time
What if I use only one stub instance with multithread appiication, each thread open difference sockets at the same time while invoking stub.xxMethod()
At the same time
T1->stub.xxMethod()
T2->stub.xxMethod()
T3->stub.xxMethod()
First of all the approcahes you have mentioned to consume web service in a client do not depend on wether the web service style is RPC or Document Literal. The client is the same for both styles. These styles merely determine how the SOAP message exchanged between client and server is structured. A post to get started on it:-
here.
Messages are sent between the client and server using the SOAP protocol running over HTTP. Hence the communication between client and server should be mainly looked at as a normal HTTP request/response model rather than when and how the connection between them is established and maintained which is the job of underlying TCP protocol; and the API in the web service client and the underlying OS completely abstract away these details for us.
However if you would like to know when a HTTP request is made by a web service client; you can trace it using any of the packet capture tools like 'wireshark' for example.Typically if you have a web service with just one method; there is usually a HTTP GET request made when you use the Service service = Service.create(url, qname) api and a HTTP POST on YourWSInterface.xxxmethod().
About when to create a stub; in a multithreaded environment; if you are going to use the BindingProvider on the client stubs to set data(and not just mere read only calls) before sending to the webservice; yes; you would need some syhcnronization in the client code(with a single instance) or create a pool of client proxies(multiple pooled instances); depending on the requirements of your app.
I hope i have answered the question.

Sending socket from Listener Service to Worker Service in a Server program in Android

I am new to android programming. I writing a client server program. I want to create ServerService which listen for incoming connections, once request comes from the client it creates two other services SendService and ReceiveService to write and read from the socket in two different threads. Hence I derived these services from IntentService. How to pass socket information to SendService and ReceiveService? Can I have a simple member variable in these two services and set it from ServerService? If so how to set this value? Using getBaseContext()?
A service is just a class that extends Service, you can have the same tool set as any class. So your answer is yes, and you assign it via your preferred method.

Pass Remote object in method to RMI server?

I have an RMI client that connects to some RMI server just to let it know it can use this new client.
Can I pass directly some Remote object so that:
serverRemoteObject.registerClient(theClientRemoteObjectTheServerShouldUse);
will actually give the server some object he can use without connecting to my client?
The following question says it is possible, but no real example was given:
Is it possible to use RMI bidirectional between two classes?
Andrew
Yes, you can. This is how exactly callbacks work in case of RMI. You send across an object to the server and when the server invokes a method on your object, it would be executed in the "client" JVM as opposed to on the server. Look into UnicastRemoteObject.export method for export any object which implements the Remote interface as a remote object which can be passed to your server.
interface UpdateListener extends Remote {
public void handleUpdate(Object update) throws RemoteException;
}
class UpdateListenerImpl implements UpdateListener {
public void handleUpdate(Object update) throws RemoteException {
// do something
}
}
//somewhere in your client code
final UpdateListener listener = new UpdateListenerImpl();
UnicastRemoteObject.export(listener);

Categories

Resources