Articles Forum Examples Download Open Source
Copyright(c) 2006, 2007 by Pocomatic Software. All rights reserved.
This examples illustrates how to assemble and deploy event supplier and event consumer applications and use OMG Notification service to build a distributed publish/subscribe system. Following POEM (namely Plain Old Event Model) scenarios are covered by this example:
typed event : The event operation signatures are defined by users in IDL interfaces.
structured event : The event operation and format are predefined by OMG notification service.
sequence event : The event is a sequence of structured events.
untyped event : The event is a CORBA::Any encapsulates arbitrary IDL types defined by users.
type event with filter : similar to typed event. The event subscriber (consumer) set a filter to eliminate certain unwanted events.
structured event with filter : similar to structured event. The event subscriber (consumer) set a filter to eliminate certain unwanted events.
Traditional programmatic approach would require significant amount of boilerplate code in developing above event supplier or consumer applications. Certain scenarios above, for instance the filters and typed event, were even challenges to most CORBA professionals. With PocoCapsule/CORBA application deployment, all above scenarios become straightforward even for novice. Most complexities and boilerplate code are moved into PocoCapsule/CORBA. Developers should only need to know and focus on implementing event emitting and receiving objects (beans), and no longer need to care how to connect them to the OMG notification service. The development procedure of a POCO+POEM application is roughly as follows:
Implement emitters and listeners as POCO beans, which emit and receive POEM events. During this phase, developers only need to focus on defining their application events formats (namely, type, topic, etc.), and implementing application/business logic of event generating and consuming.
Declare type (namely, "typed", "structured", "sequence" and "untyped") and topic (only applies to "structured" and "typed" events) of events that are going to be published/subscribed by each emitter/listener, and the location of event service (or channel, admin) in XML descriptors. At this stage, developers only need to conceptually declare “what” publish/subscribe connections they want, instead of imperatively specify “how” the container should establish these connections.
Deploy the application in PocoCapsule. which will activate emitter/listener beans and connect them to OMG notification service based on “what” is described.
As POCO beans are plain old C++ objects, and POEM events are any ordinary OMG Notification service events defined in conventional applications. An application developed in above scenario has no dependency on the PocoCapsule container itself, and therefore, their application/business logic (namely event generating and consumption) can be unit tested/used outside the container.
MyTypedEvent.idl: This is the IDL definition of a typed event interface.
Three event sending operations are defined on this typed event interface, namely hello(), headlinenews() and stockquote().
The client stub and server skeleton classes source code from this IDL can be generated using the given ORB's IDL-to-C++ pre-compiler, for instance, the idl2cpp of VisiBroker/C++..
publisher.C: This is a simple container, used to deploy event emitter beans.
This publisher example assumes the OMG Notification service's IOR or URL is specified as in the main command line arguments to be passed to the ORB_init() (see “Running this example” section)
-ORBInitRef NotificationService=<ior or url of the service>
This example also assumes the event type selector -- typed, untyped, structured or sequence, is passed in as first command-line argument. (also see “Running this example” section)
subscriber.C: This is a simple container, used to deploy event listener beans.
This subscriber example assumes the OMG Notification service's IOR or URL is specified in the main command line arguments to be passed to the ORB_init() (see “Running this example” section)
-ORBInitRef NotificationService=<ior or url of the service>
This example also assumes the event type selector -- typed, untyped, structured or sequence, is passed in as first command-line argument. (also see “Running this example” section)
EmitterImpl.h and EmitterImpl.C: They provide the implementation of an event emitter class, the EventEmitterImpl. It supports OMG standardized operations to inject typed, structured, sequence and untyped proxy consumer references.
void connect_typed_push_consumer(CosTypedEventComm::TypedPushConsumer_ptr consumer);
void connect_structured_push_consumer(CosNotifyComm::StructuredPushConsumer_ptr consumer);
void connect_sequence_push_consumer(CosNotifyComm::SequencePushConsumer_ptr consumer);
void connect_any_push_consumer(CosEventComm::PushConsumer_ptr consumer);
In this example, a native implementation is illustrated. Namely, the emitter implementation only need to provided all consumer connection (injection) operations, but does not inherit from a POA skeleton. This kind of implementation should be deployed with kind attribute of <event-supplier> equals to "native" instead of "servant" or "object" (see publish.xml).
ListenerImpl.h and ListenerImpl.C: They provide the implementation of an event listener class, the EventListenerImpl. It implements the user defined event operations:
void hello(const char* greeting, const char* sender);
void headlinenews(const sample::NewsBrief& news, const char* sender);
void stockquote(const char* id, CORBA::Float quote);
as well as OMG standardized event pushing callback operations for structured, sequence and untyped events:
void push_structured_event(const CosNotification::StructuredEvent& event);
void push_structured_events(const CosNotification::EventBatch& events);
void push(const CORBA::Any& event);
In this example, a native implementation is illustrated. Namely, the listener implementation only needs to provide all event push-in callback operations, but does not inherit from a POA skeleton. This kind of implementation should be deployed with the kind attribute of <event-consumer> equals to "native" instead of "servant" or "object" (see subscribe.xml).
publish.xml: This is the deployment descriptor of the event publisher application.
It declares 4 event supplier adapters of typed, structured, sequence and untyped respectively. These adapters are declared to be “lazy-init”, therefore, in this case, will only be instantiated when getBean() is called with their id from the main() of publisher.C. This publisher chooses an event supplier adapter to initiate based on user input args[0].
subscribe.xml: This is the deployment descriptor of the event subscriber application.
It declares 6 event consumer adapters of typed, structured, sequence, untyped, typed with filter and structured with filter respectively. These adapters are declared to be “lazy-init”, therefore, in this case, will only be instantiated when getBean() is called with their id from the main() of subscriber.C. The subscriber chooses a listener to initiate based on user input args[0].
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 starting the server, make sure 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 a OMG Notification service (or typed service, if separate), for instance, VisiNotify, TAO or JacORB's notification service. VisiNotify supports typed as well as predefined (structured/sequence/untyped) event services in one server. The default service URL is:
corbaloc::<host>:14100/NotificationService
Here, <host> is the domain or dotted IP address of the Notification service server.
JacORB notification service supports typed and predefined event services in two separate servers, therefore, if they are on same host at same time, they must be started on different ports. The 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 print out the service URL, for instance:
corbaloc::<host>:<port>/NotificationService
· Start the subscriber(s) as:
prompt> subscriber (typed|structured|sequence|untyped|typed-filter|structured-filter) \
-ORBInitRef NotificationService=<service URL>For instance, to start a structured event subscriber and connect it to a Notification service on address 192.168.2.2 port 14100, the command line should look like:
prompt> subscriber structured -ORBInitRef NotificationService=corbaloc::192.168.2.2:14100/NotificationService
Here, the -ORBInitRef option and the format of the corbaloc URL are all specified in OMG CORBA and Notification Service standard. Multiple subscribers can be started in order to observer event multi-casting.
· Start the publisher as:
prompt> publisher (typed|structured|sequence|untyped) \
-ORBInitRef NotificationService=<service URL>For instance, to start a typed event supplier and connect it to a Notification service on address 192.168.2.2 port 14100, the command line should look like:
prompt> subscriber typed -ORBInitRef NotificationService=corbaloc::192.168.2.2:14100/NotificationService
Here, the -ORBInitRef option and the format of the corbaloc URL are all specified in OMG CORBA and Notification Service standard.
On successful connection, typed emitter will push 3 typed events. On receiving these 3 events, a typed event subscriber will print out the following messages:
...
received a hello 'Greeting to everyone' event from info service
received a headline news: {'new POCO release', 'POCO is a Plain Old Common Object container'} event from info service
received a stockquote: id=POCO, quote=120.000000 event
...other emitters each will push 20 events to the notification channel. A subscriber will also print out the messages on receiving them. For instance, for each individual received structured event, a structured event subscriber will print a message similar to the following one:
...
---- received a structured event ----
event.header {
.fixed_header {
.event_type {
.domain_name = 'pocomatic'
.type_name = 'com'
}
.event_name = 'stockquote'
}
.variable_header {
[0] { .name='time', .value='12:12:59' }
}
}
.filterable_data {
[0] { .name='hello', .value='from provider' }
}
}
.reminder_of_body = 'structured event count 20'
...By default, POCO will set the destroy method to disconnect the proxy consumer created in the notification service. This method is called, when the terminate() method is called on the poco application context (see publisher.C).