Using Dynamic Skeleton Interface (DSI)

The Dynamic Skeleton Interface (DSI) is the server-side counterpart of the DII. It allows us to write servants that accept method invocation request even when an IDL interface is not known at compile time and without creating skeleton class. The servant merely defines a method invoke() which is called by the ORB providing necessary information (method name, types and values of parameters, result, etc.) encapsulated as a ServerRequest object. This invoke() method acts as a representative of methods being invoked. This method then performs the task being requested by the client, and constructs and returns the result.

1. Basic Steps

The following are the basic steps to be followed to write a server that uses DSI concept:

  • Write a servant class extending omg.CORBA.DynamicImplementation
  • Implement the invoke() method (that takes a ServerRequest parameter representing a request from client) as follows:
    • Extract method name using op_name()
    • Create an NVList to hold method parameters.
    • Populate this list by passing it to arguments() method
    • Extract the parameter values from populated NVList.
    • Perform the operation, assign new values to out and inout parameters in the NVList as appropriate.
    • Create an Any holding result (if any)
    • Pass this Any to set_result() or set_except(), as appropriate.
  • Implement the ids() method returning an array of repository IDs of the interfaces implemented by this servant.
  • Create an instance of the DSI servant and register it with the ORB using connect() method of  org.omg.

CORBA.ORB.

2. An Example

We write a servant for our calculator application that uses DSI extending org.omg.CORBA.

DynamicImplementation as follows:

class SimpleCalculatorDSI extends DynamicImplementation {

//…

public void invoke(ServerRequest request) {/*…*/}

public String[] _ids() {/*…*/}

}

This class implements two methods invoke() and _ids(). This invoke method is called by the underlying ORB when a request from a client comes to it. ORB places all method invocation information in a ServerRequest object and passes it to the invoke() method. Inside this method, we first extract the name of the method specified by the client:

String methodName = request.op_name();

A DSI servant may want to provide the functionality of many methods. An ‘if ’ statement is inserted for each such method. For our add() method of calculator, the following is used:

if (methodName.equals(”add”) == true) {

//…

}

In this if block, we write the functionality of add() method. We know that add() method takes two parameters and returns the sum of these two parameters. So, the client has certainly specified two arguments which are encapsulated in the request object. To hold these two parameters, we create an NVList as follows:

NVList nvlist = orb.create_list(2);

The list is populated with two Anys where actually the parameters are stored as follows:

Any anyl = orb.create_any(), any2 = orb.create_any();

any1.type(orb.get_primitive_tc(TCKind.tk_long));

any2.type(orb.get_primitive_tc(TCKind.tk_long));

nvlist.add_value(”arg1”, any1, ARG_IN.value);

nvlist.add_value(”arg2”, any2, ARG_IN.value);

Specifying the type of each Any is necessary so that they can hold parameter value properly. The parameter values encapsulated in request object is then transferred to the NVList as follows:

request.arguments(nvlist);

We then extract those parameter values, add them and put it in result.

int a = nvlist.item(0).value().extract_long();

int b = nvlist.item(1).value().extract_long();

int result = a + b;

The result is placed in another Any:

Any result_any = orb.create_any();

result_any.insert_long(result);

Finally, the result is sent back to the client.

request.result(result_any);

Inside _ids() method, we simply return the repository ID of our calculator interface:

static String[] id = {”IDL:CalculatorApp/Calculator:1.0”};

public String[] _ids() { return id; }

The complete source code (SimpleCalculatorDSI.java) is shown below:

import org.omg.CORBA.*;

class SimpleCalculatorDSI extends DynamicImplementation { static String[] id = {”IDL:CalculatorApp/Calculator:1.0”};

ORB orb;

SimpleCalculatorDSI(ORB orb) { this.orb = orb; }

public void invoke(ServerRequest request) {

try {

String methodName = request.op_name();

if (methodName.equals(”add”) == true) {

NVList nvlist = orb.create_list(2);

Any any1 = orb.create_any(), any2 = orb.create_any();

any1.type(orb.get_primitive_tc(TCKind.tk_long));

any2.type(orb.get_primitive_tc(TCKind.tk_long));

nvlist.add_value(”arg1”, any1, ARG_IN.value);

nvlist.add_value(”arg2”, any2, ARG_IN.value);

request.arguments(nvlist);

int a = nvlist.item(0).value().extract_long();

int b = nvlist.item(1).value().extract_long();

System.out.println(”Received: ” + a + ” and ” + b);

int result = a + b;

System.out.println(”Sent: ” + result);

Any result_any = orb.create_any();

result_any.insert_long(result);

request.result(result_any);

}

}

catch (Exception ex) {ex.printStackTrace();}

}

public String[] _ids() { return id; }

}

We then create an instance of this dynamic servant:

SimpleCalculatorDSI cal = new SimpleCalculatorDSI(orb);

It is necessary to register this object to the ORB, so that it can forward (can call its invoke() method) client request to it.

orb.connect(cal);

The IOR of this servant is registered with the naming server using a procedure used earlier. The complete source code of the server is shown below:

// CalculatorServerDSI.java import org.omg.CosNaming.*;

import org.omg.CosNaming.NamingContextPackage.*;

import org.omg.CORBA.*;

public class CalculatorServerDSI {

public static void main(String args[]) {

try{

ORB orb = ORB.init(args, null);

SimpleCalculatorDSI cal = new SimpleCalculatorDSI(orb);

orb.connect(cal);

org.omg.CORBA.Object objRef = orb.resolve_initial_references(”NameService”);

NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

NameComponent path[] = ncRef.to_name( “Calculator” );

ncRef.rebind(path, cal);

System.out.println(”Calculator Server ready…”);

orb.run();

} catch (Exception e) {

e.printStackTrace();

}

}

}

Compile and run the application as before. This dynamic server works exactly like a normal server. Clients are completely unaware of the fact that a dynamic servant is being used at the server end.

Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.

Leave a Reply

Your email address will not be published. Required fields are marked *