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"
14 #include "GaudiKernel/MsgStream.h"
15 #include "GaudiKernel/Service.h"
16 #include <Gaudi/PluginService.h>
23 #include <sys/types.h>
25 #include "uuid/uuid.h"
27 #include <boost/format.hpp>
30 using namespace Gaudi;
33 #if _XERCES_VERSION <= 30000
35 #define setIdAttribute(a, b) setIdAttribute(a)
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);
52 try { XMLPlatformUtils::Initialize(); }
53 catch (
const XMLException& e) {
54 cout <<
"Xerces-c error in initialization:" << _toString(e.getMessage()) << endl;
58 XMLPlatformUtils::Terminate();
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; }
69 struct XMLTag :
public XMLStr {
71 XMLTag(CSTR
s) : XMLStr(s), m_str(s) { }
73 operator CSTR ()
const {
return m_str; }
76 bool operator==(CSTR
c,
const XMLTag& b) {
return c==b.m_str; }
77 struct XMLCollection {
79 XMLCollection(DOMNode*
n,
bool use_children=
true) : m_node((DOMElement*)n) {
81 if ( m_node ) m_node = (DOMElement*)m_node->getFirstChild();
82 if ( m_node && m_node->getNodeType() != DOMNode::ELEMENT_NODE ) ++(*
this);
85 operator bool()
const {
return 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()); }
94 m_node = (DOMElement*)m_node->getNextSibling();
95 if ( m_node && m_node->getNodeType() == DOMNode::ELEMENT_NODE ) {
101 struct ErrHandler :
public ErrorHandler {
107 void resetErrors() { }
109 void warning(
const SAXParseException& ) { }
111 void error(
const SAXParseException& e);
113 void fatalError(
const SAXParseException& e);
114 virtual ~ErrHandler() {}
116 struct DTDRedirect :
public EntityResolver {
117 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const ) {
118 static const char* dtdID =
"redirectinmem.dtd";
119 static const char* dtd = \
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 pfn se CDATA #IMPLIED>\
135 <!ATTLIST lfn name ID #REQUIRED>\
136 <!ATTLIST metadata att_name CDATA #REQUIRED>\
137 <!ATTLIST metadata att_value CDATA #REQUIRED>\
139 static const size_t len = strlen(dtd);
140 return new MemBufInputSource((
const XMLByte*)dtd,len,dtdID,
false);
142 virtual ~DTDRedirect() =
default;
145 void ErrHandler::error(
const SAXParseException& e) {
146 string m(_toString(e.getMessage()));
147 if (m.find(
"The values for attribute 'name' must be names or name tokens")!=string::npos ||
148 m.find(
"The values for attribute 'ID' must be names or name tokens")!=string::npos ||
149 m.find(
"for attribute 'name' must be Name or Nmtoken")!=string::npos ||
150 m.find(
"for attribute 'ID' must be Name or Nmtoken")!=string::npos ||
151 m.find(
"for attribute 'name' is invalid Name or NMTOKEN value")!=string::npos ||
152 m.find(
"for attribute 'ID' is invalid Name or NMTOKEN value")!=string::npos )
154 string sys(_toString(e.getSystemId()));
156 log <<
MSG::ERROR <<
"Error at file \"" << sys
157 <<
"\", line " << e.getLineNumber() <<
", column " << e.getColumnNumber() <<
endmsg
158 <<
"Message: " << m <<
endmsg;
160 void ErrHandler::fatalError(
const SAXParseException& e) {
162 string m(_toString(e.getMessage()));
163 string sys(_toString(e.getSystemId()));
164 log <<
MSG::ERROR <<
"Fatal Error at file \"" << sys
165 <<
"\", line " << e.getLineNumber() <<
", column " << e.getColumnNumber() <<
endmsg
166 <<
"Message: " << m <<
endmsg;
167 throw runtime_error(
"Standard pool exception : Fatal Error on the DOM Parser" );
170 const XMLTag EmptyCatalog(
"<!-- Edited By POOL -->\n"
171 "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n"
172 "<POOLFILECATALOG>\n"
173 "</POOLFILECATALOG>\n");
174 const XMLTag PFNCOLL (
"physical");
175 const XMLTag LFNCOLL (
"logical");
176 const XMLTag PFNNODE (
"pfn");
177 const XMLTag LFNNODE (
"lfn");
178 const XMLTag Attr_type (
"type");
179 const XMLTag Attr_ID (
"ID");
180 const XMLTag Attr_name (
"name");
181 const XMLTag Attr_ftype (
"filetype");
182 const XMLTag MetaNode (
"metadata");
183 const XMLTag Attr_metaName (
"att_name");
184 const XMLTag Attr_metaValue (
"att_value");
190 ::uuid_generate_time(uuid);
193 unsigned short Data2;
194 unsigned short Data3;
195 unsigned char Data4[8];
198 boost::format text(
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X");
199 text %
g->Data1 %
g->Data2 %
g->Data3;
200 for (
int i = 0;
i < 8; ++
i)
201 text % (
unsigned short)
g->Data4[
i];
206 : m_rdOnly(false),m_update(false),m_doc(0),
207 m_file(uri), m_msgSvc(m)
217 if ( !
m_doc && throw_if_no_exists )
218 printError(
"The XML catalog was not started.",
true);
226 throw runtime_error(
"XMLFileCatalog> "+msg);
231 string xmlFile =
getfile(
false);
233 m_parser.reset(
new XercesDOMParser );
234 m_parser->setValidationScheme(XercesDOMParser::Val_Auto);
236 DTDRedirect dtdinmem;
237 m_parser->setEntityResolver(&dtdinmem);
240 if ( !xmlFile.empty() ) {
244 const std::string&
s = EmptyCatalog;
245 MemBufInputSource src((
const XMLByte*)s.c_str(),s.length(),
"MemCatalog");
250 catch (
const XMLException& e) {
251 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
253 catch (
const DOMException& e) {
254 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
257 printError(
"UNKNOWN XML parse error in file "+xmlFile);
263 DOMNode* e =
element(fid,
false);
264 e = e ? e->getParentNode() : 0;
265 e = e ? e->getParentNode() : 0;
267 if ( e->getAttributes() ) {
268 char* nam = XMLString::transcode(((DOMElement*)e)->getAttribute(Attr_ID));
269 if ( nam ) result = nam;
270 XMLString::release(&nam);
278 DOMNode* fde =
getDoc(
true)->getElementsByTagName(XMLStr(
"*"))->item(0);
279 for(XMLCollection
c(
child(fde,
"File"),
false);
c; ++
c)
280 fids.push_back(
c.attr(Attr_ID));
286 files.emplace_back(
c.attr(Attr_name),
c.attr(Attr_ftype));
292 files.emplace_back(
c.attr(Attr_name),fid);
298 attr.emplace_back(
c.attr(Attr_metaName),
c.attr(Attr_metaValue));
299 if ( attr.size() > 0 )
300 attr.emplace_back(
"guid",fid);
304 for(XMLCollection
c(par);
c; ++
c ) {
305 if(
c.tag() == tag ) {
306 if( !attr.empty() &&
c.attr(attr) != val)
continue;
316 DOMElement* mnod = (DOMElement*)
child(node,MetaNode,Attr_metaName,attr);
318 mnod =
getDoc(
true)->createElement(MetaNode);
319 node->appendChild(mnod);
320 mnod->setAttribute(Attr_metaName,XMLStr(attr));
322 mnod->setAttribute(Attr_metaValue,XMLStr(val));
326 printError(
"Cannot update readonly catalog!");
330 XMLCollection
c(
child(
getDoc(
true)->getElementById(XMLStr(fid)),MetaNode,Attr_metaName,attr));
331 return c ? c.attr(attr) : string(
"");
335 vector<DOMNode*> gbc;
336 DOMNode* fn =
getDoc(
true)->getElementById(XMLStr(fid));
337 for(XMLCollection
c{
child(fn,MetaNode)};
c; ++
c)
338 if ( attr[0]==
'*' || !
c.attr(attr).empty() ) gbc.push_back(
c);
339 for(
const auto &
i : gbc)
344 DOMNode* node =
getDoc(
true)->getElementById(XMLStr(element_name));
345 if ( !node && print_err )
printError(
"Cannot find element:"+element_name);
350 DOMNode *pn =
nullptr, *fn =
element(fid);
351 if ( fn ) pn = fn->getParentNode();
352 if ( pn ) pn->removeChild(fn);
356 if ( !fid.empty() ) {
357 std::pair<DOMElement*, DOMElement*> res =
i_registerFID(fid);
358 if ( res.first == 0 || res.second == 0 ) {
363 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
369 DOMElement *
file = (DOMElement*)
element(fid,
false), *phyelem = 0, *logelem = 0;
370 DOMDocument* doc =
getDoc(
true);
372 DOMNode* fde = doc->getElementsByTagName(XMLStr(
"*"))->item(0);
373 file =
m_doc->createElement(XMLStr(
"File"));
374 file->setAttribute(Attr_ID, XMLStr(fid));
375 file->setIdAttribute(Attr_ID,
true);
376 fde->appendChild(file);
379 for(XMLCollection c1(file); c1; ++c1 ) {
380 char* nam = XMLString::transcode(c1->getNodeName());
381 if ( nam == PFNCOLL ) phyelem = c1;
382 if ( nam == LFNCOLL ) logelem = c1;
383 XMLString::release(&nam);
386 phyelem = doc->createElement(PFNCOLL);
387 file->appendChild(phyelem);
391 logelem = doc->createElement(LFNCOLL);
392 file->appendChild(logelem);
395 return std::make_pair(logelem,phyelem);
397 printError(
"Cannot update readonly catalog!");
398 return std::pair<DOMElement*, DOMElement*>(0,0);
402 if ( !fid.empty() ) {
404 DOMElement* phyelem = res.second, *fnelem = 0;
405 for(XMLCollection
c(phyelem);
c; ++
c ) {
406 char* nam = XMLString::transcode(
c->getNodeName());
407 if ( nam == PFNNODE ) {
408 XMLString::release(&nam);
409 nam = XMLString::transcode(
c->getAttribute(Attr_name));
411 XMLString::release(&nam);
416 XMLString::release(&nam);
419 fnelem =
getDoc(
true)->createElement(PFNNODE);
420 phyelem->appendChild(fnelem);
421 fnelem->setAttribute(Attr_ftype,XMLStr(ftype));
422 fnelem->setAttribute(Attr_name,XMLStr(pfn));
423 fnelem->setIdAttribute(Attr_name,
true);
428 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:"+fid);
432 if ( !fid.empty() ) {
433 std::pair<DOMElement*, DOMElement*> res =
i_registerFID(fid);
434 DOMElement* logelem = res.first, *fnelem = 0;
435 for(XMLCollection
c(logelem);
c; ++
c ) {
436 char* nam = XMLString::transcode(
c->getNodeName());
437 if ( nam == LFNNODE ) {
438 XMLString::release(&nam);
439 nam = XMLString::transcode(
c->getAttribute(Attr_name));
441 XMLString::release(&nam);
448 fnelem =
getDoc(
true)->createElement(LFNNODE);
449 logelem->appendChild(fnelem);
450 fnelem->setAttribute(Attr_name,XMLStr(lfn));
451 fnelem->setIdAttribute(Attr_name,
true);
456 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
462 string xmlfile =
getfile(
true);
464 DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(ii);
465 std::unique_ptr<XMLFormatTarget> tar{
new LocalFileFormatTarget(xmlfile.c_str()) };
466 #if _XERCES_VERSION <= 30000
467 DOMWriter *wr = imp->createDOMWriter();
468 wr->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint,
true);
469 wr->writeNode(tar.get(), *
m_doc);
472 DOMLSOutput *output = imp->createLSOutput();
473 output->setByteStream(tar.get());
474 DOMLSSerializer *wr = imp->createLSSerializer();
475 wr->getDomConfig()->setParameter(XMLStr(
"format-pretty-print"),
true);
476 wr->write(
m_doc, output);
482 catch ( exception& e ) {
483 printError(
string(
"Cannot open output file:")+e.what());
491 string protocol,
path;
494 xerurl = (
const XMLCh*)XMLStr(
m_file);
495 protocol = _toString(xerurl.getProtocolName());
496 path = _toString(xerurl.getPath());
498 catch (
const XMLException& e ) {
501 if ( protocol.empty() ) {
504 else if ( protocol ==
"http" || protocol ==
"ftp" ) {
507 else if ( protocol ==
"file" ) {
510 int exist = ::stat(path.c_str(),&buff) != -1;
511 if ( create && !exist ) {
513 log <<
MSG::INFO <<
"File '" << path <<
"' does not exist. New file created." <<
endmsg;
516 out << (
CSTR)EmptyCatalog << endl;
526 else if ( !create ) {
531 printError(protocol +
": protocol not supported.");
Definition of the MsgStream class used to transmit messages.
virtual bool readOnly() const
Check if the catalog is read-only.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
bool operator==(const GaudiUtils::Allocator< T1 > &, const GaudiUtils::Allocator< T2 > &)
std::string lookupFID(CSTR lfn) const
Gaudi::PluginService::Factory< IInterface *, const std::string &, IMessageSvc * > Factory
std::string getfile(bool create)
virtual std::string getMetaDataItem(CSTR fid, CSTR name) const
Access metadata item.
virtual void dropMetaData(CSTR fid) const
Drop all metadata of one FID.
xercesc::DOMNode * element(CSTR fid, bool print_err=true) const
virtual void setMetaData(CSTR fid, CSTR name, CSTR value) const
Insert/update metadata item.
#define DECLARE_FACTORY(type, factory)
std::unique_ptr< xercesc::XercesDOMParser > m_parser
virtual void registerPFN(CSTR fid, CSTR pfn, CSTR ftype) const
Create a FileID and Node of the physical file name with all the attributes.
virtual void init()
Parse the DOM tree of the XML catalog.
virtual bool dirty() const
Check if the catalog should be updated.
xercesc::DOMNode * child(xercesc::DOMNode *par, CSTR tag, CSTR attr="", CSTR val="") const
void printError(CSTR msg, bool throw_exc=true) const
virtual void getFID(Strings &fids) const
Dump all file Identifiers.
std::unique_ptr< xercesc::ErrorHandler > m_errHdlr
The IMessage is the interface implemented by the message service.
xercesc::DOMDocument * m_doc
xercesc::DOMDocument * getDoc(bool throw_if_no_exists=true) const
virtual void getLFN(CSTR fid, Files &files) const
Dump all logical file names of the catalog associate to the FileID.
virtual void deleteFID(CSTR FileID) const
Delete FileID Node from the catalog.
std::string createGuidAsString()
Create file identifier using UUID mechanism.
virtual void commit()
Save DOM catalog to file.
virtual void getPFN(CSTR fid, Files &files) const
Dump all physical file names of the catalog and their attributes associate to the FileID...
std::pair< xercesc::DOMElement *, xercesc::DOMElement * > i_registerFID(CSTR fid) const
virtual void getMetaData(CSTR fid, Attributes &attr) const
Dump all MetaData of the catalog for a given file ID.
virtual void registerFID(CSTR fid) const
Create a FileID and Node.
This class constitutes the core of the XML based FileCatalog API for POOL.
virtual std::string createFID() const
Catalog interface.
virtual void registerLFN(CSTR fid, CSTR lfn) const
Create a FileID and Node of the logical file name with all the attributes.
Helper functions to set/get the application return code.
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".