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;
118 ~ErrHandler()
override {}
120 struct DTDRedirect :
public EntityResolver {
121 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const )
override 123 static const char* dtdID =
"redirectinmem.dtd";
124 static const char* dtd =
"\ 125 <!ELEMENT POOLFILECATALOG (META*,File*)>\ 126 <!ELEMENT META EMPTY>\ 127 <!ELEMENT File (physical,logical,metadata*)>\ 128 <!ATTLIST META name CDATA #REQUIRED>\ 129 <!ATTLIST META type CDATA #REQUIRED>\ 130 <!ELEMENT physical (pfn)+>\ 131 <!ELEMENT logical (lfn)*>\ 132 <!ELEMENT metadata EMPTY>\ 133 <!ELEMENT lfn EMPTY>\ 134 <!ELEMENT pfn EMPTY>\ 135 <!ATTLIST File ID ID #REQUIRED>\ 136 <!ATTLIST pfn name ID #REQUIRED>\ 137 <!ATTLIST pfn filetype CDATA #IMPLIED>\ 138 <!ATTLIST pfn se CDATA #IMPLIED>\ 139 <!ATTLIST lfn name ID #REQUIRED>\ 140 <!ATTLIST metadata att_name CDATA #REQUIRED>\ 141 <!ATTLIST metadata att_value CDATA #REQUIRED>\ 143 static const size_t len =
strlen( dtd );
144 return new MemBufInputSource( (
const XMLByte*)dtd, len, dtdID,
false );
146 ~DTDRedirect()
override =
default;
149 void ErrHandler::error(
const SAXParseException& e )
151 string m( _toString( e.getMessage() ) );
152 if ( m.
find(
"The values for attribute 'name' must be names or name tokens" ) != string::npos ||
153 m.
find(
"The values for attribute 'ID' must be names or name tokens" ) != string::npos ||
154 m.
find(
"for attribute 'name' must be Name or Nmtoken" ) != string::npos ||
155 m.
find(
"for attribute 'ID' must be Name or Nmtoken" ) != string::npos ||
156 m.
find(
"for attribute 'name' is invalid Name or NMTOKEN value" ) != string::npos ||
157 m.
find(
"for attribute 'ID' is invalid Name or NMTOKEN value" ) != string::npos )
159 string sys( _toString( e.getSystemId() ) );
161 log <<
MSG::ERROR <<
"Error at file \"" << sys <<
"\", line " << e.getLineNumber() <<
", column " 162 << e.getColumnNumber() <<
endmsg <<
"Message: " << m <<
endmsg;
164 void ErrHandler::fatalError(
const SAXParseException& e )
167 string m( _toString( e.getMessage() ) );
168 string sys( _toString( e.getSystemId() ) );
169 log <<
MSG::ERROR <<
"Fatal Error at file \"" << sys <<
"\", line " << e.getLineNumber() <<
", column " 170 << e.getColumnNumber() <<
endmsg <<
"Message: " << m <<
endmsg;
171 throw runtime_error(
"Standard pool exception : Fatal Error on the DOM Parser" );
174 const XMLTag EmptyCatalog(
"<!-- Edited By POOL -->\n" 175 "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n" 176 "<POOLFILECATALOG>\n" 177 "</POOLFILECATALOG>\n" );
178 const XMLTag PFNCOLL(
"physical" );
179 const XMLTag LFNCOLL(
"logical" );
180 const XMLTag PFNNODE(
"pfn" );
181 const XMLTag LFNNODE(
"lfn" );
182 const XMLTag Attr_type(
"type" );
183 const XMLTag Attr_ID(
"ID" );
184 const XMLTag Attr_name(
"name" );
185 const XMLTag Attr_ftype(
"filetype" );
186 const XMLTag MetaNode(
"metadata" );
187 const XMLTag Attr_metaName(
"att_name" );
188 const XMLTag Attr_metaValue(
"att_value" );
193 : m_rdOnly( false ), m_update( false ), m_doc( 0 ), m_file( uri ), m_msgSvc( m )
202 if ( !
m_doc && throw_if_no_exists )
printError(
"The XML catalog was not started.",
true );
217 string xmlFile =
getfile(
false );
220 m_parser->setValidationScheme( XercesDOMParser::Val_Auto );
222 DTDRedirect dtdinmem;
223 m_parser->setEntityResolver( &dtdinmem );
226 if ( !xmlFile.
empty() ) {
230 MemBufInputSource src( (
const XMLByte*)s.
c_str(), s.
length(),
"MemCatalog" );
234 }
catch (
const XMLException& e ) {
235 printError(
"XML parse error[" + xmlFile +
"]: " + _toString( e.getMessage() ) );
236 }
catch (
const DOMException& e ) {
237 printError(
"XML parse error[" + xmlFile +
"]: " + _toString( e.getMessage() ) );
239 printError(
"UNKNOWN XML parse error in file " + xmlFile );
246 DOMNode* e =
element( fid,
false );
247 e = e ? e->getParentNode() : 0;
248 e = e ? e->getParentNode() : 0;
250 if ( e->getAttributes() ) {
251 char* nam = XMLString::transcode( ( (DOMElement*)e )->getAttribute( Attr_ID ) );
252 if ( nam ) result = nam;
253 XMLString::release( &nam );
262 DOMNode* fde =
getDoc(
true )->getElementsByTagName( XMLStr(
"*" ) )->item( 0 );
263 for ( XMLCollection
c(
child( fde,
"File" ),
false );
c; ++
c ) fids.push_back(
c.attr( Attr_ID ) );
269 for ( XMLCollection
c(
child(
child(
element( fid,
false ), PFNCOLL ), PFNNODE ),
false );
c; ++
c )
270 files.emplace_back(
c.attr( Attr_name ),
c.attr( Attr_ftype ) );
276 for ( XMLCollection
c(
child(
child(
element( fid,
false ), LFNCOLL ), LFNNODE ),
false );
c; ++
c )
277 files.emplace_back(
c.attr( Attr_name ), fid );
283 for ( XMLCollection
c(
child(
element( fid ), MetaNode ),
false );
c; ++
c )
284 attr.emplace_back(
c.attr( Attr_metaName ),
c.attr( Attr_metaValue ) );
285 if ( attr.size() > 0 ) attr.emplace_back(
"guid", fid );
290 for ( XMLCollection
c( par );
c; ++
c ) {
291 if (
c.tag() == tag ) {
292 if ( !attr.
empty() &&
c.attr( attr ) != val )
continue;
302 DOMNode* node =
element( fid );
303 DOMElement* mnod = (DOMElement*)
child( node, MetaNode, Attr_metaName, attr );
305 mnod =
getDoc(
true )->createElement( MetaNode );
306 node->appendChild( mnod );
307 mnod->setAttribute( Attr_metaName, XMLStr( attr ) );
309 mnod->setAttribute( Attr_metaValue, XMLStr( val ) );
313 printError(
"Cannot update readonly catalog!" );
318 XMLCollection
c(
child(
getDoc(
true )->getElementById( XMLStr( fid ) ), MetaNode, Attr_metaName, attr ) );
319 return c ? c.attr( attr ) :
string(
"" );
325 DOMNode* fn =
getDoc(
true )->getElementById( XMLStr( fid ) );
326 for ( XMLCollection
c{
child( fn, MetaNode )};
c; ++
c )
327 if ( attr[0] ==
'*' || !
c.attr( attr ).empty() ) gbc.
push_back(
c );
328 for (
const auto& i : gbc ) fn->removeChild( i );
333 DOMNode* node =
getDoc(
true )->getElementById( XMLStr( element_name ) );
334 if ( !node && print_err )
printError(
"Cannot find element:" + element_name );
340 DOMNode *pn =
nullptr, *fn =
element( fid );
341 if ( fn ) pn = fn->getParentNode();
342 if ( pn ) pn->removeChild( fn );
347 if ( !fid.
empty() ) {
349 if ( res.first == 0 || res.second == 0 ) {
350 printError(
"Failed to register FID:" + fid );
354 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:" + fid );
360 printError(
"Cannot update readonly catalog!" );
361 return {
nullptr,
nullptr};
365 DOMElement *file = (DOMElement *)
element( fid,
false ), *phyelem = 0, *logelem = 0;
366 DOMDocument* doc =
getDoc(
true );
368 DOMNode* fde = doc->getElementsByTagName( XMLStr(
"*" ) )->item( 0 );
369 file =
m_doc->createElement( XMLStr(
"File" ) );
370 file->setAttribute( Attr_ID, XMLStr( fid ) );
371 file->setIdAttribute( Attr_ID,
true );
372 fde->appendChild( file );
375 for ( XMLCollection
c1( file );
c1; ++
c1 ) {
376 char* nam = XMLString::transcode(
c1->getNodeName() );
377 if ( nam == PFNCOLL ) phyelem =
c1;
378 if ( nam == LFNCOLL ) logelem =
c1;
379 XMLString::release( &nam );
382 phyelem = doc->createElement( PFNCOLL );
383 file->appendChild( phyelem );
387 logelem = doc->createElement( LFNCOLL );
388 file->appendChild( logelem );
391 return {logelem, phyelem};
396 if ( !fid.
empty() ) {
398 DOMElement *phyelem = res.second, *fnelem = 0;
399 for ( XMLCollection
c( phyelem );
c; ++
c ) {
400 char* nam = XMLString::transcode(
c->getNodeName() );
401 if ( nam == PFNNODE ) {
402 XMLString::release( &nam );
403 nam = XMLString::transcode(
c->getAttribute( Attr_name ) );
405 XMLString::release( &nam );
410 XMLString::release( &nam );
413 fnelem =
getDoc(
true )->createElement( PFNNODE );
414 phyelem->appendChild( fnelem );
415 fnelem->setAttribute( Attr_ftype, XMLStr( ftype ) );
416 fnelem->setAttribute( Attr_name, XMLStr( pfn ) );
417 fnelem->setIdAttribute( Attr_name,
true );
422 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:" + fid );
427 if ( !fid.
empty() ) {
429 DOMElement *logelem = res.first, *fnelem = 0;
430 for ( XMLCollection
c( logelem );
c; ++
c ) {
431 char* nam = XMLString::transcode(
c->getNodeName() );
432 if ( nam == LFNNODE ) {
433 XMLString::release( &nam );
434 nam = XMLString::transcode(
c->getAttribute( Attr_name ) );
436 XMLString::release( &nam );
443 fnelem =
getDoc(
true )->createElement( LFNNODE );
444 logelem->appendChild( fnelem );
445 fnelem->setAttribute( Attr_name, XMLStr( lfn ) );
446 fnelem->setIdAttribute( Attr_name,
true );
451 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:" + fid );
458 string xmlfile =
getfile(
true );
460 DOMImplementation* imp = DOMImplementationRegistry::getDOMImplementation( ii );
462 #if _XERCES_VERSION <= 30000 463 DOMWriter* wr = imp->createDOMWriter();
464 wr->setFeature( XMLUni::fgDOMWRTFormatPrettyPrint,
true );
465 wr->writeNode( tar.get(), *
m_doc );
468 DOMLSOutput*
output = imp->createLSOutput();
469 output->setByteStream( tar.get() );
470 DOMLSSerializer* wr = imp->createLSSerializer();
471 wr->getDomConfig()->setParameter( XMLStr(
"format-pretty-print" ),
true );
472 wr->write(
m_doc, output );
486 string protocol,
path;
489 xerurl = (
const XMLCh*)XMLStr(
m_file );
490 protocol = _toString( xerurl.getProtocolName() );
491 path = _toString( xerurl.getPath() );
492 }
catch (
const XMLException& e ) {
495 if ( protocol.
empty() ) {
497 }
else if ( protocol ==
"http" || protocol ==
"ftp" ) {
499 }
else if ( protocol ==
"file" ) {
502 int exist = ::stat( path.
c_str(), &buff ) != -1;
503 if ( create && !exist ) {
505 log <<
MSG::INFO <<
"File '" << path <<
"' does not exist. New file created." <<
endmsg;
510 printError(
"Problem creating file " + path );
513 }
else if ( exist ) {
515 }
else if ( !create ) {
519 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.
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.
#define DECLARE_FACTORY(type, 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.