
net.sf.jrtps.rtps.RTPSParticipant Maven / Gradle / Ivy
package net.sf.jrtps.rtps;
import java.io.IOException;
import java.net.URI;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import net.sf.jrtps.Configuration;
import net.sf.jrtps.QualityOfService;
import net.sf.jrtps.builtin.ParticipantData;
import net.sf.jrtps.transport.Receiver;
import net.sf.jrtps.transport.TransportProvider;
import net.sf.jrtps.types.EntityId;
import net.sf.jrtps.types.Guid;
import net.sf.jrtps.types.GuidPrefix;
import net.sf.jrtps.types.Locator;
import net.sf.jrtps.udds.security.AuthenticationPlugin;
import net.sf.jrtps.util.Watchdog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* RTPSParticipant is the main entry point to RTPS (DDS) domain. Participant is
* responsible for creating readers and writers and setting up network
* receivers.
*
* @author mcr70
*
*/
public class RTPSParticipant {
private static final Logger logger = LoggerFactory.getLogger(RTPSParticipant.class);
private final Configuration config;
private final ScheduledThreadPoolExecutor threadPoolExecutor;
private final Watchdog watchdog;
/**
* Maps that stores discovered participants. discovered participant is
* shared with all entities created by this participant.
*/
private final Map discoveredParticipants;
/**
* A Set that stores network receivers for each locator we know. (For
* listening purposes)
*/
private Set receivers = new HashSet<>();
private final List> readerEndpoints = new CopyOnWriteArrayList<>();
private final List> writerEndpoints = new CopyOnWriteArrayList<>();
private final LinkedList discoveryLocators = new LinkedList<>();
private final LinkedList userdataLocators = new LinkedList<>();
private final Guid guid;
private RTPSMessageReceiver handler;
private int domainId;
private int participantId;
private final AuthenticationPlugin aPlugin;
/**
* Creates a new participant with given domainId and participantId. Domain
* ID and participant ID is used to construct unicast locators to this
* RTPSParticipant. In general, participants in the same domain get to know
* each other through SPDP. Each participant has a unique unicast locator
* to access its endpoints.
*
* @param guid Guid, that is assigned to this participant. Every entity created by this
* RTPSParticipant will share the GuidPrefix of this Guid.
* @param domainId Domain ID of the participant
* @param participantId Participant ID of this participant. If set to -1, and port number is not given
* during starting of receivers, participantId will be determined based on the first
* suitable network socket.
* @param tpe threadPoolExecutor
* @param discoveredParticipants a Map that holds discovered participants
* @param aPlugin AuthenticationPlugin
*/
public RTPSParticipant(Guid guid, int domainId, int participantId, ScheduledThreadPoolExecutor tpe,
Map discoveredParticipants, AuthenticationPlugin aPlugin) {
this.guid = guid;
this.domainId = domainId;
this.participantId = participantId;
this.threadPoolExecutor = tpe;
this.aPlugin = aPlugin;
this.watchdog = new Watchdog(threadPoolExecutor);
this.discoveredParticipants = discoveredParticipants;
this.config = aPlugin.getConfiguration();
}
/**
* Starts this Participant. All the configured endpoints are initialized.
*/
public void start() {
BlockingQueue queue = new LinkedBlockingQueue<>(config.getMessageQueueSize());
int bufferSize = config.getBufferSize();
// NOTE: We can have only one MessageReceiver. pending samples concept
// relies on it.
handler = new RTPSMessageReceiver(aPlugin.getCryptoPlugin(), this, queue, config);
threadPoolExecutor.execute(handler);
logger.debug("Starting receivers for discovery");
List discoveryURIs = config.getDiscoveryListenerURIs();
startReceiversForURIs(queue, bufferSize, discoveryURIs, true);
logger.debug("Starting receivers for user data");
List listenerURIs = config.getListenerURIs();
startReceiversForURIs(queue, bufferSize, listenerURIs, false);
logger.debug("{} receivers, {} readers and {} writers started", receivers.size(), readerEndpoints.size(),
writerEndpoints.size());
}
/**
* Creates a new RTPSReader.
*
* @param eId EntityId of the reader
* @param topicName Name of the topic
* @param rCache ReaderCache
* @param qos QualityOfService
*
* @return RTPSReader
*/
public RTPSReader createReader(EntityId eId, String topicName, ReaderCache rCache, QualityOfService qos) {
RTPSReader reader = new RTPSReader(this, eId, topicName, rCache, qos, config);
reader.setDiscoveredParticipants(discoveredParticipants);
readerEndpoints.add(reader);
return reader;
}
/**
* Creates a new RTPSWriter.
*
* @param eId EntityId of the reader
* @param topicName Name of the topic
* @param wCache
* WriterCache
* @param qos
* QualityOfService
*
* @return RTPSWriter
*/
public RTPSWriter createWriter(EntityId eId, String topicName, WriterCache wCache, QualityOfService qos) {
RTPSWriter writer = new RTPSWriter(this, eId, topicName, wCache, qos, config);
writer.setDiscoveredParticipants(discoveredParticipants);
writerEndpoints.add(writer);
return writer;
}
/**
* Close this RTPSParticipant. All the network listeners will be stopped and
* all the history caches of all entities will be cleared.
*/
public void close() {
logger.debug("Closing RTPSParticipant {}", guid);
handler.close();
for (Receiver r : receivers) { // close network receivers
r.close();
}
readerEndpoints.clear();
for (RTPSWriter> w : writerEndpoints) { // Closes periodical announce thread
w.close();
}
writerEndpoints.clear();
}
/**
* Gets the guid of this participant.
*
* @return guid
*/
public Guid getGuid() {
return guid;
}
/**
* Gets the Locators that can be used for discovery
* @return a List of Locators
*/
public List getDiscoveryLocators() {
return discoveryLocators;
}
/**
* Gets the Locators that can be used for user data
* @return a List of Locators
*/
public List getUserdataLocators() {
return userdataLocators;
}
/**
* Ignores messages originating from given Participant
* @param prefix GuidPrefix of the participant to ignore
*/
public void ignoreParticipant(GuidPrefix prefix) {
handler.ignoreParticipant(prefix);
}
/**
* Gets the domainId of this participant;
*
* @return domainId
*/
int getDomainId() {
return domainId;
}
/**
* Waits for a given amount of milliseconds.
*
* @param millis
* @return true, if timeout occured normally
*/
boolean waitFor(int millis) {
if (millis > 0) {
try {
return !threadPoolExecutor.awaitTermination(millis, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
logger.debug("waitFor(...) was interrupted");
}
}
return false;
}
/**
* Schedules given Runnable to be executed at given rate.
*
* @param r
* @param millis
* Number of milliseconds between executions
* @return ScheduledFuture
*/
ScheduledFuture> scheduleAtFixedRate(Runnable r, long millis) {
return threadPoolExecutor.scheduleAtFixedRate(r, millis, millis, TimeUnit.MILLISECONDS);
}
ScheduledFuture> schedule(Runnable r, long delayInMillis) {
return threadPoolExecutor.schedule(r, delayInMillis, TimeUnit.MILLISECONDS);
}
/**
* Gets a Reader with given readerId. If readerId is null or
* EntityId_t.UNKNOWN_ENTITY, a search is made to match with corresponding
* writerId. I.e. If writer is SEDP_BUILTIN_PUBLICATIONS_WRITER, a search is
* made for SEDP_BUILTIN_PUBLICATIONS_READER.
*
* @param readerId
* @param sourceGuidPrefix
* @param writerId
* @return RTPSReader
*/
RTPSReader> getReader(EntityId readerId, GuidPrefix sourceGuidPrefix, EntityId writerId) {
//logger.warn("getReader({}, {}, {}", readerId, sourceGuidPrefix, writerId);
if (readerId != null && !EntityId.UNKNOWN_ENTITY.equals(readerId)) {
return getReader(readerId);
}
if (writerId.equals(EntityId.SEDP_BUILTIN_PUBLICATIONS_WRITER)) {
return getReader(EntityId.SEDP_BUILTIN_PUBLICATIONS_READER);
}
if (writerId.equals(EntityId.SEDP_BUILTIN_SUBSCRIPTIONS_WRITER)) {
return getReader(EntityId.SEDP_BUILTIN_SUBSCRIPTIONS_READER);
}
if (writerId.equals(EntityId.SEDP_BUILTIN_TOPIC_WRITER)) {
return getReader(EntityId.SEDP_BUILTIN_TOPIC_READER);
}
if (writerId.equals(EntityId.SPDP_BUILTIN_PARTICIPANT_WRITER)) {
return getReader(EntityId.SPDP_BUILTIN_PARTICIPANT_READER);
}
if (writerId.equals(EntityId.BUILTIN_PARTICIPANT_MESSAGE_WRITER)) {
return getReader(EntityId.BUILTIN_PARTICIPANT_MESSAGE_READER);
}
Guid writerGuid = new Guid(sourceGuidPrefix, writerId);
if (EntityId.UNKNOWN_ENTITY.equals(readerId)) {
StringBuffer sb = new StringBuffer();
logger.debug("writer {} wants to talk to UNKNOWN_ENTITY", writerId);
for (RTPSReader> r : readerEndpoints) {
logger.trace("Check if reader {} is matched: {}", r.getEntityId(), r.isMatchedWith(writerGuid));
sb.append(r.getEntityId() + " ");
if (r.isMatchedWith(writerGuid)) {
logger.debug("Found reader {} that is matched with {}", r.getEntityId(), writerGuid);
return r; // TODO: we should return a List
}
}
logger.trace("Known reader entities: {}", sb);
}
return null;
}
RTPSWriter> getWriter(EntityId writerId, GuidPrefix sourceGuidPrefix, EntityId readerId) {
if (writerId != null && !EntityId.UNKNOWN_ENTITY.equals(writerId)) {
return getWriter(writerId);
}
if (readerId.equals(EntityId.SEDP_BUILTIN_PUBLICATIONS_READER)) {
return getWriter(EntityId.SEDP_BUILTIN_PUBLICATIONS_WRITER);
}
if (readerId.equals(EntityId.SEDP_BUILTIN_SUBSCRIPTIONS_READER)) {
return getWriter(EntityId.SEDP_BUILTIN_SUBSCRIPTIONS_WRITER);
}
if (readerId.equals(EntityId.SEDP_BUILTIN_TOPIC_READER)) {
return getWriter(EntityId.SEDP_BUILTIN_TOPIC_WRITER);
}
if (readerId.equals(EntityId.SPDP_BUILTIN_PARTICIPANT_READER)) {
return getWriter(EntityId.SPDP_BUILTIN_PARTICIPANT_WRITER);
}
if (readerId.equals(EntityId.BUILTIN_PARTICIPANT_MESSAGE_READER)) {
return getWriter(EntityId.BUILTIN_PARTICIPANT_MESSAGE_WRITER);
}
Guid readerGuid = new Guid(sourceGuidPrefix, readerId);
if (EntityId.UNKNOWN_ENTITY.equals(writerId)) {
for (RTPSWriter> writer : writerEndpoints) {
if (writer.isMatchedWith(readerGuid)) {
return writer; // TODO: we should return a List
}
}
}
logger.warn("None of the writers were matched with reader {}", readerGuid);
return null;
}
/**
* Gets the Watchdog of this RTPSParticipant.
* @return Watchdog
*/
Watchdog getWatchdog() {
return watchdog;
}
/**
* Finds a Reader with given entity id.
*
* @param readerId
* @return RTPSReader
*/
private RTPSReader> getReader(EntityId readerId) {
for (RTPSReader> reader : readerEndpoints) {
if (reader.getGuid().getEntityId().equals(readerId)) {
return reader;
}
}
return null;
}
/**
* Finds a Writer with given entity id.
*
* @param writerId
* @return RTPSWriter
*/
private RTPSWriter> getWriter(EntityId writerId) {
for (RTPSWriter> writer : writerEndpoints) {
if (writer.getGuid().getEntityId().equals(writerId)) {
return writer;
}
}
return null;
}
private void startReceiversForURIs(BlockingQueue queue, int bufferSize, List listenerURIs,
boolean discovery) {
for (URI uri : listenerURIs) {
TransportProvider provider = TransportProvider.getInstance(uri.getScheme());
if (provider != null) {
try {
logger.debug("Starting receiver for {}", uri);
Receiver receiver = provider.createReceiver(uri, domainId, participantId, discovery,
queue, bufferSize);
//if (!receiver.getLocator().isMulticastLocator()) { // If not multicast, change participantId
this.participantId = receiver.getParticipantId();
//}
setLocator(receiver.getLocator(), discovery);
receivers.add(receiver);
threadPoolExecutor.execute(receiver);
} catch (IOException ioe) {
logger.warn("Failed to start receiver for URI {}", uri, ioe);
}
}
else {
logger.warn("Unknown scheme for URI {}", uri);
}
}
}
/**
* Assigns Receivers Locator to proper field
* @param loc
* @param discovery
*/
private void setLocator(Locator loc, boolean discovery) {
if (discovery) {
discoveryLocators.add(loc);
}
else {
userdataLocators.add(loc);
}
}
List> getReaders() {
return readerEndpoints;
}
List> getWriters() {
return writerEndpoints;
}
AuthenticationPlugin getAuthenticationPlugin() {
return aPlugin;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy