μHAL (v2.7.9)
Part of the IPbus software repository
ConnectionManager.cpp
Go to the documentation of this file.
1 /*
2 ---------------------------------------------------------------------------
3 
4  This file is part of uHAL.
5 
6  uHAL is a hardware access library and programming framework
7  originally developed for upgrades of the Level-1 trigger of the CMS
8  experiment at CERN.
9 
10  uHAL is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  uHAL is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with uHAL. If not, see <http://www.gnu.org/licenses/>.
22 
23 
24  Andrew Rose, Imperial College, London
25  email: awr01 <AT> imperial.ac.uk
26 
27  Marc Magrans de Abril, CERN
28  email: marc.magrans.de.abril <AT> cern.ch
29 
30 ---------------------------------------------------------------------------
31 */
32 
34 
35 #include "uhal/Node.hpp"
36 #include "uhal/NodeTreeBuilder.hpp"
37 #include "uhal/ClientInterface.hpp"
38 #include "uhal/ClientFactory.hpp"
39 #include "uhal/utilities/files.hpp"
40 #include "uhal/utilities/xml.hpp"
41 
42 #include "uhal/log/log.hpp"
43 
44 #include <boost/regex.hpp>
45 #include <boost/spirit/include/qi.hpp>
46 
47 
48 #if BOOST_VERSION >= 106000
49 // Resolve boost bind placeholders (_1, _2, ...) that moved within boost::laceholders namespace from v1.60
50 using boost::placeholders::_1;
51 using boost::placeholders::_2;
52 using boost::placeholders::_3;
53 #endif
54 
55 
56 namespace uhal
57 {
58 
59  ConnectionManager::ConnectionDescriptor::ConnectionDescriptor ( const pugi::xml_node& aNode , const boost::filesystem::path& aConnectionFile , bool& aSuccess ) :
60  connection_file ( aConnectionFile )
61  {
62  aSuccess=false;
63 
64  if ( ! uhal::utilities::GetXMLattribute<true> ( aNode , "id" , id ) )
65  {
66  return;
67  }
68 
69  if ( ! uhal::utilities::GetXMLattribute<true> ( aNode , "uri" , uri ) )
70  {
71  return;
72  }
73 
74  if ( ! uhal::utilities::GetXMLattribute<true> ( aNode , "address_table" , address_table ) )
75  {
76  return;
77  }
78 
79  aSuccess=true;
80  }
81 
82 
84  {
85  if ( id != aConnectionDescriptor.id )
86  {
87  return false;
88  }
89 
90  if ( uri != aConnectionDescriptor.uri )
91  {
92  return false;
93  }
94 
95  if ( address_table != aConnectionDescriptor.address_table )
96  {
97  return false;
98  }
99 
100  return true;
101  }
102 
103 
104 
105 
106  ConnectionManager::ConnectionManager ( const std::string& aFilenameExpr )
107  {
108  //Mutex lock here to be on the safe side
109  boost::lock_guard<boost::mutex> lLock ( mMutex );
110  std::vector< std::pair<std::string, std::string> > lConnectionFiles; //protocol, filename
111  uhal::utilities::ParseSemicolonDelimitedUriList ( aFilenameExpr , lConnectionFiles );
112 
113  for ( std::vector< std::pair<std::string, std::string> >::iterator lIt = lConnectionFiles.begin() ; lIt != lConnectionFiles.end() ; ++lIt )
114  {
115  uhal::utilities::OpenFile ( lIt->first , lIt->second , boost::filesystem::current_path() , boost::bind ( &ConnectionManager::CallBack, boost::ref ( *this ) , _1 , _2 , _3 ) );
116  }
117  }
118 
119 
120  ConnectionManager::ConnectionManager ( const std::string& aFilenameExpr , const std::vector<std::string>& aUserClientActivationList ) :
121  mUserClientActivationList(aUserClientActivationList)
122  {
123  //Mutex lock here to be on the safe side
124  boost::lock_guard<boost::mutex> lLock ( mMutex );
125  std::vector< std::pair<std::string, std::string> > lConnectionFiles; //protocol, filename
126  uhal::utilities::ParseSemicolonDelimitedUriList ( aFilenameExpr , lConnectionFiles );
127 
128  for ( std::vector< std::pair<std::string, std::string> >::iterator lIt = lConnectionFiles.begin() ; lIt != lConnectionFiles.end() ; ++lIt )
129  {
130  uhal::utilities::OpenFile ( lIt->first , lIt->second , boost::filesystem::current_path() , boost::bind ( &ConnectionManager::CallBack, boost::ref ( *this ) , _1 , _2 , _3 ) );
131  }
132  }
133 
134 
136  {
137  }
138 
139 
140  HwInterface ConnectionManager::getDevice ( const std::string& aId )
141  {
142  //We need a mutex lock here to protect access to the NodeTreeBuilder and the ClientFactory
143  boost::lock_guard<boost::mutex> lLock ( mMutex );
144 
145  if ( mConnectionDescriptors.size() == 0 )
146  {
147  exception::ConnectionUIDDoesNotExist lExc;
148  log ( lExc , "Connection map contains no entries" );
149  throw lExc;
150  }
151 
152  std::map< std::string, ConnectionDescriptor >::iterator lIt = mConnectionDescriptors.find ( aId );
153 
154  if ( lIt == mConnectionDescriptors.end() )
155  {
156  exception::ConnectionUIDDoesNotExist lExc;
157  log ( lExc , "Device ID , " , Quote ( aId ) , ", does not exist in connection map" );
158  throw lExc;
159  }
160 
161  //The node tree builder returns a newly created Node which we can safely wrap as a shared_ptr
162  boost::shared_ptr< Node > lNode ( NodeTreeBuilder::getInstance().getNodeTree ( lIt->second.address_table , lIt->second.connection_file ) );
163  log ( Info() , "ConnectionManager created node tree: " , *lNode );
164  boost::shared_ptr<ClientInterface> lClientInterface ( ClientFactory::getInstance().getClient ( lIt->second.id , lIt->second.uri , mUserClientActivationList ) );
165  return HwInterface ( lClientInterface , lNode );
166  }
167 
168 
169  HwInterface ConnectionManager::getDevice ( const std::string& aId , const std::string& aUri , const std::string& aAddressFileExpr )
170  {
171  //We need a mutex lock here to protect access to the TodeTreeBuilder and the ClientFactory
172  boost::lock_guard<boost::mutex> lLock ( mMutex );
173  boost::shared_ptr< Node > lNode ( NodeTreeBuilder::getInstance().getNodeTree ( aAddressFileExpr , boost::filesystem::current_path() / "." ) );
174  log ( Info() , "ConnectionManager created node tree: " , *lNode );
175  boost::shared_ptr<ClientInterface> lClientInterface ( ClientFactory::getInstance().getClient ( aId , aUri ) );
176  return HwInterface ( lClientInterface , lNode );
177  }
178 
179 
180  HwInterface ConnectionManager::getDevice ( const std::string& aId , const std::string& aUri , const std::string& aAddressFileExpr, const std::vector<std::string>& aUserClientActivationList )
181  {
182  //We need a mutex lock here to protect access to the TodeTreeBuilder and the ClientFactory
183  boost::lock_guard<boost::mutex> lLock ( mMutex );
184  boost::shared_ptr< Node > lNode ( NodeTreeBuilder::getInstance().getNodeTree ( aAddressFileExpr , boost::filesystem::current_path() / "." ) );
185  log ( Info() , "ConnectionManager created node tree: " , *lNode );
186  boost::shared_ptr<ClientInterface> lClientInterface ( ClientFactory::getInstance().getClient ( aId , aUri , aUserClientActivationList ) );
187  return HwInterface ( lClientInterface , lNode );
188  }
189 
190 
191  std::vector<std::string> ConnectionManager::getDevices ( ) const
192  {
193  std::vector<std::string> lDevices;
194  lDevices.reserve ( mConnectionDescriptors.size() ); //prevent reallocations
195 
196  for ( std::map< std::string, ConnectionDescriptor >::const_iterator lIt = mConnectionDescriptors.begin() ; lIt != mConnectionDescriptors.end() ; ++lIt )
197  {
198  lDevices.push_back ( lIt->first );
199  }
200 
201  return lDevices;
202  }
203 
204 
205  std::vector<std::string> ConnectionManager::getDevices ( const std::string& aRegex ) const
206  {
207  std::vector<std::string> lDevices;
208  lDevices.reserve ( mConnectionDescriptors.size() ); //prevent reallocations
209 
210  for ( std::map< std::string, ConnectionDescriptor >::const_iterator lIt = mConnectionDescriptors.begin() ; lIt != mConnectionDescriptors.end() ; ++lIt )
211  {
212  boost::cmatch lMatch;
213 
214  if ( boost::regex_match ( lIt->first.c_str() , lMatch , boost::regex ( aRegex ) ) ) //to allow partial match, add boost::match_default|boost::match_partial as fourth argument
215  {
216  lDevices.push_back ( lIt->first );
217  }
218  }
219 
220  return lDevices;
221  }
222 
223 
225  {
226  // Need a mutex lock here to protect access to NodeTreeBuilder
227  boost::lock_guard<boost::mutex> lLock ( mMutex );
228  log( Info(), "ConnectionManager is clearing the address filename -> Node tree cache");
230  }
231 
232 
233  void ConnectionManager::CallBack ( const std::string& aProtocol , const boost::filesystem::path& aPath , std::vector<uint8_t>& aFile )
234  {
235  std::pair< std::set< std::string >::iterator , bool > lInsert = mPreviouslyOpenedFiles.insert ( aProtocol+ ( aPath.string() ) );
236 
237  if ( ! lInsert.second )
238  {
239  log ( Info() , "File " , Quote ( aProtocol+ ( aPath.string() ) ) , " has already been parsed. I am not reparsing and will continue with next document for now but be aware!" );
240  return;
241  }
242 
243  pugi::xml_document lXmlDocument;
244  pugi::xml_parse_result lLoadResult = lXmlDocument.load_buffer_inplace ( & ( aFile[0] ) , aFile.size() );
245 
246  if ( !lLoadResult )
247  {
248  //Mark says to throw on this condition, I will leave it continuing for now...
249  uhal::utilities::PugiXMLParseResultPrettifier ( lLoadResult , aPath , aFile );
250  return;
251  }
252 
253  pugi::xpath_node_set lConnections = lXmlDocument.select_nodes ( "/connections/connection" );
254 
255  for ( pugi::xpath_node_set::const_iterator lConnectionIt = lConnections.begin(); lConnectionIt != lConnections.end(); ++lConnectionIt )
256  {
257  bool lSuccess;
258  ConnectionDescriptor lDescriptor ( lConnectionIt->node() , aPath , lSuccess );
259 
260  if ( lSuccess )
261  {
262  std::pair< std::map< std::string, ConnectionDescriptor >::iterator , bool > lInsert = mConnectionDescriptors.insert ( std::make_pair ( lDescriptor.id , lDescriptor ) );
263 
264  if ( !lInsert.second )
265  {
266  if ( lInsert.first->second == lDescriptor )
267  {
268  log ( Info() , "Duplicate connection entry found:"
269  "\n > id = " , lDescriptor.id ,
270  "\n > uri = " , lDescriptor.uri ,
271  "\n > address_table = " , lDescriptor.address_table ,
272  "\n Continuing for now but be aware!" );
273  }
274  else
275  {
276  exception::DuplicatedUID lExc;
277  log ( lExc , "Duplicate connection ID " , Quote ( lDescriptor.id ) , " found in connections file " ,
278  Quote ( aProtocol+ ( aPath.string() ) ) , " but parameters do not match! Bailing!" );
279  throw lExc;
280  }
281  }
282  }
283  else
284  {
285  log ( Error() , "Construction of Connection Descriptor failed. Continuing with next Connection Descriptor for now but be aware!" );
286  }
287  }
288  }
289 
290 
291  boost::mutex ConnectionManager::mMutex;
292 
293 }
294 
uhal::HwInterface
A class which bundles a node tree and an IPbus client interface together providing everything you nee...
Definition: HwInterface.hpp:61
pugi::xpath_node_set::end
const_iterator end() const
Definition: pugixml.cpp:12211
uhal::ConnectionManager::getDevice
HwInterface getDevice(const std::string &aId)
Retrieves protocol, host, and port from the connection file to create an IPbus Client Retrieves the a...
Definition: ConnectionManager.cpp:140
uhal::ConnectionManager::mUserClientActivationList
const std::vector< std::string > mUserClientActivationList
Definition: ConnectionManager.hpp:172
pugi::xpath_node
Definition: pugixml.hpp:1290
pugi::xml_node::select_nodes
xpath_node_set select_nodes(const char_t *query, xpath_variable_set *variables=0) const
Definition: pugixml.cpp:12770
boost::shared_ptr
Definition: DerivedNodeFactory.hpp:52
uhal::ConnectionManager::ConnectionDescriptor::uri
std::string uri
The full uri for making the connection.
Definition: ConnectionManager.hpp:102
uhal::ClientFactory::getInstance
static ClientFactory & getInstance()
Static method to retrieve the single instance of the class.
Definition: ClientFactory.cpp:65
pugi::xpath_node_set
Definition: pugixml.hpp:1331
pugi::xpath_node_set::begin
const_iterator begin() const
Definition: pugixml.cpp:12206
xml.hpp
Node.hpp
uhal::ConnectionManager::~ConnectionManager
virtual ~ConnectionManager()
Destructor.
Definition: ConnectionManager.cpp:135
uhal::ConnectionManager::ConnectionDescriptor::operator==
bool operator==(const ConnectionDescriptor &aConnectionDescriptor) const
Comparison operation.
Definition: ConnectionManager.cpp:83
uhal::ConnectionManager::mMutex
static boost::mutex mMutex
A mutex lock to protect access to the factory methods in multithreaded environments.
Definition: ConnectionManager.hpp:162
uhal::ConnectionManager::ConnectionDescriptor::ConnectionDescriptor
ConnectionDescriptor(const pugi::xml_node &aNode, const boost::filesystem::path &aConnectionFile, bool &aSuccess)
Constructor.
Definition: ConnectionManager.cpp:59
uhal
Definition: HttpResponseGrammar.hpp:49
uhal::utilities::ParseSemicolonDelimitedUriList
void ParseSemicolonDelimitedUriList(const std::string &aSemicolonDelimitedUriList, std::vector< std::pair< std::string, std::string > > &aUriList)
Parse a semicolon delimited list of URIs into a vector of protocol/address pairs.
Definition: files.cpp:46
files.hpp
uhal::Info
InfoLevel Info
Definition: LogLevels.cpp:115
uhal::log
void log(FatalLevel &aFatal, const T0 &aArg0)
Function to add a log entry at Fatal level.
Definition: log.hxx:20
uhal::ConnectionManager::ConnectionManager
ConnectionManager(const std::string &aFilenameExpr)
Default constructor Given a semi-colon delimeted list of glob expressions, parse all the files matchi...
Definition: ConnectionManager.cpp:106
pugi::xml_node
Definition: pugixml.hpp:455
uhal::ConnectionManager::ConnectionDescriptor::address_table
std::string address_table
The address table for building the node tree.
Definition: ConnectionManager.hpp:104
uhal::ConnectionManager::ConnectionDescriptor
A struct to hold the fields of each entry in the XML connections file.
Definition: ConnectionManager.hpp:83
uhal::ConnectionManager::clearAddressFileCache
static void clearAddressFileCache()
Clears cache of Node tree structure for previously-opened address files (thread safe)
Definition: ConnectionManager.cpp:224
uhal::Error
ErrorLevel Error
Definition: LogLevels.cpp:61
uhal::Quote
_Quote< T > Quote(const T &aT)
Definition: log_inserters.quote.hxx:49
uhal::ConnectionManager::ConnectionDescriptor::id
std::string id
An identifier for an individual.
Definition: ConnectionManager.hpp:100
uhal::utilities::GetXMLattribute< true >
template bool GetXMLattribute< true >(const pugi::xml_node &aNode, const std::string &aAttrName, std::string &aTarget)
uhal::ConnectionManager::mConnectionDescriptors
std::map< std::string, ConnectionDescriptor > mConnectionDescriptors
A map of connection identifiers to stucts containing details of the parsed XML node.
Definition: ConnectionManager.hpp:175
uhal::tests::uri
std::string uri
Definition: test_single.cpp:89
uhal::utilities::OpenFile
void OpenFile(const std::string &aProtocol, const std::string &aFilenameExpr, const boost::filesystem::path &aParentPath, boost::_bi::bind_t< R, F, L > aBinder)
Given a protocol and either a URL or a linux shell expression, open the file and call the callback fu...
Definition: files.hpp:353
uhal::utilities::PugiXMLParseResultPrettifier
void PugiXMLParseResultPrettifier(const pugi::xml_parse_result &aLoadResult, const boost::filesystem::path &aPath, const std::vector< uint8_t > &aFile)
Helper function to make debugging failures when parsing XML files easier.
Definition: xml.cpp:57
log.hpp
ConnectionManager.hpp
pugi::xml_document
Definition: pugixml.hpp:1001
NodeTreeBuilder.hpp
pugi::xml_document::load_buffer_inplace
xml_parse_result load_buffer_inplace(void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7142
uhal::ConnectionManager::mPreviouslyOpenedFiles
std::set< std::string > mPreviouslyOpenedFiles
A set of previously opened filenames, so that the same file is not parsed multiple times.
Definition: ConnectionManager.hpp:178
uhal::NodeTreeBuilder::getInstance
static NodeTreeBuilder & getInstance()
Static method to retrieve the single instance of the class.
Definition: NodeTreeBuilder.cpp:144
uhal::ConnectionManager::getDevices
std::vector< std::string > getDevices() const
Return all device IDs known to this connection manager.
Definition: ConnectionManager.cpp:191
ClientInterface.hpp
pugi::xml_parse_result
Definition: pugixml.hpp:979
uhal::NodeTreeBuilder::clearAddressFileCache
void clearAddressFileCache()
Clears address filename -> Node tree cache. NOT thread safe; for tread-safety, use ConnectionManager ...
Definition: NodeTreeBuilder.cpp:182
ClientFactory.hpp
uhal::ConnectionManager::CallBack
void CallBack(const std::string &aProtocol, const boost::filesystem::path &aPath, std::vector< uint8_t > &aFile)
Method called once the file specified in the constructor has been opened.
Definition: ConnectionManager.cpp:233