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);
368 printError(
"Cannot update readonly catalog!");
369 return {
nullptr,
nullptr};
373 DOMElement *
file = (DOMElement*)
element(fid,
false), *phyelem = 0, *logelem = 0;
374 DOMDocument* doc =
getDoc(
true);
376 DOMNode* fde = doc->getElementsByTagName(XMLStr(
"*"))->item(0);
377 file =
m_doc->createElement(XMLStr(
"File"));
378 file->setAttribute(Attr_ID, XMLStr(fid));
379 file->setIdAttribute(Attr_ID,
true);
380 fde->appendChild(file);
383 for(XMLCollection
c1(file);
c1; ++
c1 ) {
384 char* nam = XMLString::transcode(
c1->getNodeName());
385 if ( nam == PFNCOLL ) phyelem =
c1;
386 if ( nam == LFNCOLL ) logelem =
c1;
387 XMLString::release(&nam);
390 phyelem = doc->createElement(PFNCOLL);
391 file->appendChild(phyelem);
395 logelem = doc->createElement(LFNCOLL);
396 file->appendChild(logelem);
399 return {logelem,phyelem};
403 if ( !fid.empty() ) {
405 DOMElement* phyelem = res.second, *fnelem = 0;
406 for(XMLCollection
c(phyelem);
c; ++
c ) {
407 char* nam = XMLString::transcode(
c->getNodeName());
408 if ( nam == PFNNODE ) {
409 XMLString::release(&nam);
410 nam = XMLString::transcode(
c->getAttribute(Attr_name));
412 XMLString::release(&nam);
417 XMLString::release(&nam);
420 fnelem =
getDoc(
true)->createElement(PFNNODE);
421 phyelem->appendChild(fnelem);
422 fnelem->setAttribute(Attr_ftype,XMLStr(ftype));
423 fnelem->setAttribute(Attr_name,XMLStr(pfn));
424 fnelem->setIdAttribute(Attr_name,
true);
429 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:"+fid);
433 if ( !fid.empty() ) {
434 std::pair<DOMElement*, DOMElement*> res =
i_registerFID(fid);
435 DOMElement* logelem = res.first, *fnelem = 0;
436 for(XMLCollection
c(logelem);
c; ++
c ) {
437 char* nam = XMLString::transcode(
c->getNodeName());
438 if ( nam == LFNNODE ) {
439 XMLString::release(&nam);
440 nam = XMLString::transcode(
c->getAttribute(Attr_name));
442 XMLString::release(&nam);
449 fnelem =
getDoc(
true)->createElement(LFNNODE);
450 logelem->appendChild(fnelem);
451 fnelem->setAttribute(Attr_name,XMLStr(lfn));
452 fnelem->setIdAttribute(Attr_name,
true);
457 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
463 string xmlfile =
getfile(
true);
465 DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(ii);
466 std::unique_ptr<XMLFormatTarget> tar{
new LocalFileFormatTarget(xmlfile.c_str()) };
467 #if _XERCES_VERSION <= 30000
468 DOMWriter *wr = imp->createDOMWriter();
469 wr->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint,
true);
470 wr->writeNode(tar.get(), *
m_doc);
473 DOMLSOutput *output = imp->createLSOutput();
474 output->setByteStream(tar.get());
475 DOMLSSerializer *wr = imp->createLSSerializer();
476 wr->getDomConfig()->setParameter(XMLStr(
"format-pretty-print"),
true);
477 wr->write(
m_doc, output);
483 catch ( exception& e ) {
484 printError(
string(
"Cannot open output file:")+e.what());
492 string protocol,
path;
495 xerurl = (
const XMLCh*)XMLStr(
m_file);
496 protocol = _toString(xerurl.getProtocolName());
497 path = _toString(xerurl.getPath());
499 catch (
const XMLException& e ) {
502 if ( protocol.empty() ) {
505 else if ( protocol ==
"http" || protocol ==
"ftp" ) {
508 else if ( protocol ==
"file" ) {
511 int exist = ::stat(path.c_str(),&buff) != -1;
512 if ( create && !exist ) {
514 log <<
MSG::INFO <<
"File '" << path <<
"' does not exist. New file created." <<
endmsg;
517 out << (
CSTR)EmptyCatalog << endl;
527 else if ( !create ) {
532 printError(protocol +
": protocol not supported.");
Definition of the MsgStream class used to transmit messages.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
virtual bool readOnly() const
Check if the catalog is read-only.
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.
#define DECLARE_FACTORY(type, factory)
xercesc::DOMNode * element(CSTR fid, bool print_err=true) const
virtual void setMetaData(CSTR fid, CSTR name, CSTR value) const
Insert/update metadata item.
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.
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
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.
bool operator==(const GaudiUtils::Allocator< T1 > &, const GaudiUtils::Allocator< T2 > &)