otsdaq  v1_01_02
 All Classes Namespaces Functions
ConfigurationInfoReader.cc
1 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationInfoReader.h"
2 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationBase.h"
3 #include "otsdaq-core/XmlUtilities/DOMTreeErrorReporter.h"
4 #include "otsdaq-core/XmlUtilities/ConvertFromXML.h"
5 //#include "TimeFormatter.h"
6 
7 
8 #include <xercesc/parsers/XercesDOMParser.hpp>
9 #include <xercesc/dom/DOMElement.hpp>
10 #include <xercesc/dom/DOMImplementation.hpp>
11 #include <xercesc/dom/DOMImplementationRegistry.hpp>
12 #include <xercesc/dom/DOMNodeList.hpp>
13 #include <xercesc/dom/DOMText.hpp>
14 //#include <xercesc/dom/DOMWriter.hpp>
15 
16 #include <xercesc/util/OutOfMemoryException.hpp>
17 #include <xercesc/framework/LocalFileFormatTarget.hpp>
18 
19 #include <stdexcept>
20 #include <iostream>
21 #include <sstream>
22 
23 #include <sys/stat.h>
24 #include <errno.h>
25 
26 using namespace ots;
27 
28 #undef __MOUT_HDR__
29 #define __MOUT_HDR__ "ConfigInfoReader"
30 
31 
32 //==============================================================================
33 ConfigurationInfoReader::ConfigurationInfoReader(bool allowIllegalColumns)
34 : allowIllegalColumns_(allowIllegalColumns)
35 {
36  initPlatform();
37  rootTag_ = xercesc::XMLString::transcode("ROOT");
38  configurationTag_ = xercesc::XMLString::transcode("CONFIGURATION");
39  configurationNameAttributeTag_ = xercesc::XMLString::transcode("Name");
40  viewTag_ = xercesc::XMLString::transcode("VIEW");
41  viewNameAttributeTag_ = xercesc::XMLString::transcode("Name");
42  viewTypeAttributeTag_ = xercesc::XMLString::transcode("Type");
43  viewDescriptionAttributeTag_ = xercesc::XMLString::transcode("Description");
44  columnTag_ = xercesc::XMLString::transcode("COLUMN");
45  columnTypeAttributeTag_ = xercesc::XMLString::transcode("Type");
46  columnNameAttributeTag_ = xercesc::XMLString::transcode("Name");
47  columnStorageNameAttributeTag_ = xercesc::XMLString::transcode("StorageName");
48  columnDataTypeAttributeTag_ = xercesc::XMLString::transcode("DataType");
49  columnDataChoicesAttributeTag_ = xercesc::XMLString::transcode("DataChoices");
50 }
51 
52 //==============================================================================
53 ConfigurationInfoReader::~ConfigurationInfoReader(void)
54 {
55  try
56  {
57  xercesc::XMLString::release( &rootTag_ );
58  xercesc::XMLString::release( &configurationTag_ );
59  xercesc::XMLString::release( &configurationNameAttributeTag_ );
60  xercesc::XMLString::release( &viewTag_ );
61  xercesc::XMLString::release( &viewNameAttributeTag_ );
62  xercesc::XMLString::release( &viewTypeAttributeTag_ );
63  xercesc::XMLString::release( &viewDescriptionAttributeTag_ );
64  xercesc::XMLString::release( &columnTag_ );
65  xercesc::XMLString::release( &columnTypeAttributeTag_ );
66  xercesc::XMLString::release( &columnNameAttributeTag_ );
67  xercesc::XMLString::release( &columnStorageNameAttributeTag_ );
68  xercesc::XMLString::release( &columnDataTypeAttributeTag_ );
69  xercesc::XMLString::release( &columnDataChoicesAttributeTag_ );
70 
71  }
72  catch( ... )
73  {
74  mf::LogError(__FILE__) << "Unknown exception encountered in TagNames destructor" << std::endl;
75  }
76  terminatePlatform();
77 }
78 
79 //==============================================================================
80 void ConfigurationInfoReader::initPlatform(void)
81 {
82  try
83  {
84  xercesc::XMLPlatformUtils::Initialize(); // Initialize Xerces infrastructure
85  }
86  catch( xercesc::XMLException& e )
87  {
88  mf::LogError(__FILE__) << "XML toolkit initialization error: " << XML_TO_CHAR(e.getMessage()) << std::endl;
89  // throw exception here to return ERROR_XERCES_INIT
90  }
91 }
92 
93 //==============================================================================
94 void ConfigurationInfoReader::terminatePlatform(void)
95 {
96  try
97  {
98  xercesc::XMLPlatformUtils::Terminate(); // Terminate after release of memory
99  }
100  catch( xercesc::XMLException& e )
101  {
102  mf::LogError(__FILE__) << "XML tolkit teardown error: " << XML_TO_CHAR(e.getMessage()) << std::endl;
103  }
104 }
105 
106 
107 //==============================================================================
108 void ConfigurationInfoReader::setAllowColumnErrors(bool setValue)
109 {
110  allowIllegalColumns_ = setValue;
111 }
112 //==============================================================================
113 const bool& ConfigurationInfoReader::getAllowColumnErrors(void)
114 {
115  return allowIllegalColumns_;
116 }
117 
118 //==============================================================================
119 bool ConfigurationInfoReader::checkViewType(std::string type)
120 {
121  std::vector<std::string> types;
122  int currentIndex = 0;
123  while( type.find(',',currentIndex) != std::string::npos )
124  {
125  types.push_back(type.substr(currentIndex,type.find(',',currentIndex)-currentIndex));
126  currentIndex = type.find(',',currentIndex)+1;
127  }
128  types.push_back(type.substr(currentIndex,type.size()));
129 
130  std::string systemType = getenv("CONFIGURATION_TYPE");
131  for(unsigned int i=0; i<types.size(); i++)
132  {
133  if( types[i] == systemType )
134  return true;
135  }
136  //In case I don't succeed let's check if maybe there is something wrong with the names
137  const unsigned int allowedNamesSize = 3;
138  const std::string allowedNames[allowedNamesSize] =
139  {"File","Database","DatabaseTest"
140  };
141  if(systemType != allowedNames[0] && systemType != allowedNames[1] && systemType != allowedNames[2] )
142  {
143  __MOUT__ << "The type defined in CONFIGURATION_TYPE ("
144  << systemType << ") doesn't match with any of the allowed types: File,Database or DatabaseTest"
145  << std::endl;
146 
147  throw(std::runtime_error( "Illegal configuration type" ));
148  }
149  for(unsigned int i=0; i<types.size(); i++)
150  {
151  if(types[i] != allowedNames[0] && types[i] != allowedNames[1] && types[i] != allowedNames[2] )
152  {
153  __MOUT__ << "The type defined in the info file ("
154  << types[i] << ") doesn't match with any of the allowed types: "
155  << allowedNames[0] << ", " << allowedNames[1] << " or " << allowedNames[2]
156  << std::endl;
157  throw(std::runtime_error( "Illegal Type!" ));
158  }
159  }
160 
161  return false;
162 }
163 
164 //==============================================================================
165 xercesc::DOMNode* ConfigurationInfoReader::getNode(XMLCh* tagName, xercesc::DOMNode* parent, unsigned int itemNumber)
166 {
167  return getNode(tagName, dynamic_cast< xercesc::DOMElement* >(parent), itemNumber);
168 }
169 
170 //==============================================================================
171 xercesc::DOMNode* ConfigurationInfoReader::getNode(XMLCh* tagName, xercesc::DOMElement* parent, unsigned int itemNumber)
172 {
173  xercesc::DOMNodeList* nodeList = parent->getElementsByTagName(tagName);
174  if( !nodeList )
175  {
176  throw(std::runtime_error( std::string("Can't find ") + XML_TO_CHAR(tagName) + " tag!"));
177  __MOUT__ << (std::string("Can't find ") + XML_TO_CHAR(tagName) + " tag!") << std::endl;
178  }
179  // __MOUT__<< "Name: " << XML_TO_CHAR(nodeList->item(itemNumber)->getNodeName()) << std::endl;
180  // if( nodeList->item(itemNumber)->getFirstChild() != 0 )
181  // __MOUT__<< "Value: " << XML_TO_CHAR(nodeList->item(itemNumber)->getFirstChild()->getNodeValue()) << std::endl;
182  return nodeList->item(itemNumber);
183 }
184 
185 //==============================================================================
186 xercesc::DOMElement* ConfigurationInfoReader::getElement(XMLCh* tagName, xercesc::DOMNode* parent, unsigned int itemNumber)
187 {
188  return dynamic_cast< xercesc::DOMElement* >(getNode(tagName,parent,itemNumber));
189 }
190 
191 //==============================================================================
192 xercesc::DOMElement* ConfigurationInfoReader::getElement(XMLCh* tagName, xercesc::DOMElement* parent, unsigned int itemNumber)
193 {
194  return dynamic_cast< xercesc::DOMElement* >(getNode(tagName,parent,itemNumber));
195 }
196 
197 //==============================================================================
198 std::string ConfigurationInfoReader::read(ConfigurationBase& configuration)
199 {
200  std::string accumulatedExceptions = "";
201 
202  //KEEP For debugging... added by Gennadiy...
203  //if configuration name starts with "TestConfiguration00" then turn off the reading of information
204  // auto tmp_test_config_prefix = std::string{"TestConfiguration00"};
205  // auto tmp_config_name = configuration.getConfigurationName();
206  // if (std::equal(tmp_test_config_prefix.begin(), tmp_test_config_prefix.end(), tmp_config_name.begin())) return accumulatedExceptions;
207  //KEEP End debugging... for Gennadiy...
208 
209 
210  //These environment variables are required
211  if(getenv("CONFIGURATION_TYPE" ) == NULL) __MOUT__ << "Missing env variable: CONFIGURATION_TYPE. It must be set!" << std::endl;
212  if(getenv("CONFIGURATION_DATA_PATH") == NULL) __MOUT__ << "Missing env variable: CONFIGURATION_DATA_PATH. It must be set!" << std::endl;
213  if(getenv("CONFIGURATION_INFO_PATH") == NULL) __MOUT__ << "Missing env variable: CONFIGURATION_INFO_PATH. It must be set!" << std::endl;
214 
215 
216  //example c++ setting of necessary environment variables
217  //setenv("CONFIGURATION_TYPE","File",1);
218  //setenv("CONFIGURATION_DATA_PATH",(std::string(getenv("USER_DATA")) + "/ConfigurationDataExamples").c_str(),1);
219  //setenv("CONFIGURATION_INFO_PATH",(std::string(getenv("USER_DATA")) + "/ConfigurationInfo").c_str(),1);
220 
221 
222  std::string configurationDataDir = std::string(getenv("CONFIGURATION_INFO_PATH")) + "/";
223  std::string configFile = configurationDataDir + configuration.getConfigurationName() + "Info.xml";
224  //__MOUT__ << configFile << std::endl;
225  struct stat fileStatus;
226 
227  int iretStat = stat(configFile.c_str(), &fileStatus);
228  if( iretStat == ENOENT )
229  throw ( std::runtime_error("Path file_name does not exist, or path is an empty std::string.") );
230  else if( iretStat == ENOTDIR )
231  throw ( std::runtime_error("A component of the path is not a directory."));
232  else if( iretStat == ELOOP )
233  throw ( std::runtime_error("Too many symbolic links encountered while traversing the path."));
234  else if( iretStat == EACCES )
235  throw ( std::runtime_error("Permission denied."));
236  else if( iretStat == ENAMETOOLONG )
237  throw ( std::runtime_error("File can not be read\n"));
238 
239  xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser;
240  // Configure DOM parser.
241  parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);//Val_Never
242  parser->setDoNamespaces ( true );
243  parser->setDoSchema ( true );
244  parser->useCachedGrammarInParse ( false );
245 
246  DOMTreeErrorReporter* errorHandler = new DOMTreeErrorReporter() ;
247  parser->setErrorHandler(errorHandler);
248  try
249  {
250  parser->parse( configFile.c_str() );
251 
252  // no need to free this pointer - owned by the parent parser object
253  xercesc::DOMDocument* xmlDocument = parser->getDocument();
254 
255  // Get the top-level element: Name is "root". No attributes for "root"
256  xercesc::DOMElement* elementRoot = xmlDocument->getDocumentElement();
257  if( !elementRoot )
258  {
259  delete parser;
260  delete errorHandler;
261  throw(std::runtime_error( "empty XML document" ));
262  }
263 
264  //<CONFIGURATION>
265  xercesc::DOMElement* configurationElement = getElement(configurationTag_, elementRoot, 0);
266  if( configuration.getConfigurationName() != XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_)) )
267  {
268 
269  __SS__ << "In " << configFile << " the configuration name " << XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_))
270  << " doesn't match the the class configuration name " << configuration.getConfigurationName() << std::endl;
271 
272  delete parser;
273  delete errorHandler;
274  __MOUT_ERR__ << "\n" << ss.str();
275  throw(std::runtime_error( ss.str()));
276  }
277  //<VIEW>
278  xercesc::DOMNodeList* viewNodeList = configurationElement->getElementsByTagName(viewTag_);
279  bool storageTypeFound = false;
280 
281  if(viewNodeList->getLength() != 1)
282  {
283 
284  __SS__ << "In " << configFile << " the configuration name " << XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_))
285  << " there must only be one view. There were " <<
286  viewNodeList->getLength() << " found." << std::endl;
287 
288  delete parser;
289  delete errorHandler;
290  __MOUT_ERR__ << "\n" << ss.str();
291  throw(std::runtime_error( ss.str()));
292  }
293 
294  for( XMLSize_t view = 0; view < viewNodeList->getLength(); view++ )
295  {
296  if( !viewNodeList->item(view)->getNodeType() || viewNodeList->item(view)->getNodeType() != xercesc::DOMNode::ELEMENT_NODE )//true is not 0 && is element
297  continue;
298  xercesc::DOMElement* viewElement = dynamic_cast< xercesc::DOMElement* >( viewNodeList->item(view) );
299  std::string viewType = XML_TO_CHAR(viewElement->getAttribute(viewTypeAttributeTag_));
300  if(!checkViewType(viewType))
301  continue;
302  storageTypeFound = true;
303  configuration.getMockupViewP()->setTableName(XML_TO_CHAR(viewElement->getAttribute(viewNameAttributeTag_)));
304  xercesc::DOMNodeList* columnNodeList = viewElement->getElementsByTagName(columnTag_);
305  for( XMLSize_t column = 0; column < columnNodeList->getLength(); column++ )
306  {
307  //<COLUMN>
308  xercesc::DOMElement* columnElement = dynamic_cast< xercesc::DOMElement* >( columnNodeList->item(column) );
309  //__MOUT__ << XML_TO_CHAR(columnElement->getAttribute(columnNameAttributeTag_)) << std::endl;
310 
311  //automatically delete the persistent version of the column info
312  std::string capturedException;
313  configuration.getMockupViewP()->getColumnsInfoP()->push_back(
315  XML_TO_CHAR(columnElement->getAttribute(columnTypeAttributeTag_)),
316  XML_TO_CHAR(columnElement->getAttribute(columnNameAttributeTag_)),
317  XML_TO_CHAR(columnElement->getAttribute(columnStorageNameAttributeTag_)),
318  XML_TO_CHAR(columnElement->getAttribute(columnDataTypeAttributeTag_)),
319  XML_TO_CHAR(columnElement->getAttribute(columnDataChoicesAttributeTag_)),
320  allowIllegalColumns_?&capturedException:0)); //capture exception string if allowing illegal columns
321 
322  //if error detected (this implies allowing illegal columns)
323  // accumulate and return accumulated errors at end
324  if(capturedException != "")
325  accumulatedExceptions += std::string("\n\nColumn Error:") + capturedException;
326 
327  //</COLUMN>
328  }
329 
330  //handle view description (which is actually the configuration
331  // description since only one view allowed)
332  std::string configurationDescription = XML_TO_CHAR(viewElement->getAttribute(
333  viewDescriptionAttributeTag_));
334 
335  configuration.setConfigurationDescription(
336  ConfigurationView::decodeURIComponent(configurationDescription));
337  //__MOUT__ << "configurationDescription = " << configurationDescription << std::endl;
338 
339  //</VIEW>
340  }
341  if( !storageTypeFound )
342  {
343  __MOUT__ << "The type defined in CONFIGURATION_TYPE ("
344  << getenv("CONFIGURATION_TYPE") << ") doesn't match with any of the types defined in " << configFile << std::endl;
345 
346  delete parser;
347  delete errorHandler;
348  throw(std::runtime_error( "Configuration Type mismatch!" ));
349  }
350 
351  //</CONFIGURATION>
352  }
353  catch( xercesc::XMLException& e )
354  {
355  std::ostringstream errBuf;
356  errBuf << "Error parsing file: " << XML_TO_CHAR(e.getMessage()) << std::flush;
357  }
358  delete parser;
359  delete errorHandler;
360 
361  //__MOUT__ << std::endl;
362 
363  //if exceptions have been accumulated
364  // then in allowIllegalColumns mode
365  //return accumulated exception strings to next level
366  return accumulatedExceptions;
367 }
368 
369 //==============================================================================
370 //returns accumulated exception string (while allowIllegalColumns == true)
371 // otherwise "" if no exceptions
372 std::string ConfigurationInfoReader::read(ConfigurationBase* configuration)
373 {
374  return read(*configuration);
375 }