## Publish/Subscribe

RCF provides a built in publish/subscribe implementation. Publishers can publish remote calls to a group of peer components (subscribers). Publishing servers can publish on any number of topics, and subscribers can pick which topics to subscribe to.

Publish/subscribe can be used in the presence of firewalls and NAT's. The only network topology requirement is that the subscriber must be able to initiate a network connection to the publisher. Publishers will never attempt to establish network connections to their subscribers.

### Publishers

To create a publisher, use `RcfServer::createPublisher<>()`:

    RCF::RcfServer pubServer( RCF::TcpEndpoint(50001) );
    pubServer.start();

    typedef RCF::Publisher<I_HelloWorld> HelloWorldPublisher;
    typedef boost::shared_ptr< HelloWorldPublisher > HelloWorldPublisherPtr;
    HelloWorldPublisherPtr publisherPtr = pubServer.createPublisher<I_HelloWorld>();

This will create a publisher with a default topic name. The default topic name is the runtime name of the RCF interface passed to `RcfServer::createPublisher<>()` (in this case `"I_HelloWorld"`).

The topic name can also be set manually. For example, to create two distinct publishers, using the same RCF interface:

    RCF::PublisherParms pubParms;
    pubParms.setTopicName("HelloWorld_Topic_1");
    HelloWorldPublisherPtr publisher1Ptr = pubServer.createPublisher<I_HelloWorld>(pubParms);

    pubParms.setTopicName("HelloWorld_Topic_2");
    HelloWorldPublisherPtr publisher2Ptr = pubServer.createPublisher<I_HelloWorld>(pubParms);

The `Publisher<>` object returned by `RcfServer::createPublisher<>()` is used to publish remote calls. Published remote calls always have one-way semantics, and are received by all subscribers currently subscribing to that publishing topic:

    publisherPtr->publish().Print("First published message.");
    publisherPtr->publish().Print("Second published message.");

The publishing topic is closed, and all of its subscribers disconnected, when the `Publisher<>` object is destroyed, or when `Publisher<>::close()` is called.

    // Close the publishing topic. All subscribers will be disconnected.
    publisherPtr->close();

### Subscribers

To subscribe to a publisher, use `RcfServer::createSubscription<>()`:

    RCF::RcfServer subServer( RCF::TcpEndpoint(-1) );
    subServer.start();

    HelloWorldImpl helloWorldImpl;
    RCF::SubscriptionParms subParms;
    subParms.setPublisherEndpoint( RCF::TcpEndpoint(50001) );

    RCF::SubscriptionPtr subscriptionPtr = subServer.createSubscription<I_HelloWorld>(
        helloWorldImpl,
        subParms);

The topic name defaults to the runtime name of the RCF interface (in this case `"I_HelloWorld"`). The topic name can also be specified manually:

    HelloWorldImpl helloWorldImpl;

    RCF::SubscriptionParms subParms;
    subParms.setPublisherEndpoint( RCF::TcpEndpoint(50001) );
    subParms.setTopicName("HelloWorld_Topic1");

    RCF::SubscriptionPtr subscription1Ptr = subServer.createSubscription<I_HelloWorld>(
        helloWorldImpl,
        subParms);

    subParms.setTopicName("HelloWorld_Topic2");

    RCF::SubscriptionPtr subscription2Ptr = subServer.createSubscription<I_HelloWorld>(
        helloWorldImpl,
        subParms);

The first parameter passed to `createSubscription<>()` is the object which will receive the published messages. It is the applications responsibility to make sure this object is not destroyed while the subscription is still connected.

A disconnect callback can be provided, which will be called if the subscriber is disconnected:

    void onSubscriptionDisconnected(RCF::RcfSession & session)
    {
        // Handle subscription disconnection here.
        // ...
    }

    HelloWorldImpl helloWorldImpl;

    RCF::SubscriptionParms subParms;
    subParms.setPublisherEndpoint( RCF::TcpEndpoint(50001) );
    subParms.setOnSubscriptionDisconnect(&onSubscriptionDisconnected);

    RCF::SubscriptionPtr subscriptionPtr = subServer.createSubscription<I_HelloWorld>(
        helloWorldImpl,
        subParms);

To terminate a subscription, destroy the `Subscription` object, or call `Subscription::close()`:

    subscriptionPtr->close();

### Access control

Access controls can be applied to publishers, in the form of an access control callback which will be called for each subscriber attempting to subscribe to the publisher. Similarly to servant binding access controls, publisher access controls can be used to inspect the `RcfSession` of the subscriber connections for any relevant authentication information:

    bool onSubscriberConnect(RCF::RcfSession & session, const std::string & topicName)
    {
        // Return true to allow access, false otherwise.
        // ...

        return true;
    }

    void onSubscriberDisconnect(RCF::RcfSession & session, const std::string & topicName)
    {
        // ...
    }

    RCF::PublisherParms pubParms;
    pubParms.setOnSubscriberConnect(onSubscriberConnect);
    pubParms.setOnSubscriberDisconnect(onSubscriberDisconnect);
    HelloWorldPublisherPtr publisher1Ptr = pubServer.createPublisher<I_HelloWorld>(pubParms);