Chapter 10: The IDL Compiler

This chapter discusses the VisiBroker IDL compiler and includes the following major sections:

The IDL Compiler

Code Generated for Clients

Code Generated for Servers

Interface Attributes

Oneway Methods

Mapping Object References

Interface Inheritance

The IDL Compiler

You use the Interface Definition Language, IDL, to define the object interfaces that client applications may use. The IDL compiler uses your interface definition to generate C++ code. Figure 10-1 shows how the compiler generates code for the client application and for the object implementation, or server. The file names used for discussion in this chapter apply to systems that support long file names.

The following figure shows C++ files generated by the IDL compiler.

The Interface Definition

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. Figure 10-2 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);

};

Code Generated for Clients

The next example shows how the IDL compiler generates two client files; ex_client.hh and ex_client.cc. These two files provide an example class in C++ that the client will use. Files generated by the IDL compiler always have either a ".cc" or ".hh" suffix to make them easy to distinguish from file you create yourself.

Caution: You should not modify the contents of the files generated by the IDL compiler.

The following example shows the example class generated in ex_client.hh.

class example : public virtual CORBA::Object

{

private:

// Methods used internally by VisiBroker to store type information

...

public:

// More methods used internally by VisiBroker to create object

// references and manage type information

protected:

example(const char *obj_name = NULL) : CORBA::Object(obj_name, 1);

example(NCistream& strm) :CORBA::Object(strm);

virtual ~example();

public:

static example_ptr _bind(const char *object_name = NULL,

const char *host_name = NULL,

const CORBA::BindOptions* opt = NULL);

static example_ptr _duplicate(example_ptr obj);

static example_ptr _nil();

static example_ptr _narrow(CORBA::Object *obj)

virtual CORBA::Long op1(CORBA::Char x, CORBA::Short& y);

};

Methods Generated

Figure 10-3 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 application 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 reflects the results to your application.

Since the example class is derived from the CORBA::Object class, several inherited methods are available for your use. The CORBA::Object class methods are described in the VisiBroker for C++ Reference Guide.

The _ptr Definition

The IDL compiler always provides a pointer type definition. Figure 10-4shows the type definition for the example class.

typedef example *example_ptr;

The _var Class

The IDL compiler also generates a class named example_var, which you can use instead of the example class. The example_var class will automatically manage the memory associated with the object reference.When the an example_var object is deleted, the object associated with example_ptr is released. When an example_var object is assigned, 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:

example_var();

example_var(example_ptr ptr);

example_var(const example_var& var);

~example_var();

example_var& operator=(example_ptr p);

example operator=(const example_ptr p);

example_ptr operator->();

...

protected:

example_ptr _ptr;

private:

...

};

Code Generated for Servers

Figure 10-1 shows how the IDL compiler generates two server files: ex_server.hh and ex_server.cc. These two files provide an _sk_example class in C++ that the server will use to derive an implementation class. The _sk_example class is derived from the client's example class.

Caution: You should not modify the contents of the files generated by the IDL compiler.

The following example shows the _sk_example class generated in ex_server.hh.


class _sk_example : public example

{

protected:

_sk_example(const char *object_name = (const char *)NULL);

virtual ~_sk_example();

public:

static const CORBA::TypeInfo _skel_info;

virtual CORBA::Long op1(CORBA::Char x, CORBA::Short& y) = 0;

static void _op1(void *obj), CORBA::MarshalStream &strm,

CORBA::Principal_ptr principal,

const char *oper);

};

Generated Methods

Notice that the op1 method defined in the IDL specification in Figure 10-2 is generated, along with an _op1 method. The op1 method is a pure virtual method and must be implemented by the class you derive from _sk_example.

The _op1 method is called a skeleton and is invoked by the BOA when a client request is received. This method will marshal all the parameters from the request, invoke the op1 method and then marshal the return parameters or exceptions into a response message. The ORB will then send the response to the client application. Skeleton methods should not be explicitly invoked by the server or object implementation.

The constructor and destructor are both protected. The constructor accepts an object name so that multiple objects can be instantiated by a server.

The Class Template

In addition to the _sk_example class, the IDL compiler generates a class template named _tie_example. This template can be used if you wish to avoid the overhead associated with deriving a class from _sk_example. Templates can also be useful for providing a wrapper class for existing applications that cannot be modified to inherit from a new class. The following example shows the template class generated by the IDL compiler for the example class.


template <class T>

class _tie_example : public example

{

public:

_tie_example(T& t, const char *obj_name=(char *)NULL);

~_tie_example();

CORBA::Long op1(CORBA::Char x, CORBA::Short& y);

private:

T& _ref;

};

Using the Template

To use the _tie_example template class you must first create your own Example class. The following example shows what your Example class might look like. Notice that, unlike most object implementation classes, this Example class does not inherit from the client's example class or any class supplied by VisiBroker.


class Example

{

public:

Example();

CORBA::Long op1(CORBA::Char x, CORBA::Short& y);

};

Given the _tie_example template generated by the IDL compiler and the Example class you defined, the following example shows the server's main routine.

void main(int argc, char * const *argv)

{

// Initialize ORB and BOA

CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

CORBA::BOA_ptr boa = orb->BOA_init(argc, argv);

// Instantiate the Example class

Example myExample;

// Instantiate the template, passing a reference to the

// example object instantiated above and an ORB object instance

// name.

_tie_example<Example> tieExample(myExample, "test");

boa->impl_is_ready();

return(1);

};

Interface Attributes

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.

The following example shows the class definition generated for the object implementation.


// IDL

interface test

{

attribute long count;

readonly attribute string name;

};

The following example shows the resulting class definition generated by the IDL compiler for the client application.


class test : public virtual CORBA::Object

{

...

// Methods for read-write attribute

virtual CORBA::Long count();

virtual void count(CORBA::Long val);

// Method for read-only attribute.

virtual char * name();

...

};

The following example shows the class generated for the server.


class _sk_test : public test

{

virtual CORBA::Long count() = 0;

virtual void count(CORBA::Long val) = 0;

virtual char * name() = 0;

};

Oneway methods

The IDL allows you to specify operations that have no return value, called oneway 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 guaranteed delivery of all datagrams 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: Oneway operations cannot throw exceptions.


// IDL

interface oneway_example

{

oneway void set_value(in long val);

};

The following example shows the code generated for the client application.


class oneway_example : public virtual CORBA::Object

{

virtual void set_value(CORBA::Long val);

...

};

The following example shows the base class generated for the implementation.


class _sk_oneway_example : public oneway_example

{

virtual void set_value(CORBA::Long val) = 0;

};

Mapping Object References

In addition to generating C++ classes from your interface specification, the IDL compiler will also create object references for your classes.

typedef example *example_ptr;
typedef example_ptr exampleRef;

Interface Inheritance

IDL allows you to specify an interface that inherits from another interface. The C++ 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.


// IDL

interface parent

{

void operation1();

}

interface child : parent

{

...

long operation2(in short s);

};

The following example shows the C++ code generated from the preceding example.


...

class parent : public virtual CORBA::Object

{

...

void operation1(CORBA::Environment& _env);

...

};

class child : public virtual parent

{

...

CORBA::Long operation2(CORBA::Short s, CORBA::Environment& _env);

...

};


[Preface] [Chapter 1] [Chapter 2] [Chapter 3] [Chapter 4] [Chapter 5] [Chapter 6]
[Chapter 7] [Chapter 8] [Chapter 9] [Chapter 10] [Chapter 11] [Chapter 12] [Appendix A]