5. Writing an Event Service Client

5.1. Connecting
5.2. Using any type
5.3. Disconnecting

The examples are a great place to start learning about the event service. Feel free to use them as a starting point for your own clients. The same examples are available as C++, Python and Java. However, this section provides a few more general instructions.

5.1. Connecting

Here's a list of all the ways clients can locate the omniEvents server's EventChannelFactory object:

by IOR. (omniEvents -v)

The -v option prints the EventChannelFactory's IOR. You can then use a straightforward string_to_object() method call to turn this into an object reference.

by corbaloc::host:port/omniEvents

The EventChannelFactory is registered in the omniORB INSPOA as omniEvents which means that you can use the human readable ‘corbaloc’ string above instead of the IOR. Replace host with omniEvents' hostname and port with the TCP port: 11169 (or whatever you chose with the -p option).

resolve_initial_references("EventService")

If omniORB.cfg is properly configured, you can use resolve_initial_references() to find the event service, just as is usually done for the Naming Service. Just add a line like this:

InitRef = EventService=corbaloc::host:port/omniEvents
The naming service (omniEvents -N NAME)

omniEvents always registers the EventChannelFactory as a top-level entry in the naming service. Use the -N option to control the context, id & kind. (EventChannelFactory by default).

5.2. Using any type

The “events” pushed and pulled around by the Event Service are simply CORBA any values. The any type can hold any CORBA type. The examples simply send a long value, but a more realistic problem would employ a user-defined struct as the event.

For user-defined types you first need to define the type in IDL, then compile the IDL. For omniORB with C++ you would use omniidl -bcxx -Wba. The -Wba generates the operators you will need to use your type with CORBA::Any.

Here's a small example:

  module MyMessages {
    struct NVPair {
      NameType  name;
      ValueType value;
    };
  };

Assuming you compile this IDL correctly, you will have insertion & extraction methods: operator>>=() and operator<<=(). Here are examples of how to use them:

  CORBA::Any data;

  // Insert by value
  MyMessages::NVPair inputNvPair = ...
  data <<= inputNvPair; // takes a deep copy.

  // Insert by pointer
  MyMessages::NVPair* inputNvPairPtr = ...
  data <<= inputNvPairPtr; // does NOT copy - assumes ownership
  //XX delete inputNvPairPtr;  <== NO!! 
  .
  .
  .
  // Extract
  const MyMessages::NVPair* outputNvPairPtr = NULL;
  if(data >>= outputNvPairPtr)
  {
    // Use outputNvPairPtr BUT DON'T DELETE IT!!
  }
  else
  {
    cerr<<"Wrong type!!"<<endl;
  }

Notice the memory ownership issues. It's best to double check each time you use <<= or >>= until you're confident you've got it right.

5.3. Disconnecting

All Supplier and Consumer objects have a disconnect_*() method. This means that each connection has two disconnect methods, one at each end. Which method should you call to terminate the connection?

The best approach is to call the Proxy's disconnect_*(), rather than your own. (Either will work, but instructing the Proxy to disconnect is more efficient.)

The rule for implementing your own servant's disconnect_*() method is quite simple. Each disconnect_*() method should call the other disconnect_*() method. It is the responsibility of the Event Service end (the Proxy) to ensure that an infinite loop doesn't occur. So clients don't have to worry - they should always just call the Proxy's disconnect_*() when their own disconnect_*() is called.

There is of course NO GUARANTEE that a disconnect_*() method will only be called once. You should never assume that your servants' methods will not be called until the object has actually been deactivated in the POA.

It is possible to connect to ProxyPushConsumer & ProxyPullSupplier objects without providing an address for callbacks. When you do that, the proxies cannot call your disconnect method. If you choose to connect to these proxies without providing an address for callbacks, then you must clean up your own objects without help from the Event Service.

Note

These semantics only apply to Event Service v1.1 implementations such as omniEvents v2.6. Earlier specifications were vague about disconnection semantics, so you must be VERY careful if you want to interoperate with an older Event Service implementation (such as omniEvents v2.4 and earlier).