All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jrtps.rtps.RTPSParticipant Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
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.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.transport.UDPProvider;
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 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 log = LoggerFactory.getLogger(RTPSParticipant.class);

    private final Configuration config;
    private final ScheduledThreadPoolExecutor threadPoolExecutor;

    /**
     * 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 LinkedList<>();
    private final List> writerEndpoints = new LinkedList<>();

    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 Locator discovery_mc_Locator; // TODO: remove these
    private Locator discovery_uc_Locator;
    private Locator userdata_mc_Locator;
    private Locator userdata_uc_Locator;
    
    /**
     * 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 config Configuration used
     */
    public RTPSParticipant(Guid guid, int domainId, int participantId, ScheduledThreadPoolExecutor tpe, 
            Map discoveredParticipants, Configuration config) {
        this.guid = guid;
        this.domainId = domainId; 
        this.participantId = participantId;
        this.threadPoolExecutor = tpe;
        this.discoveredParticipants = discoveredParticipants;
        this.config = config;

        UDPProvider handler = new UDPProvider(config); 
        TransportProvider.registerTransportProvider("udp", handler, Locator.LOCATOR_KIND_UDPv4, Locator.LOCATOR_KIND_UDPv6);
    }

    /**
     * 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(this, queue);
        threadPoolExecutor.execute(handler);

        log.debug("Starting receivers for discovery");
        List discoveryURIs = config.getDiscoveryListenerURIs();
        startReceiversForURIs(queue, bufferSize, discoveryURIs, true);

        log.debug("Starting receivers for user data");
        List listenerURIs = config.getListenerURIs();
        startReceiversForURIs(queue, bufferSize, listenerURIs, false);
        
        log.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() {
        log.debug("Closing RTPSParticipant {}", guid);

        for (RTPSWriter w : writerEndpoints) { // Closes periodical announce
                                                  // thread
            w.close();
        }

        // close network receivers
        for (Receiver r : receivers) {
            r.close();
        }
    }

    /**
     * Gets the guid of this participant.
     * 
     * @return guid
     */
    public Guid getGuid() {
        return guid;
    }

    /**
     * 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) {
                log.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);
    }

    /**
     * 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 writerId
     * @return RTPSReader
     */
    RTPSReader getReader(EntityId readerId, EntityId 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);
        }
    
        log.warn("Failed to find RTPSReader for reader entity {} or matching writer entity {}", readerId, writerId);
        return null;
    }

    RTPSWriter getWriter(EntityId writerId, 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);
        }
    
        log.warn("Failed to find Writer for writer {} or matching reader {}", writerId, readerId);
        return null;
    }

    /**
     * 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 {
                    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) {
                    log.warn("Failed to start receiver for URI {}", uri, ioe);
                }
            }
            else {
                log.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);
        }
        
        // TODO: remove rest of this method
        
        if (loc.isMulticastLocator()) {
            if (discovery) {
                discovery_mc_Locator = loc;
            }
            else {
                userdata_mc_Locator = loc;
            }
        }
        else {
            if (discovery) {
                discovery_uc_Locator = loc;
            }
            else {
                userdata_uc_Locator = loc;
            }                        
        }        
    }

    public Locator getDiscoveryMulticastLocator() {
        return discovery_mc_Locator;
    }
    public Locator getDiscoveryUnicastLocator() {
        return discovery_uc_Locator;
    }
    public Locator getUserdataMulticastLocator() {
        return userdata_mc_Locator;
    }
    public Locator getUserdataUnicastLocator() {
        return userdata_uc_Locator;
    }


    public List getDiscoveryLocators() {
        return discoveryLocators;
    }
    public List getUserdataLocators() {
        return userdataLocators;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy