This section introduces Java IDL support for servers of transient CORBA objects. The Hello World example includes a transient object server.
Topics in this section include:
A transient CORBA object has the same lifetime as the execution of the server process that creates it. When a server terminates, its transient objects disappear with it and any object references held by the client become invalid. Transient objects are often used to effect asynchronous, or callback communication between applications and objects. For example, suppose a timing service notifies a client application when an interval expires; it could do so as follows:
The arrangement, in other words, is much like a callback in procedural programming.
By contrast, a persistent object lives until it is explicitly destroyed. If a client has a reference to a persistent CORBA object, that reference can be used even if the object's server is not running -- an ORB daemon will start the server when the ORB receives an invocation on the object.
At present, Java IDL supports only transient object servers. Although persistent object servers can't yet be written using Java IDL, Java applets and applications can be clients of persistent CORBA objects whose servers are written in other languages, such as C++, or in other Java ORB implementations.
To implement a server for transient CORBA objects of some type, you write a Java class called a servant, which inherits from a class called the servant base; servant base classes are optionally generated by the idlj compiler. An instance of a transient CORBA object is implemented by an instance of its servant class.
The servant base class is the CORBA type-specific interface between the ORB and the servant code (skeleton) for the type. It unmarshals incoming parameters, invokes servant methods, marshals results, and directs the ORB to return results to the client ORB.
A servant class extends its servant base with a method for each operation in the IDL interface definition it implements. (OMG IDL attributes require one method if they are read only, two if they are writable.) For example, consider the following OMG IDL:
module Notifiers { interface SimpleNotifier { void alert (in long alert_id); }; };
A servant for this type might look as follows:
import Notifiers.* class SimpleNotifierServant extends _SimpleNotifierImplBase { void alert (int alert_id) { // do something about the alert ... return; } }
The server class could create an instance of SimpleNotifierServant as follows:
SimpleNotifierServant SimpleNotifier = new SimpleNotifierServant(); orb.connect(SimpleNotifier);
The orb.connect() call registers the object and the servant with the ORB so that the ORB will invoke the servant when the CORBA object is invoked. When the server terminates, the ORB destroys its records for that server's CORBA objects so that subsequent invocations will result in an OBJECT_NOT_EXIST exception. A server can alternatively annul its CORBA objects before terminating by calling orb.disconnect().
A transient CORBA object is implemented by a Java servant object. A servant object can be passed as a parameter to any method that needs a CORBA object reference of that type. For example, suppose a Java program wants to learn when the price of Sun Microsystems stock rises above 150. The program has obtained a reference to a CORBA stock-watcher object that provides the following operation (shown in IDL and Java):
// IDL interface StockWatcher { void set_threshold( in string stock_symbol, in short stock_price, in Notifiers::SimpleNotifier notifier_obj); }; // Java void set_threshold( String stock_symbol, short stock_price, Notifiers.SimpleNotifier notifier_obj) { // set the threshold ... }
To call set_threshold()
, you need to create a
SimpleNotifier
CORBA object. Assuming you've imported a
servant class called SimpleNotifierImpl
, here's how to
do it:
SimpleNotifier SUNWnotifier = new SimpleNotifierImpl(); int stockPrice = 150; orb.connect(SUNWnotifier); StockWatcher aStockWatcher = // code to get a stock-watcher reference; aStockWatcher.set_threshold ("SUNW", stockPrice, SUNWnotifier);
DSI allows servers to serve a servant object without prior (compile time) knowledge of the object's interface. Instead of using skeleton code compiled from the IDL interface definition, the server constructs an operation invocation dynamically.
Use DSI for servers that cannot have compile-time knowledge of the implementation interface. For example, you might need a bridging application to allow CORBA clients to invoke services residing in a COM environment while allowing COM clients the same access to services residing in the CORBA realm. Each environment has its own, very different way of building requests and responses.
This bridging application would use DSI to convert a CORBA client request to a format understood by a COM server. And it would use DII to convert a COM client request to a format understood by a CORBA server. The application programmer writes all the code to perform this work.
Contrast this with a typical static object invocation. The server has access to the compiled skeletons for the interfaces being invoked upon. These skeletons are generated by compiling the IDL interface definitions with the idlj compiler. When the ORB receives a request, it uses the skeleton code to build the operation arguments on the server side and to send back any result.
To use DSI, implement and register a dynamic servant by doing the following:
org.omg.CORBA.DynamicImplementation
.
invoke()
method.
invoke()
method code to work with a
ServerRequest
object to:
op_name()
.
NVList
of the operation parameters (this requires type
information on the parameters, possibly from an interface repository).
params()
, passing
the NVList
.
NVList
as appropriate.
result()
or except()
, as appropriate.
params()
and then to result()
or
except()
must be made in the proper order. You must call
params()
before calling either of the other two methods, and you
must call only one of result()
or except()
once
only. Failure to observe any of these limitations results in a
BAD_INV_ORDER
exception.
_ids()
method.
org.omg.CORBA.portable.ObjectImpl
, the superclass of
DynamicImplementation
. It returns the repository IDs of the
interfaces implemented by this dynamic server.
org.omg.CORBA.ORB.connect()
.
Here is DSI.idl, which defines a very simple interface to be implemented dynamically.
//IDL module JavaIDL { interface DSIExample { void print_args(in string arg1, in short arg2); }; };
Here is the corresponding Java code, from the file DSIServer.java. This portion shows the implementation of invoke()
and the dynamic handling of the print_args()
operation defined in DSI.idl.
//Java import java.util.*; import org.omg.CORBA.*; // Dynamic servant class implementation class DSIExampleServantImpl extends DynamicImplementation { // Store the repository ID for the interface implemented static String[] myIds = {"IDL:JavaIDL/DSIExample:1.0"}; // Create a reference to the ORB ORB orb; DSIExampleServantImpl(ORB orb) { this.orb = orb; } // Implementation of invoke() for handling dynamic requests public void invoke(ServerRequest request) { try { System.out.println("DSI: invoke called, op = "+ request.op_name()); // Create an NVList to hold the parameters NVList nvlist = orb.create_list(0); // Check if the request is for the operation // "print_args" if (request.op_name().equals("print_args") == true) { // Add first argument to NVList Any any1 = orb.create_any(); any1.insert_string(""); nvlist.add_value("arg1", any1, ARG_IN.value); // Add second argument to NVList Any any2 = orb.create_any(); any2.insert_short((short)0); nvlist.add_value("arg2", any2, ARG_IN.value); //Pass the NVList to the request, to get values request.params(nvlist); // Extract values and print arguments System.err.println("Argument 1: In value: " + nvlist.item(0).value().extract_string()); System.err.println("Argument 2: In value: " + nvlist.item(1).value().extract_short()); TypeCode result_tc = orb.get_primitive_tc(TCKind.tk_void); Any result_any = orb.create_any(); result_any.type(result_tc); // Set the void result request.result(result_any); } } catch ( Exception ex ) { ex.printStackTrace(); System.out.println("DSIExample: Exception thrown: " + ex); } } // Implement the _ids() method to return repository ID of interface public String[] _ids() { return myIds; } } // File DSIServer.java continuesHere is the remainder of DSIServer.java, showing a standard server implementation. Note that you register a dynamic servant with the ORB by using the same operation you would for a static servant.
// Java // DSIServer implementation public class DSIServer { // Main public static void main(String[] args) { try { // Access and initialize the ORB org.omg.CORBA.ORB orb = ORB.init(args, null); // Create an instance of the dynamic implementation DSIExampleServantImpl servant = new DSIExampleServantImpl(orb); // Register the dynamic servant with the ORB orb.connect(servant); // Write IOR into file. // Alternatively, the naming service could be used. OutputStream f = new FileOutputStream( System.getProperty("user.home") + System.getProperty("file.separator") + "DSI.ior") ; DataOutputStream out = new DataOutputStream(f) ; String ior = orb.object_to_string(servant) ; out.writeBytes(ior) ; out.close(); System.out.println("IOR is " + ior) ; // Wait for requests from client java.lang.Object sync = new java.lang.Object(); synchronized(sync){ sync.wait(); } } catch (Exception ex) { ex.printStackTrace(); System.err.println("DSIServer: Exception thrown: " + ex); } } }
Because Java allows a class to inherit implementation from only a single superclass, it is sometimes awkward to provide CORBA object implementations for objects that rightfully belong in a class hierarchy--the servant base class occupies the single available superclass position. These objects can become CORBA servants most easily by use of delegation-based skeletons.
Delegation-based skeletons move the required CORBA operations from a servant base class (from which your object must inherit) to the generated Tie class. The Tie class acts as the skeleton for this object, receiving invocations from the ORB and delegating them to the servant that actually does the work.
The idlj compiler is installed to the J2SDK's bin directory when you installed the Java 2 Platform, Standard Edition, v1.3. These steps are based on this version of the J2SDK.
To use ties, first compile the IDL interface using the
-ftie Compiling Frog.idl with idlj generates the standard client and
server files (servant classes, etc.) and the special files for delegation-based
skeletons: _FrogTie and _FrogOperations.
The standard implementation of this IDL looks like this:
Note that, because FrogImpl.java inherits its CORBA functionality
(such as the dispatch upcall from the ORB) from _FrogImplBase, it must contain
the implementation code for the rest of its methods; it cannot
inherit them even if they are identical to those in another class.
The same class, using a delegation-based skeleton, would look
like this:
Using ties, FrogImpl reserves its superclass slot for inheritance
of amphibian behavior while implementing the CORBA operations defined in
the IDL interface (and in _FrogOperations).
Note the difference in the orb.connect() call. With a
delegation-based skeleton, you pass a new tie class instance to the
ORB, rather than passing the actual object implementation.
Clients | Servers | Exceptions | Initialization | Naming
Using Ties
Ties Example
Consider the following simple IDL interface:
// IDL
interface Frog{
void croak();
};
// FrogImpl.java--without using ties, inherits required
// CORBA functionality from _FrogImplBase
public class FrogImpl extends _FrogImplBase {
public void croak() {
getAudioClip(getCodeBase(), "frog.au").play();
}
public static void main(String[] args) {
ORB orb = ORB.init();
Frog frogRef = new FrogImpl();
orb.connect(frogRef);
// remainder of code deleted
}
}
// Amphibian.java--provides general behavior
public class Amphibian extends Applet {
public void breathWater(){
// implementation deleted
}
}
// FrogImpl.java--using ties
public class FrogImpl extends Amphibian implements _FrogOperations {
public void croak() {
// croak method must still be here; it is in the Operations interface
getAudioClip(getCodeBase(), "frog.au").play();
}
public static void main(String[] args) {
ORB orb = ORB.init();
FrogImpl servant = new FrogImpl();
Frog frogRef = new _FrogTie(servant);
orb.connect(frogRef);
// remainder of code deleted
}
}
Home
Fundamentals
Programming
References
Tutorial
Copyright
© 1996, 1997 Sun Microsystems, Inc.,
2550 Garcia Ave., Mtn. View, CA. 94043-1100 USA., All rights
reserved.