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 __MOUT_HDR__
00029 #define __MOUT_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 __MOUT__ << "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 __MOUT__ << "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 __MOUT__ << (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) __MOUT__ << "Missing env variable: CONFIGURATION_TYPE. It must be set!" << std::endl;
00212 if(getenv("CONFIGURATION_DATA_PATH") == NULL) __MOUT__ << "Missing env variable: CONFIGURATION_DATA_PATH. It must be set!" << std::endl;
00213 if(getenv("CONFIGURATION_INFO_PATH") == NULL) __MOUT__ << "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 throw ( std::runtime_error("Path file_name does not exist, or path is an empty std::string.") );
00230 else if( iretStat == ENOTDIR )
00231 throw ( std::runtime_error("A component of the path is not a directory."));
00232 else if( iretStat == ELOOP )
00233 throw ( std::runtime_error("Too many symbolic links encountered while traversing the path."));
00234 else if( iretStat == EACCES )
00235 throw ( std::runtime_error("Permission denied."));
00236 else if( iretStat == ENAMETOOLONG )
00237 throw ( std::runtime_error("File can not be read\n"));
00238
00239 xercesc::XercesDOMParser* parser = new xercesc::XercesDOMParser;
00240
00241 parser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);
00242 parser->setDoNamespaces ( true );
00243 parser->setDoSchema ( true );
00244 parser->useCachedGrammarInParse ( false );
00245
00246 DOMTreeErrorReporter* errorHandler = new DOMTreeErrorReporter() ;
00247 parser->setErrorHandler(errorHandler);
00248 try
00249 {
00250 parser->parse( configFile.c_str() );
00251
00252
00253 xercesc::DOMDocument* xmlDocument = parser->getDocument();
00254
00255
00256 xercesc::DOMElement* elementRoot = xmlDocument->getDocumentElement();
00257 if( !elementRoot )
00258 {
00259 delete parser;
00260 delete errorHandler;
00261 throw(std::runtime_error( "empty XML document" ));
00262 }
00263
00264
00265 xercesc::DOMElement* configurationElement = getElement(configurationTag_, elementRoot, 0);
00266 if( configuration.getConfigurationName() != XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_)) )
00267 {
00268
00269 __SS__ << "In " << configFile << " the configuration name " << XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_))
00270 << " doesn't match the the class configuration name " << configuration.getConfigurationName() << std::endl;
00271
00272 delete parser;
00273 delete errorHandler;
00274 __MOUT_ERR__ << "\n" << ss.str();
00275 throw(std::runtime_error( ss.str()));
00276 }
00277
00278 xercesc::DOMNodeList* viewNodeList = configurationElement->getElementsByTagName(viewTag_);
00279 bool storageTypeFound = false;
00280
00281 if(viewNodeList->getLength() != 1)
00282 {
00283
00284 __SS__ << "In " << configFile << " the configuration name " << XML_TO_CHAR(configurationElement->getAttribute(configurationNameAttributeTag_))
00285 << " there must only be one view. There were " <<
00286 viewNodeList->getLength() << " found." << std::endl;
00287
00288 delete parser;
00289 delete errorHandler;
00290 __MOUT_ERR__ << "\n" << ss.str();
00291 throw(std::runtime_error( ss.str()));
00292 }
00293
00294 for( XMLSize_t view = 0; view < viewNodeList->getLength(); view++ )
00295 {
00296 if( !viewNodeList->item(view)->getNodeType() || viewNodeList->item(view)->getNodeType() != xercesc::DOMNode::ELEMENT_NODE )
00297 continue;
00298 xercesc::DOMElement* viewElement = dynamic_cast< xercesc::DOMElement* >( viewNodeList->item(view) );
00299 std::string viewType = XML_TO_CHAR(viewElement->getAttribute(viewTypeAttributeTag_));
00300 if(!checkViewType(viewType))
00301 continue;
00302 storageTypeFound = true;
00303 configuration.getMockupViewP()->setTableName(XML_TO_CHAR(viewElement->getAttribute(viewNameAttributeTag_)));
00304 xercesc::DOMNodeList* columnNodeList = viewElement->getElementsByTagName(columnTag_);
00305 for( XMLSize_t column = 0; column < columnNodeList->getLength(); column++ )
00306 {
00307
00308 xercesc::DOMElement* columnElement = dynamic_cast< xercesc::DOMElement* >( columnNodeList->item(column) );
00309
00310
00311
00312 std::string capturedException;
00313 configuration.getMockupViewP()->getColumnsInfoP()->push_back(
00314 ViewColumnInfo(
00315 XML_TO_CHAR(columnElement->getAttribute(columnTypeAttributeTag_)),
00316 XML_TO_CHAR(columnElement->getAttribute(columnNameAttributeTag_)),
00317 XML_TO_CHAR(columnElement->getAttribute(columnStorageNameAttributeTag_)),
00318 XML_TO_CHAR(columnElement->getAttribute(columnDataTypeAttributeTag_)),
00319 XML_TO_CHAR(columnElement->getAttribute(columnDataChoicesAttributeTag_)),
00320 allowIllegalColumns_?&capturedException:0));
00321
00322
00323
00324 if(capturedException != "")
00325 accumulatedExceptions += std::string("\n\nColumn Error:") + capturedException;
00326
00327
00328 }
00329
00330
00331
00332 std::string configurationDescription = XML_TO_CHAR(viewElement->getAttribute(
00333 viewDescriptionAttributeTag_));
00334
00335 configuration.setConfigurationDescription(
00336 ConfigurationView::decodeURIComponent(configurationDescription));
00337
00338
00339
00340 }
00341 if( !storageTypeFound )
00342 {
00343 __MOUT__ << "The type defined in CONFIGURATION_TYPE ("
00344 << getenv("CONFIGURATION_TYPE") << ") doesn't match with any of the types defined in " << configFile << std::endl;
00345
00346 delete parser;
00347 delete errorHandler;
00348 throw(std::runtime_error( "Configuration Type mismatch!" ));
00349 }
00350
00351
00352 }
00353 catch( xercesc::XMLException& e )
00354 {
00355 std::ostringstream errBuf;
00356 errBuf << "Error parsing file: " << XML_TO_CHAR(e.getMessage()) << std::flush;
00357 }
00358 delete parser;
00359 delete errorHandler;
00360
00361
00362
00363
00364
00365
00366 return accumulatedExceptions;
00367 }
00368
00369
00370
00371
00372 std::string ConfigurationInfoReader::read(ConfigurationBase* configuration)
00373 {
00374 return read(*configuration);
00375 }