00001 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationInfoReader.h"
00002 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationBase.h"
00003 #include "otsdaq-core/XmlUtilities/DOMTreeErrorReporter.h"
00004 #include "otsdaq-core/XmlUtilities/ConvertFromXML.h"
00005
00006
00007
00008 #include <xercesc/parsers/XercesDOMParser.hpp>
00009 #include <xercesc/dom/DOMElement.hpp>
00010 #include <xercesc/dom/DOMImplementation.hpp>
00011 #include <xercesc/dom/DOMImplementationRegistry.hpp>
00012 #include <xercesc/dom/DOMNodeList.hpp>
00013 #include <xercesc/dom/DOMText.hpp>
00014
00015
00016 #include <xercesc/util/OutOfMemoryException.hpp>
00017 #include <xercesc/framework/LocalFileFormatTarget.hpp>
00018
00019 #include <stdexcept>
00020 #include <iostream>
00021 #include <sstream>
00022
00023 #include <sys/stat.h>
00024 #include <errno.h>
00025
00026 using namespace ots;
00027
00028 #undef __COUT_HDR__
00029 #define __COUT_HDR__ "ConfigInfoReader"
00030
00031
00032
00033 ConfigurationInfoReader::ConfigurationInfoReader(bool allowIllegalColumns)
00034 : allowIllegalColumns_(allowIllegalColumns)
00035 {
00036 initPlatform();
00037 rootTag_ = xercesc::XMLString::transcode("ROOT");
00038 configurationTag_ = xercesc::XMLString::transcode("CONFIGURATION");
00039 configurationNameAttributeTag_ = xercesc::XMLString::transcode("Name");
00040 viewTag_ = xercesc::XMLString::transcode("VIEW");
00041 viewNameAttributeTag_ = xercesc::XMLString::transcode("Name");
00042 viewTypeAttributeTag_ = xercesc::XMLString::transcode("Type");
00043 viewDescriptionAttributeTag_ = xercesc::XMLString::transcode("Description");
00044 columnTag_ = xercesc::XMLString::transcode("COLUMN");
00045 columnTypeAttributeTag_ = xercesc::XMLString::transcode("Type");
00046 columnNameAttributeTag_ = xercesc::XMLString::transcode("Name");
00047 columnStorageNameAttributeTag_ = xercesc::XMLString::transcode("StorageName");
00048 columnDataTypeAttributeTag_ = xercesc::XMLString::transcode("DataType");
00049 columnDataChoicesAttributeTag_ = xercesc::XMLString::transcode("DataChoices");
00050 }
00051
00052
00053 ConfigurationInfoReader::~ConfigurationInfoReader(void)
00054 {
00055 try
00056 {
00057 xercesc::XMLString::release( &rootTag_ );
00058 xercesc::XMLString::release( &configurationTag_ );
00059 xercesc::XMLString::release( &configurationNameAttributeTag_ );
00060 xercesc::XMLString::release( &viewTag_ );
00061 xercesc::XMLString::release( &viewNameAttributeTag_ );
00062 xercesc::XMLString::release( &viewTypeAttributeTag_ );
00063 xercesc::XMLString::release( &viewDescriptionAttributeTag_ );
00064 xercesc::XMLString::release( &columnTag_ );
00065 xercesc::XMLString::release( &columnTypeAttributeTag_ );
00066 xercesc::XMLString::release( &columnNameAttributeTag_ );
00067 xercesc::XMLString::release( &columnStorageNameAttributeTag_ );
00068 xercesc::XMLString::release( &columnDataTypeAttributeTag_ );
00069 xercesc::XMLString::release( &columnDataChoicesAttributeTag_ );
00070
00071 }
00072 catch( ... )
00073 {
00074 mf::LogError(__FILE__) << "Unknown exception encountered in TagNames destructor" << std::endl;
00075 }
00076 terminatePlatform();
00077 }
00078
00079
00080 void ConfigurationInfoReader::initPlatform(void)
00081 {
00082 try
00083 {
00084 xercesc::XMLPlatformUtils::Initialize();
00085 }
00086 catch( xercesc::XMLException& e )
00087 {
00088 mf::LogError(__FILE__) << "XML toolkit initialization error: " << XML_TO_CHAR(e.getMessage()) << std::endl;
00089
00090 }
00091 }
00092
00093
00094 void ConfigurationInfoReader::terminatePlatform(void)
00095 {
00096 try
00097 {
00098 xercesc::XMLPlatformUtils::Terminate();
00099 }
00100 catch( xercesc::XMLException& e )
00101 {
00102 mf::LogError(__FILE__) << "XML tolkit teardown error: " << XML_TO_CHAR(e.getMessage()) << std::endl;
00103 }
00104 }
00105
00106
00107
00108 void ConfigurationInfoReader::setAllowColumnErrors(bool setValue)
00109 {
00110 allowIllegalColumns_ = setValue;
00111 }
00112
00113 const bool& ConfigurationInfoReader::getAllowColumnErrors(void)
00114 {
00115 return allowIllegalColumns_;
00116 }
00117
00118
00119 bool ConfigurationInfoReader::checkViewType(std::string type)
00120 {
00121 std::vector<std::string> types;
00122 int currentIndex = 0;
00123 while( type.find(',',currentIndex) != std::string::npos )
00124 {
00125 types.push_back(type.substr(currentIndex,type.find(',',currentIndex)-currentIndex));
00126 currentIndex = type.find(',',currentIndex)+1;
00127 }
00128 types.push_back(type.substr(currentIndex,type.size()));
00129
00130 std::string systemType = getenv("CONFIGURATION_TYPE");
00131 for(unsigned int i=0; i<types.size(); i++)
00132 {
00133 if( types[i] == systemType )
00134 return true;
00135 }
00136
00137 const unsigned int allowedNamesSize = 3;
00138 const std::string allowedNames[allowedNamesSize] =
00139 {"File","Database","DatabaseTest"
00140 };
00141 if(systemType != allowedNames[0] && systemType != allowedNames[1] && systemType != allowedNames[2] )
00142 {
00143 __COUT__ << "The type defined in CONFIGURATION_TYPE ("
00144 << systemType << ") doesn't match with any of the allowed types: File,Database or DatabaseTest"
00145 << std::endl;
00146
00147 throw(std::runtime_error( "Illegal configuration type" ));
00148 }
00149 for(unsigned int i=0; i<types.size(); i++)
00150 {
00151 if(types[i] != allowedNames[0] && types[i] != allowedNames[1] && types[i] != allowedNames[2] )
00152 {
00153 __COUT__ << "The type defined in the info file ("
00154 << types[i] << ") doesn't match with any of the allowed types: "
00155 << allowedNames[0] << ", " << allowedNames[1] << " or " << allowedNames[2]
00156 << std::endl;
00157 throw(std::runtime_error( "Illegal Type!" ));
00158 }
00159 }
00160
00161 return false;
00162 }
00163
00164
00165 xercesc::DOMNode* ConfigurationInfoReader::getNode(XMLCh* tagName, xercesc::DOMNode* parent, unsigned int itemNumber)
00166 {
00167 return getNode(tagName, dynamic_cast< xercesc::DOMElement* >(parent), itemNumber);
00168 }
00169
00170
00171 xercesc::DOMNode* ConfigurationInfoReader::getNode(XMLCh* tagName, xercesc::DOMElement* parent, unsigned int itemNumber)
00172 {
00173 xercesc::DOMNodeList* nodeList = parent->getElementsByTagName(tagName);
00174 if( !nodeList )
00175 {
00176 throw(std::runtime_error( std::string("Can't find ") + XML_TO_CHAR(tagName) + " tag!"));
00177 __COUT__ << (std::string("Can't find ") + XML_TO_CHAR(tagName) + " tag!") << std::endl;
00178 }
00179
00180
00181
00182 return nodeList->item(itemNumber);
00183 }
00184
00185
00186 xercesc::DOMElement* ConfigurationInfoReader::getElement(XMLCh* tagName, xercesc::DOMNode* parent, unsigned int itemNumber)
00187 {
00188 return dynamic_cast< xercesc::DOMElement* >(getNode(tagName,parent,itemNumber));
00189 }
00190
00191
00192 xercesc::DOMElement* ConfigurationInfoReader::getElement(XMLCh* tagName, xercesc::DOMElement* parent, unsigned int itemNumber)
00193 {
00194 return dynamic_cast< xercesc::DOMElement* >(getNode(tagName,parent,itemNumber));
00195 }
00196
00197
00198 std::string ConfigurationInfoReader::read(ConfigurationBase& configuration)
00199 {
00200 std::string accumulatedExceptions = "";
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 if(getenv("CONFIGURATION_TYPE" ) == NULL) __COUT__ << "Missing env variable: CONFIGURATION_TYPE. It must be set!" << std::endl;
00212 if(getenv("CONFIGURATION_DATA_PATH") == NULL) __COUT__ << "Missing env variable: CONFIGURATION_DATA_PATH. It must be set!" << std::endl;
00213 if(getenv("CONFIGURATION_INFO_PATH") == NULL) __COUT__ << "Missing env variable: CONFIGURATION_INFO_PATH. It must be set!" << std::endl;
00214
00215
00216
00217
00218
00219
00220
00221
00222 std::string configurationDataDir = std::string(getenv("CONFIGURATION_INFO_PATH")) + "/";
00223 std::string configFile = configurationDataDir + configuration.getConfigurationName() + "Info.xml";
00224
00225 struct stat fileStatus;
00226
00227 int iretStat = stat(configFile.c_str(), &fileStatus);
00228 if( iretStat == ENOENT )
00229 {
00230 __SS__ << ("Path file_name does not exist, or path is an empty std::string.") << std::endl;
00231 __COUT_ERR__ << ss.str();
00232 throw std::runtime_error(ss.str());
00233 }
00234 else if( iretStat == ENOTDIR )
00235 {
00236 __SS__ << ("A component of the path is not a directory.") << std::endl;
00237 __COUT_ERR__ << ss.str();
00238 throw std::runtime_error(ss.str());
00239 }
00240 else if( iretStat == ELOOP )
00241 {
00242 __SS__ << ("Too many symbolic links encountered while traversing the path.") << std::endl;
00243 __COUT_ERR__ << ss.str();
00244 throw std::runtime_error(ss.str());
00245 }
00246 else if( iretStat == EACCES )
00247 {
00248 __SS__ << ("Permission denied.") << std::endl;
00249 __COUT_ERR__ << ss.str();
00250 throw std::runtime_error(ss.str());
00251 }
00252 else if( iretStat == ENAMETOOLONG )
00253 {
00254 __SS__ << ("File can not be read. Name too long.") << std::endl;
00255 __COUT_ERR__ << ss.str();
00256 throw std::runtime_error(ss.str());
00257 }
00258
00259 xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser;
00260
00261 parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);
00262 parser->setDoNamespaces ( true );
00263 parser->setDoSchema ( true );
00264 parser->useCachedGrammarInParse ( false );
00265
00266 DOMTreeErrorReporter* errorHandler = new DOMTreeErrorReporter() ;
00267 parser->setErrorHandler(errorHandler);
00268 try
00269 {
00270 parser->parse( configFile.c_str() );
00271
00272
00273 xercesc::DOMDocument* xmlDocument = parser->getDocument();
00274
00275
00276 xercesc::DOMElement* elementRoot = xmlDocument->getDocumentElement();
00277 if( !elementRoot )
00278 {
00279 delete parser;
00280 delete errorHandler;
00281 throw(std::runtime_error( "empty XML document" ));
00282 }
00283
00284
00285 xercesc::DOMElement* configurationElement = getElement(configurationTag_, elementRoot, 0);
00286 if( configuration.getConfigurationName() != XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_)) )
00287 {
00288
00289 __SS__ << "In " << configFile << " the configuration name " << XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_))
00290 << " doesn't match the the class configuration name " << configuration.getConfigurationName() << std::endl;
00291
00292 delete parser;
00293 delete errorHandler;
00294 __COUT_ERR__ << "\n" << ss.str();
00295 throw(std::runtime_error( ss.str()));
00296 }
00297
00298 xercesc::DOMNodeList* viewNodeList = configurationElement->getElementsByTagName(viewTag_);
00299 bool storageTypeFound = false;
00300
00301 if(viewNodeList->getLength() != 1)
00302 {
00303
00304 __SS__ << "In " << configFile << " the configuration name " << XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_))
00305 << " there must only be one view. There were " <<
00306 viewNodeList->getLength() << " found." << std::endl;
00307
00308 delete parser;
00309 delete errorHandler;
00310 __COUT_ERR__ << "\n" << ss.str();
00311 throw(std::runtime_error( ss.str()));
00312 }
00313
00314 for( XMLSize_t view = 0; view < viewNodeList->getLength(); view++ )
00315 {
00316 if( !viewNodeList->item(view)->getNodeType() || viewNodeList->item(view)->getNodeType() != xercesc::DOMNode::ELEMENT_NODE )
00317 continue;
00318 xercesc::DOMElement* viewElement = dynamic_cast< xercesc::DOMElement* >( viewNodeList->item(view) );
00319 std::string viewType = XML_TO_CHAR(viewElement->getAttribute(viewTypeAttributeTag_));
00320 if(!checkViewType(viewType))
00321 continue;
00322 storageTypeFound = true;
00323 configuration.getMockupViewP()->setTableName(XML_TO_CHAR(viewElement->getAttribute(viewNameAttributeTag_)));
00324 xercesc::DOMNodeList* columnNodeList = viewElement->getElementsByTagName(columnTag_);
00325 for( XMLSize_t column = 0; column < columnNodeList->getLength(); column++ )
00326 {
00327
00328 xercesc::DOMElement* columnElement = dynamic_cast< xercesc::DOMElement* >( columnNodeList->item(column) );
00329
00330
00331
00332 std::string capturedException;
00333 configuration.getMockupViewP()->getColumnsInfoP()->push_back(
00334 ViewColumnInfo(
00335 XML_TO_CHAR(columnElement->getAttribute(columnTypeAttributeTag_)),
00336 XML_TO_CHAR(columnElement->getAttribute(columnNameAttributeTag_)),
00337 XML_TO_CHAR(columnElement->getAttribute(columnStorageNameAttributeTag_)),
00338 XML_TO_CHAR(columnElement->getAttribute(columnDataTypeAttributeTag_)),
00339 XML_TO_CHAR(columnElement->getAttribute(columnDataChoicesAttributeTag_)),
00340 allowIllegalColumns_?&capturedException:0));
00341
00342
00343
00344 if(capturedException != "")
00345 accumulatedExceptions += std::string("\n\nColumn Error:") + capturedException;
00346
00347
00348 }
00349
00350
00351
00352 std::string configurationDescription = XML_TO_CHAR(viewElement->getAttribute(
00353 viewDescriptionAttributeTag_));
00354
00355 configuration.setConfigurationDescription(
00356 ConfigurationView::decodeURIComponent(configurationDescription));
00357
00358
00359
00360 }
00361 if( !storageTypeFound )
00362 {
00363 __COUT__ << "The type defined in CONFIGURATION_TYPE ("
00364 << getenv("CONFIGURATION_TYPE") << ") doesn't match with any of the types defined in " << configFile << std::endl;
00365
00366 delete parser;
00367 delete errorHandler;
00368 throw(std::runtime_error( "Configuration Type mismatch!" ));
00369 }
00370
00371
00372 }
00373 catch( xercesc::XMLException& e )
00374 {
00375 std::ostringstream errBuf;
00376 errBuf << "Error parsing file: " << XML_TO_CHAR(e.getMessage()) << std::flush;
00377 }
00378 delete parser;
00379 delete errorHandler;
00380
00381
00382
00383
00384
00385
00386 return accumulatedExceptions;
00387 }
00388
00389
00390
00391
00392 std::string ConfigurationInfoReader::read(ConfigurationBase* configuration)
00393 {
00394 return read(*configuration);
00395 }