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 lfn name ID #REQUIRED>\
135 <!ATTLIST metadata att_name CDATA #REQUIRED>\
136 <!ATTLIST metadata att_value CDATA #REQUIRED>\
138 static const size_t len = strlen(dtd);
139 return new MemBufInputSource((
const XMLByte*)dtd,len,dtdID,
false);
141 virtual ~DTDRedirect() {}
144 void ErrHandler::error(
const SAXParseException& e) {
145 string m(_toString(e.getMessage()));
146 if (m.find(
"The values for attribute 'name' must be names or name tokens")!=string::npos ||
147 m.find(
"The values for attribute 'ID' must be names or name tokens")!=string::npos ||
148 m.find(
"for attribute 'name' must be Name or Nmtoken")!=string::npos ||
149 m.find(
"for attribute 'ID' must be Name or Nmtoken")!=string::npos ||
150 m.find(
"for attribute 'name' is invalid Name or NMTOKEN value")!=string::npos ||
151 m.find(
"for attribute 'ID' is invalid Name or NMTOKEN value")!=string::npos )
153 string sys(_toString(e.getSystemId()));
155 log <<
MSG::ERROR <<
"Error at file \"" << sys
156 <<
"\", line " << e.getLineNumber() <<
", column " << e.getColumnNumber() <<
endmsg
157 <<
"Message: " << m <<
endmsg;
159 void ErrHandler::fatalError(
const SAXParseException& e) {
161 string m(_toString(e.getMessage()));
162 string sys(_toString(e.getSystemId()));
163 log <<
MSG::ERROR <<
"Fatal Error at file \"" << sys
164 <<
"\", line " << e.getLineNumber() <<
", column " << e.getColumnNumber() <<
endmsg
165 <<
"Message: " << m <<
endmsg;
166 throw runtime_error(
"Standard pool exception : Fatal Error on the DOM Parser" );
169 const XMLTag EmptyCatalog(
"<!-- Edited By POOL -->\n"
170 "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n"
171 "<POOLFILECATALOG>\n"
172 "</POOLFILECATALOG>\n");
173 const XMLTag PFNCOLL (
"physical");
174 const XMLTag LFNCOLL (
"logical");
175 const XMLTag PFNNODE (
"pfn");
176 const XMLTag LFNNODE (
"lfn");
177 const XMLTag Attr_type (
"type");
178 const XMLTag Attr_ID (
"ID");
179 const XMLTag Attr_name (
"name");
180 const XMLTag Attr_ftype (
"filetype");
181 const XMLTag MetaNode (
"metadata");
182 const XMLTag Attr_metaName (
"att_name");
183 const XMLTag Attr_metaValue (
"att_value");
189 ::uuid_generate_time(uuid);
192 unsigned short Data2;
193 unsigned short Data3;
194 unsigned char Data4[8];
197 boost::format text(
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X");
198 text %
g->Data1 %
g->Data2 %
g->Data3;
199 for (
int i = 0;
i < 8; ++
i)
200 text % (
unsigned short)
g->Data4[
i];
205 : m_rdOnly(false),m_update(false),m_doc(0),m_parser(0),m_errHdlr(0),
206 m_file(uri), m_msgSvc(m)
224 if ( !
m_doc && throw_if_no_exists )
225 printError(
"The XML catalog was not started.",
true);
233 throw runtime_error(
"XMLFileCatalog> "+msg);
238 string xmlFile =
getfile(
false);
242 m_parser->setValidationScheme(XercesDOMParser::Val_Auto);
244 DTDRedirect dtdinmem;
245 m_parser->setEntityResolver(&dtdinmem);
248 if ( !xmlFile.empty() ) {
252 const std::string&
s = EmptyCatalog;
253 MemBufInputSource src((
const XMLByte*)s.c_str(),s.length(),
"MemCatalog");
258 catch (
const XMLException& e) {
259 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
261 catch (
const DOMException& e) {
262 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
265 printError(
"UNKNOWN XML parse error in file "+xmlFile);
271 DOMNode* e =
element(fid,
false);
272 e = e ? e->getParentNode() : 0;
273 e = e ? e->getParentNode() : 0;
275 if ( e->getAttributes() ) {
276 char* nam = XMLString::transcode(((DOMElement*)e)->getAttribute(Attr_ID));
277 if ( nam ) result = nam;
278 XMLString::release(&nam);
286 DOMNode* fde =
getDoc(
true)->getElementsByTagName(XMLStr(
"*"))->item(0);
287 for(XMLCollection
c(
child(fde,
"File"),
false);
c; ++
c)
288 fids.push_back(
c.attr(Attr_ID));
294 files.push_back(make_pair(
c.attr(Attr_name),
c.attr(Attr_ftype)));
300 files.push_back(make_pair(
c.attr(Attr_name),fid));
306 attr.push_back(make_pair(
c.attr(Attr_metaName),
c.attr(Attr_metaValue)));
307 if ( attr.size() > 0 )
308 attr.push_back(make_pair(
"guid",fid));
312 for(XMLCollection
c(par);
c; ++
c ) {
313 if(
c.tag() == tag ) {
314 if( !attr.empty() &&
c.attr(attr) != val)
continue;
324 DOMElement* mnod = (DOMElement*)
child(node,MetaNode,Attr_metaName,attr);
326 mnod =
getDoc(
true)->createElement(MetaNode);
327 node->appendChild(mnod);
328 mnod->setAttribute(Attr_metaName,XMLStr(attr));
330 mnod->setAttribute(Attr_metaValue,XMLStr(val));
334 printError(
"Cannot update readonly catalog!");
338 XMLCollection
c(
child(
getDoc(
true)->getElementById(XMLStr(fid)),MetaNode,Attr_metaName,attr));
339 return c ? c.attr(attr) : string(
"");
343 vector<DOMNode*> gbc;
344 DOMNode* fn =
getDoc(
true)->getElementById(XMLStr(fid));
345 for(XMLCollection
c(
child(fn,MetaNode));
c; ++
c)
346 if ( attr[0]==
'*' || !
c.attr(attr).empty() ) gbc.push_back(
c);
347 for(vector<DOMNode*>::iterator
i=gbc.begin();
i != gbc.end();
i++)
352 DOMNode* node =
getDoc(
true)->getElementById(XMLStr(element_name));
353 if ( !node && print_err )
printError(
"Cannot find element:"+element_name);
358 DOMNode *pn = 0, *fn =
element(fid);
359 if ( fn ) pn = fn->getParentNode();
360 if ( pn ) pn->removeChild(fn);
364 if ( !fid.empty() ) {
365 std::pair<DOMElement*, DOMElement*> res =
i_registerFID(fid);
366 if ( res.first == 0 || res.second == 0 ) {
371 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
377 DOMElement *
file = (DOMElement*)
element(fid,
false), *phyelem = 0, *logelem = 0;
378 DOMDocument* doc =
getDoc(
true);
380 DOMNode* fde = doc->getElementsByTagName(XMLStr(
"*"))->item(0);
381 file =
m_doc->createElement(XMLStr(
"File"));
382 file->setAttribute(Attr_ID, XMLStr(fid));
383 file->setIdAttribute(Attr_ID,
true);
384 fde->appendChild(file);
387 for(XMLCollection c1(file); c1; ++c1 ) {
388 char* nam = XMLString::transcode(c1->getNodeName());
389 if ( nam == PFNCOLL ) phyelem = c1;
390 if ( nam == LFNCOLL ) logelem = c1;
391 XMLString::release(&nam);
394 phyelem = doc->createElement(PFNCOLL);
395 file->appendChild(phyelem);
399 logelem = doc->createElement(LFNCOLL);
400 file->appendChild(logelem);
403 return std::make_pair(logelem,phyelem);
405 printError(
"Cannot update readonly catalog!");
406 return std::pair<DOMElement*, DOMElement*>(0,0);
410 if ( !fid.empty() ) {
412 DOMElement* phyelem = res.second, *fnelem = 0;
413 for(XMLCollection
c(phyelem);
c; ++
c ) {
414 char* nam = XMLString::transcode(
c->getNodeName());
415 if ( nam == PFNNODE ) {
416 XMLString::release(&nam);
417 nam = XMLString::transcode(
c->getAttribute(Attr_name));
419 XMLString::release(&nam);
424 XMLString::release(&nam);
427 fnelem =
getDoc(
true)->createElement(PFNNODE);
428 phyelem->appendChild(fnelem);
429 fnelem->setAttribute(Attr_ftype,XMLStr(ftype));
430 fnelem->setAttribute(Attr_name,XMLStr(pfn));
431 fnelem->setIdAttribute(Attr_name,
true);
436 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:"+fid);
440 if ( !fid.empty() ) {
441 std::pair<DOMElement*, DOMElement*> res =
i_registerFID(fid);
442 DOMElement* logelem = res.first, *fnelem = 0;
443 for(XMLCollection
c(logelem);
c; ++
c ) {
444 char* nam = XMLString::transcode(
c->getNodeName());
445 if ( nam == LFNNODE ) {
446 XMLString::release(&nam);
447 nam = XMLString::transcode(
c->getAttribute(Attr_name));
449 XMLString::release(&nam);
456 fnelem =
getDoc(
true)->createElement(LFNNODE);
457 logelem->appendChild(fnelem);
458 fnelem->setAttribute(Attr_name,XMLStr(lfn));
459 fnelem->setIdAttribute(Attr_name,
true);
464 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
470 string xmlfile =
getfile(
true);
472 DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(ii);
473 XMLFormatTarget *tar =
new LocalFileFormatTarget(xmlfile.c_str());
474 #if _XERCES_VERSION <= 30000
475 DOMWriter *wr = imp->createDOMWriter();
476 wr->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint,
true);
477 wr->writeNode(tar, *
m_doc);
480 DOMLSOutput *output = imp->createLSOutput();
481 output->setByteStream(tar);
482 DOMLSSerializer *wr = imp->createLSSerializer();
483 wr->getDomConfig()->setParameter(XMLStr(
"format-pretty-print"),
true);
484 wr->write(
m_doc, output);
491 catch ( exception& e ) {
492 printError(
string(
"Cannot open output file:")+e.what());
500 string protocol,
path;
503 xerurl = (
const XMLCh*)XMLStr(
m_file);
504 protocol = _toString(xerurl.getProtocolName());
505 path = _toString(xerurl.getPath());
507 catch (
const XMLException& e ) {
510 if ( protocol.empty() ) {
513 else if ( protocol ==
"http" || protocol ==
"ftp" ) {
516 else if ( protocol ==
"file" ) {
519 int exist = ::stat(path.c_str(),&buff) != -1;
520 if ( create && !exist ) {
522 log <<
MSG::INFO <<
"File '" << path <<
"' does not exist. New file created." <<
endmsg;
523 ofstream out(path.c_str());
525 out << (
CSTR)EmptyCatalog << endl;
535 else if ( !create ) {
540 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
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
AIDA -> ROTO converter.
std::pair< xercesc::DOMElement *, xercesc::DOMElement * > i_registerFID(CSTR fid) const
Gaudi::PluginService::Factory2< IInterface *, const std::string &, IMessageSvc * > Factory
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.