-\r
-ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e, Category& log)\r
- : m_root(e), m_local(true), m_validate(false), m_filestamp(0), m_reloadInterval(0), m_lock(NULL), m_log(log)\r
-{\r
-#ifdef _DEBUG\r
- NDC ndc("ReloadableXMLFile");\r
-#endif\r
-\r
- // Establish source of data...\r
- const XMLCh* source=e->getAttributeNS(NULL,uri);\r
- if (!source || !*source) {\r
- source=e->getAttributeNS(NULL,url);\r
- if (!source || !*source) {\r
- source=e->getAttributeNS(NULL,path);\r
- if (!source || !*source) {\r
- source=e->getAttributeNS(NULL,pathname);\r
- if (!source || !*source) {\r
- source=e->getAttributeNS(NULL,file);\r
- if (!source || !*source) {\r
- source=e->getAttributeNS(NULL,filename);\r
- }\r
- }\r
- }\r
- }\r
- else\r
- m_local=false;\r
- }\r
- else\r
- m_local=false;\r
-\r
- if (source && *source) {\r
- const XMLCh* flag=e->getAttributeNS(NULL,validate);\r
- m_validate=(XMLString::equals(flag,xmlconstants::XML_TRUE) || XMLString::equals(flag,xmlconstants::XML_ONE));\r
-\r
- auto_ptr_char temp(source);\r
- m_source=temp.get();\r
-\r
- if (!m_local && !strstr(m_source.c_str(),"://")) {\r
- log.warn("deprecated usage of uri/url attribute for a local resource, use path instead");\r
- m_local=true;\r
- }\r
-\r
- if (m_local) {\r
- XMLToolingConfig::getConfig().getPathResolver()->resolve(m_source, PathResolver::XMLTOOLING_CFG_FILE);\r
-\r
- flag=e->getAttributeNS(NULL,reloadChanges);\r
- if (!XMLString::equals(flag,xmlconstants::XML_FALSE) && !XMLString::equals(flag,xmlconstants::XML_ZERO)) {\r
-#ifdef WIN32\r
- struct _stat stat_buf;\r
- if (_stat(m_source.c_str(), &stat_buf) == 0)\r
-#else\r
- struct stat stat_buf;\r
- if (stat(m_source.c_str(), &stat_buf) == 0)\r
-#endif\r
- m_filestamp=stat_buf.st_mtime;\r
- else\r
- throw IOException("Unable to access local file ($1)", params(1,m_source.c_str()));\r
- m_lock=RWLock::create();\r
- }\r
- log.debug("using local resource (%s), will %smonitor for changes", m_source.c_str(), m_lock ? "" : "not ");\r
- }\r
- else {\r
- log.debug("using remote resource (%s)", m_source.c_str());\r
- source = e->getAttributeNS(NULL,backingFilePath);\r
- if (source && *source) {\r
- auto_ptr_char temp2(source);\r
- m_backing=temp2.get();\r
- XMLToolingConfig::getConfig().getPathResolver()->resolve(m_backing, PathResolver::XMLTOOLING_RUN_FILE);\r
- log.debug("backup remote resource with (%s)", m_backing.c_str());\r
- }\r
- source = e->getAttributeNS(NULL,reloadInterval);\r
- if (source && *source) {\r
- m_reloadInterval = XMLString::parseInt(source);\r
- if (m_reloadInterval > 0) {\r
- m_log.debug("will reload remote resource at most every %d seconds", m_reloadInterval);\r
- m_lock=RWLock::create();\r
- }\r
- }\r
- m_filestamp = time(NULL); // assume it gets loaded initially\r
- }\r
- }\r
- else {\r
- log.debug("no resource uri/path/name supplied, will load inline configuration");\r
- }\r
-}\r
-\r
-pair<bool,DOMElement*> ReloadableXMLFile::load(bool backup)\r
-{\r
-#ifdef _DEBUG\r
- NDC ndc("init");\r
-#endif\r
-\r
- try {\r
- if (m_source.empty()) {\r
- // Data comes from the DOM we were handed.\r
- m_log.debug("loading inline configuration...");\r
- return make_pair(false,XMLHelper::getFirstChildElement(m_root));\r
- }\r
- else {\r
- // Data comes from a file we have to parse.\r
- if (backup)\r
- m_log.warn("using local backup of remote resource");\r
- else\r
- m_log.debug("loading configuration from external resource...");\r
-\r
- DOMDocument* doc=NULL;\r
- if (m_local || backup) {\r
- auto_ptr_XMLCh widenit(backup ? m_backing.c_str() : m_source.c_str());\r
- LocalFileInputSource src(widenit.get());\r
- Wrapper4InputSource dsrc(&src,false);\r
- if (m_validate)\r
- doc=XMLToolingConfig::getConfig().getValidatingParser().parse(dsrc);\r
- else\r
- doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);\r
- }\r
- else {\r
- URLInputSource src(m_root);\r
- Wrapper4InputSource dsrc(&src,false);\r
- if (m_validate)\r
- doc=XMLToolingConfig::getConfig().getValidatingParser().parse(dsrc);\r
- else\r
- doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);\r
- }\r
-\r
- m_log.infoStream() << "loaded XML resource (" << (backup ? m_backing : m_source) << ")" << logging::eol;\r
-\r
- if (!backup && !m_backing.empty()) {\r
- m_log.debug("backing up remote resource to (%s)", m_backing.c_str());\r
- try {\r
- ofstream backer(m_backing.c_str());\r
- backer << *doc;\r
- }\r
- catch (exception& ex) {\r
- m_log.crit("exception while backing up resource: %s", ex.what());\r
- }\r
- }\r
-\r
- return make_pair(true,doc->getDocumentElement());\r
- }\r
- }\r
- catch (XMLException& e) {\r
- auto_ptr_char msg(e.getMessage());\r
- m_log.errorStream() << "Xerces error while loading resource (" << (backup ? m_backing : m_source) << "): "\r
- << msg.get() << logging::eol;\r
- if (!backup && !m_backing.empty())\r
- return load(true);\r
- throw XMLParserException(msg.get());\r
- }\r
- catch (exception& e) {\r
- m_log.errorStream() << "error while loading configuration from ("\r
- << (m_source.empty() ? "inline" : (backup ? m_backing : m_source)) << "): " << e.what() << logging::eol;\r
- if (!backup && !m_backing.empty())\r
- return load(true);\r
- throw;\r
- }\r
-}\r
-\r
-Lockable* ReloadableXMLFile::lock()\r
-{\r
- if (!m_lock)\r
- return this;\r
-\r
- m_lock->rdlock();\r
-\r
- // Check if we need to refresh.\r
- if (m_local) {\r
-#ifdef WIN32\r
- struct _stat stat_buf;\r
- if (_stat(m_source.c_str(), &stat_buf) != 0)\r
- return this;\r
-#else\r
- struct stat stat_buf;\r
- if (stat(m_source.c_str(), &stat_buf) != 0)\r
- return this;\r
-#endif\r
- if (m_filestamp>=stat_buf.st_mtime)\r
- return this;\r
-\r
- // Elevate lock and recheck.\r
- m_log.debug("timestamp of local resource changed, elevating to a write lock");\r
- m_lock->unlock();\r
- m_lock->wrlock();\r
- if (m_filestamp>=stat_buf.st_mtime) {\r
- // Somebody else handled it, just downgrade.\r
- m_log.debug("update of local resource handled by another thread, downgrading lock");\r
- m_lock->unlock();\r
- m_lock->rdlock();\r
- return this;\r
- }\r
-\r
- // Update the timestamp regardless. No point in repeatedly trying.\r
- m_filestamp=stat_buf.st_mtime;\r
- m_log.info("change detected, reloading local resource...");\r
- }\r
- else {\r
- time_t now = time(NULL);\r
-\r
- // Time to reload? If we have no data, filestamp is zero\r
- // and there's no way current time is less than the interval.\r
- if (now - m_filestamp < m_reloadInterval)\r
- return this;\r
-\r
- // Elevate lock and recheck.\r
- m_log.debug("reload interval for remote resource elapsed, elevating to a write lock");\r
- m_lock->unlock();\r
- m_lock->wrlock();\r
- if (now - m_filestamp < m_reloadInterval) {\r
- // Somebody else handled it, just downgrade.\r
- m_log.debug("update of remote resource handled by another thread, downgrading lock");\r
- m_lock->unlock();\r
- m_lock->rdlock();\r
- return this;\r
- }\r
-\r
- m_filestamp = now;\r
- m_log.info("reloading remote resource...");\r
- }\r
-\r
- // Do this once...\r
- try {\r
- // At this point we're holding the write lock, so make sure we pop it.\r
- SharedLock lockwrap(m_lock,false);\r
- pair<bool,DOMElement*> ret=load();\r
- if (ret.first)\r
- ret.second->getOwnerDocument()->release();\r
- } catch (exception& ex) {\r
- m_log.crit("maintaining existing configuration, error reloading resource (%s): %s", m_source.c_str(), ex.what());\r
- }\r
-\r
- // If we made it here, the swap may or may not have worked, but we need to relock.\r
- m_log.debug("attempt to update resource complete, relocking");\r
- m_lock->rdlock();\r
- return this;\r
-}\r
-\r
+
+ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e, Category& log)
+ : m_root(e), m_local(true), m_validate(false), m_filestamp(0), m_reloadInterval(0), m_lock(NULL), m_log(log)
+{
+#ifdef _DEBUG
+ NDC ndc("ReloadableXMLFile");
+#endif
+
+ // Establish source of data...
+ const XMLCh* source=e->getAttributeNS(NULL,uri);
+ if (!source || !*source) {
+ source=e->getAttributeNS(NULL,url);
+ if (!source || !*source) {
+ source=e->getAttributeNS(NULL,path);
+ if (!source || !*source) {
+ source=e->getAttributeNS(NULL,pathname);
+ if (!source || !*source) {
+ source=e->getAttributeNS(NULL,file);
+ if (!source || !*source) {
+ source=e->getAttributeNS(NULL,filename);
+ }
+ }
+ }
+ }
+ else
+ m_local=false;
+ }
+ else
+ m_local=false;
+
+ if (source && *source) {
+ const XMLCh* flag=e->getAttributeNS(NULL,validate);
+ m_validate=(XMLString::equals(flag,xmlconstants::XML_TRUE) || XMLString::equals(flag,xmlconstants::XML_ONE));
+
+ auto_ptr_char temp(source);
+ m_source=temp.get();
+
+ if (!m_local && !strstr(m_source.c_str(),"://")) {
+ log.warn("deprecated usage of uri/url attribute for a local resource, use path instead");
+ m_local=true;
+ }
+
+ if (m_local) {
+ XMLToolingConfig::getConfig().getPathResolver()->resolve(m_source, PathResolver::XMLTOOLING_CFG_FILE);
+
+ flag=e->getAttributeNS(NULL,reloadChanges);
+ if (!XMLString::equals(flag,xmlconstants::XML_FALSE) && !XMLString::equals(flag,xmlconstants::XML_ZERO)) {
+#ifdef WIN32
+ struct _stat stat_buf;
+ if (_stat(m_source.c_str(), &stat_buf) == 0)
+#else
+ struct stat stat_buf;
+ if (stat(m_source.c_str(), &stat_buf) == 0)
+#endif
+ m_filestamp=stat_buf.st_mtime;
+ else
+ throw IOException("Unable to access local file ($1)", params(1,m_source.c_str()));
+ m_lock=RWLock::create();
+ }
+ log.debug("using local resource (%s), will %smonitor for changes", m_source.c_str(), m_lock ? "" : "not ");
+ }
+ else {
+ log.debug("using remote resource (%s)", m_source.c_str());
+ source = e->getAttributeNS(NULL,backingFilePath);
+ if (source && *source) {
+ auto_ptr_char temp2(source);
+ m_backing=temp2.get();
+ XMLToolingConfig::getConfig().getPathResolver()->resolve(m_backing, PathResolver::XMLTOOLING_RUN_FILE);
+ log.debug("backup remote resource with (%s)", m_backing.c_str());
+ }
+ source = e->getAttributeNS(NULL,reloadInterval);
+ if (source && *source) {
+ m_reloadInterval = XMLString::parseInt(source);
+ if (m_reloadInterval > 0) {
+ m_log.debug("will reload remote resource at most every %d seconds", m_reloadInterval);
+ m_lock=RWLock::create();
+ }
+ }
+ m_filestamp = time(NULL); // assume it gets loaded initially
+ }
+ }
+ else {
+ log.debug("no resource uri/path/name supplied, will load inline configuration");
+ }
+}
+
+pair<bool,DOMElement*> ReloadableXMLFile::load(bool backup)
+{
+#ifdef _DEBUG
+ NDC ndc("init");
+#endif
+
+ try {
+ if (m_source.empty()) {
+ // Data comes from the DOM we were handed.
+ m_log.debug("loading inline configuration...");
+ return make_pair(false,XMLHelper::getFirstChildElement(m_root));
+ }
+ else {
+ // Data comes from a file we have to parse.
+ if (backup)
+ m_log.warn("using local backup of remote resource");
+ else
+ m_log.debug("loading configuration from external resource...");
+
+ DOMDocument* doc=NULL;
+ if (m_local || backup) {
+ auto_ptr_XMLCh widenit(backup ? m_backing.c_str() : m_source.c_str());
+ LocalFileInputSource src(widenit.get());
+ Wrapper4InputSource dsrc(&src,false);
+ if (m_validate)
+ doc=XMLToolingConfig::getConfig().getValidatingParser().parse(dsrc);
+ else
+ doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
+ }
+ else {
+ URLInputSource src(m_root);
+ Wrapper4InputSource dsrc(&src,false);
+ if (m_validate)
+ doc=XMLToolingConfig::getConfig().getValidatingParser().parse(dsrc);
+ else
+ doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
+ }
+
+ m_log.infoStream() << "loaded XML resource (" << (backup ? m_backing : m_source) << ")" << logging::eol;
+
+ if (!backup && !m_backing.empty()) {
+ m_log.debug("backing up remote resource to (%s)", m_backing.c_str());
+ try {
+ ofstream backer(m_backing.c_str());
+ backer << *doc;
+ }
+ catch (exception& ex) {
+ m_log.crit("exception while backing up resource: %s", ex.what());
+ }
+ }
+
+ return make_pair(true,doc->getDocumentElement());
+ }
+ }
+ catch (XMLException& e) {
+ auto_ptr_char msg(e.getMessage());
+ m_log.errorStream() << "Xerces error while loading resource (" << (backup ? m_backing : m_source) << "): "
+ << msg.get() << logging::eol;
+ if (!backup && !m_backing.empty())
+ return load(true);
+ throw XMLParserException(msg.get());
+ }
+ catch (exception& e) {
+ m_log.errorStream() << "error while loading configuration from ("
+ << (m_source.empty() ? "inline" : (backup ? m_backing : m_source)) << "): " << e.what() << logging::eol;
+ if (!backup && !m_backing.empty())
+ return load(true);
+ throw;
+ }
+}
+
+Lockable* ReloadableXMLFile::lock()
+{
+ if (!m_lock)
+ return this;
+
+ m_lock->rdlock();
+
+ // Check if we need to refresh.
+ if (m_local) {
+#ifdef WIN32
+ struct _stat stat_buf;
+ if (_stat(m_source.c_str(), &stat_buf) != 0)
+ return this;
+#else
+ struct stat stat_buf;
+ if (stat(m_source.c_str(), &stat_buf) != 0)
+ return this;
+#endif
+ if (m_filestamp>=stat_buf.st_mtime)
+ return this;
+
+ // Elevate lock and recheck.
+ m_log.debug("timestamp of local resource changed, elevating to a write lock");
+ m_lock->unlock();
+ m_lock->wrlock();
+ if (m_filestamp>=stat_buf.st_mtime) {
+ // Somebody else handled it, just downgrade.
+ m_log.debug("update of local resource handled by another thread, downgrading lock");
+ m_lock->unlock();
+ m_lock->rdlock();
+ return this;
+ }
+
+ // Update the timestamp regardless. No point in repeatedly trying.
+ m_filestamp=stat_buf.st_mtime;
+ m_log.info("change detected, reloading local resource...");
+ }
+ else {
+ time_t now = time(NULL);
+
+ // Time to reload? If we have no data, filestamp is zero
+ // and there's no way current time is less than the interval.
+ if (now - m_filestamp < m_reloadInterval)
+ return this;
+
+ // Elevate lock and recheck.
+ m_log.debug("reload interval for remote resource elapsed, elevating to a write lock");
+ m_lock->unlock();
+ m_lock->wrlock();
+ if (now - m_filestamp < m_reloadInterval) {
+ // Somebody else handled it, just downgrade.
+ m_log.debug("update of remote resource handled by another thread, downgrading lock");
+ m_lock->unlock();
+ m_lock->rdlock();
+ return this;
+ }
+
+ m_filestamp = now;
+ m_log.info("reloading remote resource...");
+ }
+
+ // Do this once...
+ try {
+ // At this point we're holding the write lock, so make sure we pop it.
+ SharedLock lockwrap(m_lock,false);
+ pair<bool,DOMElement*> ret=load();
+ if (ret.first)
+ ret.second->getOwnerDocument()->release();
+ } catch (exception& ex) {
+ m_log.crit("maintaining existing configuration, error reloading resource (%s): %s", m_source.c_str(), ex.what());
+ }
+
+ // If we made it here, the swap may or may not have worked, but we need to relock.
+ m_log.debug("attempt to update resource complete, relocking");
+ m_lock->rdlock();
+ return this;
+}
+