Articles Forum Examples Download Open Source
Copyright(c) 2006, 2007 by Pocomatic Software. All rights reserved.
Developing and deploying DDS applications in traditional programmatic approach imposes significant challenges to most CORBA professionals. It requires a considerable learning curve for a CORBA expert to be able to develop/deploy decent DDS applications, not to mention the maintenance cost of these applications. PocoCapsule/CORBA+DDS drastically lowered the entry barrier of DDS. With PocoCapsule/CORBA+DDS, developing, deploying, and maintaining DDS applications not only become straightforward for CORBA experts but also impose no challenges for CORBA novice. Specifically, domain experts and application developers no longer need to learn and deal with many system level plumbing details of DDS. Rather, they can focus on solving their own domain issues with DDS.
The development and deployment procedure of a POCO+DDS application is roughly as follows:
Declaring or generating DDS type implementations.
This is DDS implementations dependent. Some DDS implementations use script tools to generate DDS type implementations, and others may simply use macros. Developers should check and follow the user documents of their chosen DDSs.
For convenience of playing this example right out-of-the-box, this example comes with a functionality simplified and limited implementation of DDS inside the pocodds sub-directory. By this demo DDS, DDS types (IDL structs) and their implementations are declared using macros (and therefore, will be automatically generated by IDL and C++ pre-compiler) as follows:
use the DDS_TYPE() macro in IDL file(s) to declare an IDL struct(s) as a DDS type(s) (see example MyDataTypeDefs.idl). The IDL header file typesupport.idl in the demo DDS should be included in the IDL file(s) to use this macro.
use the DDS_TYPE() macro in C++ header files to declare a DDS type's implementation (see example MyDataTypeImpls.h). The C++ header file typesupport.h in the demo DDS should be included in the header file(s) to use this macro.
Implementing emitters and listeners, which perform DDS data writings and readings.
These implementation assumes DDS DataWriter and DataReader references will be injected to them by PocoCapsule container and/or the underlying DDS engine.
The emitter beans can be any class, having public methods for container to inject a DDS data reader reference (see example EmitterImpl.h and EmitterImpl.C).
The listener beans can be either a PortableServer servant that supports DDS::DataReaderListener (e.g. inherits the POA_DDS::DataReaderListener), or a local or remote CORBA object reference that can be narrowed to DDS::DataReaderListener. In the demo DDS implementation comes with this example, all DDS interfaces are local, therefore, a listener implementation can simply inherit and implement the DDS::DataListener local stub directly (see example ListenerImpl.h and ListenerImpl.C)
Declaring the following DDS and/or application entities (beans) in XML files
(see examples reader.xml and writer.xml):
DDS participants (with domain id),
topics (name and type Id),
subscribers (this is optional. if the default subscriber QoS is sufficient, the implicit subscriber can be used),
publishers (this is optional. if the default publisher QoS is sufficient, the implicit publisher can be used),
readers (with given listener), and writers (and emitter bean(s) to inject these writers).
writer beans for container to inject the associated DDS data writer.
Developers only need to declare “what” is the application structure, namely which listener/writer beans should read/write which topics, instead of imperatively specifying "how" to set it up.
Deploying the application in PocoCapsule.
This will activate declared beans and deploy them to the underlying OMG DDS based on “what” is described.
MyDataTypeDefs.idl: This IDL file defines IDL structs, and declares them as DDS types (if the demo DDS is used).
Two IDL structs are declared, Foo and Bar.
These two IDL structs are further declared as DDS types using the DDS_TYPE() macro, if the demo DDS implementation is used.
MyDataTypeImpls.h: This header provides implementations of the above declared DDS types.
Implementations of two declared DDS structs are generated using the DDS_TYPE() macro, if the demo DDS implementation is used.
EmitterImpl.h and EmitterImpl.C: They provide the implementation of an data emitter class, the MyDataWriterEmitterImpl. This class is simply a plain old C++ object without any super class. Two arbitrary member functions are defined on this class for the container to inject DDS data writer(s). On receiving an injected data writer, these member write narrow them down to the user specified DDS type writers and write 20 DDS data out.
ListenerImpl.h and ListenerImpl.C: They provide the implementation of two data reader listener classes, the MyFooDataReaderListenerImpl and MyBarDataReaderListenerImpl. As the demo DDS simplifies all DDS interface to CORBA local interfaces, these implementation classes are simply implemented by inheriting the DDS::DataReaderListener local stub. When data are available for reading, the underlying DDS will callback the on_data_available() method of these implementations and inject DDS data reader references. These listeners will narrow the injected reference down to the user specified DDS type reader (FooDataReader or BarDataReader) and read all queued DDS data in a loop.
writer.xml: This is the deployment descriptor of the DDS data writer application. Two data writers are declared, one under the implicit publisher and another under an explicit publisher. An emitter bean is declared to be instantiated as eager singleton, and has the above two writer references injected in post-instantiation IoC methods.
reader.xml: This is the deployment descriptor of the DDS data reader application. Two data readers are declared, to demonstrate declaring a data readers under implicit as well as explicit subscribers.
writer.C: This is a simple container, used to deploy the DDS data write application declared in the writer.xml.
Because the demo DDS implementation is built on top of OMG Notification service, one must pass the service's IOR or URL to the deployment environment as follows (also see “Running this example” section):
-ORBInitRef NotificationService=<ior or url of the service>
reader.C: This is a simple container, used to deploy the DDS data read application declared in the reader.xml.
Because the demo DDS implementation is built on top of OMG Notification service, one must pass the service's IOR or URL to the deployment environment as follows (also see “Running this example” section):
-ORBInitRef NotificationService=<ior or url of the service>
pocodds: This directory contains a small, simple, functionally limited DDS implementation that, for minimizing the effort, is built on top of existing OMG notification service. PocoCapsule/CORBA-DDS does not couple with or rely on this demo DDS at all. It, as well as this example, are designed to be able to work with other DDS implementations. The purpose of this small demo DDS implementation is merely for the convenience of being able to play this example right out-of-the-box without the complexity of obtaining, installing, and setting up a full blown DDS, as most ORBs come with their own notification service in-box, but rare come with DDS.
To build this example, the environment variable POCOCAPSULE_DIR should point to the PocoCapsule/C++ installed directory. Also, this example assumes an underneath ORB (e.g. VisiBroker/C++, TAO, etc.) is installed and its runtime and development environment (such as POCOCAPSULE_DIR, VBROKER_DIR or TAO_ROOT, etc. env variable) are set according to its product specification. Then, this example can be built by simply invoking gmake/make on linux/unix or nmake on windows.
· Before playing this example, please ensure the LD_LIBRARY_PATH (on linux and solaris) or the PATH (on windows) environment variable is set correctly to include the ${POCOCAPSULE_DIR}/lib directory and the ${VBROKREDIR}/lib (if VisiBroker is used) or the ${TAO_ROOT}/lib directory (if TAO is used).
· Start the DDS service. This depends on the DDS implementation. Typically, it is simply to start a standalone server. For instance, the small demo DDS comes with this example uses a OMG compliant structured event service as the underlying mechanism to perform DDS data publishing/subscribing. Therefore, to play with the example using this out-of-the-box demo DDS, one only needs to start a notification service server, such as, VisiNotify, TAO or JacORB's, then get the URL or IOR of this service and pass it to the DDS reader and writer applications. Typically, the URLs of the above structured event service have the following corbaloc format:
corbaloc::<host>:<port>/NotificationService
Here, the <host> is the domain name or the dotted IP address of the Notification service server host.
For instance, the VisiNotify's default service port is 14100. JacORB server port by default is chosen automatically from dynamic port range. User can also specify a desired port number with -port <port> command line option. On successful startup, JacORB notification server prints out the service URL.
· Start the data reader(s) as:
prompt> reader -ORBInitRef NotificationService=<service URL or IOR>
Here, the -ORBInitRef option and the format of the corbaloc URL are all specified in OMG CORBA and Notification Service standard. Multiple data readers can be started in order to observer data multi-casting.
· Start the data writer(s) as:
prompt> writer -ORBInitRef NotificationService=<service URL or IOR>
Here, the -ORBInitRef option and the format of the corbaloc URL are all specified in OMG CORBA and Notification Service standard.
On successful connection, a writer application will write 20 data values of type Foo, and 20 data values of type Bar. On receiving these 40 DDS data values, the data reader application will print out the contents of these Foo or Bar data values.