Gaudi Framework, version v23r9

Home   Generated: Thu Jul 18 2013
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
XMLFileCatalog.cpp
Go to the documentation of this file.
1 #include "xercesc/framework/LocalFileFormatTarget.hpp"
2 #include "xercesc/framework/MemBufInputSource.hpp"
3 #include "xercesc/sax/SAXParseException.hpp"
4 #include "xercesc/sax/EntityResolver.hpp"
5 #include "xercesc/sax/InputSource.hpp"
6 #include "xercesc/parsers/XercesDOMParser.hpp"
7 #include "xercesc/util/PlatformUtils.hpp"
8 #include "xercesc/util/XercesDefs.hpp"
9 #include "xercesc/util/XMLUni.hpp"
10 #include "xercesc/util/XMLURL.hpp"
11 #include "xercesc/util/XMLString.hpp"
12 #include "xercesc/dom/DOM.hpp"
13 
14 #include "GaudiKernel/MsgStream.h"
15 #include "GaudiKernel/Service.h"
16 #include "Reflex/PluginService.h"
17 
18 #include "XMLFileCatalog.h"
19 
20 #include <fstream>
21 #include <iostream>
22 #include <stdexcept>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include "uuid/uuid.h"
26 
27 #include <boost/format.hpp>
28 
29 using namespace xercesc;
30 using namespace Gaudi;
31 using namespace std;
32 
33 #if _XERCES_VERSION <= 30000
34 // API change between XercesC 2 and 3
35 #define setIdAttribute(a, b) setIdAttribute(a)
36 #endif
37 
38 PLUGINSVC_FACTORY(XMLFileCatalog,IInterface*(std::string, IMessageSvc*))
39 
40 namespace {
41 
42  typedef const string& CSTR;
43  inline string _toString(const XMLCh *toTranscode) {
44  char * buff = XMLString::transcode(toTranscode);
45  string tmp(buff==0 ? "" : buff);
46  XMLString::release(&buff);
47  return tmp;
48  }
49  struct __Init {
50  __Init() {
51  try { XMLPlatformUtils::Initialize(); }
52  catch (const XMLException& e) {
53  cout << "Xerces-c error in initialization:" << _toString(e.getMessage()) << endl;
54  }
55  }
56  ~__Init() {
57  XMLPlatformUtils::Terminate();
58  }
59  };
60  __Init __In__;
61 
62  struct XMLStr {
63  XMLCh* m_xml;
64  XMLStr(CSTR c) { m_xml=XMLString::transcode(c.c_str()); }
65  ~XMLStr() { if (m_xml) XMLString::release(&m_xml); }
66  operator const XMLCh*() const { return m_xml; }
67  };
68  struct XMLTag : public XMLStr {
69  string m_str;
70  XMLTag(CSTR s) : XMLStr(s), m_str(s) { }
71  ~XMLTag() { }
72  operator CSTR () const { return m_str; }
73  };
74  // bool operator==(const XMLTag& b, CSTR c) { return c==b.m_str; }
75  bool operator==(CSTR c, const XMLTag& b) { return c==b.m_str; }
76  struct XMLCollection {
77  DOMElement* m_node;
78  XMLCollection(DOMNode* n, bool use_children=true) : m_node((DOMElement*)n) {
79  if ( use_children ) {
80  if ( m_node ) m_node = (DOMElement*)m_node->getFirstChild();
81  if ( m_node && m_node->getNodeType() != DOMNode::ELEMENT_NODE ) ++(*this);
82  }
83  }
84  operator bool() const { return 0 != m_node; }
85  operator DOMNode* () const { return m_node; }
86  operator DOMElement* () const { return m_node; }
87  DOMElement* operator->() const { return m_node; }
88  string attr(const XMLTag& tag) const { return _toString(m_node->getAttribute(tag));}
89  string attr(CSTR tag) const { return attr(XMLTag(tag)); }
90  string tag() const { return _toString(m_node->getTagName()); }
91  void operator++() {
92  while(m_node) {
93  m_node = (DOMElement*)m_node->getNextSibling();
94  if ( m_node && m_node->getNodeType() == DOMNode::ELEMENT_NODE ) {
95  return;
96  }
97  }
98  }
99  };
100  struct ErrHandler : public ErrorHandler {
102  IMessageSvc* m_msg;
104  ErrHandler(IMessageSvc* m) : m_msg(m) {}
106  void resetErrors() { }
108  void warning(const SAXParseException& /* e */) { }
110  void error(const SAXParseException& e);
112  void fatalError(const SAXParseException& e);
113  virtual ~ErrHandler() {}
114  };
115  struct DTDRedirect : public EntityResolver {
116  InputSource* resolveEntity(const XMLCh* const /* pubId */, const XMLCh* const /* sysId */) {
117  static const char* dtdID = "redirectinmem.dtd";
118  static const char* dtd = \
119  "\
120  <!ELEMENT POOLFILECATALOG (META*,File*)>\
121  <!ELEMENT META EMPTY>\
122  <!ELEMENT File (physical,logical,metadata*)>\
123  <!ATTLIST META name CDATA #REQUIRED>\
124  <!ATTLIST META type CDATA #REQUIRED>\
125  <!ELEMENT physical (pfn)+>\
126  <!ELEMENT logical (lfn)*>\
127  <!ELEMENT metadata EMPTY>\
128  <!ELEMENT lfn EMPTY>\
129  <!ELEMENT pfn EMPTY>\
130  <!ATTLIST File ID ID #REQUIRED>\
131  <!ATTLIST pfn name ID #REQUIRED>\
132  <!ATTLIST pfn filetype CDATA #IMPLIED>\
133  <!ATTLIST lfn name ID #REQUIRED>\
134  <!ATTLIST metadata att_name CDATA #REQUIRED>\
135  <!ATTLIST metadata att_value CDATA #REQUIRED>\
136  ";
137  static const size_t len = strlen(dtd);
138  return new MemBufInputSource((const XMLByte*)dtd,len,dtdID,false);
139  }
140  virtual ~DTDRedirect() {}
141  };
142 
143  void ErrHandler::error(const SAXParseException& e) {
144  string m(_toString(e.getMessage()));
145  if (m.find("The values for attribute 'name' must be names or name tokens")!=string::npos ||
146  m.find("The values for attribute 'ID' must be names or name tokens")!=string::npos ||
147  m.find("for attribute 'name' must be Name or Nmtoken")!=string::npos ||
148  m.find("for attribute 'ID' must be Name or Nmtoken")!=string::npos ||
149  m.find("for attribute 'name' is invalid Name or NMTOKEN value")!=string::npos ||
150  m.find("for attribute 'ID' is invalid Name or NMTOKEN value")!=string::npos )
151  return;
152  string sys(_toString(e.getSystemId()));
153  MsgStream log(m_msg,"XMLCatalog");
154  log << MSG::ERROR << "Error at file \"" << sys
155  << "\", line " << e.getLineNumber() << ", column " << e.getColumnNumber() << endmsg
156  << "Message: " << m << endmsg;
157  }
158  void ErrHandler::fatalError(const SAXParseException& e) {
159  MsgStream log(m_msg,"XMLCatalog");
160  string m(_toString(e.getMessage()));
161  string sys(_toString(e.getSystemId()));
162  log << MSG::ERROR << "Fatal Error at file \"" << sys
163  << "\", line " << e.getLineNumber() << ", column " << e.getColumnNumber() << endmsg
164  << "Message: " << m << endmsg;
165  throw runtime_error( "Standard pool exception : Fatal Error on the DOM Parser" );
166  }
167 
168  const XMLTag EmptyCatalog("<!-- Edited By POOL -->\n"
169  "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n"
170  "<POOLFILECATALOG>\n"
171  "</POOLFILECATALOG>\n");
172  const XMLTag PFNCOLL ("physical");
173  const XMLTag LFNCOLL ("logical");
174  const XMLTag PFNNODE ( "pfn");
175  const XMLTag LFNNODE ( "lfn");
176  const XMLTag Attr_type ( "type");
177  const XMLTag Attr_ID ( "ID");
178  const XMLTag Attr_name ( "name");
179  const XMLTag Attr_ftype ( "filetype");
180  const XMLTag MetaNode ( "metadata");
181  const XMLTag Attr_metaName ( "att_name");
182  const XMLTag Attr_metaValue ( "att_value");
183 }
184 
187  uuid_t uuid;
188  ::uuid_generate_time(uuid);
189  struct Guid {
190  unsigned int Data1;
191  unsigned short Data2;
192  unsigned short Data3;
193  unsigned char Data4[8];
194  } *g = (Guid*)&uuid;
195 
196  boost::format text("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X");
197  text % g->Data1 % g->Data2 % g->Data3;
198  for (int i = 0; i < 8; ++i)
199  text % (unsigned short)g->Data4[i];
200  return text.str();
201 }
202 // ----------------------------------------------------------------------------
203 XMLFileCatalog::XMLFileCatalog(CSTR uri, IMessageSvc* m)
204 : m_rdOnly(false),m_update(false),m_doc(0),m_parser(0),m_errHdlr(0),
205  m_file(uri), m_msgSvc(m)
206 {
207 }
208 // ----------------------------------------------------------------------------
209 XMLFileCatalog::~XMLFileCatalog() {
210  if (m_parser) delete m_parser;
211  m_parser = 0;
212  if (m_errHdlr) delete m_errHdlr;
213  m_errHdlr = 0;
214  m_doc = 0;
215 }
216 // ----------------------------------------------------------------------------
218 std::string XMLFileCatalog::createFID() const {
219  return createGuidAsString();
220 }
221 // ----------------------------------------------------------------------------
222 DOMDocument* XMLFileCatalog::getDoc(bool throw_if_no_exists) const {
223  if ( !m_doc && throw_if_no_exists )
224  printError("The XML catalog was not started.",true);
225  return m_doc;
226 }
227 // ----------------------------------------------------------------------------
228 void XMLFileCatalog::printError(CSTR msg, bool rethrow) const {
229  MsgStream log(m_msgSvc,"XMLCatalog");
230  log << MSG::FATAL << msg << endmsg;
231  if ( rethrow ) {
232  throw runtime_error("XMLFileCatalog> "+msg);
233  }
234 }
235 // ----------------------------------------------------------------------------
236 void XMLFileCatalog::init() {
237  string xmlFile = getfile(false);
238  try{
239  if ( m_parser ) delete m_parser;
240  m_parser = new XercesDOMParser;
241  m_parser->setValidationScheme(XercesDOMParser::Val_Auto);
242  m_parser->setDoNamespaces(false);
243  DTDRedirect dtdinmem;
244  m_parser->setEntityResolver(&dtdinmem);
245  if ( ! m_errHdlr ) m_errHdlr = new ErrHandler(m_msgSvc);
246  m_parser->setErrorHandler(m_errHdlr);
247  if ( !xmlFile.empty() ) {
248  m_parser->parse(xmlFile.c_str());
249  }
250  else {
251  const std::string& s = EmptyCatalog;
252  MemBufInputSource src((const XMLByte*)s.c_str(),s.length(),"MemCatalog");
253  m_parser->parse(src);
254  }
255  m_doc = m_parser->getDocument();
256  }
257  catch (const XMLException& e) {
258  printError("XML parse error["+xmlFile+"]: "+_toString(e.getMessage()));
259  }
260  catch (const DOMException& e) {
261  printError("XML parse error["+xmlFile+"]: "+_toString(e.getMessage()));
262  }
263  catch (...) {
264  printError("UNKNOWN XML parse error in file "+xmlFile);
265  }
266 }
267 // ----------------------------------------------------------------------------
268 string XMLFileCatalog::lookupFID(const std::string& fid) const {
269  std::string result;
270  DOMNode* e = element(fid,false);
271  e = e ? e->getParentNode() : 0; // Mode up to <logical>
272  e = e ? e->getParentNode() : 0; // Mode up to <File>
273  if ( e ) {
274  if ( e->getAttributes() ) { // Need to check this. The node may be no DOMElement
275  char* nam = XMLString::transcode(((DOMElement*)e)->getAttribute(Attr_ID));
276  if ( nam ) result = nam;
277  XMLString::release(&nam);
278  }
279  }
280  return result;
281 }
282 // ----------------------------------------------------------------------------
283 void XMLFileCatalog::getFID(Strings& fids) const {
284  fids.clear();
285  DOMNode* fde = getDoc(true)->getElementsByTagName(XMLStr("*"))->item(0);
286  for(XMLCollection c(child(fde,"File"), false); c; ++c)
287  fids.push_back(c.attr(Attr_ID));
288 }
289 // ----------------------------------------------------------------------------
290 void XMLFileCatalog::getPFN(CSTR fid, Files& files) const {
291  files.clear();
292  for(XMLCollection c(child(child(element(fid,false),PFNCOLL),PFNNODE), false); c; ++c)
293  files.push_back(make_pair(c.attr(Attr_name),c.attr(Attr_ftype)));
294 }
295 // ----------------------------------------------------------------------------
296 void XMLFileCatalog::getLFN(CSTR fid, Files& files) const {
297  files.clear();
298  for(XMLCollection c(child(child(element(fid,false),LFNCOLL),LFNNODE), false); c; ++c)
299  files.push_back(make_pair(c.attr(Attr_name),fid));
300 }
301 // ----------------------------------------------------------------------------
302 void XMLFileCatalog::getMetaData(CSTR fid, Attributes& attr) const {
303  attr.clear();
304  for(XMLCollection c(child(element(fid),MetaNode), false); c; ++c)
305  attr.push_back(make_pair(c.attr(Attr_metaName),c.attr(Attr_metaValue)));
306  if ( attr.size() > 0 )
307  attr.push_back(make_pair("guid",fid));
308 }
309 // ----------------------------------------------------------------------------
310 DOMNode* XMLFileCatalog::child(DOMNode* par,CSTR tag,CSTR attr,CSTR val) const {
311  for(XMLCollection c(par); c; ++c ) {
312  if( c.tag() == tag ) {
313  if( !attr.empty() && c.attr(attr) != val) continue;
314  return c;
315  }
316  }
317  return 0;
318 }
319 // ----------------------------------------------------------------------------
320 void XMLFileCatalog::setMetaData(CSTR fid, CSTR attr, CSTR val) const {
321  if ( !readOnly() ) {
322  DOMNode* node = element(fid);
323  DOMElement* mnod = (DOMElement*)child(node,MetaNode,Attr_metaName,attr);
324  if (!mnod){
325  mnod = getDoc(true)->createElement(MetaNode);
326  node->appendChild(mnod);
327  mnod->setAttribute(Attr_metaName,XMLStr(attr));
328  }
329  mnod->setAttribute(Attr_metaValue,XMLStr(val));
330  m_update = true;
331  return;
332  }
333  printError("Cannot update readonly catalog!");
334 }
335 // ----------------------------------------------------------------------------
336 string XMLFileCatalog::getMetaDataItem(CSTR fid,CSTR attr) const {
337  XMLCollection c(child(getDoc(true)->getElementById(XMLStr(fid)),MetaNode,Attr_metaName,attr));
338  return c ? c.attr(attr) : string("");
339 }
340 // ----------------------------------------------------------------------------
341 void XMLFileCatalog::dropMetaData(CSTR fid,CSTR attr) const {
342  vector<DOMNode*> gbc;
343  DOMNode* fn = getDoc(true)->getElementById(XMLStr(fid));
344  for(XMLCollection c(child(fn,MetaNode)); c; ++c)
345  if ( attr[0]=='*' || !c.attr(attr).empty() ) gbc.push_back(c);
346  for(vector<DOMNode*>::iterator i=gbc.begin(); i != gbc.end(); i++)
347  fn->removeChild(*i);
348 }
349 // ----------------------------------------------------------------------------
350 DOMNode* XMLFileCatalog::element(CSTR element_name,bool print_err) const {
351  DOMNode* node = getDoc(true)->getElementById(XMLStr(element_name));
352  if ( !node && print_err ) printError("Cannot find element:"+element_name);
353  return node;
354 }
355 // ----------------------------------------------------------------------------
356 void XMLFileCatalog::deleteFID(CSTR fid) const {
357  DOMNode *pn = 0, *fn = element(fid);
358  if ( fn ) pn = fn->getParentNode();
359  if ( pn ) pn->removeChild(fn);
360 }
361 // ----------------------------------------------------------------------------
362 void XMLFileCatalog::registerFID(CSTR fid) const {
363  if ( !fid.empty() ) {
364  std::pair<DOMElement*, DOMElement*> res = i_registerFID(fid);
365  if ( res.first == 0 || res.second == 0 ) {
366  printError("Failed to register FID:"+fid);
367  }
368  return;
369  }
370  throw runtime_error("XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
371 }
372 // ----------------------------------------------------------------------------
373 std::pair<DOMElement*,DOMElement*> XMLFileCatalog::i_registerFID(CSTR fid) const {
374  if ( !readOnly() ) {
376  DOMElement *file = (DOMElement*)element(fid,false), *phyelem = 0, *logelem = 0;
377  DOMDocument* doc = getDoc(true);
378  if ( !file ) {
379  DOMNode* fde = doc->getElementsByTagName(XMLStr("*"))->item(0);
380  file = m_doc->createElement(XMLStr("File"));
381  file->setAttribute(Attr_ID, XMLStr(fid));
382  file->setIdAttribute(Attr_ID, true);
383  fde->appendChild(file);
384  m_update = true;
385  }
386  for(XMLCollection c1(file); c1; ++c1 ) {
387  char* nam = XMLString::transcode(c1->getNodeName());
388  if ( nam == PFNCOLL ) phyelem = c1;
389  if ( nam == LFNCOLL ) logelem = c1;
390  XMLString::release(&nam);
391  }
392  if ( !phyelem ) {
393  phyelem = doc->createElement(PFNCOLL);
394  file->appendChild(phyelem);
395  m_update = true;
396  }
397  if ( !logelem ) {
398  logelem = doc->createElement(LFNCOLL);
399  file->appendChild(logelem);
400  m_update = true;
401  }
402  return std::make_pair(logelem,phyelem);
403  }
404  printError("Cannot update readonly catalog!");
406 }
407 // ----------------------------------------------------------------------------
408 void XMLFileCatalog::registerPFN(CSTR fid, CSTR pfn, CSTR ftype) const {
409  if ( !fid.empty() ) {
410  std::pair<DOMElement*,DOMElement*> res = i_registerFID(fid);
411  DOMElement* phyelem = res.second, *fnelem = 0;
412  for(XMLCollection c(phyelem); c; ++c ) {
413  char* nam = XMLString::transcode(c->getNodeName());
414  if ( nam == PFNNODE ) {
415  XMLString::release(&nam);
416  nam = XMLString::transcode(c->getAttribute(Attr_name));
417  if ( nam == pfn ) {
418  XMLString::release(&nam);
419  fnelem = c;
420  break;
421  }
422  }
423  XMLString::release(&nam);
424  }
425  if ( !fnelem ) {
426  fnelem = getDoc(true)->createElement(PFNNODE);
427  phyelem->appendChild(fnelem);
428  fnelem->setAttribute(Attr_ftype,XMLStr(ftype));
429  fnelem->setAttribute(Attr_name,XMLStr(pfn));
430  fnelem->setIdAttribute(Attr_name, true);
431  m_update = true;
432  }
433  return;
434  }
435  throw runtime_error("XMLFileCatalog> Cannot register PFN for invalid FID:"+fid);
436 }
437 // ----------------------------------------------------------------------------
438 void XMLFileCatalog::registerLFN(CSTR fid, CSTR lfn) const {
439  if ( !fid.empty() ) {
440  std::pair<DOMElement*, DOMElement*> res = i_registerFID(fid);
441  DOMElement* logelem = res.first, *fnelem = 0;
442  for(XMLCollection c(logelem); c; ++c ) {
443  char* nam = XMLString::transcode(c->getNodeName());
444  if ( nam == LFNNODE ) {
445  XMLString::release(&nam);
446  nam = XMLString::transcode(c->getAttribute(Attr_name));
447  if ( nam == lfn ) {
448  XMLString::release(&nam);
449  fnelem = c;
450  break;
451  }
452  }
453  }
454  if ( !fnelem ) {
455  fnelem = getDoc(true)->createElement(LFNNODE);
456  logelem->appendChild(fnelem);
457  fnelem->setAttribute(Attr_name,XMLStr(lfn));
458  fnelem->setIdAttribute(Attr_name, true);
459  m_update = true;
460  }
461  return;
462  }
463  throw runtime_error("XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
464 }
465 // ----------------------------------------------------------------------------
466 void XMLFileCatalog::commit() {
467  try {
468  if ( dirty() && !readOnly() ) {
469  string xmlfile = getfile(true);
470  XMLStr ii("LS");
471  DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(ii);
472  XMLFormatTarget *tar = new LocalFileFormatTarget(xmlfile.c_str());
473 #if _XERCES_VERSION <= 30000
474  DOMWriter *wr = imp->createDOMWriter();
475  wr->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
476  wr->writeNode(tar, *m_doc);
477  wr->release();
478 #else
479  DOMLSOutput *output = imp->createLSOutput();
480  output->setByteStream(tar);
481  DOMLSSerializer *wr = imp->createLSSerializer();
482  wr->getDomConfig()->setParameter(XMLStr("format-pretty-print"), true);
483  wr->write(m_doc, output);
484  output->release();
485  wr->release();
486 #endif
487  delete tar;
488  }
489  }
490  catch ( exception& e ) {
491  printError(string("Cannot open output file:")+e.what());
492  }
493  catch (...) {
494  printError("Unknown IO rrror.");
495  }
496 }
497 // ----------------------------------------------------------------------------
498 string XMLFileCatalog::getfile(bool create) {
499  string protocol, path;
500  XMLURL xerurl;
501  try{
502  xerurl = (const XMLCh*)XMLStr(m_file);
503  protocol = _toString(xerurl.getProtocolName());
504  path = _toString(xerurl.getPath());
505  }
506  catch (const XMLException& e ) {
507  printError(_toString(e.getMessage()));
508  }
509  if ( protocol.empty() ) {
510  printError("Missing protocol.");
511  }
512  else if ( protocol == "http" || protocol == "ftp" ) {
513  m_rdOnly = true;
514  }
515  else if ( protocol == "file" ) {
516  m_rdOnly = false;
517  struct stat buff;
518  int exist = ::stat(path.c_str(),&buff) != -1;
519  if ( create && !exist ) {
520  MsgStream log(m_msgSvc,"XMLCatalog");
521  log << MSG::INFO << "File '" << path << "' does not exist. New file created." << endmsg;
522  ofstream out(path.c_str());
523  if( !m_rdOnly && out.is_open() ) {
524  out << (CSTR)EmptyCatalog << endl;
525  }
526  else {
527  printError("Problem creating file "+path);
528  }
529  out.close();
530  }
531  else if ( exist ) {
532  return path;
533  }
534  else if ( !create ) {
535  return "";
536  }
537  }
538  else {
539  printError(protocol + ": protocol not supported.");
540  }
541  return path;
542 }

Generated at Thu Jul 18 2013 12:18:05 for Gaudi Framework, version v23r9 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004