The Dynamic Skeleton Interface (DSI) provides a mechanism for creating an object implementation that does not inherit from a generated skeleton interface. Normally, an object implementation is derived from a skeleton class generated by the idl2java compiler. The DSI allows an object to register itself with the VisiBroker ORB, receive operation requests from a client, process the requests, and return the results to the client without inheriting from a skeleton class generated by the 
idl2java compiler.
 
      
      
      
      The VisiBroker ORB presents client operation requests to a DSI object implementation by calling the object's invoke method and passing it a 
ServerRequest object. The object implementation is responsible for determining the operation being requested, interpreting the arguments associated with the request, invoking the appropriate internal method or methods to fulfill the request, and returning the appropriate values.
 
      
      
      The idl2java compiler has a flag (
-dynamic_marshal) which, when switched on, generates skeleton code using DSI. To understand how to do any type of DSI: 
 
      
      
      
      
      
      
      
      
      
      
      
      
      This example is used to illustrate DSI concepts in this section. The Bank.idl file, shown below, illustrates the interfaces implemented in this example.
 
      // Bank.idl
module Bank {
  interface 
Account {
    float balance();
  };
  interface 
AccountManager {
    Account open(in string name);
  };
};
 
      
      To use the DSI, object implementations should be derived from the DynamicImplementation base class shown below. This class offers several constructors and the 
invoke method, which you must implement.
 
      
      
      The code sample below shows the declaration of the AccountImpl class that is to be implemented with the DSI. It is derived from the 
DynamicImplementation class, which declares the 
invoke method. The VisiBroker ORB will call the 
invoke method to pass client operation requests to the implementation in the form of 
ServerRequest objects.
 
      The code sample below shows the Account class constructor and 
_primary_interface function.
 
      import java.util.*;
import org.omg.PortableServer.*;
public class AccountImpl extends DynamicImplementation {
   public AccountImpl(org.omg.CORBA.ORB orb, POA poa) {
      _orb = orb;
      _poa = poa;
   }
   public synchronized org.omg.CORBA.Object get(String name) {
      org.omg.CORBA.Object obj;
      // Check if account exists
      Float balance = (Float)_registry.get(name);
      if (balance == null) {
         // simulate delay while creating new account
         try {
            Thread.currentThread().sleep(3000);
         } catch (Exception e) {
            e.printStackTrace();
         }
         // Make up the account's balance, between 0 and 1000 dollars
         balance = new Float(Math.abs(_random.nextInt()) % 100000 / 100f);
         // Print out the new account
         System.out.println("Created " + name + "'s account: " +
                balance.floatValue());
         _registry.put(name, balance);
      }
      // Return object reference
      byte[] accountId = name.getBytes();
      try {
         obj = _poa.create_reference_with_id(accountId, "IDL:Bank/
				Account:1.0");
      } catch (org.omg.PortableServer.POAPackage.WrongPolicy e) {
         throw new org.omg.CORBA.INTERNAL(e.toString());
      }
      return obj;
   }
   public String[] _all_interfaces(POA poa, byte[] objectId) { return null; }
   public void 
invoke(org.omg.CORBA.ServerRequest request) {
      Float balance;
      // Get the account name from the object id
      String name = new String(_object_id());
      // Ensure that the operation name is correct
      if (!request.operation().equals("balance")) {
         throw new org.omg.CORBA.BAD_OPERATION();
      }
      // Find out balance and fill out the result
      org.omg.CORBA.NVList params = _orb.create_list(0);
      request.arguments(params);
      balance = (Float)_registry.get(name);
      if (balance == null) {
         throw new org.omg.CORBA.OBJECT_NOT_EXIST();
      }
      org.omg.CORBA.Any result = _orb.create_any();
      result.insert_float(balance.floatValue());
      request.set_result(result);
      System.out.println("Checked " + name + "'s balance: " + 
             balance.floatValue());
   }
   private Random _random = new Random();
   static private Hashtable _registry = new Hashtable();
   private POA _poa;
   private org.omg.CORBA.ORB _orb;
}
 
      The following code sample shows the implementation of the AccountManagerImpl class that need to be implemented with the DSI. It is also derived from the 
DynamicImplementation class, which declares the 
invoke method. The VisiBroker ORB will call the 
invoke method to pass client operation requests to the implementation in the form of 
ServerRequest objects.
 
      import org.omg.PortableServer.*;
public class AccountManagerImpl extends DynamicImplementation {
   public AccountManagerImpl(org.omg.CORBA.ORB orb, AccountImpl accounts) {
      _orb = orb;
      _accounts = accounts;
   }
   public synchronized org.omg.CORBA.Object open(String name) {
      return _accounts.get(name);
   }
   public String[] _all_interfaces(POA poa, byte[] objectId) { return null; }
   public void 
invoke(org.omg.CORBA.ServerRequest request) {
      // Ensure that the operation name is correct
      if (!request.operation().equals("open")) {
         throw new org.omg.CORBA.BAD_OPERATION();
      }
 // Fetch the input parameter 
String name = null;
try {
org.omg.CORBA.NVList params = _orb.create_list(1);
org.omg.CORBA.Any any = _orb.create_any();
any.insert_string(new String(""));
params.add_value("name", any, org.omg.CORBA.ARG_IN.value);
request.arguments(params);
name = params.item(0).value().extract_string();
} catch (Exception e) {
throw new org.omg.CORBA.BAD_PARAM();
}
// Invoke the actual implementation and fill out the result
org.omg.CORBA.Object account = open(name);
org.omg.CORBA.Any result = _orb.create_any();
result.insert_Object(account);
request.set_result(result);
}
private AccountImpl _accounts;
private org.omg.CORBA.ORB _orb;
}
 
      
      The_primary_interface method should be implemented to return supported repository identifiers. To determine the correct repository identifier to specify, start with the IDL interface name of an object and use these steps:
 
      
      
        
          
            | 
                2	
               | Add “IDL:” to the beginning of the string. | 
        
       
      
        
          
            | 
                3	
               | Add “:1.0” to the end of the string. | 
        
       
      
      
      
      
      
      A ServerRequest object is passed as a parameter to an object implementation's 
invoke method. The 
ServerRequest object represents the operation request and provides methods for obtaining the name of the requested operation, the parameter list, and the context. It also provides methods for setting the result to be returned to the caller and for reflecting exceptions.
 
      package org.omg.CORBA;
public abstract class ServerRequest {
   public java.lang.String 
operation();
   public void 
arguments(org.omg.CORBA.NVList args);
   public void 
set_result(org.omg.CORBA.Any result);
   public void 
set_exception(org.omg.CORBA.Any except);
   public abstract org.omg.CORBA.Context 
ctx();
   // the following methods are deprecated
   public java.lang.String 
op_name(); // use operation()
   public void 
params(org.omg.CORBA.NVList params); // use arguments()
   public void 
result(org.omg.CORBA.Any result); // use set_result()
   public abstract void 
except(org.omg.CORBA.Any except); // use set_exception()
}
 
      All arguments passed into the arguments, 
set_result, or set_
exception methods are thereafter owned by the VisiBroker ORB. The memory for these arguments will be released by the VisiBroker ORB; you should not release them.
 
      
      
      
      
      
      
      
      
      The invoke method first checks to see if the requested operation has the name “balance.” If the name does not match, a 
BAD_OPERATION exception is raised. If the 
Account object were to offer more than one method, the 
invoke method would need to check for all possible operation names and use the appropriate internal methods to process the operation request.
 
      Since the balance method does not accept any parameters, there is no parameter list associated with its operation request. The 
balance method is simply invoked and the result is packaged in an 
Any object that is returned to the caller, using the 
ServerRequest object's
 set_result method.
 
      
      Like the Account object, the 
AccountManager interface also declares one method. However, the 
AccountManagerImpl object's
open method does accept an account name parameter. This makes the processing done by the 
invoke method a little more complicated.
 
      The method first checks to see that the requested operation has the name “open”. If the name does not match, a 
BAD_OPERATION exception is raised. If the 
AccountManager object were to offer more than one method, its 
invoke method would need to check for all possible operation names and use the appropriate internal methods to process the operation request.
 
      
      The following are the steps the AccountManagerImpl object's
invoke method uses to process the operation request's input parameters.
 
      
        
          
            | 
                1	
               | Create an NVList to hold the parameter list for the operation. | 
        
       
      
        
          
            | 
                2	
               | Create Any objects for each expected parameter and add them to the NVList , setting their TypeCode  and parameter type (ARG_IN , ARG_OUT , or ARG_INOUT ). | 
        
       
      
        
          
            | 
                3	
               | Invoke the ServerRequest object'sarguments  method, passing the NVList , to update the values for all the parameters in the list. | 
        
       
      The open method expects an account name parameter; therefore, an 
NVList object is created to hold the parameters contained in the 
ServerRequest. The 
NVList class implements a parameter list containing one or more 
NamedValue objects. The 
NVList and 
NamedValue classes are described in 
“Using the Dynamic Invocation Interface”.
 
      An Any object is created to hold the account name. This 
Any is then added to 
NVList with the argument's name set to 
name and the parameter type set to 
ARG_IN.
 
      Once the NVList has been initialized, the 
ServerRequest object's
arguments method is invoked to obtain the values of all of the parameters in the list.
 
      
      After invoking the arguments method, the 
NVList will be owned by the VisiBroker ORB. This means that if an object implementation modifies an 
ARG_INOUT parameter in the 
NVList, the change will automatically be apparent to the VisiBroker ORB. This NVList should not be released by the caller.
 
      
      An alternative to constructing the NVList for the input arguments is to use the VisiBroker 
ORB object's
create_operation_list method. This method accepts an 
OperationDef and returns an 
NVList object, completely initialized with all the necessary 
Any objects. The appropriate 
OperationDef object may be obtained from the interface repository, described in 
“Using Interface Repositories”.
 
      
      After invoking the ServerRequest object's 
arguments method, the value of the 
name parameter can be extracted and used to create a new 
Account object. An 
Any object is created to hold the newly created 
Account object, which is returned to the caller by invoking the 
ServerRequest object's set_
result method.
 
      
      The implementation of the main routine, shown in the following code sample, is almost identical to the original example in 
“Developing an example application with VisiBroker”.