uDDS tries to be as simple as possible. And yet function as 100% wire compatible DDS participant. By providing a simplistic API, means that not all of the features available on DDS specification just cannot be implemented. And there might be situations, where communication cannot be established because of these restrictions.
For this reason, there are extensions points that can be used to provide missing features, while keeping uDDS API as simple as possible. Note, that extensions are a constant work-in-progress type of thing. They will be added and modified as needed to uDDS and jRTPS.
EntityFactory is used to create DataWriter and DataReader entities. One can provide a custom EntityFactory to udds Participant, which is used to extend functionality of DataWriter and DataReader entities. For example, DDS specification (Java 5 PSM) has defined write methods for DataWriter, that take a timestamp as one of arguments. uDDS DataWriter has no such method available. Fortunately, there is such a method: HistoryCache.write(T, long). And luckily, HistoryCache is provided to EntityFactory when creating a DataWriter.
public class CustomEntityFactory extends EntityFactory { @Override public <T> DataWriter<T> createDataWriter(Participant p, Class<T> type, RTPSWriter<T> rtpsWriter, HistoryCache<T> hCache) { return new CustomDataWriter<>(p, type, rtpsWriter, hCache); } } public class CustomDataWriter<T> extends DataWriter<T> { CustomDataWriter(Participant p, Class<T> type, RTPSWriter<T> writer, HistoryCache<T> hCache) { super(p, type, writer, hCache); } public void write(T sample, long timestamp) { try { hCache.write(sample, timestamp); // Write a sample with given timestamp } finally { super.notifyReaders(); // notify remote readers of new data in HistoryCache } } }
The code above would allow one to use CustomDataWriter by type casting DataWriter created by Participant.
Participant p = new Participant(0, 2, new CustomEntityFactory(), null); CustomDataWriter<HelloMessage> cdw = (CustomDataWriter<HelloMessage>) p.createDataWriter(HelloMessage.class); cdw.write(new HelloMessage(1, "hello"), System.currentTimeMillis());
RTPS specification says that only UDP based communication is mandatory for interoperability. There might be good reasons to provide alternate transports. TransportProvider is used to provide transports of any kind. As a proof-of-concept, In-memory TransportProvider with scheme mem is provided. Actually, it is more than just a proof-of-concept. It is intented to be used with automated tests, that test correct behaviour of two participants.
TransportProvider serves two purposes. One is to provide actual transport specific receivers and transmitters. Other is to provide Locators, that are used to advertise participants communication capabilities to others.
Participant uses configuration parametes jrtps.listener-uris, jrtps.discovery.listener-uris and jrtps.discovery.announce-uris to create Receivers and Transmitters for readers and writers. For these URIs, Participant uses the scheme of the URI to find a suitable TransportProvider. In order for a TransportProvider to be accessible for this purpose, one needs to register one. This is how it is done with MemProvider, which extends a TransportProvider
Configuration cfg = new Configuration("/mem-test-1.properties"); MemProvider mp = new MemProvider(cfg); TransportProvider.registerTransportProvider("mem", mp, MemProvider.LOCATOR_KIND_MEM);
Note, that UDP Transport provider is automatically registered the same way, so it is always accessible for Participant(and for configuration files). The code above would allow to use these configuration options in configuration file:
jrtps.listener-uris = mem://10.10.10.11:1234 jrtps.discovery.listener-uris = mem://10.10.10.11:1024 jrtps.discovery.announce-uris = mem://10.10.10.12:1024
AuthenticationPlugin is used to provide different authentication mechanisms. jRTPS has one predefined AuthenticationPlugin available: jks, which is automatically registered during startup. Configuration parameter udds.security.authentication is used to indicate which plugin to use.
One can use a custom AuthenticationPlugin by registering
AuthenticationPlugin.registerPlugin(new CustomAuthPlugin());
The code above would allow this configuration to be used in jrtps.properties, if the name. of the plugin is defined as 'custom' by CustomAuthPlugin:
udds.security.authentication = custom
CryptoPlugin is used to encode/decode bytes that are sent on wire. One can register new tranfromations to CryptoPlugin by calling CryptoPlugin.registerTransformer(Transformer).