How to properly identify and hold client references in RMI callback? - java

I have a server and several "clients" (servers actually because of callbacks). A client can send a message to another only through the server. For this, the server must:
Identify the calling client.
Hold the clients' information and exported object reference so it is able to lookup the recipient.
I have read on the Remote Session pattern (1, 2, 3) and here and here, but I couldn't find the answer I was looking for.
For (1), I see the following options:
The client sends its exported object reference during the call to the server.
The client sends some identification information during the call to the server.
The client is identified with getClientHost.
The recipient must be sent as some identification information since clients do not hold a reference to each other.
public interface RemoteClient extends Remote {
void message(String sender, String message);
}
public interface RemoteServer extends Remote {
void relayMessage(String recipient, RemoteClient sender, String msg);
// or some identifier? // or string/identifier?
}
public class RemoteServerImpl extends UnicastRemoteObject implements RemoteServer {
void relayMessage(String recipient, RemoteClient sender, String msg) {
RemoteClient recp = lookup(recipient); // See point 2 below
String sndr = getRepresentation(sender); // See below...
recp.message(sndr, msg);
// OR using
String sndr = getRepresentation(getClientHost());
// Then sender parameter is not needed
}
}
I'm pretty sure getClientHost is not a reliable way of identifying the caller because it can disconnect and reconnect with a different IP, and I'm not sure if there are 2 computer in the same LAN that this method will be able to distinguish between them.
For (2), the options I see are:
Keep a Map of the identification information and the clients' exported objects (as mentioned, but not recommended, in one of the above answers).
Keep a Set of client information objects where these objects hold the remote object reference and whatever relevant information.
These are updated during login (registration) and logout.
Then lookup takes the information and returns the remote object reference and getRepresentation is similar to a reverse lookup.
My problem is not to make it work (it's working), it's to make it work correctly. Is there any advantage or preferred way from the above or otherwise?

You don't appear to have understood the remote session pattern at all. The session object the client is calling remote methods on is unique to the client, so there is no necessity for it to further identify itself during subsequent calls to the session. Whatever information the client sent to the login object to obtain the session can be stored in the session object, or the server can assign a unique client ID itself. The session object should also contain the callback of course: it's the only sensible place to put it.

Related

DDD: How to hide specific aggregate root constructors from integration layers in Kotlin

I'm kinda new on DDD and even after read the blue and red book I still have some questions about how to transform some principles to code, specifically using Kotlin and Java.
For example, I identify a Client aggregate root that receive some parameters need it for the creation like Name and Address:
class Client: AggregateRoot {
var clientId: ClienteId
var name: Name
var address: Address
constructor(name: Name,address: Address) : super(){
// validations ....
this.name = name
this.address = address
}
Easy part:
To create a new Client I receive a DTO inside the RS service and try to create a new Client class passing the parameters above, case everything was solid and all rules fulfilled I send the new instance of Client to the repository, pretty straight foward.
clientRepository.store(client)
Other part:
I need to search my Client to change the address so I send the id to the repository and find the Client inside the database then I need to convert the database entity to the aggregate root and return to the caller.
override fun getById(id: Long): Client {
val clientEntity = em.find(...)
val client: Client(.....) //But I need another constructor with ClientId
return client
}
Then I will need a new constructor one that receive more parameters like the ClientId
constructor(clientId: ClienteId,name: Name,address: Address) : super(){
The problem is that every service can call this new constructor and create a incorrect instance of my aggregation root, so my questions are:
Is there a way to hide the complete constructor just for the repository or specific layers to see. Like in C# when you could use internal.
Is there any solution for Java or Kotlin to not expose this constructor that should be used just on tests and integrations ?
Another example is if I didn't need the address to be passed every time a client is created but just after in another method like:
client.addAddress(address)
But in both cases I will need to fulfill the entire Client from the database so I will need a second constructor with the address parameter.
So, the problem is how to rehydrate an Aggregate from the persistence without breaking its encapsulation by exposing the wrong interface to the client code (i.e. the Application layer or the Presentation layer).
I see two solutions to this:
Use reflection to populate the fields. This is the solution that most ORMs use and it is also the most generic. It works for most persistence types, even when there is an impedance mismatch. Some ORMs need to annotate fields or relations.
Expose a different interface to the client code. This means that your Aggregate implementation is larger that the interface and contains additional initialization methods used only by the infrastructure.
As an example in pseudo-code your could have:
// what you want the upper layers to see
interface Client {
void addAddress(address);
}
// the actual implementations
public class ClientAggregate implements Client
{
void rehidrate(clientId,name,address){...}
void addAddress(address){...}
}
public class ClientRepository
{
// this method returns Client (interface)
Client getById(id){
val clientEntity = em.find(...)
val client = new ClientAggregate()
client.rehydrate(clientEntity.id, clientEntity.name, clientEntity.address)
return client //you are returning ClientAggregate but the other see only Client (interface)
}
}
As a side note, I don't expose the constructor to create an Aggregate from the Domain point of view. I like to have empty constructors and a dedicated method, named from the Ubiquitous language, that creates the Aggregate. The reason is that is not clear that the constructor creates a new Aggregate. The constructor instantiate a new instance of a class; it is more a implementation details than a domain concern. An example:
class Client {
constructor(){ //some internal initializations, if needed }
void register(name){ ... }
}

Vaadin 7 send data from client to server

I am struggling to apprehend the way client and server communicate in vaadin 7. I have understood it well when it comes to server->client communication, but I still I cannot grasp how it works the other way round, namely from client to server. I have read that on the client side one should not change the State, but they should send the relevant data through rpc. On the client side there is a MyComponentClientRpc inteface which contains some methods and the developer should implement them in the Connector class. Then one can instantiate the inteface as anonymous class on server and can call the method. However in case one has a String "myString" on client how can it be transfered to the server, since one can only call the method on server passing the parameters on the time of calling it? How can then one get the data lying on client?
public interface MyComponentClientRpc extends ClientRpc {
public void getString(String s);
}
public class MyComponentConnector extends AbstractComponentConnector {
#SuppressWarnings("serial")
MyComponentClientRpc mcRpc = new MyComponentClientRpc() {
public void getString(String s) {
// TODO Do something useful
????
}
};
public MyComponentConnector() {
registerRpc(MyComponentClientRpc.class, mcRpc);
String a = "myString";
....
}
In particular, how does one implement the method on client, how does one insert the data in it and how should it be called on the server?
However in case one has a String "myString" on client how can it be
transfered to the server, since one can only call the method on server
passing the parameters on the time of calling it? How can then one get
the data lying on client?
You are using the wrong mechanism. There are actually two RPCs, ClientRpc and ServerRpc. In your example, you use ClientRpc, which is for calls from the server to the client.
To communicate from the client to the server, you have to extend from ServerRpc.
In the client, you call
MyComponentClientRpc rpc = RpcProxy.create(MyComponentClientRpc.class, this)
in order to get the proxy.

How to keep SSH connection available?

I'm writing an application which uses sshj library for SSH connections. User opens Connect Dialog from menu, types login data and clicks Connect button to establish a connection. Then the user performs various operations from different panels and frames. My question is: where should I keep this connection to make it available to every panel and frame that needs it until the user clicks Disconnect button? I thought about static field in some custom class but I'm not convinced to do so. What are your ideas?
It sounds like you are interested in some type of pool.
You can do this in different ways. One way is to have a class that handles all the connections, which is a singleton, sort of. Then you simply ask the pool for a connection, for instance
SSHConnection con = ConnectionPool.getConnection(host, port);
You could also use a proxy for this. In a proxy, you actually get a placeholder instead of the actual connection. The proxy shares information with other instances, sort of like
class ConnectionProxy {
private static SSHConnection connection;
}
the connection variable is shared, and when you create a new ConnectionProxy, you will actually get the old connection, but it looks like you get a new connection.
Another option is to simply pass the instance around to all classes that needs it. This will allow you to keep track of who does what, but you will loose the flexibility of getting a connection from wherever you want.
Passing an instance around will help if you are debugging though, think of it like this. You are in a crowded room and you have a some money laying in a box that needs a key to open. If you hand that key to one person (the class that needs it) and leave the room and come back and the money is gone, you can blame that person. If instead you just leave the key on the table next to the box (the instance is global) and leave the room, come back and the money is gone, then good luck finding out who took it.
References:
*] Proxy pattern - WikiPedia
Proxy example
More specifically, it could look something like this:
public class ConnectionProxy implements Connectable {
// where Connectable is some shared interface between ConnectionProxy
// and SSHConnection. The proxy should "look like" a connection, it just
// hides the actual connection behind the scenes.
private static SSHConnection connection;
public ConnectionProxy() { }
public ConnectionProxy(String host, int port) {
connection = new SSHConnection(host, port);
}
public void connect(String host, int port) {
if (isConnected()) {
return;
}
connection = new SSHConnection(host, port);
}
public void reconnect() {
connection = new SSHConnection(connection.getHost(), connection.getPort());
}
public boolean isConnected() {
return connection != null && connection.isConnected();
}
}
You use the class by either instantiating it or connecting it.
class Program {
public void sendMessage() {
ConnectionProxy proxy = new ConnectionProxy();
if (!proxy.isConnected()) {
// I guess noone connected it
return;
}
proxy.sendBytes();
}
}
And in your connection dialog you instantiate or connect the ConnectionProxy. You could add support for several connections, i.e. different hosts and ports, just by making the variable connection a list instead, and checking the host and port for the right connection. You basically create a pool of connections, but to the client class it looks like it is creating the connection.
Doesn't matter where you put it, so long as you provide a getter method for retrieving it, and that getting method is public.
I think it's more a question of where it logically belongs. If it's a property of the application (as opposed to a window, frame, profile, whatever) put the getter in the main application class.
Design-wise, I'd recommend wrapping the operations you can perform over SSH in a separate class (RemoteCommands or some such), and injecting (setting as a property) an instance of this class everywhere you need to perform a remote command from.
If this seems like a lot of extra boilerplate code because every single frame and panel needs it, this shouldn't say "I need a global variable" to you. It should say "I should reduce the number of components that directly execute remote commands".

Restlet modify inbound object and return it or return new copy?

I'm trying to learn about restlets more coming from a soap-rpc background. One thing that I can't seem to figure out how to do (and maybe isn't possible) is to modify objects on requests or send back a copied version with modifications.
I'm trying to do something like this:
public interface AddressService {
#Get
Address addOnZipCode( Address address );
}
The server would be deployed out with the implementation and the client could make use of dynamic proxies to do its work.
The server starts just fine but when the client makes the call there is no indication on the server that the implementing method is being called. Furthermore, the client doesn't error until the call to the server returns - the returned object is null?!?
Is what I'm trying to do here possible with restlets? If so, any ideas on what I might be doing wrong?
I can post more code if necessary.
Thanks in advance.
EDIT #1:
I've even tried simplifying it to not use custom objects:
#Post
String execute( String message );
I get the following:
INFO: Starting the default HTTP client
Exception in thread "main" Method Not Allowed (405) - Method Not Allowed
at org.restlet.resource.ClientResource$1.invoke(ClientResource.java:1615)
at $Proxy5.execute(Unknown Source)
I'm beginning to think this is not possible, thus, I have a hard time seeing how this is a viable alternative to SOAP+RPC web services.
EDIT #2:
It looks like this is possible based on examples in the book: "Restlets in Action"
public interface AccountsResource {
#Get("txt")
public String represent();
#Post("txt")
public String add(String account);
}
EDIT #3:
It turns out that simply hitting the "stop" button in my Eclipse console was not shutting down the server instance. Opening a browser to the server URL showed some fishy results - there were multiple old server instances running. After shutting them all down I got it to work. Ultimately the answer was to use #Post instead of #Get1.
Have a look at this:
http://wiki.restlet.org/docs_2.0/13-restlet/21-restlet/318-restlet/303-restlet.html
On the server side your implementation must be like so:
class AddressServerResource extends ServerResource implements AddressService {
// implementation
}
On the client side:
ClientResource cr = new ClientResource("http://your-api.com/address/123");
AddressService service = cr.wrap(AddressService.class);
// use the service transparently
Edit:
#Post
Address addOnZipCode( Address address );

What is the best way to communicate with Bonjour?

There is a nice method provided by Bonjour: DNSSD.browse("_killerapp._tcp", this);. As the first argument of this method I give type of service which potentially can be available in the network, and as the second argument I give a "callback object". The considered method "browse" for the services of the indicated type (first argument).
During the browsing it can "find" and then "lose" a service. If service is found (lost) bonjour call serviceFound (serviceLost) method of the callback object. The serviceFound is called with some parameters of the found service. In more details:
serviceFound(DNSSDService browser, int flags, int ifIndex, String serviceName, String regType, String domain)
But to get the IP address and port of the service we need to do additional operation (people call it "to resolve a service"). This is logic is kind of strange to me. Why this information cannot be given by serviceFound? I mean why Bonjour cannot resolve the service automatically whenever it finds a service.
Anyway, I just accept the given logic and try to use it. From the serviceFound I call DNSSD.resolve(0, ifIndex, serviceName, regType, domain, this).
As before I give a callback object to the resolve (the last argument). Unfortunately I need to use different classes to provide the callback objects for browse and resolve. The reason for that is that browse and resolve can call a operationFailed method of the callback object and, if I use callback objects from the same class I will not know which method is calling the operationFailed (browse or resolve).
So, I create a separate class to instantiate a callback object for the resolve method. In this class I have a method called serviceResolved which is called by Bonjour with IP address and port of the resolved service:
serviceResolved(DNSSDService resolver, int flags, int ifIndex, String fullname, String hostname, int port, TXTRecord txtRecord)
I think that the IP address and port should be fields of the objects which perform browsing. So, in the serviceResolved I have IP and port and I want to set these values to the corresponding field of the instance which browse the service. But how can I do it? This instance is not given as an argument of the serviceResolved method. So, it is invisible!
Moreover, I see that serviceResolved and serviceFound take, as a first argument, DNSSDService resolver. Does anybody know what is it? May be this object can be used to set parameters of the service? I know that an object of this type is returned by the browse.
Not really an answer, but would like to point out that,
besides the Bonjour library, you may want to try JmDNS, which is a pure Java, open sourced module.

Categories