VisiBroker for C++ Developer’s Guide : Using IDL

Using IDL
This section describes how to use the CORBA interface description language (IDL).
The Interface Definition Language (IDL) is a descriptive language (not a programming language) to describe the interfaces being implemented by the remote objects. Within IDL, you define the name of the interface, the names of each of the attributes and methods, and so forth. Once you've created the IDL file, you can use an IDL compiler to generate the client stub file and the server skeleton file in the C++ programming language.
For more information see “Programmer tools for C++”.
The OMG has defined specifications for such language mapping. Information about the language mapping is not covered in this manual since VisiBroker Edition adheres to the specification set forth by OMG. If you need more information about language mapping, see the OMG web site at http://www.omg.org.
Note
The CORBA 3.0 formal specification can be found at: http://www.omg.org/technology/documents/vault.htm#CORBA_IIOP.
Discussions on the IDL can be quite extensive. Because VisiBroker adheres to the specification defined by OMG, you can visit the OMG site for more information about IDL.
How the IDL compiler generates code
You use the Interface Definition Language (IDL) to define the object interfaces that client programs may use. The idl2cpp compiler uses your interface definition to generate code.
Example IDL specification
Your interface definition defines the name of the object as well as all of the methods the object offers. Each method specifies the parameters that will be passed to the method, their type, and whether they are for input or output or both. The IDL sample below shows an IDL specification for an object named example. The example object has only one method, op1.
// IDL specification for the example object
interface
example {
long op1(in char x, out short y);
};
Looking at generated code for clients
The code sample below shows how the IDL compiler generates two client files, example_c.hh and example_c.cc from the example that follows. These two files provide an example class that the client uses. By convention, files generated by the IDL compiler always have either a .cc or an .hh suffix to make them easy to distinguish from files that you create yourself. If you wish, you can alter the convention to produce files with a different suffix.
Important
Do not modify the contents of the files generated by the IDL compiler.
class example : public virtual CORBA_Object {
protected:
example() {}
example(const example&) {}
public:
virtual ~example() {}
static const CORBA::TypeInfo *_desc();
virtual const CORBA::TypeInfo *_type_info() const;
virtual void *_safe_narrow(const CORBA::TypeInfo& ) const;
static CORBA::Object*_factory();
example_ptr _this();
static example_ptr _duplicate(example_ptr _obj) { /* . . . */ }
static example_ptr _nil() { /* . . . */ }
static example_ptr _narrow(CORBA::Object* _obj);
static example_ptr _clone(example_ptr _obj) { /* . . . */ }
static example_ptr _bind(
const char *_object_name = NULL,
const char *_host_name = NULL,
const CORBA::BindOptions* _opt = NULL,
CORBA::ORB_ptr _orb = NULL);
static example_ptr _bind(
const char *_poa_name,
const CORBA::OctetSequence& _id,
const char *_host_name = NULL,
const CORBA::BindOptions* _opt = NULL,
CORBA::ORB_ptr _orb = NULL);
virtual CORBA::Long op1(
CORBA::Char _x, CORBA::Short_out _y);
};
Methods (stubs) generated by the IDL compiler
The code sample above shows the op1 method generated by the IDL complier, along with several other methods. The op1 method is called a stub because when your client program invokes it, it actually packages the interface request and arguments into a message, sends the message to the object implementation, waits for a response, decodes the response, and returns the results to your program.
Since the example class is derived from the CORBA::Object class, several inherited methods are available for your use.
Pointer type <interface_name>_ptr definition
The IDL compiler always provides a pointer type definition. The code sample below shows the type definition for the example class.
typedef example *example_ptr;
Automatic memory management <interface_name>_var class
The IDL compiler also generates a class named example_var, which you can use instead of an example_ptr. The example_var class will automatically manage the memory associated with the dynamically allocated object reference. When the example_var object is deleted, the object associated with example_ptr is released. When an example_var object is assigned a new value, the old object reference pointed to by example_ptr is released after the assignment takes place. A casting operator is also provided to allow you to assign an example_var to a type example_ptr.
class example_var : public CORBA::_var {
. . .
public:
static example_ptr _duplicate(example_ptr);
static void _release(example_ptr);
example_var();
example_var(example_ptr);
example_var(const example_var &);
~example_var();
example_var& operator=(example_ptr);
example_var& operator=(const example_var& _var) { /* . . . */ }
operator example* () const { return _ptr; }
. . .
};
The following table describes the methods in the _var class.
Constructor that creates an object with the_ptr initialized to the argument passed. The var invokes release() on _ptr at the time of destruction. When the _ptr's reference count reaches 0, that object will be deleted.
Constructor that makes a copy of the object passed as a parameter var and points _ptr to the newly copied object.
Destructor that invokes _release() once on the object to which _ptr points.
Assignment operator invokes _release() on the object to which _ptr points and then stores p in _ptr.
Assignment operator invokes _release() on the object to which _ptr points and then stores a _duplicate() of p in _ptr.
Returns the _ptr stored in this object. This operator should not be called until this object has been properly initialized.
Looking at generated code for servers
The code sample below shows how the IDL compiler generates two server files: example_s.hh and example_s.cc. These two files provide a POA_example class that the server uses to derive an implementation class. The POA_example class is derived from the PortableServer_ServantBase class.
Important
You should not modify the contents of the files generated by the IDL compiler.
class POA_example : public virtual PortableServer_ServantBase {
protected:
POA_example() {}
virtual ~POA_example() {}
public:
static const CORBA::TypeInfo _skel_info;
virtual const CORBA::TypeInfo *_type_info() const;
example_ptr _this();
virtual void *_safe_narrow(const CORBA::TypeInfo& ) const;
static POA_example * _narrow(PortableServer_ServantBase *_obj);
// The following operations need to be implemented
virtual CORBA::Long op1(CORBA::Char _x, CORBA::Short_out _y) = 0;
// Skeleton Operations implemented automatically
static void _op1(void *_obj, CORBA::MarshalInBuffer &_istrm,
const char *_oper, VISReplyHandler& handler);
};
Methods (skeletons) generated by the IDL compiler
Notice that the op1 method declared in the IDL specification below is generated, along with an _op1 method. The POA_example class declares a pure virtual method named op1. The implementation class that is derived from POA_example must provide an implementation for this method.
The POA_example class is called a skeleton and its method (_op1) is invoked by the POA when a client request is received. The skeleton's internal method will marshal all the parameters for the request, invoke your op1 method and then marshal the return parameters or exceptions into a response message. The ORB will then send the response to the client program.
The constructor and destructor are both protected and can only be invoked by inherited members. The constructor accepts an object name so that multiple distinct objects can be instantiated by a server.
Class template generated by the IDL compiler
In addition to the POA_example class, the IDL compiler generates a class template named _tie_example. This template can be used if you wish to avoid deriving a class from POA_example. Templates can be useful for providing a wrapper class for existing applications that cannot be modified to inherit from a new class. The sample below shows the template class generated by the IDL compiler for the example class.
template <class T>
class
POA_example_tie : public POA_example {
public:
POA_example_tie (T& t): _ptr(&t),
_poa(NULL), _rel((CORBA::Boolean)0) {}
POA_example_tie (T& t,
PortableServer::POA_ptr poa): _ptr(&t),
_poa(PortableServer::_duplicate(poa)),
_rel((CORBA::Boolean)0) {}
POA_example_tie (T *p, CORBA::Boolean release= 1)
: _ptr(p),_poa(NULL), _rel(release) {}
POA_example_tie (T *p, PortableServer::POA_ptr poa,
CORBA::Boolean release =1)
: _ptr(p), _poa(PortableServer::_duplicate(poa)), _rel(release) {}
virtual ~POA_example_tie() { /* . . . */ }
T* _tied_object() { /* . . . */ }
void _tied_object(T& t) { /* . . . */ }
void _tied_object(T *p, CORBA::Boolean release=1) { /* . . . */ }
CORBA::Boolean _is_owner() { /* . . . */ }
void _is_owner(CORBA::Boolean b) { /* . . . */ }
CORBA::Long op1(CORBA::Char _x, CORBA::Short_out _y) { /* . . . */ }
PortableServer::POA_ptr _default_POA() { /* . . . */ }
};
For complete details on using the _tie template class, see “Using the tie mechanism”.
You may also generate a _ptie template for integrating an object database with your servers.
Defining interface attributes in IDL
In addition to operations, an interface specification can also define attributes as part of the interface. By default, all attributes are read-write and the IDL compiler will generate two methods, one to set the attribute's value, and one to get the attribute's value. You can also specify read-only attributes, for which only the reader method is generated.
The IDL sample below shows an IDL specification that defines two attributes, one read-write and one read-only.
interface Test {
attribute long count;
readonly attribute string name;
};
The following code sample shows the operations class generated for the interface declared in the IDL.
class test : public virtual CORBA::Object {
...
// Methods for read-write attribute
virtual CORBA::Long count();
virtual void count(CORBA::Long __count);
// Method for read-only attribute.
virtual char * name();
...
};
Specifying one-way methods with no return value
IDL allows you to specify operations that have no return value, called one-way methods. These operations may only have input parameters. When a oneway method is invoked, a request is sent to the server, but there is no confirmation from the object implementation that the request was actually received.
VisiBroker uses TCP/IP for connecting clients to servers. This provides reliable delivery of all packets so the client can be sure the request will be delivered to the server, as long as the server remains available. Still, the client has no way of knowing if the request was actually processed by the object implementation itself.
Note
One-way operations cannot raise exceptions or return values.
interface oneway_example {
oneway void set_value(in long val);
};
Specifying an interface in IDL that inherits from another interface
IDL allows you to specify an interface that inherits from another interface. The classes generated by the IDL compiler will reflect the inheritance relationship. All methods, data type definitions, constants and enumerations declared by the parent interface will be visible to the derived interface.
interface parent {
void operation1();
};
interface child : parent {
. . .
long operation2(in short s);
};
The code sample below shows the code that is generated from the interface specification shown above.
class parent : public virtual CORBA::Object {
...
void operation1( );
...
};
class child : public virtual parent {
...
CORBA::Long operation2(CORBA::Short s);
...
};