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" 24 #include <sys/types.h> 28 using namespace Gaudi;
31 #if _XERCES_VERSION <= 30000 33 #define setIdAttribute(a, b) setIdAttribute(a) 41 typedef const string&
CSTR;
42 inline string _toString(
const XMLCh *toTranscode) {
43 char * buff = XMLString::transcode(toTranscode);
44 string tmp(buff==0 ?
"" : buff);
45 XMLString::release(&buff);
50 try { XMLPlatformUtils::Initialize(); }
51 catch (
const XMLException& e) {
52 cout <<
"Xerces-c error in initialization:" << _toString(e.getMessage()) <<
endl;
56 XMLPlatformUtils::Terminate();
63 XMLStr(CSTR
c) { m_xml=XMLString::transcode(c.
c_str()); }
64 ~XMLStr() {
if (m_xml) XMLString::release(&m_xml); }
65 operator const XMLCh*()
const {
return m_xml; }
67 struct XMLTag :
public XMLStr {
69 XMLTag(CSTR
s) : XMLStr(s), m_str(s) { }
71 operator CSTR ()
const {
return m_str; }
74 bool operator==(CSTR
c,
const XMLTag& b) {
return c==b.m_str; }
75 struct XMLCollection {
77 XMLCollection(DOMNode*
n,
bool use_children=
true) : m_node((DOMElement*)n) {
79 if ( m_node ) m_node = (DOMElement*)m_node->getFirstChild();
80 if ( m_node && m_node->getNodeType() != DOMNode::ELEMENT_NODE ) ++(*
this);
83 operator bool()
const {
return m_node; }
84 operator DOMNode* ()
const {
return m_node; }
85 operator DOMElement* ()
const {
return m_node; }
86 DOMElement* operator->()
const {
return m_node; }
87 string attr(
const XMLTag& tag)
const {
return _toString(m_node->getAttribute(tag));}
88 string attr(CSTR tag)
const {
return attr(XMLTag(tag)); }
89 string tag()
const {
return _toString(m_node->getTagName()); }
92 m_node = (DOMElement*)m_node->getNextSibling();
93 if ( m_node && m_node->getNodeType() == DOMNode::ELEMENT_NODE ) {
99 struct ErrHandler :
public ErrorHandler {
105 void resetErrors()
override { }
107 void warning(
const SAXParseException& )
override { }
109 void error(
const SAXParseException& e)
override;
111 void fatalError(
const SAXParseException& e)
override;
112 ~ErrHandler()
override {}
114 struct DTDRedirect :
public EntityResolver {
115 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const )
override {
116 static const char* dtdID =
"redirectinmem.dtd";
117 static const char* dtd = \
119 <!ELEMENT POOLFILECATALOG (META*,File*)>\ 120 <!ELEMENT META EMPTY>\ 121 <!ELEMENT File (physical,logical,metadata*)>\ 122 <!ATTLIST META name CDATA #REQUIRED>\ 123 <!ATTLIST META type CDATA #REQUIRED>\ 124 <!ELEMENT physical (pfn)+>\ 125 <!ELEMENT logical (lfn)*>\ 126 <!ELEMENT metadata EMPTY>\ 127 <!ELEMENT lfn EMPTY>\ 128 <!ELEMENT pfn EMPTY>\ 129 <!ATTLIST File ID ID #REQUIRED>\ 130 <!ATTLIST pfn name ID #REQUIRED>\ 131 <!ATTLIST pfn filetype CDATA #IMPLIED>\ 132 <!ATTLIST pfn se CDATA #IMPLIED>\ 133 <!ATTLIST lfn name ID #REQUIRED>\ 134 <!ATTLIST metadata att_name CDATA #REQUIRED>\ 135 <!ATTLIST metadata att_value CDATA #REQUIRED>\ 137 static const size_t len =
strlen(dtd);
138 return new MemBufInputSource((
const XMLByte*)dtd,len,dtdID,
false);
140 ~DTDRedirect()
override =
default;
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 )
152 string sys(_toString(e.getSystemId()));
154 log <<
MSG::ERROR <<
"Error at file \"" << sys
155 <<
"\", line " << e.getLineNumber() <<
", column " << e.getColumnNumber() <<
endmsg 156 <<
"Message: " << m <<
endmsg;
158 void ErrHandler::fatalError(
const SAXParseException& e) {
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" );
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");
187 : m_rdOnly(false),m_update(false),m_doc(0),
188 m_file(uri), m_msgSvc(m)
198 if ( !
m_doc && throw_if_no_exists )
199 printError(
"The XML catalog was not started.",
true);
212 string xmlFile =
getfile(
false);
215 m_parser->setValidationScheme(XercesDOMParser::Val_Auto);
217 DTDRedirect dtdinmem;
218 m_parser->setEntityResolver(&dtdinmem);
221 if ( !xmlFile.
empty() ) {
226 MemBufInputSource src((
const XMLByte*)s.
c_str(),s.
length(),
"MemCatalog");
231 catch (
const XMLException& e) {
232 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
234 catch (
const DOMException& e) {
235 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
238 printError(
"UNKNOWN XML parse error in file "+xmlFile);
244 DOMNode* e =
element(fid,
false);
245 e = e ? e->getParentNode() : 0;
246 e = e ? e->getParentNode() : 0;
248 if ( e->getAttributes() ) {
249 char* nam = XMLString::transcode(((DOMElement*)e)->getAttribute(Attr_ID));
250 if ( nam ) result = nam;
251 XMLString::release(&nam);
259 DOMNode* fde =
getDoc(
true)->getElementsByTagName(XMLStr(
"*"))->item(0);
260 for(XMLCollection
c(
child(fde,
"File"),
false);
c; ++
c)
261 fids.push_back(
c.attr(Attr_ID));
267 files.emplace_back(
c.attr(Attr_name),
c.attr(Attr_ftype));
273 files.emplace_back(
c.attr(Attr_name),fid);
279 attr.emplace_back(
c.attr(Attr_metaName),
c.attr(Attr_metaValue));
280 if ( attr.size() > 0 )
281 attr.emplace_back(
"guid",fid);
285 for(XMLCollection
c(par);
c; ++
c ) {
286 if(
c.tag() == tag ) {
287 if( !attr.
empty() &&
c.attr(attr) != val)
continue;
297 DOMElement* mnod = (DOMElement*)
child(node,MetaNode,Attr_metaName,attr);
299 mnod =
getDoc(
true)->createElement(MetaNode);
300 node->appendChild(mnod);
301 mnod->setAttribute(Attr_metaName,XMLStr(attr));
303 mnod->setAttribute(Attr_metaValue,XMLStr(val));
307 printError(
"Cannot update readonly catalog!");
311 XMLCollection
c(
child(
getDoc(
true)->getElementById(XMLStr(fid)),MetaNode,Attr_metaName,attr));
312 return c ? c.attr(attr) :
string(
"");
317 DOMNode* fn =
getDoc(
true)->getElementById(XMLStr(fid));
318 for(XMLCollection
c{
child(fn,MetaNode)};
c; ++
c)
319 if ( attr[0]==
'*' || !
c.attr(attr).empty() ) gbc.
push_back(
c);
320 for(
const auto &i : gbc)
325 DOMNode* node =
getDoc(
true)->getElementById(XMLStr(element_name));
326 if ( !node && print_err )
printError(
"Cannot find element:"+element_name);
331 DOMNode *pn =
nullptr, *fn =
element(fid);
332 if ( fn ) pn = fn->getParentNode();
333 if ( pn ) pn->removeChild(fn);
337 if ( !fid.
empty() ) {
339 if ( res.first == 0 || res.second == 0 ) {
344 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
349 printError(
"Cannot update readonly catalog!");
350 return {
nullptr,
nullptr};
354 DOMElement *file = (DOMElement*)
element(fid,
false), *phyelem = 0, *logelem = 0;
355 DOMDocument* doc =
getDoc(
true);
357 DOMNode* fde = doc->getElementsByTagName(XMLStr(
"*"))->item(0);
358 file =
m_doc->createElement(XMLStr(
"File"));
359 file->setAttribute(Attr_ID, XMLStr(fid));
360 file->setIdAttribute(Attr_ID,
true);
361 fde->appendChild(file);
364 for(XMLCollection
c1(file);
c1; ++
c1 ) {
365 char* nam = XMLString::transcode(
c1->getNodeName());
366 if ( nam == PFNCOLL ) phyelem =
c1;
367 if ( nam == LFNCOLL ) logelem =
c1;
368 XMLString::release(&nam);
371 phyelem = doc->createElement(PFNCOLL);
372 file->appendChild(phyelem);
376 logelem = doc->createElement(LFNCOLL);
377 file->appendChild(logelem);
380 return {logelem,phyelem};
384 if ( !fid.
empty() ) {
386 DOMElement* phyelem = res.second, *fnelem = 0;
387 for(XMLCollection
c(phyelem);
c; ++
c ) {
388 char* nam = XMLString::transcode(
c->getNodeName());
389 if ( nam == PFNNODE ) {
390 XMLString::release(&nam);
391 nam = XMLString::transcode(
c->getAttribute(Attr_name));
393 XMLString::release(&nam);
398 XMLString::release(&nam);
401 fnelem =
getDoc(
true)->createElement(PFNNODE);
402 phyelem->appendChild(fnelem);
403 fnelem->setAttribute(Attr_ftype,XMLStr(ftype));
404 fnelem->setAttribute(Attr_name,XMLStr(pfn));
405 fnelem->setIdAttribute(Attr_name,
true);
410 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:"+fid);
414 if ( !fid.
empty() ) {
416 DOMElement* logelem = res.first, *fnelem = 0;
417 for(XMLCollection
c(logelem);
c; ++
c ) {
418 char* nam = XMLString::transcode(
c->getNodeName());
419 if ( nam == LFNNODE ) {
420 XMLString::release(&nam);
421 nam = XMLString::transcode(
c->getAttribute(Attr_name));
423 XMLString::release(&nam);
430 fnelem =
getDoc(
true)->createElement(LFNNODE);
431 logelem->appendChild(fnelem);
432 fnelem->setAttribute(Attr_name,XMLStr(lfn));
433 fnelem->setIdAttribute(Attr_name,
true);
438 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
444 string xmlfile =
getfile(
true);
446 DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(ii);
448 #if _XERCES_VERSION <= 30000 449 DOMWriter *wr = imp->createDOMWriter();
450 wr->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint,
true);
451 wr->writeNode(tar.get(), *
m_doc);
454 DOMLSOutput *
output = imp->createLSOutput();
455 output->setByteStream(tar.get());
456 DOMLSSerializer *wr = imp->createLSSerializer();
457 wr->getDomConfig()->setParameter(XMLStr(
"format-pretty-print"),
true);
458 wr->write(
m_doc, output);
473 string protocol,
path;
476 xerurl = (
const XMLCh*)XMLStr(
m_file);
477 protocol = _toString(xerurl.getProtocolName());
478 path = _toString(xerurl.getPath());
480 catch (
const XMLException& e ) {
483 if ( protocol.
empty() ) {
486 else if ( protocol ==
"http" || protocol ==
"ftp" ) {
489 else if ( protocol ==
"file" ) {
492 int exist = ::stat(path.
c_str(),&buff) != -1;
493 if ( create && !exist ) {
495 log <<
MSG::INFO <<
"File '" << path <<
"' does not exist. New file created." <<
endmsg;
508 else if ( !create ) {
513 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.
#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()
Helper function creating file identifier using the 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.