1 #include "xercesc/dom/DOM.hpp" 2 #include "xercesc/framework/LocalFileFormatTarget.hpp" 3 #include "xercesc/framework/MemBufInputSource.hpp" 4 #include "xercesc/parsers/XercesDOMParser.hpp" 5 #include "xercesc/sax/EntityResolver.hpp" 6 #include "xercesc/sax/InputSource.hpp" 7 #include "xercesc/sax/SAXParseException.hpp" 8 #include "xercesc/util/PlatformUtils.hpp" 9 #include "xercesc/util/XMLString.hpp" 10 #include "xercesc/util/XMLURL.hpp" 11 #include "xercesc/util/XMLUni.hpp" 12 #include "xercesc/util/XercesDefs.hpp" 25 #include <sys/types.h> 27 using namespace xercesc;
28 using namespace Gaudi;
31 #if _XERCES_VERSION <= 30000 33 # define setIdAttribute( a, b ) setIdAttribute( a ) 40 typedef const string&
CSTR;
41 inline string _toString(
const XMLCh* toTranscode ) {
42 char* buff = XMLString::transcode( toTranscode );
43 string tmp( buff == 0 ?
"" : buff );
44 XMLString::release( &buff );
50 XMLPlatformUtils::Initialize();
51 }
catch (
const XMLException& e ) {
52 cout <<
"Xerces-c error in initialization:" << _toString( e.getMessage() ) <<
endl;
55 ~__Init() { XMLPlatformUtils::Terminate(); }
61 XMLStr(
CSTR c ) { m_xml = XMLString::transcode(
c.c_str() ); }
63 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; }
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 ) {
return; }
97 struct ErrHandler :
public ErrorHandler {
103 void resetErrors()
override {}
105 void warning(
const SAXParseException& )
override {}
107 void error(
const SAXParseException& e )
override;
109 void fatalError(
const SAXParseException& e )
override;
111 struct DTDRedirect :
public EntityResolver {
112 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const )
override {
113 static const char* dtdID =
"redirectinmem.dtd";
114 static const char* dtd =
"\ 115 <!ELEMENT POOLFILECATALOG (META*,File*)>\ 116 <!ELEMENT META EMPTY>\ 117 <!ELEMENT File (physical,logical,metadata*)>\ 118 <!ATTLIST META name CDATA #REQUIRED>\ 119 <!ATTLIST META type CDATA #REQUIRED>\ 120 <!ELEMENT physical (pfn)+>\ 121 <!ELEMENT logical (lfn)*>\ 122 <!ELEMENT metadata EMPTY>\ 123 <!ELEMENT lfn EMPTY>\ 124 <!ELEMENT pfn EMPTY>\ 125 <!ATTLIST File ID ID #REQUIRED>\ 126 <!ATTLIST pfn name ID #REQUIRED>\ 127 <!ATTLIST pfn filetype CDATA #IMPLIED>\ 128 <!ATTLIST pfn se CDATA #IMPLIED>\ 129 <!ATTLIST lfn name ID #REQUIRED>\ 130 <!ATTLIST metadata att_name CDATA #REQUIRED>\ 131 <!ATTLIST metadata att_value CDATA #REQUIRED>\ 133 static const size_t len =
strlen( dtd );
134 return new MemBufInputSource( (
const XMLByte*)dtd, len, dtdID,
false );
138 void ErrHandler::error(
const SAXParseException& e ) {
139 string m( _toString( e.getMessage() ) );
140 if (
m.find(
"The values for attribute 'name' must be names or name tokens" ) != string::npos ||
141 m.find(
"The values for attribute 'ID' must be names or name tokens" ) != string::npos ||
142 m.find(
"for attribute 'name' must be Name or Nmtoken" ) != string::npos ||
143 m.find(
"for attribute 'ID' must be Name or Nmtoken" ) != string::npos ||
144 m.find(
"for attribute 'name' is invalid Name or NMTOKEN value" ) != string::npos ||
145 m.find(
"for attribute 'ID' is invalid Name or NMTOKEN value" ) != string::npos )
147 string sys( _toString( e.getSystemId() ) );
149 log <<
MSG::ERROR <<
"Error at file \"" << sys <<
"\", line " << e.getLineNumber() <<
", column " 150 << e.getColumnNumber() <<
endmsg <<
"Message: " <<
m <<
endmsg;
152 void ErrHandler::fatalError(
const SAXParseException& e ) {
154 string m( _toString( e.getMessage() ) );
155 string sys( _toString( e.getSystemId() ) );
156 log <<
MSG::ERROR <<
"Fatal Error at file \"" << sys <<
"\", line " << e.getLineNumber() <<
", column " 157 << e.getColumnNumber() <<
endmsg <<
"Message: " <<
m <<
endmsg;
158 throw runtime_error(
"Standard pool exception : Fatal Error on the DOM Parser" );
161 const XMLTag EmptyCatalog(
"<!-- Edited By POOL -->\n" 162 "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n" 163 "<POOLFILECATALOG>\n" 164 "</POOLFILECATALOG>\n" );
165 const XMLTag PFNCOLL(
"physical" );
166 const XMLTag LFNCOLL(
"logical" );
167 const XMLTag PFNNODE(
"pfn" );
168 const XMLTag LFNNODE(
"lfn" );
169 const XMLTag Attr_type(
"type" );
170 const XMLTag Attr_ID(
"ID" );
171 const XMLTag Attr_name(
"name" );
172 const XMLTag Attr_ftype(
"filetype" );
173 const XMLTag MetaNode(
"metadata" );
174 const XMLTag Attr_metaName(
"att_name" );
175 const XMLTag Attr_metaValue(
"att_value" );
185 if ( !
m_doc && throw_if_no_exists )
printError(
"The XML catalog was not started.",
true );
196 string xmlFile =
getfile(
false );
198 m_parser = std::make_unique<XercesDOMParser>();
199 m_parser->setValidationScheme( XercesDOMParser::Val_Auto );
201 DTDRedirect dtdinmem;
202 m_parser->setEntityResolver( &dtdinmem );
205 if ( !xmlFile.
empty() ) {
209 MemBufInputSource src( (
const XMLByte*)
s.
c_str(),
s.
length(),
"MemCatalog" );
213 }
catch (
const XMLException& e ) {
214 printError(
"XML parse error[" + xmlFile +
"]: " + _toString( e.getMessage() ) );
215 }
catch (
const DOMException& e ) {
216 printError(
"XML parse error[" + xmlFile +
"]: " + _toString( e.getMessage() ) );
217 }
catch ( ... ) {
printError(
"UNKNOWN XML parse error in file " + xmlFile ); }
222 DOMNode* e =
element( fid,
false );
223 e = e ? e->getParentNode() : 0;
224 e = e ? e->getParentNode() : 0;
226 if ( e->getAttributes() ) {
227 char* nam = XMLString::transcode( ( (DOMElement*)e )->getAttribute( Attr_ID ) );
228 if ( nam ) result = nam;
229 XMLString::release( &nam );
237 DOMNode* fde =
getDoc(
true )->getElementsByTagName( XMLStr(
"*" ) )->item( 0 );
238 for ( XMLCollection
c(
child( fde,
"File" ),
false );
c; ++
c ) fids.push_back(
c.attr( Attr_ID ) );
243 for ( XMLCollection
c(
child(
child(
element( fid,
false ), PFNCOLL ), PFNNODE ),
false );
c; ++
c )
244 files.emplace_back(
c.attr( Attr_name ),
c.attr( Attr_ftype ) );
249 for ( XMLCollection
c(
child(
child(
element( fid,
false ), LFNCOLL ), LFNNODE ),
false );
c; ++
c )
250 files.emplace_back(
c.attr( Attr_name ), fid );
255 for ( XMLCollection
c(
child(
element( fid ), MetaNode ),
false );
c; ++
c )
256 attr.emplace_back(
c.attr( Attr_metaName ),
c.attr( Attr_metaValue ) );
257 if ( attr.size() > 0 ) attr.emplace_back(
"guid", fid );
261 for ( XMLCollection
c(
par );
c; ++
c ) {
262 if (
c.tag() == tag ) {
263 if ( !attr.
empty() &&
c.attr( attr ) != val )
continue;
272 DOMNode* node =
element( fid );
273 DOMElement* mnod = (DOMElement*)
child( node, MetaNode, Attr_metaName, attr );
275 mnod =
getDoc(
true )->createElement( MetaNode );
276 node->appendChild( mnod );
277 mnod->setAttribute( Attr_metaName, XMLStr( attr ) );
279 mnod->setAttribute( Attr_metaValue, XMLStr( val ) );
283 printError(
"Cannot update readonly catalog!" );
287 XMLCollection
c(
child(
getDoc(
true )->getElementById( XMLStr( fid ) ), MetaNode, Attr_metaName, attr ) );
288 return c ?
c.attr( attr ) :
string(
"" );
293 DOMNode* fn =
getDoc(
true )->getElementById( XMLStr( fid ) );
294 for ( XMLCollection
c{
child( fn, MetaNode )};
c; ++
c )
295 if ( attr[0] ==
'*' || !
c.attr( attr ).empty() ) gbc.
push_back(
c );
296 for (
const auto& i : gbc ) fn->removeChild( i );
300 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( element_name ) );
301 if ( !node && print_err )
printError(
"Cannot find element:" + element_name );
306 DOMNode *pn =
nullptr, *fn =
element( fid );
307 if ( fn ) pn = fn->getParentNode();
308 if ( pn ) pn->removeChild( fn );
312 if ( !fid.
empty() ) {
314 if ( res.first == 0 || res.second == 0 ) {
printError(
"Failed to register FID:" + fid ); }
317 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:" + fid );
321 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( pfn ) );
322 if ( node && node->getNodeType() == DOMNode::ELEMENT_NODE ) {
323 ( (DOMElement*)node )->setAttribute( Attr_name, XMLStr( new_pfn ) );
329 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( pfn ) );
331 DOMNode* pcoll_node = node->getParentNode();
332 pcoll_node->removeChild( node );
334 for ( XMLCollection pcoll( pcoll_node,
true ); pcoll; ++pcoll ) {
338 DOMNode* file_node = pcoll_node->getParentNode();
339 file_node->getParentNode()->removeChild( file_node );
345 printError(
"Cannot update readonly catalog!" );
346 return {
nullptr,
nullptr};
350 DOMElement * file = (DOMElement*)
element( fid,
false ), *phyelem = 0, *logelem = 0;
351 DOMDocument* doc =
getDoc(
true );
353 DOMNode* fde = doc->getElementsByTagName( XMLStr(
"*" ) )->item( 0 );
354 file =
m_doc->createElement( XMLStr(
"File" ) );
355 file->setAttribute( Attr_ID, XMLStr( fid ) );
356 file->setIdAttribute( Attr_ID,
true );
357 fde->appendChild( file );
360 for ( XMLCollection c1( file ); c1; ++c1 ) {
361 char* nam = XMLString::transcode( c1->getNodeName() );
362 if ( nam == PFNCOLL ) phyelem = c1;
363 if ( nam == LFNCOLL ) logelem = c1;
364 XMLString::release( &nam );
367 phyelem = doc->createElement( PFNCOLL );
368 file->appendChild( phyelem );
372 logelem = doc->createElement( LFNCOLL );
373 file->appendChild( logelem );
376 return {logelem, phyelem};
380 if ( !fid.
empty() ) {
382 DOMElement * phyelem = res.second, *fnelem = 0;
383 for ( XMLCollection
c( phyelem );
c; ++
c ) {
384 char* nam = XMLString::transcode(
c->getNodeName() );
385 if ( nam == PFNNODE ) {
386 XMLString::release( &nam );
387 nam = XMLString::transcode(
c->getAttribute( Attr_name ) );
389 XMLString::release( &nam );
394 XMLString::release( &nam );
397 fnelem =
getDoc(
true )->createElement( PFNNODE );
398 phyelem->appendChild( fnelem );
399 fnelem->setAttribute( Attr_ftype, XMLStr( ftype ) );
400 fnelem->setAttribute( Attr_name, XMLStr( pfn ) );
401 fnelem->setIdAttribute( Attr_name,
true );
406 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:" + fid );
410 if ( !fid.
empty() ) {
412 DOMElement * logelem = res.first, *fnelem = 0;
413 for ( XMLCollection
c( logelem );
c; ++
c ) {
414 char* nam = XMLString::transcode(
c->getNodeName() );
415 if ( nam == LFNNODE ) {
416 XMLString::release( &nam );
417 nam = XMLString::transcode(
c->getAttribute( Attr_name ) );
419 XMLString::release( &nam );
426 fnelem =
getDoc(
true )->createElement( LFNNODE );
427 logelem->appendChild( fnelem );
428 fnelem->setAttribute( Attr_name, XMLStr( lfn ) );
429 fnelem->setIdAttribute( Attr_name,
true );
434 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:" + fid );
440 string xmlfile =
getfile(
true );
442 DOMImplementation* imp = DOMImplementationRegistry::getDOMImplementation( ii );
443 auto tar = std::make_unique<LocalFileFormatTarget>( xmlfile.
c_str() );
444 #if _XERCES_VERSION <= 30000 445 DOMWriter* wr = imp->createDOMWriter();
446 wr->setFeature( XMLUni::fgDOMWRTFormatPrettyPrint,
true );
447 wr->writeNode( tar.get(), *
m_doc );
450 DOMLSOutput*
output = imp->createLSOutput();
451 output->setByteStream( tar.get() );
452 DOMLSSerializer* wr = imp->createLSSerializer();
453 wr->getDomConfig()->setParameter( XMLStr(
"format-pretty-print" ),
true );
465 string protocol,
path;
468 xerurl = (
const XMLCh*)XMLStr(
m_file );
469 protocol = _toString( xerurl.getProtocolName() );
470 path = _toString( xerurl.getPath() );
471 }
catch (
const XMLException& e ) {
printError( _toString( e.getMessage() ) ); }
472 if ( protocol.
empty() ) {
474 }
else if ( protocol ==
"http" || protocol ==
"ftp" ) {
476 }
else if ( protocol ==
"file" ) {
479 int exist = ::stat(
path.c_str(), &buff ) != -1;
480 if ( create && !exist ) {
490 }
else if ( exist ) {
492 }
else if ( !create ) {
496 printError( protocol +
": protocol not supported." );
void registerPFN(CSTR fid, CSTR pfn, CSTR ftype) const override
Create a FileID and Node of the physical file name with all the attributes.
std::string getMetaDataItem(CSTR fid, CSTR name) const override
Access metadata item.
Definition of the MsgStream class used to transmit messages.
bool dirty() const override
Check if the catalog should be updated.
void registerLFN(CSTR fid, CSTR lfn) const override
Create a FileID and Node of the logical file name with all the attributes.
#define DECLARE_FACTORY(type, factory)
void registerFID(CSTR fid) const override
Create a FileID and Node.
void getFID(Strings &fids) const override
Dump all file Identifiers.
void getMetaData(CSTR fid, Attributes &attr) const override
Dump all MetaData of the catalog for a given file ID.
std::string getfile(bool create)
void setMetaData(CSTR fid, CSTR name, CSTR value) const override
Insert/update metadata item.
void renamePFN(CSTR pfn, CSTR new_pfn) const override
rename a PFN
std::string lookupFID(CSTR lfn) const
std::unique_ptr< xercesc::XercesDOMParser > m_parser
void dropMetaData(CSTR fid) const override
Drop all metadata of one FID.
std::pair< xercesc::DOMElement *, xercesc::DOMElement * > i_registerFID(CSTR fid) const
void getLFN(CSTR fid, Files &files) const override
Dump all logical file names of the catalog associate to the FileID.
void deletePFN(CSTR pfn) const override
remove a PFN
bool operator==(const GaudiUtils::Allocator< T1 > &, const GaudiUtils::Allocator< T2 > &)
std::unique_ptr< xercesc::ErrorHandler > m_errHdlr
The IMessage is the interface implemented by the message service.
xercesc::DOMDocument * m_doc
void getPFN(CSTR fid, Files &files) const override
Dump all physical file names of the catalog and their attributes associate to the FileID.
Gaudi::PluginService::Factory< IInterface *(const std::string &, IMessageSvc *)> Factory
std::string createGuidAsString()
Helper function creating file identifier using the UUID mechanism.
bool readOnly() const override
Check if the catalog is read-only.
void deleteFID(CSTR FileID) const override
Delete FileID Node from the catalog.
std::string createFID() const override
Catalog interface.
void commit() override
Save DOM catalog to file.
xercesc::DOMDocument * getDoc(bool throw_if_no_exists=true) const
xercesc::DOMNode * child(xercesc::DOMNode *par, CSTR tag, CSTR attr="", CSTR val="") const
void init() override
Parse the DOM tree of the XML catalog.
xercesc::DOMNode * element(CSTR fid, bool print_err=true) const
This class constitutes the core of the XML based FileCatalog API for POOL.
Header file for std:chrono::duration-based Counters.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
void printError(CSTR msg, bool throw_exc=true) const