Recipe 1. How to distinguish clients on the server side.

As agreed on 29th Tango meeting let's start our collaborative work on the Tango Cookbook. And here is my first recipe:

How to distinguish clients on the server side


Problem overview

Some times Tango device is not just about talking with the hardware. Now-days a Tango device could be a sophisticated thing that performs complex work and serves numbers of clients simultaneously. And it might be required that the context of these clients may vary (context - a set of parameters of the task or result configuration etc). This is especially true due to multithreading reality we have.

Detailed cases

Client wants to specify in which format it receives an output from the server. Lets say it can be plain text or JSON or XML etc.

Server runs several tasks in parallel. One task per client. And each client wants to know its task ID, let's say to control or monitor the task's execution.

Solution overview

CORBA provides clnt_idnt, i.e. client identity. This can be used to create a concurrent map: ClientIdentity -> Context. And then each requests from the client can be served within the specified context.

Java:

//Server.java
     //ConcurrentMap to hold each client's context
     private final ConcurrentMap<String, RequestContext> ctxs =  Maps.newConcurrentMap();

    //see Tango Java API for deviceManagment
    @DeviceManagement
    private DeviceManager deviceManager;

    //this will be an attribute, each client will see its own value
    @Attribute
    //this method returns client identity from CORBA as String
    public String getClientId() throws Exception {
        //deviceManager exports CORBA's client identity feature
        return ClientIDUtil.toString(deviceManager.getClientIdentity());
    }
 
    //command that returns its result in the format defined in the client's context
    @Command
    public String doJob() throws Exception {
        String clientId = getClientId();
        RequestContext ctx = ctxs.get(clientId);
        switch(ctx.outputType){
            case OutputType.PLAIN:
                return plainResult();
            case OutputType.JSON:
                return jsonResult();
        }
    }


//RequestContext.java
//NOTE this class must be thread safe
@Immutale
public class RequestContext {
        //OutputType is an enum
        public final OutputType outputType;

        public RequestContext(OutputType outputType) {
            this.outputType = outputType;
        }

        /**
         * Creates default context
         */
        public RequestContext() {
            this(OutputType.PLAIN);
        }
    }

CPP:

TODO

Python:

TODO


So this is it – my first receipt for Tango Java server.

CPP and Python guys could you provide similar examples for your languages?

Any input is welcome!!!

Cheers,

Igor.
Edited 8 years ago
UPDATE:

Since revision 28455 DeviceManager#getClientIdentity is deprecated.

So the new way of obtaining client identity looks like this:


// local field to pass clienId across method calls
private String clientId;
    
@AroundInvoke
public void aroundInvoke(InvocationContext ctx){
    clientId = ClientIDUtil.toString(ctx.getClientID());
}

NOTE: currently there is an issue #738 which breaks this functionality for commands

NOTE: aroundInvoke does not work with pipes: issue #739

NOTE: currently (JTangoServer-9.0.5) it is not possible to use clientId with TransactionMode=NONE
Edited 8 years ago
Since JTangoServer-9.0.7 one can obtain clientIdent like this:


// local field to pass clienId across method calls
private ThreadLocal<String> clientId;
    
@AroundInvoke
public void aroundInvoke(InvocationContext ctx){
    clientId.set(ClientIDUtil.toString(ctx.getClientID()));
}

This is thread safe and can be used with TransactionMode = NONE
 
Register or login to create to post a reply.