| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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