#include "HelloS.h"By default, the TAO IDL compiler generates code that doesn't require C++ exceptions to be supported. The C++ mapping allows that, in lieu of exceptions, a CORBA::Environment structure may be passed as an additional parameter to each operation of a CORBA interface. The state of this structure may be queried after an invocation to determine whether an exception was raised. This can make for some pretty ugly code -- exceptions are much "cleaner." The -Ge option to tao_idl should prevent the inclusion of the unnecessary parameter, but this option is ignored at present. So, our implementations of the interface methods must contain this unused parameter. To make the code a little more bearable, I define this macro:
#define ENV CORBA::Environment& unnecessary_with_exceptionsHere is the definition for our World servant, World_impl. It is derived from our skeleton class, POA_World. We must override the pure virtual function, hello. Due to a bug in tao_idl, we must include a CORBA::Environment& parameter in our signature. Note that our return value is a char *.
class World_impl : public POA_World
{
char * hello (ENV);
};
Here is our implementation of the hello method:
char *
World_impl::hello (ENV)
{
The C++ mapping makes the caller responsible for the
deallocation of a variable-length result. In other words,
whomever calls this function is going to try to delete the memory
referenced by the return value, so we want to make sure we
dynamically allocate it. Because the C++ operators, new
and delete, are not portable across platforms, CORBA
provides the functions, CORBA::string_alloc(),
CORBA::string_free(), and CORBA::string_dup() which
combines an allocation with a copy. Just so you're not too
concerned about memory leaks in the server process, remember that
the string allocated in this function is actually released by the
skeleton code after it has sent a copy of it over the network to
the client.
return CORBA::string_dup("Greetings from C++ World server!!");
}
So much for our servant! Now we construct the obligatory main
routine in which we'll instantiate it.
main (int argc, char** argv)
{
I'm assuming our C++ compiler supports exceptions, although
neither CORBA nor TAO requires it. In fact, most of the TAO
examples utilize somewhat clumsy macros (TAO_TRY, TAO_CATCH, etc.)
to support either environment. Any invocation on a CORBA object
reference may throw an exception, so they should always exist
within a try-catch block.
try {
You must always initialize the ORB by calling the function,
CORBA::ORB_init(). For this tutorial, that's really all
I should say, but I'm going to say more because there are some
interesting things to say about the following line of code, and
I'd rather not forget them.
// Initialize the ORB
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
Now we must obtain a POA (Portable Object Adapter). I'm going
to talk more about POA's below, but right now let's concentrate on
the ORB method, resolve_initial_references, which is a
mechanism that allows you to portably bootstrap your CORBA
application by obtaining necessary object references. The OMG
standardizes the set of identifiers (strings) recognized by
resolve_initial_references(). Currently, they are "RootPOA",
"POACurrent", "InterfaceRepository", "NameService",
"TradingService", "SecurityCurrent", and "TransactionCurrent".
You may call list_initial_services to see which identifiers
are supported by your ORB.
// Get the Root POA
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
Because resolve_initial_references returns a CORBA::Object, we
must down-cast the reference to the appropriate type,
PortableServer::POA. For every IDL interface, the IDL compiler
generates a static member function called _narrow() that does
just this. It behaves very much like the C++
dynamic_cast template. If it fails, it returns a nil
reference, similar to the way dynamic_cast would return 0. If
it succeeds, however, it returns a copy of the reference
converted to the new type. Therefore, it's important that both
variables, obj and poa, are _var types that will free their
memory when they go out of scope. Also, depending on the type
we're narrowing, _narrow() may need to contact the server, so
not only might it indicate failure by returning a nil reference,
but it could possibly raise an exception.
PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
Perhaps now is a good time to talk about object
adapters. They are simply the means by which CORBA objects
are linked (or adapted) to programming language servants. They
are responsible for the creation of CORBA objects and their
references and for dispatching requests to the proper servants.
The standard CORBA object adapter is the Portable Object Adapter
(POA) which provides features necessary for a programming
language servant to be portable across different ORB
implementations. All CORBA server applications contain at least
one POA, the RootPOA, and possibly more, each with
different characteristics. The discussion of those
characteristics is beyond the scope of this tutorial. Each POA
contains a reference to its POAManager, obtained by the
operation, the_POAManager.
// Activate POA manager
PortableServer::POAManager_var mgr = poa->the_POAManager();
The POAManager controls the flow of requests into each POA,
and that flow won't begin unless the POAManager is activated.
mgr->activate();
So far, we've done the things required for every CORBA server
application: initialize the ORB and the POA. Now we need to
create our servant so that we may incarnate our CORBA object.
// Create the servant(s)
World_impl world_servant;
Ok, we created our servant, but we've not linked it to any
CORBA object yet. That is accomplished by calling the deceptively
simple _this method of our servant. That does four
things:
// Activate object implicitly by calling _this()
World_var world = world_servant._this();
Ok, we're almost home. We still need to make ourself (our
object reference) known to potential clients in the outside world.
This is commonly done by associating our object reference with a
name and registering that association with a Naming or Trader
service. That's beyond the scope of this tutorial, though.
Instead, we're going to stringify the object reference and
echo it to standard output. The ORB interface provides two
functions, object_to_string and string_to_object,
that do exactly what their names imply: they convert a CORBA
object reference to and from a human-readable string,
respectively.
// Write stringified reference to stdout
CORBA::String_var str = orb->object_to_string(world);
Because the CORBA::String type defines a conversion operator
that results in a const char *, we can do this:
cout << str << endl;
Now the only thing left to do is run the orb. This
starts an event loop that blocks awaiting client requests. The
run method completes when the ORB's shutdown method is
called. (This stupefyingly simple application has no facility for
calling shutdown: we'll just kill the server when we're done with
it and rely on the OS to clean up after us.)
// Accept requests
orb->run();
Our "try block" is complete, so now we catch any CORBA
exception that may have been thrown from within it.
}
catch (const CORBA::Exception& e)
{
The following line of code is the only non-portable code in
this program. It is a convenient TAO extension that allows one to
easily obtain the repository id of any exception. All CORBA
vendors provide "extensions" in order to distinguish themselves.
Can you blame them? Whether you consider it good or bad that they
do, remember that because CORBA is an open standard, good ideas
can be incorporated into the specification. The OMG is
constantly "refactoring" CORBA.
const char* err = e._id();
Give the user an idea of what happened...
cerr << "Server caught CORBA exception: " << err << endl;
...and exit with a value indicating an error.
return 100;
}
Return success. We'll probably never reach this line of code
because orb->run() will block until the process is terminated.
return 0;
}
Whew! That's a lot to explain about such a small program. Let's see if writing a C++ client is any easier.
Back to... [ Corba Tutorials ]