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> 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 )
44 char* buff = XMLString::transcode( toTranscode );
45 string tmp( buff == 0 ?
"" : buff );
46 XMLString::release( &buff );
53 XMLPlatformUtils::Initialize();
54 }
catch (
const XMLException& e ) {
55 cout <<
"Xerces-c error in initialization:" << _toString( e.getMessage() ) <<
endl;
58 ~__Init() { XMLPlatformUtils::Terminate(); }
64 XMLStr( CSTR
c ) { m_xml = XMLString::transcode( c.
c_str() ); }
67 if ( m_xml ) XMLString::release( &m_xml );
69 operator const XMLCh*()
const {
return m_xml; }
71 struct XMLTag :
public XMLStr {
73 XMLTag( CSTR
s ) : XMLStr( s ), m_str( s ) {}
75 operator CSTR()
const {
return m_str; }
78 bool operator==( CSTR
c,
const XMLTag& b ) {
return c == b.m_str; }
79 struct XMLCollection {
81 XMLCollection( DOMNode*
n,
bool use_children =
true ) : m_node( (DOMElement*)n )
84 if ( m_node ) m_node = (DOMElement*)m_node->getFirstChild();
85 if ( m_node && m_node->getNodeType() != DOMNode::ELEMENT_NODE ) ++( *
this );
88 operator bool()
const {
return m_node; }
89 operator DOMNode*()
const {
return m_node; }
90 operator DOMElement*()
const {
return m_node; }
91 DOMElement* operator->()
const {
return m_node; }
92 string attr(
const XMLTag& tag )
const {
return _toString( m_node->getAttribute( tag ) ); }
93 string attr( CSTR tag )
const {
return attr( XMLTag( tag ) ); }
94 string tag()
const {
return _toString( m_node->getTagName() ); }
98 m_node = (DOMElement*)m_node->getNextSibling();
99 if ( m_node && m_node->getNodeType() == DOMNode::ELEMENT_NODE ) {
105 struct ErrHandler :
public ErrorHandler {
111 void resetErrors()
override {}
113 void warning(
const SAXParseException& )
override {}
115 void error(
const SAXParseException& e )
override;
117 void fatalError(
const SAXParseException& e )
override;
119 struct DTDRedirect :
public EntityResolver {
120 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const )
override 122 static const char* dtdID =
"redirectinmem.dtd";
123 static const char* dtd =
"\ 124 <!ELEMENT POOLFILECATALOG (META*,File*)>\ 125 <!ELEMENT META EMPTY>\ 126 <!ELEMENT File (physical,logical,metadata*)>\ 127 <!ATTLIST META name CDATA #REQUIRED>\ 128 <!ATTLIST META type CDATA #REQUIRED>\ 129 <!ELEMENT physical (pfn)+>\ 130 <!ELEMENT logical (lfn)*>\ 131 <!ELEMENT metadata EMPTY>\ 132 <!ELEMENT lfn EMPTY>\ 133 <!ELEMENT pfn EMPTY>\ 134 <!ATTLIST File ID ID #REQUIRED>\ 135 <!ATTLIST pfn name ID #REQUIRED>\ 136 <!ATTLIST pfn filetype CDATA #IMPLIED>\ 137 <!ATTLIST pfn se CDATA #IMPLIED>\ 138 <!ATTLIST lfn name ID #REQUIRED>\ 139 <!ATTLIST metadata att_name CDATA #REQUIRED>\ 140 <!ATTLIST metadata att_value CDATA #REQUIRED>\ 142 static const size_t len =
strlen( dtd );
143 return new MemBufInputSource( (
const XMLByte*)dtd, len, dtdID,
false );
147 void ErrHandler::error(
const SAXParseException& e )
149 string m( _toString( e.getMessage() ) );
150 if ( m.
find(
"The values for attribute 'name' must be names or name tokens" ) != string::npos ||
151 m.
find(
"The values for attribute 'ID' must be names or name tokens" ) != string::npos ||
152 m.
find(
"for attribute 'name' must be Name or Nmtoken" ) != string::npos ||
153 m.
find(
"for attribute 'ID' must be Name or Nmtoken" ) != string::npos ||
154 m.
find(
"for attribute 'name' is invalid Name or NMTOKEN value" ) != string::npos ||
155 m.
find(
"for attribute 'ID' is invalid Name or NMTOKEN value" ) != string::npos )
157 string sys( _toString( e.getSystemId() ) );
159 log <<
MSG::ERROR <<
"Error at file \"" << sys <<
"\", line " << e.getLineNumber() <<
", column " 160 << e.getColumnNumber() <<
endmsg <<
"Message: " << m <<
endmsg;
162 void ErrHandler::fatalError(
const SAXParseException& e )
165 string m( _toString( e.getMessage() ) );
166 string sys( _toString( e.getSystemId() ) );
167 log <<
MSG::ERROR <<
"Fatal Error at file \"" << sys <<
"\", line " << e.getLineNumber() <<
", column " 168 << e.getColumnNumber() <<
endmsg <<
"Message: " << m <<
endmsg;
169 throw runtime_error(
"Standard pool exception : Fatal Error on the DOM Parser" );
172 const XMLTag EmptyCatalog(
"<!-- Edited By POOL -->\n" 173 "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n" 174 "<POOLFILECATALOG>\n" 175 "</POOLFILECATALOG>\n" );
176 const XMLTag PFNCOLL(
"physical" );
177 const XMLTag LFNCOLL(
"logical" );
178 const XMLTag PFNNODE(
"pfn" );
179 const XMLTag LFNNODE(
"lfn" );
180 const XMLTag Attr_type(
"type" );
181 const XMLTag Attr_ID(
"ID" );
182 const XMLTag Attr_name(
"name" );
183 const XMLTag Attr_ftype(
"filetype" );
184 const XMLTag MetaNode(
"metadata" );
185 const XMLTag Attr_metaName(
"att_name" );
186 const XMLTag Attr_metaValue(
"att_value" );
190 XMLFileCatalog::XMLFileCatalog(
CSTR uri,
IMessageSvc*
m ) : m_file( uri ), m_msgSvc( m ) {}
197 if ( !
m_doc && throw_if_no_exists )
printError(
"The XML catalog was not started.",
true );
205 if ( rethrow )
throw runtime_error(
"XMLFileCatalog> " + msg );
210 string xmlFile =
getfile(
false );
212 m_parser = std::make_unique<XercesDOMParser>();
213 m_parser->setValidationScheme( XercesDOMParser::Val_Auto );
215 DTDRedirect dtdinmem;
216 m_parser->setEntityResolver( &dtdinmem );
219 if ( !xmlFile.
empty() ) {
223 MemBufInputSource src( (
const XMLByte*)s.
c_str(), s.
length(),
"MemCatalog" );
227 }
catch (
const XMLException& e ) {
228 printError(
"XML parse error[" + xmlFile +
"]: " + _toString( e.getMessage() ) );
229 }
catch (
const DOMException& e ) {
230 printError(
"XML parse error[" + xmlFile +
"]: " + _toString( e.getMessage() ) );
232 printError(
"UNKNOWN XML parse error in file " + xmlFile );
239 DOMNode* e =
element( fid,
false );
240 e = e ? e->getParentNode() : 0;
241 e = e ? e->getParentNode() : 0;
243 if ( e->getAttributes() ) {
244 char* nam = XMLString::transcode( ( (DOMElement*)e )->getAttribute( Attr_ID ) );
245 if ( nam ) result = nam;
246 XMLString::release( &nam );
255 DOMNode* fde =
getDoc(
true )->getElementsByTagName( XMLStr(
"*" ) )->item( 0 );
256 for ( XMLCollection
c(
child( fde,
"File" ),
false );
c; ++
c ) fids.push_back(
c.attr( Attr_ID ) );
262 for ( XMLCollection
c(
child(
child(
element( fid,
false ), PFNCOLL ), PFNNODE ),
false );
c; ++
c )
263 files.emplace_back(
c.attr( Attr_name ),
c.attr( Attr_ftype ) );
269 for ( XMLCollection
c(
child(
child(
element( fid,
false ), LFNCOLL ), LFNNODE ),
false );
c; ++
c )
270 files.emplace_back(
c.attr( Attr_name ), fid );
276 for ( XMLCollection
c(
child(
element( fid ), MetaNode ),
false );
c; ++
c )
277 attr.emplace_back(
c.attr( Attr_metaName ),
c.attr( Attr_metaValue ) );
278 if ( attr.size() > 0 ) attr.emplace_back(
"guid", fid );
283 for ( XMLCollection
c( par );
c; ++
c ) {
284 if (
c.tag() == tag ) {
285 if ( !attr.
empty() &&
c.attr( attr ) != val )
continue;
295 DOMNode* node =
element( fid );
296 DOMElement* mnod = (DOMElement*)
child( node, MetaNode, Attr_metaName, attr );
298 mnod =
getDoc(
true )->createElement( MetaNode );
299 node->appendChild( mnod );
300 mnod->setAttribute( Attr_metaName, XMLStr( attr ) );
302 mnod->setAttribute( Attr_metaValue, XMLStr( val ) );
306 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(
"" );
318 DOMNode* fn =
getDoc(
true )->getElementById( XMLStr( fid ) );
319 for ( XMLCollection
c{
child( fn, MetaNode )};
c; ++
c )
320 if ( attr[0] ==
'*' || !
c.attr( attr ).empty() ) gbc.
push_back(
c );
321 for (
const auto& i : gbc ) fn->removeChild( i );
326 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( element_name ) );
327 if ( !node && print_err )
printError(
"Cannot find element:" + element_name );
333 DOMNode *pn =
nullptr, *fn =
element( fid );
334 if ( fn ) pn = fn->getParentNode();
335 if ( pn ) pn->removeChild( fn );
340 if ( !fid.
empty() ) {
342 if ( res.first == 0 || res.second == 0 ) {
343 printError(
"Failed to register FID:" + fid );
347 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:" + fid );
352 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( pfn ) );
353 if ( node && node->getNodeType() == DOMNode::ELEMENT_NODE ) {
354 ( (DOMElement*)node )->setAttribute( Attr_name, XMLStr( new_pfn ) );
361 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( pfn ) );
363 DOMNode* pcoll_node = node->getParentNode();
364 pcoll_node->removeChild( node );
366 for ( XMLCollection pcoll( pcoll_node,
true ); pcoll; ++pcoll ) {
370 DOMNode* file_node = pcoll_node->getParentNode();
371 file_node->getParentNode()->removeChild( file_node );
378 printError(
"Cannot update readonly catalog!" );
379 return {
nullptr,
nullptr};
383 DOMElement * file = (DOMElement *)
element( fid,
false ), *phyelem = 0, *logelem = 0;
384 DOMDocument* doc =
getDoc(
true );
386 DOMNode* fde = doc->getElementsByTagName( XMLStr(
"*" ) )->item( 0 );
387 file =
m_doc->createElement( XMLStr(
"File" ) );
388 file->setAttribute( Attr_ID, XMLStr( fid ) );
389 file->setIdAttribute( Attr_ID,
true );
390 fde->appendChild( file );
393 for ( XMLCollection c1( file ); c1; ++c1 ) {
394 char* nam = XMLString::transcode( c1->getNodeName() );
395 if ( nam == PFNCOLL ) phyelem = c1;
396 if ( nam == LFNCOLL ) logelem = c1;
397 XMLString::release( &nam );
400 phyelem = doc->createElement( PFNCOLL );
401 file->appendChild( phyelem );
405 logelem = doc->createElement( LFNCOLL );
406 file->appendChild( logelem );
409 return {logelem, phyelem};
414 if ( !fid.
empty() ) {
416 DOMElement *phyelem = res.second, *fnelem = 0;
417 for ( XMLCollection
c( phyelem );
c; ++
c ) {
418 char* nam = XMLString::transcode(
c->getNodeName() );
419 if ( nam == PFNNODE ) {
420 XMLString::release( &nam );
421 nam = XMLString::transcode(
c->getAttribute( Attr_name ) );
423 XMLString::release( &nam );
428 XMLString::release( &nam );
431 fnelem =
getDoc(
true )->createElement( PFNNODE );
432 phyelem->appendChild( fnelem );
433 fnelem->setAttribute( Attr_ftype, XMLStr( ftype ) );
434 fnelem->setAttribute( Attr_name, XMLStr( pfn ) );
435 fnelem->setIdAttribute( Attr_name,
true );
440 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:" + fid );
445 if ( !fid.
empty() ) {
447 DOMElement *logelem = res.first, *fnelem = 0;
448 for ( XMLCollection
c( logelem );
c; ++
c ) {
449 char* nam = XMLString::transcode(
c->getNodeName() );
450 if ( nam == LFNNODE ) {
451 XMLString::release( &nam );
452 nam = XMLString::transcode(
c->getAttribute( Attr_name ) );
454 XMLString::release( &nam );
461 fnelem =
getDoc(
true )->createElement( LFNNODE );
462 logelem->appendChild( fnelem );
463 fnelem->setAttribute( Attr_name, XMLStr( lfn ) );
464 fnelem->setIdAttribute( Attr_name,
true );
469 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:" + fid );
476 string xmlfile =
getfile(
true );
478 DOMImplementation* imp = DOMImplementationRegistry::getDOMImplementation( ii );
479 auto tar = std::make_unique<LocalFileFormatTarget>( xmlfile.
c_str() );
480 #if _XERCES_VERSION <= 30000 481 DOMWriter* wr = imp->createDOMWriter();
482 wr->setFeature( XMLUni::fgDOMWRTFormatPrettyPrint,
true );
483 wr->writeNode( tar.get(), *
m_doc );
486 DOMLSOutput*
output = imp->createLSOutput();
487 output->setByteStream( tar.get() );
488 DOMLSSerializer* wr = imp->createLSSerializer();
489 wr->getDomConfig()->setParameter( XMLStr(
"format-pretty-print" ),
true );
490 wr->write(
m_doc, output );
504 string protocol,
path;
507 xerurl = (
const XMLCh*)XMLStr(
m_file );
508 protocol = _toString( xerurl.getProtocolName() );
509 path = _toString( xerurl.getPath() );
510 }
catch (
const XMLException& e ) {
513 if ( protocol.
empty() ) {
515 }
else if ( protocol ==
"http" || protocol ==
"ftp" ) {
517 }
else if ( protocol ==
"file" ) {
520 int exist = ::stat( path.
c_str(), &buff ) != -1;
521 if ( create && !exist ) {
523 log <<
MSG::INFO <<
"File '" << path <<
"' does not exist. New file created." <<
endmsg;
528 printError(
"Problem creating file " + path );
531 }
else if ( exist ) {
533 }
else if ( !create ) {
537 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
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 deletePFN(CSTR pfn) const override
remove a PFN
void getLFN(CSTR fid, Files &files) const override
Dump all logical file names of the catalog associate to the FileID.
Gaudi::PluginService::Factory< IInterface *(const std::string &, IMessageSvc *)> Factory
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.
void renamePFN(CSTR pfn, CSTR new_pfn) const override
rename a PFN