EventService - Using the CORBA Event Service
Description:
The CORBA Event Service is one of the basic Common Object Services, implementing a distributed variation of the well known 'Observer' pattern. It is defined by two standard OMG IDL files. Therefore, the CORBA Event Service is implemented as a normal CORBA server, and will be published via the CORBA Naming Service (s.f. the HelloNS example).
To use the Event Service, an Event Consumer (implementing a standard interface) has to be provided by the developer, which receives the events. Optionally, if there are resources to be released on the client side when the communication stops, an Event Supplier interface may be implemented, too. (For the sake of simplicity, we do not do that within this example.)
Usually, the necessary stubs and skeletons for this would have to be generated by compiling the published standard IDL files, but for convenience the J-Integra® Espresso runtime DLL already contains the compiled stubs and skeletons for all roles within the Event Service.
Source:
\Demo\EventService
Goal:
Using the CORBA Event Service according the standard 'Push' scenario
Example
Step 1. The Standard OMG IDL:
The CORBA Event Service is descibed by two interfaces
- CosEventChannelComm,
containing the Supplier & Consumer interfaces to be implemented by the user.
- CosEventChannelAdmin,
containing the interfaces of the actual service object (see the OMG for publications).
We will implement a PushConsumer (within CosEventComm):
module CosEventComm
{
exception Disconnected {};
interface PushConsumer
{
/// Receive one event from the Consumer's peer.
void push (in any data) raises (Disconnected);
/// The peer has disconnected from the PushConsumer.
void disconnect_push_consumer ();
};
};
|
Step 2. The Implementation (EventMng.cs):
class EventMng: Ics.CosEventComm.PushConsumerPOA
{
public EventMng ()
{
}
public override void push( Ics.CORBA.Any _data )
{
string str = _data.extract_string();
System.Console.WriteLine("Push: '{0}'", str);
}
public override void disconnect_push_consumer( )
{
}
}
|
(Regarding the use of CORBA 'any's, refer to the Any example.)
Step 3. The Server / Consumer Process (Consumer.cs):
To attach our PushConsumer implementation to the CORBA Event Service, we have to retrieve
a reference of the service from the CORBA Naming Service first (s.f. the HelloNS example):
Ics.CORBA.Object oObjNsRef = m_oOrb.resolve_initial_references("NameService");
Ics.CosNaming.NamingContext oNsCtx = Ics.CosNaming.NamingContextHelper.narrow( oObjNsRef);
|
Retrieve the Event Service that was previously registered under the name 'EvtBsp':
Ics.CosNaming.NameComponent[] arNameComp = new Ics.CosNaming.NameComponent[1];
arNameComp[0].id = "EvtBsp";
arNameComp[0].kind = "";
Ics.CORBA.Object oRef = null;
oRef = oNsCtx.resolve( arNameComp);
Ics.CosEventChannelAdmin.EventChannel oEc = Ics.CosEventChannelAdmin.EventChannelHelper.narrow( oRef);
|
Create an instance of the PushConsumer implementation:
EventMng oEventMng = new EventMng();
|
Obtain a ConsumerAdmin from the EventChannel:
Ics.CosEventChannelAdmin.ConsumerAdmin oConsumerAdmin = oEc.for_consumers();
|
Obtain a ProxyPushSupplier from the ConsumerAdmin:
Ics.CosEventChannelAdmin.ProxyPushSupplier oSupplierProxy = oConsumerAdmin.obtain_push_supplier();
|
Finally, connect the ProxyPushSupplier with our PushConsumer's servant:
oSupplierProxy.connect_push_consumer( oEventMng._this() );
|
Now the PushConsumer should be ready to receive events.
Step 4. The Client / Supplier Process (Supplier.cs):
Like the consumer, the supplier has to get a reference of the Event Service from the Naming Service:
Ics.CORBA.Object oObjNsRef = m_oOrb.resolve_initial_references("NameService");
Ics.CosNaming.NamingContext oNsCtx = Ics.CosNaming.NamingContextHelper.narrow( oObjNsRef);
Ics.CosNaming.NameComponent[] arNameComp = new Ics.CosNaming.NameComponent[1];
arNameComp[0].id = "EvtBsp";
arNameComp[0].kind = "";
Ics.CORBA.Object oRef = null;
oRef = oNsCtx.resolve( arNameComp);
Ics.CosEventChannelAdmin.EventChannel oEc = Ics.CosEventChannelAdmin.EventChannelHelper.narrow( oRef);
|
Obtain a SupplierAdmin from the EventChannel and a ProxyPushConsumer from the SupplierAdmin.
Because we decided not to explicitly implement a PushSupplier, we activate the ProxyPushConsumer
by connecting a 'null' Supplier:
Ics.CosEventChannelAdmin.SupplierAdmin oSupplierAdmin = oEc.for_suppliers();
Ics.CosEventChannelAdmin.ProxyPushConsumer oProxyPushConsumer = oSupplierAdmin.obtain_push_consumer();
oProxyPushConsumer.connect_push_supplier( null);
|
Finally, we are ready to push our events into the EventChannel (using its ProxyPushConsumer):
Ics.CORBA.Any anyEvent = m_oOrb.create_any();
string strLine;
while( true )
{
Console.Write("Enter a Name :");
strLine = Console.ReadLine();
anyEvent.insert_string( strLine);
oProxyPushConsumer.push( anyEvent);
}
|
(Note, that all event data will be wrapped into an 'any', because we use only the simple untyped Event Service.
There is also a Typed Event Service available, which allows defining own event structures to pass through the
Event Channel.)
Step 5. Running the Example:
a.) Start the J-Integra® Espresso Naming Service:
b.) Start an Event Service.
J-Integra® Espresso does not come with an Event Service, but there are several CORBA Event Service implementations
available, often for free use. A good start could be TAO (The ACE ORB), a free C++ ORB implementation, which
comes with a lot of ready-for-use service implementations.
Start the TAO Event Service with a reference to a CORBA Naming Service on TCP/IP port 2809, which is the
default port used by the J-Integra® Espresso Naming Service 'IcsNs.exe', and the name 'EvtBsp':
> CosEvent_Service.exe -ORBInitRef NameService=corbaloc:iiop:1.1@localhost:2809/NameService -ORBDebug -n EvtBsp
|
c.) Start the Consumer.
d.) Start the Supplier.