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>
29 using namespace xercesc;
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 0 != 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() { }
109 void warning(
const SAXParseException& ) { }
111 void error(
const SAXParseException& e);
113 void fatalError(
const SAXParseException& e);
114 virtual ~ErrHandler() {}
116 struct DTDRedirect :
public EntityResolver {
117 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const ) {
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 virtual ~DTDRedirect() {}
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),m_parser(0),m_errHdlr(0),
207 m_file(uri), m_msgSvc(m)
225 if ( !
m_doc && throw_if_no_exists )
226 printError(
"The XML catalog was not started.",
true);
234 throw runtime_error(
"XMLFileCatalog> "+msg);
239 string xmlFile =
getfile(
false);
243 m_parser->setValidationScheme(XercesDOMParser::Val_Auto);
245 DTDRedirect dtdinmem;
246 m_parser->setEntityResolver(&dtdinmem);
249 if ( !xmlFile.empty() ) {
253 const std::string&
s = EmptyCatalog;
254 MemBufInputSource src((
const XMLByte*)s.c_str(),s.length(),
"MemCatalog");
259 catch (
const XMLException& e) {
260 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
262 catch (
const DOMException& e) {
263 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
266 printError(
"UNKNOWN XML parse error in file "+xmlFile);
272 DOMNode* e =
element(fid,
false);
273 e = e ? e->getParentNode() : 0;
274 e = e ? e->getParentNode() : 0;
276 if ( e->getAttributes() ) {
277 char* nam = XMLString::transcode(((DOMElement*)e)->getAttribute(Attr_ID));
278 if ( nam ) result = nam;
279 XMLString::release(&nam);
287 DOMNode* fde =
getDoc(
true)->getElementsByTagName(XMLStr(
"*"))->item(0);
288 for(XMLCollection
c(
child(fde,
"File"),
false);
c; ++
c)
289 fids.push_back(
c.attr(Attr_ID));
295 files.push_back(make_pair(
c.attr(Attr_name),
c.attr(Attr_ftype)));
301 files.push_back(make_pair(
c.attr(Attr_name),fid));
307 attr.push_back(make_pair(
c.attr(Attr_metaName),
c.attr(Attr_metaValue)));
308 if ( attr.size() > 0 )
309 attr.push_back(make_pair(
"guid",fid));
313 for(XMLCollection
c(par);
c; ++
c ) {
314 if(
c.tag() == tag ) {
315 if( !attr.empty() &&
c.attr(attr) != val)
continue;
325 DOMElement* mnod = (DOMElement*)
child(node,MetaNode,Attr_metaName,attr);
327 mnod =
getDoc(
true)->createElement(MetaNode);
328 node->appendChild(mnod);
329 mnod->setAttribute(Attr_metaName,XMLStr(attr));
331 mnod->setAttribute(Attr_metaValue,XMLStr(val));
335 printError(
"Cannot update readonly catalog!");
339 XMLCollection
c(
child(
getDoc(
true)->getElementById(XMLStr(fid)),MetaNode,Attr_metaName,attr));
340 return c ? c.attr(attr) : string(
"");
344 vector<DOMNode*> gbc;
345 DOMNode* fn =
getDoc(
true)->getElementById(XMLStr(fid));
346 for(XMLCollection
c(
child(fn,MetaNode));
c; ++
c)
347 if ( attr[0]==
'*' || !
c.attr(attr).empty() ) gbc.push_back(
c);
348 for(vector<DOMNode*>::iterator
i=gbc.begin();
i != gbc.end();
i++)
353 DOMNode* node =
getDoc(
true)->getElementById(XMLStr(element_name));
354 if ( !node && print_err )
printError(
"Cannot find element:"+element_name);
359 DOMNode *pn = 0, *fn =
element(fid);
360 if ( fn ) pn = fn->getParentNode();
361 if ( pn ) pn->removeChild(fn);
365 if ( !fid.empty() ) {
366 std::pair<DOMElement*, DOMElement*> res =
i_registerFID(fid);
367 if ( res.first == 0 || res.second == 0 ) {
372 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
378 DOMElement *
file = (DOMElement*)
element(fid,
false), *phyelem = 0, *logelem = 0;
379 DOMDocument* doc =
getDoc(
true);
381 DOMNode* fde = doc->getElementsByTagName(XMLStr(
"*"))->item(0);
382 file =
m_doc->createElement(XMLStr(
"File"));
383 file->setAttribute(Attr_ID, XMLStr(fid));
384 file->setIdAttribute(Attr_ID,
true);
385 fde->appendChild(file);
388 for(XMLCollection c1(file); c1; ++c1 ) {
389 char* nam = XMLString::transcode(c1->getNodeName());
390 if ( nam == PFNCOLL ) phyelem = c1;
391 if ( nam == LFNCOLL ) logelem = c1;
392 XMLString::release(&nam);
395 phyelem = doc->createElement(PFNCOLL);
396 file->appendChild(phyelem);
400 logelem = doc->createElement(LFNCOLL);
401 file->appendChild(logelem);
404 return std::make_pair(logelem,phyelem);
406 printError(
"Cannot update readonly catalog!");
407 return std::pair<DOMElement*, DOMElement*>(0,0);
411 if ( !fid.empty() ) {
413 DOMElement* phyelem = res.second, *fnelem = 0;
414 for(XMLCollection
c(phyelem);
c; ++
c ) {
415 char* nam = XMLString::transcode(
c->getNodeName());
416 if ( nam == PFNNODE ) {
417 XMLString::release(&nam);
418 nam = XMLString::transcode(
c->getAttribute(Attr_name));
420 XMLString::release(&nam);
425 XMLString::release(&nam);
428 fnelem =
getDoc(
true)->createElement(PFNNODE);
429 phyelem->appendChild(fnelem);
430 fnelem->setAttribute(Attr_ftype,XMLStr(ftype));
431 fnelem->setAttribute(Attr_name,XMLStr(pfn));
432 fnelem->setIdAttribute(Attr_name,
true);
437 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:"+fid);
441 if ( !fid.empty() ) {
442 std::pair<DOMElement*, DOMElement*> res =
i_registerFID(fid);
443 DOMElement* logelem = res.first, *fnelem = 0;
444 for(XMLCollection
c(logelem);
c; ++
c ) {
445 char* nam = XMLString::transcode(
c->getNodeName());
446 if ( nam == LFNNODE ) {
447 XMLString::release(&nam);
448 nam = XMLString::transcode(
c->getAttribute(Attr_name));
450 XMLString::release(&nam);
457 fnelem =
getDoc(
true)->createElement(LFNNODE);
458 logelem->appendChild(fnelem);
459 fnelem->setAttribute(Attr_name,XMLStr(lfn));
460 fnelem->setIdAttribute(Attr_name,
true);
465 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
471 string xmlfile =
getfile(
true);
473 DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(ii);
474 XMLFormatTarget *tar =
new LocalFileFormatTarget(xmlfile.c_str());
475 #if _XERCES_VERSION <= 30000
476 DOMWriter *wr = imp->createDOMWriter();
477 wr->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint,
true);
478 wr->writeNode(tar, *
m_doc);
481 DOMLSOutput *output = imp->createLSOutput();
482 output->setByteStream(tar);
483 DOMLSSerializer *wr = imp->createLSSerializer();
484 wr->getDomConfig()->setParameter(XMLStr(
"format-pretty-print"),
true);
485 wr->write(
m_doc, output);
492 catch ( exception& e ) {
493 printError(
string(
"Cannot open output file:")+e.what());
501 string protocol,
path;
504 xerurl = (
const XMLCh*)XMLStr(
m_file);
505 protocol = _toString(xerurl.getProtocolName());
506 path = _toString(xerurl.getPath());
508 catch (
const XMLException& e ) {
511 if ( protocol.empty() ) {
514 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;
524 ofstream out(path.c_str());
526 out << (
CSTR)EmptyCatalog << endl;
536 else if ( !create ) {
541 printError(protocol +
": protocol not supported.");
Definition of the MsgStream class used to transmit messages.
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
virtual bool readOnly() const
Check if the catalog is read-only.
#define DECLARE_FACTORY(type, factory)
xercesc::XercesDOMParser * m_parser
virtual ~XMLFileCatalog()
Destructor,.
std::string lookupFID(CSTR lfn) const
Gaudi::PluginService::Factory< IInterface *, const std::string &, IMessageSvc * > Factory
std::string getfile(bool create)
virtual std::string getMetaDataItem(CSTR fid, CSTR name) const
Access metadata item.
virtual void dropMetaData(CSTR fid) const
Drop all metadata of one FID.
xercesc::DOMNode * element(CSTR fid, bool print_err=true) const
virtual void setMetaData(CSTR fid, CSTR name, CSTR value) const
Insert/update metadata item.
virtual void registerPFN(CSTR fid, CSTR pfn, CSTR ftype) const
Create a FileID and Node of the physical file name with all the attributes.
virtual void init()
Parse the DOM tree of the XML catalog.
virtual bool dirty() const
Check if the catalog should be updated.
xercesc::DOMNode * child(xercesc::DOMNode *par, CSTR tag, CSTR attr="", CSTR val="") const
bool operator==(const GaudiUtils::Allocator< T1 > &, const GaudiUtils::Allocator< T2 > &)
void printError(CSTR msg, bool throw_exc=true) const
virtual void getFID(Strings &fids) const
Dump all file Identifiers.
The IMessage is the interface implemented by the message service.
xercesc::DOMDocument * m_doc
xercesc::DOMDocument * getDoc(bool throw_if_no_exists=true) const
virtual void getLFN(CSTR fid, Files &files) const
Dump all logical file names of the catalog associate to the FileID.
virtual void deleteFID(CSTR FileID) const
Delete FileID Node from the catalog.
GAUDI_API std::string path(const AIDA::IBaseHistogram *aida)
get the path in THS for AIDA histogram
xercesc::ErrorHandler * m_errHdlr
std::string createGuidAsString()
Create file identifier using UUID mechanism.
virtual void commit()
Save DOM catalog to file.
virtual void getPFN(CSTR fid, Files &files) const
Dump all physical file names of the catalog and their attributes associate to the FileID...
std::pair< xercesc::DOMElement *, xercesc::DOMElement * > i_registerFID(CSTR fid) const
virtual void getMetaData(CSTR fid, Attributes &attr) const
Dump all MetaData of the catalog for a given file ID.
virtual void registerFID(CSTR fid) const
Create a FileID and Node.
This is a number of static methods for bootstrapping the Gaudi framework.
This class constitutes the core of the XML based FileCatalog API for POOL.
virtual std::string createFID() const
Catalog interface.
virtual void registerLFN(CSTR fid, CSTR lfn) const
Create a FileID and Node of the logical file name with all the attributes.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.