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" 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()
override { }
109 void warning(
const SAXParseException& )
override { }
111 void error(
const SAXParseException& e)
override;
113 void fatalError(
const SAXParseException& e)
override;
114 ~ErrHandler()
override {}
116 struct DTDRedirect :
public EntityResolver {
117 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const )
override {
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 ~DTDRedirect()
override =
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);
231 string xmlFile =
getfile(
false);
234 m_parser->setValidationScheme(XercesDOMParser::Val_Auto);
236 DTDRedirect dtdinmem;
237 m_parser->setEntityResolver(&dtdinmem);
240 if ( !xmlFile.
empty() ) {
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(
"");
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() ) {
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() ) {
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);
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);
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;
527 else if ( !create ) {
532 printError(protocol +
": protocol not supported.");
std::string getMetaDataItem(CSTR fid, CSTR name) const override
Access metadata item.
bool readOnly() const override
Check if the catalog is read-only.
Definition of the MsgStream class used to transmit messages.
void registerPFN(CSTR fid, CSTR pfn, CSTR ftype) const override
Create a FileID and Node of the physical file name with all the attributes.
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
#define DECLARE_FACTORY(type, factory)
std::string lookupFID(CSTR lfn) const
Gaudi::PluginService::Factory< IInterface *, const std::string &, IMessageSvc * > Factory
std::string getfile(bool create)
xercesc::DOMNode * element(CSTR fid, bool print_err=true) const
std::unique_ptr< xercesc::XercesDOMParser > m_parser
xercesc::DOMNode * child(xercesc::DOMNode *par, CSTR tag, CSTR attr="", CSTR val="") const
bool operator==(const GaudiUtils::Allocator< T1 > &, const GaudiUtils::Allocator< T2 > &)
void getMetaData(CSTR fid, Attributes &attr) const override
Dump all MetaData of the catalog for a given file ID.
void printError(CSTR msg, bool throw_exc=true) const
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
void getLFN(CSTR fid, Files &files) const override
Dump all logical file names of the catalog associate to the FileID.
void setMetaData(CSTR fid, CSTR name, CSTR value) const override
Insert/update metadata item.
std::string createGuidAsString()
Create file identifier using UUID mechanism.
void registerLFN(CSTR fid, CSTR lfn) const override
Create a FileID and Node of the logical file name with all the attributes.
void commit() override
Save DOM catalog to file.
std::pair< xercesc::DOMElement *, xercesc::DOMElement * > i_registerFID(CSTR fid) const
void init() override
Parse the DOM tree of the XML catalog.
void registerFID(CSTR fid) const override
Create a FileID and Node.
void getPFN(CSTR fid, Files &files) const override
Dump all physical file names of the catalog and their attributes associate to the FileID...
This class constitutes the core of the XML based FileCatalog API for POOL.
bool dirty() const override
Check if the catalog should be updated.
std::string createFID() const override
Catalog interface.
Helper functions to set/get the application return code.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
void getFID(Strings &fids) const override
Dump all file Identifiers.
void dropMetaData(CSTR fid) const override
Drop all metadata of one FID.
void deleteFID(CSTR FileID) const override
Delete FileID Node from the catalog.