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"
16 #include "Reflex/PluginService.h"
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)
42 typedef const string&
CSTR;
43 inline string _toString(
const XMLCh *toTranscode) {
44 char * buff = XMLString::transcode(toTranscode);
45 string tmp(buff==0 ?
"" : buff);
46 XMLString::release(&buff);
51 try { XMLPlatformUtils::Initialize(); }
52 catch (
const XMLException& e) {
53 cout <<
"Xerces-c error in initialization:" << _toString(e.getMessage()) <<
endl;
57 XMLPlatformUtils::Terminate();
64 XMLStr(CSTR
c) { m_xml=XMLString::transcode(c.c_str()); }
65 ~XMLStr() {
if (m_xml) XMLString::release(&m_xml); }
66 operator const XMLCh*()
const {
return m_xml; }
68 struct XMLTag :
public XMLStr {
70 XMLTag(CSTR
s) : XMLStr(s), m_str(s) { }
72 operator CSTR ()
const {
return m_str; }
75 bool operator==(CSTR
c,
const XMLTag& b) {
return c==b.m_str; }
76 struct XMLCollection {
78 XMLCollection(DOMNode* n,
bool use_children=
true) : m_node((DOMElement*)n) {
80 if ( m_node ) m_node = (DOMElement*)m_node->getFirstChild();
81 if ( m_node && m_node->getNodeType() != DOMNode::ELEMENT_NODE ) ++(*
this);
84 operator bool()
const {
return 0 != m_node; }
85 operator DOMNode* ()
const {
return m_node; }
86 operator DOMElement* ()
const {
return m_node; }
87 DOMElement* operator->()
const {
return m_node; }
88 string attr(
const XMLTag& tag)
const {
return _toString(m_node->getAttribute(tag));}
89 string attr(CSTR tag)
const {
return attr(XMLTag(tag)); }
90 string tag()
const {
return _toString(m_node->getTagName()); }
93 m_node = (DOMElement*)m_node->getNextSibling();
94 if ( m_node && m_node->getNodeType() == DOMNode::ELEMENT_NODE ) {
100 struct ErrHandler :
public ErrorHandler {
106 void resetErrors() { }
108 void warning(
const SAXParseException& ) { }
110 void error(
const SAXParseException& e);
112 void fatalError(
const SAXParseException& e);
113 virtual ~ErrHandler() {}
115 struct DTDRedirect :
public EntityResolver {
116 InputSource* resolveEntity(
const XMLCh*
const ,
const XMLCh*
const ) {
117 static const char* dtdID =
"redirectinmem.dtd";
118 static const char* dtd = \
120 <!ELEMENT POOLFILECATALOG (META*,File*)>\
121 <!ELEMENT META EMPTY>\
122 <!ELEMENT File (physical,logical,metadata*)>\
123 <!ATTLIST META name CDATA #REQUIRED>\
124 <!ATTLIST META type CDATA #REQUIRED>\
125 <!ELEMENT physical (pfn)+>\
126 <!ELEMENT logical (lfn)*>\
127 <!ELEMENT metadata EMPTY>\
128 <!ELEMENT lfn EMPTY>\
129 <!ELEMENT pfn EMPTY>\
130 <!ATTLIST File ID ID #REQUIRED>\
131 <!ATTLIST pfn name ID #REQUIRED>\
132 <!ATTLIST pfn filetype CDATA #IMPLIED>\
133 <!ATTLIST lfn name ID #REQUIRED>\
134 <!ATTLIST metadata att_name CDATA #REQUIRED>\
135 <!ATTLIST metadata att_value CDATA #REQUIRED>\
137 static const size_t len = strlen(dtd);
138 return new MemBufInputSource((
const XMLByte*)dtd,len,dtdID,
false);
140 virtual ~DTDRedirect() {}
143 void ErrHandler::error(
const SAXParseException& e) {
144 string m(_toString(e.getMessage()));
145 if (m.find(
"The values for attribute 'name' must be names or name tokens")!=string::npos ||
146 m.find(
"The values for attribute 'ID' must be names or name tokens")!=string::npos ||
147 m.find(
"for attribute 'name' must be Name or Nmtoken")!=string::npos ||
148 m.find(
"for attribute 'ID' must be Name or Nmtoken")!=string::npos ||
149 m.find(
"for attribute 'name' is invalid Name or NMTOKEN value")!=string::npos ||
150 m.find(
"for attribute 'ID' is invalid Name or NMTOKEN value")!=string::npos )
152 string sys(_toString(e.getSystemId()));
154 log <<
MSG::ERROR <<
"Error at file \"" << sys
155 <<
"\", line " << e.getLineNumber() <<
", column " << e.getColumnNumber() <<
endmsg
156 <<
"Message: " << m <<
endmsg;
158 void ErrHandler::fatalError(
const SAXParseException& e) {
160 string m(_toString(e.getMessage()));
161 string sys(_toString(e.getSystemId()));
162 log <<
MSG::ERROR <<
"Fatal Error at file \"" << sys
163 <<
"\", line " << e.getLineNumber() <<
", column " << e.getColumnNumber() <<
endmsg
164 <<
"Message: " << m <<
endmsg;
165 throw runtime_error(
"Standard pool exception : Fatal Error on the DOM Parser" );
168 const XMLTag EmptyCatalog(
"<!-- Edited By POOL -->\n"
169 "<!DOCTYPE POOLFILECATALOG SYSTEM \"InMemory\">\n"
170 "<POOLFILECATALOG>\n"
171 "</POOLFILECATALOG>\n");
172 const XMLTag PFNCOLL (
"physical");
173 const XMLTag LFNCOLL (
"logical");
174 const XMLTag PFNNODE (
"pfn");
175 const XMLTag LFNNODE (
"lfn");
176 const XMLTag Attr_type (
"type");
177 const XMLTag Attr_ID (
"ID");
178 const XMLTag Attr_name (
"name");
179 const XMLTag Attr_ftype (
"filetype");
180 const XMLTag MetaNode (
"metadata");
181 const XMLTag Attr_metaName (
"att_name");
182 const XMLTag Attr_metaValue (
"att_value");
188 ::uuid_generate_time(uuid);
191 unsigned short Data2;
192 unsigned short Data3;
193 unsigned char Data4[8];
196 boost::format text(
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X");
197 text %
g->Data1 %
g->Data2 %
g->Data3;
198 for (
int i = 0;
i < 8; ++
i)
199 text % (
unsigned short)
g->Data4[
i];
204 : m_rdOnly(false),m_update(false),m_doc(0),m_parser(0),m_errHdlr(0),
205 m_file(uri), m_msgSvc(m)
209 XMLFileCatalog::~XMLFileCatalog() {
210 if (m_parser)
delete m_parser;
212 if (m_errHdlr)
delete m_errHdlr;
222 DOMDocument* XMLFileCatalog::getDoc(
bool throw_if_no_exists)
const {
223 if ( !m_doc && throw_if_no_exists )
224 printError(
"The XML catalog was not started.",
true);
228 void XMLFileCatalog::printError(
CSTR msg,
bool rethrow)
const {
236 void XMLFileCatalog::init() {
237 string xmlFile = getfile(
false);
239 if ( m_parser )
delete m_parser;
240 m_parser =
new XercesDOMParser;
241 m_parser->setValidationScheme(XercesDOMParser::Val_Auto);
242 m_parser->setDoNamespaces(
false);
243 DTDRedirect dtdinmem;
244 m_parser->setEntityResolver(&dtdinmem);
245 if ( ! m_errHdlr ) m_errHdlr =
new ErrHandler(m_msgSvc);
246 m_parser->setErrorHandler(m_errHdlr);
247 if ( !xmlFile.empty() ) {
248 m_parser->parse(xmlFile.c_str());
252 MemBufInputSource src((
const XMLByte*)s.c_str(),s.length(),
"MemCatalog");
253 m_parser->parse(src);
255 m_doc = m_parser->getDocument();
257 catch (
const XMLException& e) {
258 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
260 catch (
const DOMException& e) {
261 printError(
"XML parse error["+xmlFile+
"]: "+_toString(e.getMessage()));
264 printError(
"UNKNOWN XML parse error in file "+xmlFile);
270 DOMNode* e = element(fid,
false);
271 e = e ? e->getParentNode() : 0;
272 e = e ? e->getParentNode() : 0;
274 if ( e->getAttributes() ) {
275 char* nam = XMLString::transcode(((DOMElement*)e)->getAttribute(Attr_ID));
276 if ( nam ) result = nam;
277 XMLString::release(&nam);
283 void XMLFileCatalog::getFID(Strings& fids)
const {
285 DOMNode* fde = getDoc(
true)->getElementsByTagName(XMLStr(
"*"))->item(0);
286 for(XMLCollection
c(child(fde,
"File"),
false);
c; ++
c)
287 fids.push_back(
c.attr(Attr_ID));
290 void XMLFileCatalog::getPFN(
CSTR fid, Files& files)
const {
292 for(XMLCollection
c(child(child(element(fid,
false),PFNCOLL),PFNNODE),
false);
c; ++
c)
293 files.push_back(
make_pair(
c.attr(Attr_name),
c.attr(Attr_ftype)));
296 void XMLFileCatalog::getLFN(
CSTR fid, Files& files)
const {
298 for(XMLCollection
c(child(child(element(fid,
false),LFNCOLL),LFNNODE),
false);
c; ++
c)
299 files.push_back(
make_pair(
c.attr(Attr_name),fid));
302 void XMLFileCatalog::getMetaData(
CSTR fid, Attributes& attr)
const {
304 for(XMLCollection
c(child(element(fid),MetaNode),
false);
c; ++
c)
305 attr.push_back(
make_pair(
c.attr(Attr_metaName),
c.attr(Attr_metaValue)));
306 if ( attr.size() > 0 )
311 for(XMLCollection
c(par);
c; ++
c ) {
312 if(
c.tag() == tag ) {
313 if( !attr.empty() &&
c.attr(attr) != val)
continue;
320 void XMLFileCatalog::setMetaData(
CSTR fid,
CSTR attr,
CSTR val)
const {
322 DOMNode* node = element(fid);
323 DOMElement* mnod = (DOMElement*)child(node,MetaNode,Attr_metaName,attr);
325 mnod = getDoc(
true)->createElement(MetaNode);
326 node->appendChild(mnod);
327 mnod->setAttribute(Attr_metaName,XMLStr(attr));
329 mnod->setAttribute(Attr_metaValue,XMLStr(val));
333 printError(
"Cannot update readonly catalog!");
336 string XMLFileCatalog::getMetaDataItem(
CSTR fid,
CSTR attr)
const {
337 XMLCollection
c(child(getDoc(
true)->getElementById(XMLStr(fid)),MetaNode,Attr_metaName,attr));
338 return c ? c.attr(attr) :
string(
"");
341 void XMLFileCatalog::dropMetaData(
CSTR fid,
CSTR attr)
const {
343 DOMNode* fn = getDoc(
true)->getElementById(XMLStr(fid));
344 for(XMLCollection
c(child(fn,MetaNode));
c; ++
c)
345 if ( attr[0]==
'*' || !
c.attr(attr).empty() ) gbc.
push_back(
c);
350 DOMNode* XMLFileCatalog::element(
CSTR element_name,
bool print_err)
const {
351 DOMNode* node = getDoc(
true)->getElementById(XMLStr(element_name));
352 if ( !node && print_err ) printError(
"Cannot find element:"+element_name);
356 void XMLFileCatalog::deleteFID(
CSTR fid)
const {
357 DOMNode *pn = 0, *fn = element(fid);
358 if ( fn ) pn = fn->getParentNode();
359 if ( pn ) pn->removeChild(fn);
362 void XMLFileCatalog::registerFID(
CSTR fid)
const {
363 if ( !fid.empty() ) {
366 printError(
"Failed to register FID:"+fid);
370 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
376 DOMElement *
file = (DOMElement*)element(fid,
false), *phyelem = 0, *logelem = 0;
377 DOMDocument* doc = getDoc(
true);
379 DOMNode* fde = doc->getElementsByTagName(XMLStr(
"*"))->item(0);
380 file = m_doc->createElement(XMLStr(
"File"));
381 file->setAttribute(Attr_ID, XMLStr(fid));
382 file->setIdAttribute(Attr_ID,
true);
383 fde->appendChild(file);
386 for(XMLCollection c1(file); c1; ++c1 ) {
387 char* nam = XMLString::transcode(c1->getNodeName());
388 if ( nam == PFNCOLL ) phyelem = c1;
389 if ( nam == LFNCOLL ) logelem = c1;
390 XMLString::release(&nam);
393 phyelem = doc->createElement(PFNCOLL);
394 file->appendChild(phyelem);
398 logelem = doc->createElement(LFNCOLL);
399 file->appendChild(logelem);
404 printError(
"Cannot update readonly catalog!");
408 void XMLFileCatalog::registerPFN(
CSTR fid,
CSTR pfn,
CSTR ftype)
const {
409 if ( !fid.empty() ) {
411 DOMElement* phyelem = res.
second, *fnelem = 0;
412 for(XMLCollection
c(phyelem);
c; ++
c ) {
413 char* nam = XMLString::transcode(
c->getNodeName());
414 if ( nam == PFNNODE ) {
415 XMLString::release(&nam);
416 nam = XMLString::transcode(
c->getAttribute(Attr_name));
418 XMLString::release(&nam);
423 XMLString::release(&nam);
426 fnelem = getDoc(
true)->createElement(PFNNODE);
427 phyelem->appendChild(fnelem);
428 fnelem->setAttribute(Attr_ftype,XMLStr(ftype));
429 fnelem->setAttribute(Attr_name,XMLStr(pfn));
430 fnelem->setIdAttribute(Attr_name,
true);
435 throw runtime_error(
"XMLFileCatalog> Cannot register PFN for invalid FID:"+fid);
438 void XMLFileCatalog::registerLFN(
CSTR fid,
CSTR lfn)
const {
439 if ( !fid.empty() ) {
441 DOMElement* logelem = res.
first, *fnelem = 0;
442 for(XMLCollection
c(logelem);
c; ++
c ) {
443 char* nam = XMLString::transcode(
c->getNodeName());
444 if ( nam == LFNNODE ) {
445 XMLString::release(&nam);
446 nam = XMLString::transcode(
c->getAttribute(Attr_name));
448 XMLString::release(&nam);
455 fnelem = getDoc(
true)->createElement(LFNNODE);
456 logelem->appendChild(fnelem);
457 fnelem->setAttribute(Attr_name,XMLStr(lfn));
458 fnelem->setIdAttribute(Attr_name,
true);
463 throw runtime_error(
"XMLFileCatalog> Cannot register LFN for invalid FID:"+fid);
466 void XMLFileCatalog::commit() {
468 if ( dirty() && !readOnly() ) {
469 string xmlfile = getfile(
true);
471 DOMImplementation *imp = DOMImplementationRegistry::getDOMImplementation(ii);
472 XMLFormatTarget *tar =
new LocalFileFormatTarget(xmlfile.c_str());
473 #if _XERCES_VERSION <= 30000
474 DOMWriter *wr = imp->createDOMWriter();
475 wr->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint,
true);
476 wr->writeNode(tar, *m_doc);
479 DOMLSOutput *output = imp->createLSOutput();
480 output->setByteStream(tar);
481 DOMLSSerializer *wr = imp->createLSSerializer();
482 wr->getDomConfig()->setParameter(XMLStr(
"format-pretty-print"),
true);
483 wr->write(m_doc, output);
491 printError(
string(
"Cannot open output file:")+e.
what());
494 printError(
"Unknown IO rrror.");
498 string XMLFileCatalog::getfile(
bool create) {
499 string protocol,
path;
502 xerurl = (
const XMLCh*)XMLStr(m_file);
503 protocol = _toString(xerurl.getProtocolName());
504 path = _toString(xerurl.getPath());
506 catch (
const XMLException& e ) {
507 printError(_toString(e.getMessage()));
509 if ( protocol.empty() ) {
510 printError(
"Missing protocol.");
512 else if ( protocol ==
"http" || protocol ==
"ftp" ) {
515 else if ( protocol ==
"file" ) {
518 int exist = ::stat(path.c_str(),&buff) != -1;
519 if ( create && !exist ) {
521 log <<
MSG::INFO <<
"File '" << path <<
"' does not exist. New file created." <<
endmsg;
523 if( !m_rdOnly && out.is_open() ) {
527 printError(
"Problem creating file "+path);
534 else if ( !create ) {
539 printError(protocol +
": protocol not supported.");