/** * @RDE_HEADER@ * Routing Test - main connection handling * $Id$ * $HeadURL$ * $Author$ */ #include "connection.h" #include "data_writer_task.h" #include #include #include #include namespace RoutingService { Connection::Connection(const dds::domain::DomainParticipant &domainParticipant, const std::string &partition, const std::vector &topicsToRoute, const std::string &desc) : m_output(nullptr) , m_domainParticipant(domainParticipant) , m_publisher(new DDSConnector::Publisher(domainParticipant, partition)) , m_subscriber(new DDSConnector::Subscriber(domainParticipant, partition, false)) , m_dataWriterTask(nullptr) , m_topicsToRoute(topicsToRoute) , m_partition(partition) , m_description(desc) , m_logger(getLogger("Connection")) { INFO_LOG(m_logger) << "Create connection: " << partition << ", domain: " << domainParticipant.domain_id() << ", direction: " << m_description << " (" << this << ")"; } Connection::~Connection() { setOutput(nullptr); shutdown(); try { if (m_subscriber) m_subscriber->getDdsSubscriber().close(); } catch (const dds::core::Exception &ex) { ERROR_LOG(m_logger) << "sub close ex: " << ex.what(); } m_subscriber = nullptr; try { if (m_publisher) m_publisher->getDdsPublisher().close(); } catch (const dds::core::Exception &ex) { ERROR_LOG(m_logger) << "pub close ex: " << ex.what(); } m_publisher = nullptr; m_domainParticipant = nullptr; } void Connection::setOutput(Connection *output) { if (m_output == output) return; m_output = output; } bool Connection::initialize() { DEBUG_LOG(m_logger) << "initialize new connection for " << m_partition << ", direction: " << m_description << " (" << this << ")"; if (m_writerThread.valid()) shutdown(); m_dataWriterTask.reset(new DataWriterTask); if (!m_output) { ERROR_LOG(m_logger) << "Error initializing connection for " << m_partition << ", direction: " << m_description << " - no output set!"; return false; } m_writerThread = std::async(std::launch::async, [this]() { this->m_dataWriterTask->writeSamples();}); return initTopics(); } void Connection::shutdown() { if (m_topicsToRoute.empty()) return; QElapsedTimer timer; timer.start(); DEBUG_LOG(m_logger) << "shutting down connection for " << m_partition << ", direction: " << m_description << " (" << this << "), dwt: " << m_dataWriterTask.get(); // inform DataWriterTask about its destruction in the near future // it removes it not yet sent samples and does not enqueue new samples if (m_dataWriterTask) m_dataWriterTask->shutdown(); // now remove topics, they don't have outstanding loans since dataWrterTask does // not enqueue samples anymore for (auto topic : m_topicsToRoute) { if (timer.elapsed() > 1000) { QCoreApplication::processEvents(); // for e.g. paceMaker timer.start(); } topic->shutdown(); } qDeleteAll(m_topicsToRoute); m_topicsToRoute.clear(); // now we can wait until the data writer task has finished if (m_dataWriterTask) { m_writerThread.wait(); m_dataWriterTask = nullptr; } } dds::domain::DomainParticipant Connection::domainParticipant() const { return m_domainParticipant; } dds::pub::Publisher Connection::publisher() const { return m_publisher->getDdsPublisher(); } dds::sub::Subscriber Connection::subscriber() const { return m_subscriber->getDdsSubscriber(); } bool Connection::initTopics() { DEBUG_LOG(m_logger) << "Init topics for " << m_partition << ", direction: " << m_description; if (!m_output) return false; QElapsedTimer timer; timer.start(); auto dpOut = m_output->domainParticipant(); auto pubOut = m_output->publisher(); for (auto dp : m_topicsToRoute) { if (!dp) continue; if (!dp->init(m_dataWriterTask.get(), m_domainParticipant, m_subscriber->getDdsSubscriber(), dpOut, pubOut)) return false; if (timer.elapsed() > 1000) { QCoreApplication::processEvents(); // for e.g. paceMaker timer.start(); } } return true; } } // namespace RoutingService