Detect the presence of DomainParticipants, DataWriters and DataReaders in the DDS Domain

DDS has a built-in discovery service. This means it can automatically detect the presence of other DDS applications and their entities, that is DomainParticipants, DataWriters, DataReaders, Topics, as they appear and disappear from the DDS domain.

DDS uses this internally to perform its function, for example, matching the local DataWriters on a Topic with the DataReaders it discovers on that same Topic, detecting that a previously-discovered DataWriter is no longer present and triggering application notifications and potential reassignment of instance ownership, etc.

Applications may also want to access this discovery information. This can be used to develop monitoring/supervision tools, or as a means to reactively create DDS entities in response to the presence of other DDS entities in the domain. For example the "RTI Recording Service" tool automatically detects the presence of DataWriters in the DDS domain, it uses the discovery information to create a matching DataReader, and then uses the DataReader to receive the data and store it into disk.  The "rtiddsspy" application uses a similar technique to log the presence or DataWriters and DataReaders, show when they are publishing data, and even print the data that is published on the DDS Domain.

Accessing Discovery Information from an application is very simple:  It is done using the same DataReader API's the application uses to read regular data on application defined Topics. The only difference is that the Topics used, and the DataReader are already built-in into the system. All the application needs to do is look up the DDS entities by their names and start using them.

The entities use to access the discovery information appear summarized in the table below

Built-in DataReader Data TypeTopic Name
ParticipantBuiltinTopicDataDataReaderParticipantBuiltinTopic"DCPSParticipant"
PublicationBuiltinTopicDataDataReaderPublicationBuiltinTopic"DCPSPublication"
SubcriptionBuiltinTopicDataDataReaderSubcriptionBuiltinTopic"DCPSSubscription"

As mentioned these data-types, and DataReaders are already built-into the system so all the application needs to do is retrieve them using the lookup_datareader() on the builtin-subscriber. The concrete syntax depends on the language used. 

For example using the Java API:

Subscriber *builtinSubscriber = participant.get_builtin_subscriber();

    ParticipantBuiltinTopicDataDataReader participantsDR = (ParticipantBuiltinTopicDataDataReader)
        builtinSubscriber.lookup_datareader("DCPSParticipant");

    PublicationBuiltinTopicDataDataReader publicationsDR = (PublicationBuiltinTopicDataDataReader) 
        builtinSubscriber.lookup_datareader("DCPSPublication");

    SubscriptionBuiltinTopicDataDataReader  subscriptionsDR = (SubscriptionBuiltinTopicDataDataReader) 
        builtinSubscriber.lookup_datareader("DCPSSubscription");

For example using the Traditional C++ API:

Subscriber *builtinSubscriber = participant.get_builtin_subscriber();

    ParticipantBuiltinTopicDataDataReader   *participantsDR = ParticipantBuiltinTopicDataDataReader::narrow(
        builtinSubscriber->lookup_datareader("DCPSParticipant"));

    PublicationBuiltinTopicDataDataReader   *publicationsDR = PublicationBuiltinTopicDataDataReader::narrow(
        builtinSubscriber->lookup_datareader("DCPSPublication"));

    SubscriptionBuiltinTopicDataDataReader  *subscriptionsDR = SubscriptionBuiltinTopicDataDataReader::narrow(
        builtinSubscriber->lookup_datareader("DCPSSubscription"));

For example using the C API:

DDS_Subscriber *builtinSubscriber = DDS_DomainParticipant_get_builtin_subscriber(participant);
    DDS_ParticipantBuiltinTopicDataDataReader   *participantsDR = DDS_ParticipantBuiltinTopicDataDataReader_narrow(
        DDS_Subscriber_lookup_datareader(builtinSubscriber, "DCPSParticipant"));
    DDS_PublicationBuiltinTopicDataDataReader   *publicationsDR = DDS_PublicationBuiltinTopicDataDataReader_narrow(
        DDSSubscriber_lookup_datareader(builtinSubscriber, "DCPSPublication"));
    DDS_SubscriptionBuiltinTopicDataDataReader  *subscriptionsDR = DDS_SubscriptionBuiltinTopicDataDataReader_narrow(
        DDS_Subscriber_lookup_datareader(builtinSubscriber, "DCPSSubscription"));

For example using the Modern C++ API:

Subscriber builtin_subscriber = dds::sub::builtin_subscriber(participant);

    std::vector< DataReader<ParticipantBuiltinTopicData> > participant_reader;
    find< DataReader<ParticipantBuiltinTopicData> >(
        builtin_subscriber,
        dds::topic::participant_topic_name(),
        std::back_inserter(participant_reader));

    std::vector< DataReader<SubscriptionBuiltinTopicData> > subscription_reader;
    find< DataReader<SubscriptionBuiltinTopicData> >(
        builtin_subscriber,
        dds::topic::subscription_topic_name(),
        std::back_inserter(subscription_reader));

    std::vector< DataReader<PublicationBuiltinTopicData> > publication_reader;
    find<DataReader<PublicationBuiltinTopicData>>(
        builtin_subscriber,
        dds::topic::publication_topic_name(),
        std::back_inserter(publication_reader));
    
 

A complete Java Example is attached. This example was developed using RTI DDS Version 4.5f.

See also the solution https://community.rti.com/kb/how-can-i-detect-new-datawriters-and-datareaders-joining-domain for a C++ (traditional API) example.

Tags:

Comments

I've tried both of the MonitorDiscovery java snippets.  Neither of them seem to discover existing topics.  It only displays topics that are created after the monitor application is running.

Is there a way to list all the topics that already exist?  I've tried the following code, but I get an exception when I try to execute the get_discovered_topic_data method: 

InstanceHandleSeq seq = new InstanceHandleSeq();

participant.get_discovered_topics(seq);
TopicBuiltinTopicData ttd = new TopicBuiltinTopicData();
for (int i=0;i<seq.size();i++){
  InstanceHandle_t p = (InstanceHandle_t)seq.get(i);
  logger.info(p.toString());
  participant.get_discovered_topic_data(ttd, p);
  logger.info(ttd.toString());
}

The exception I get is "com.rti.dds.infrastructure.RETCODE_UNSUPPORTED".  Which seems to imply that the topic is remote... but I'm running all this on a single machine.

Helloeveryboy. I'm trying to detect when adatawriter fail using on_liveliness_changed. I'm using DDS to communicate twoopendaylight controllers. Both controllers are publisher and subscriber at the same time. In order to optimize my scenario I'm using the listener on_liveliness_changed,howeverI'm having the next error in my simulations when a datawriter is detected.

Exception in thread "Thread-107" java.lang.NullPointerException
at org.sdnhub.odl.tutorial.learningswitch.impl.TutorialL2Forwarding.on_liveliness_changed(TutorialL2Forwarding.java:691)
at com.rti.dds.subscription.DataReaderListenerImpl.on_liveliness_changed(Unknown Source)

The line code referenced in the error is:

builtinSubscriber = participant.get_builtin_subscriber();

the rest of the code is:

ParticipantBuiltinTopicDataDataReader participantsDR = (ParticipantBuiltinTopicDataDataReader) builtinSubscriber.lookup_datareader("DCPSParticipant");
PublicationBuiltinTopicDataDataReader publicationsDR = (PublicationBuiltinTopicDataDataReader) builtinSubscriber.lookup_datareader("DCPSPublication");
SubscriptionBuiltinTopicDataDataReader subscriptionsDR = (SubscriptionBuiltinTopicDataDataReader) builtinSubscriber.lookup_datareader("DCPSSubscription");
PublicationBuiltinTopicData publicationData = new PublicationBuiltinTopicData();
SampleInfo info = new SampleInfo();

because I need to know which datawriter fail. Ihope you can help me. Best regards

Alex