static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
static const XMLCh reloadChanges[] = UNICODE_LITERAL_13(r,e,l,o,a,d,C,h,a,n,g,e,s);
static const XMLCh reloadInterval[] = UNICODE_LITERAL_14(r,e,l,o,a,d,I,n,t,e,r,v,a,l);
+static const XMLCh maxRefreshDelay[] = UNICODE_LITERAL_15(m,a,x,R,e,f,r,e,s,h,D,e,l,a,y);
static const XMLCh backingFilePath[] = UNICODE_LITERAL_15(b,a,c,k,i,n,g,F,i,l,e,P,a,t,h);
static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e);
static const XMLCh certificate[] = UNICODE_LITERAL_11(c,e,r,t,i,f,i,c,a,t,e);
static const XMLCh _CredentialResolver[] = UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);
-ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e, Category& log)
- : m_root(e), m_local(true), m_validate(false), m_backupIndicator(true), m_filestamp(0), m_reloadInterval(0), m_lock(nullptr), m_log(log),
+ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e, Category& log, bool startReloadThread)
+ : m_root(e), m_local(true), m_validate(false), m_filestamp(0), m_reloadInterval(0),
+ m_lock(nullptr), m_loaded(false), m_log(log),
#ifndef XMLTOOLING_LITE
- m_credResolver(nullptr), m_trust(nullptr),
+ m_credResolver(nullptr), m_trust(nullptr),
#endif
- m_shutdown(false), m_reload_wait(nullptr), m_reload_thread(nullptr)
+ m_shutdown(false), m_reload_wait(nullptr), m_reload_thread(nullptr)
{
#ifdef _DEBUG
NDC ndc("ReloadableXMLFile");
log.debug("backup remote resource to (%s)", m_backing.c_str());
}
source = e->getAttributeNS(nullptr,reloadInterval);
+ if (!source || !*source)
+ source = e->getAttributeNS(nullptr,maxRefreshDelay);
if (source && *source) {
m_reloadInterval = XMLString::parseInt(source);
if (m_reloadInterval > 0) {
m_filestamp = time(nullptr); // assume it gets loaded initially
}
- if (m_lock) {
- m_reload_wait = CondWait::create();
- m_reload_thread = Thread::create(&reload_fn, this);
- }
+ if (startReloadThread)
+ startup();
}
else {
log.debug("no resource uri/path/name supplied, will load inline configuration");
delete m_lock;
}
+void ReloadableXMLFile::startup()
+{
+ if (m_lock && !m_reload_thread) {
+ m_reload_wait = CondWait::create();
+ m_reload_thread = Thread::create(&reload_fn, this);
+ }
+}
+
void ReloadableXMLFile::shutdown()
{
if (m_reload_thread) {
}
#endif
-
- if (!backup && !m_backing.empty()) {
- // If the indicator is true, we're responsible for the backup.
- if (m_backupIndicator) {
- m_log.debug("backing up remote resource to (%s)", m_backing.c_str());
- try {
- Locker locker(getBackupLock());
- ofstream backer(m_backing.c_str());
- backer << *doc;
- }
- catch (exception& ex) {
- m_log.crit("exception while backing up resource: %s", ex.what());
- }
- }
- else {
- // If the indicator was false, set true to signal that a backup is needed.
- // The caller will presumably flip it back to false once that's done.
- m_backupIndicator = true;
- }
- }
-
return make_pair(true, doc->getDocumentElement());
}
}
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 resource ("
<< (m_source.empty() ? "inline" : (backup ? m_backing : m_source)) << "): " << e.what() << logging::eol;
- if (!backup && !m_backing.empty())
+ throw;
+ }
+}
+
+pair<bool,DOMElement*> ReloadableXMLFile::load()
+{
+ // If this method is used, we're responsible for managing failover to a
+ // backup of a remote resource (if available), and for backing up remote
+ // resources.
+ try {
+ pair<bool,DOMElement*> ret = load(false);
+ if (!m_backing.empty()) {
+ m_log.debug("backing up remote resource to (%s)", m_backing.c_str());
+ try {
+ Locker locker(getBackupLock());
+ ofstream backer(m_backing.c_str());
+ backer << *(ret.second->getOwnerDocument());
+ }
+ catch (exception& ex) {
+ m_log.crit("exception while backing up resource: %s", ex.what());
+ }
+ }
+ return ret;
+ }
+ catch (long&) {
+ // If there's an HTTP error or the document hasn't changed,
+ // use the backup iff we have no "valid" resource in place.
+ // That prevents reload of the backup copy any time the document
+ // hasn't changed.
+ if (!m_loaded && !m_backing.empty())
+ return load(true);
+ throw;
+ }
+ catch (exception&) {
+ // Same as above, but for general load/parse errors.
+ if (!m_loaded && !m_backing.empty())
return load(true);
throw;
}
}
+pair<bool,DOMElement*> ReloadableXMLFile::background_load()
+{
+ // If this method isn't overridden, we acquire a write lock
+ // and just call the old override.
+ if (m_lock)
+ m_lock->wrlock();
+ SharedLock locker(m_lock, false);
+ return load();
+}
+
+Lockable* ReloadableXMLFile::getBackupLock()
+{
+ return &XMLToolingConfig::getConfig();
+}
+
#ifndef XMLTOOLING_LITE
void ReloadableXMLFile::validateSignature(Signature& sigObj) const
}
#endif
-
-pair<bool,DOMElement*> ReloadableXMLFile::load()
-{
- return load(false);
-}
-
-pair<bool,DOMElement*> ReloadableXMLFile::background_load()
-{
- // If this method isn't overridden, we acquire a write lock
- // and just call the old override.
- if (m_lock)
- m_lock->wrlock();
- SharedLock locker(m_lock, false);
- return load();
-}
-
-Lockable* ReloadableXMLFile::getBackupLock()
-{
- return &XMLToolingConfig::getConfig();
-}
* <dd>use a validating parser</dd>
* <dt>reloadChanges</dt>
* <dd>enables monitoring of local file for changes</dd>
- * <dt>reloadInterval</dt>
+ * <dt>reloadInterval or maxRefreshDelay</dt>
* <dd>enables periodic refresh of remote file</dd>
* <dt>backingFilePath</dt>
* <dd>location for backup of remote resource</dd>
* <dd>requires XML be signed with an enveloped signature verifiable with specified TrustEngine</dd>
* </dl>
*
- * @param e DOM to supply configuration
- * @param log logging object to use
+ * @param e DOM to supply configuration
+ * @param log logging object to use
+ * @param startReloadThread true iff refresh thread for resources should be started by constructor
*/
- ReloadableXMLFile(const xercesc::DOMElement* e, logging::Category& log);
+ ReloadableXMLFile(const xercesc::DOMElement* e, logging::Category& log, bool startReloadThread=true);
virtual ~ReloadableXMLFile();
virtual std::pair<bool,xercesc::DOMElement*> background_load();
/**
+ * @deprecated
* Basic load/parse of configuration material.
*
* <p>The base version performs basic parsing duties and returns the result.
virtual std::pair<bool,xercesc::DOMElement*> load();
/**
+ * Basic load/parse of configuration material.
+ *
+ * <p>The base version performs basic parsing duties and returns the result.
+ * Subclasses should override the new background_load() method and perform
+ * their own locking in conjunction with use of this method.
+ *
+ * <p>This version allows subclasses to explicitly control the use of a
+ * backup for remote resources, which allows additional validation to be
+ * performed besides just successful XML parsing.
+ *
+ * @param backup true iff the backup source should be loaded
+ * @return a pair consisting of a flag indicating whether to take ownership of
+ * the document, and the root element of the tree to load
+ */
+ virtual std::pair<bool,xercesc::DOMElement*> load(bool backup);
+
+ /**
* Accesses a lock interface protecting use of backup file associated with the
* object.
*
virtual Lockable* getBackupLock();
/**
+ * Starts up reload thread, can be automatically called by constructor, or
+ * manually invoked by subclass.
+ */
+ void startup();
+
+ /**
* Shuts down reload thread, should be called from subclass destructor.
*/
void shutdown();
/** Path to backup copy for remote resource. */
std::string m_backing;
- /**
- * Before load, indicates whether the backup is handled by the base class,
- * after load, will be true iff it started false and a backup needs to be done.
- */
- bool m_backupIndicator;
-
/** Last modification of local resource. */
time_t m_filestamp;
/** Plugin identifier. */
std::string m_id;
+ /** Indicates whether a usable version of the resource is in place. */
+ bool m_loaded;
+
#ifndef XMLTOOLING_LITE
/** CredentialResolver for signature verification. */
CredentialResolver* m_credResolver;
void unlock();
private:
- std::pair<bool,xercesc::DOMElement*> load(bool backup);
#ifndef XMLTOOLING_LITE
void validateSignature(xmlsignature::Signature& sigObj) const;
#endif