AlarmNotifications
PANDA Slow Control Alarm Daemon
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
cmsclient.cpp
Go to the documentation of this file.
1 
34 #include "cmsclient.h"
35 
36 #include <iostream>
37 #include <stdexcept>
38 
39 #include <activemq/library/ActiveMQCPP.h>
40 #include <cms/Connection.h>
41 #include <cms/ConnectionFactory.h>
42 #include <cms/Destination.h>
43 #include <cms/MapMessage.h>
44 #include <cms/MessageConsumer.h>
45 #include <cms/Session.h>
46 
47 #include "alarmconfiguration.h"
48 #include "alarmserverconnector.h"
49 
50 using namespace AlarmNotifications;
51 
53  : _asc ( asc ),
54  _connection ( nullptr ),
55  _session ( nullptr ),
56  _topicServer ( nullptr ),
57  _consumerServer ( nullptr )
58 {
59  try
60  {
61  activemq::library::ActiveMQCPP::initializeLibrary(); // If you don't do this, all calls to ActiveMQ will segfault...
62  }
63  catch ( std::runtime_error& ex )
64  {
65  std::cerr << "Runtime error while initializing ActiveMQCPP library!" << std::endl;
66  std::cerr << ex.what() << std::endl;
67  throw;
68  }
69  try
70  {
71  cms::ConnectionFactory* factory = cms::ConnectionFactory::createCMSConnectionFactory ( AlarmConfiguration::instance().getActiveMQURI() );
72  _connection = factory->createConnection (
73  AlarmConfiguration::instance().getActiveMQUsername(),
74  AlarmConfiguration::instance().getActiveMQPassword()
75  );
76  }
77  catch ( cms::CMSException& ex )
78  {
79  std::cerr << "Cannot create CMS connection!" << std::endl;
80  std::cerr << ex.getMessage() << std::endl;
81  ex.printStackTrace();
82  _connection = nullptr;
83  throw;
84  }
85  _connection->start();
86  _connection->setExceptionListener ( this );
87  try
88  {
89  //Taken one-to-one from the documentation...
90  _session = _connection->createSession ( cms::Session::AUTO_ACKNOWLEDGE );
91  _topicServer = _session->createTopic ( AlarmConfiguration::instance().getActiveMQTopicName() );
92  _consumerServer = _session->createConsumer ( _topicServer );
93  _consumerServer->setMessageListener ( this );
94  }
95  catch ( cms::CMSException& ex )
96  {
97  std::cerr << "Cannot create CMS session/topic!" << std::endl;
98  std::cerr << ex.getMessage() << std::endl;
99  ex.printStackTrace();
100  if ( _session != nullptr )
101  _session->close();
102  _connection->close(); // Clean things up...
103  delete _consumerServer;
104  delete _topicServer;
105  delete _session;
106  delete _connection;
107  _consumerServer = nullptr;
108  _topicServer = nullptr;
109  _session = nullptr;
110  _connection = nullptr;
111  throw; //... and escalate the exception
112  }
113 }
114 
116 {
117  // According to the documentation, this calls may result in an excpetion.
118  // As destructors are noexcept in C++11 unless explicitly stated otherwise, this is
119  // a very bad idea and will instantly crash the program.
120  // To avoid this, all the clean-up commands are but in a try-catch block that throws away
121  // any exception (theres no handling that could be done)
122  // And to stop one error from stopping the rest of the cleanup, each command got its own
123  // try-catch block.
124  try
125  {
126  if ( _session != nullptr )
127  _session->close();
128  }
129  catch ( ... ) {}
130  try
131  {
132  if ( _connection != nullptr )
133  _connection->close();
134  }
135  catch ( ... ) {}
136  try
137  {
138  delete _consumerServer;
139  }
140  catch ( ... ) {}
141  try
142  {
143  delete _topicServer;
144  }
145  catch ( ... ) {}
146  try
147  {
148  delete _session;
149  }
150  catch ( ... ) {}
151  try
152  {
153  delete _connection;
154  }
155  catch ( ... ) {}
156  try
157  {
158  activemq::library::ActiveMQCPP::shutdownLibrary(); // Final close down
159  }
160  catch ( ... ) {}
161 }
162 
163 void CMSClient::onMessage ( const cms::Message* message ) noexcept
164 {
165  const cms::MapMessage*const mapmessage = dynamic_cast<const cms::MapMessage*> ( message );
166  // There are four message types in CMS, but the CSS Alarm Server uses MapMessage only
167  // If message is not a MapMessage, dynamic_cast will return a nullptr...
168  if ( mapmessage == nullptr )
169  return; // ... and we throw the message away
170  if ( !mapmessage->itemExists ( "TEXT" ) )
171  return;
172  // The Alarm Server sends frequent "IDLE" messages to show that it's still there...
173  if ( mapmessage->getString ( "TEXT" ) != "STATE" )
174  return; // ...but we don't have to forward them.
175  if ( !mapmessage->itemExists ( "NAME" ) || !mapmessage->itemExists ( "SEVERITY" ) || !mapmessage->itemExists ( "STATUS" ) )
176  return; // Make sure all required keys are present
177  std::string rawname = mapmessage->getString ( "NAME" ); // The alarm server uses the pseudo-procotol denomination "epics://" in
178  const std::string name = rawname.replace ( rawname.find ( "epics://" ), 8, "" ); // front of the PV names, so we strip it
179  const AlarmStatusEntry ase (
180  name,
181  mapmessage->getString ( "SEVERITY" ),
182  mapmessage->getString ( "STATUS" )
183  );
184  _asc.notifyStatusChange ( ase ); // This message passed filtering, so it's relevant and forwarded to the AlarmServerConnector
185 }
186 
187 void CMSClient::onException ( const cms::CMSException& ex ) noexcept
188 {
189  ex.printStackTrace();
190 }
#define nullptr
Allow using the nullptr keyword with GCC < 4.6.
Definition: oldgcccompat.h:56
virtual void onException(const cms::CMSException &ex) noexcept
Exception listener.
Definition: cmsclient.cpp:187
cms::Session * _session
CMS session.
Definition: cmsclient.h:90
CMSClient(AlarmServerConnector &asc)
Constructor.
Definition: cmsclient.cpp:52
Entry in the AlarmServerConnector statusmap.
Interface to the CMS (C++ Messaging Service) library of Apache ActiveMQ.
Namespace for Alarm Notifications application.
virtual void onMessage(const cms::Message *message) noexcept
Message listener.
Definition: cmsclient.cpp:163
Provides connectivity to the CSS Alarm Server.
#define noexcept
Allow using the noexcept keyword with GCC < 4.6.
Definition: oldgcccompat.h:52
cms::Connection * _connection
CMS connection.
Definition: cmsclient.h:84
cms::Destination * _topicServer
CMS topic.
Definition: cmsclient.h:96
cms::MessageConsumer * _consumerServer
CMS receiver.
Definition: cmsclient.h:102
Singleton to read and change the configuration of this application.
static AlarmConfiguration & instance() noexcept
Get singleton instance.