From: cantor Date: Fri, 4 May 2007 03:15:06 +0000 (+0000) Subject: Pulled out curl accessor, doesn't seem to work anyway. X-Git-Tag: 1.4.1~523 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fxmltooling.git;a=commitdiff_plain;h=5ffbbf4ed5b10785a3ce058c998c5c1b7dbfa889 Pulled out curl accessor, doesn't seem to work anyway. Rework XML resource loader with file backup and time-based reloading. git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/trunk@300 de75baf8-a10c-0410-a50a-987c0e22f00f --- diff --git a/xmltooling/Makefile.am b/xmltooling/Makefile.am index a930ab2..080f2cf 100644 --- a/xmltooling/Makefile.am +++ b/xmltooling/Makefile.am @@ -88,8 +88,6 @@ soapinclude_HEADERS = \ soap/OpenSSLSOAPTransport.h utilinclude_HEADERS = \ - util/CurlNetAccessor.h \ - util/CurlURLInputStream.h \ util/DateTime.h \ util/NDC.h \ util/ParserPool.h \ @@ -164,8 +162,6 @@ libxmltooling_la_SOURCES = \ soap/impl/SOAPImpl.cpp \ soap/impl/SOAPSchemaValidators.cpp \ soap/impl/CURLSOAPTransport.cpp \ - util/CurlNetAccessor.cpp \ - util/CurlURLInputStream.cpp \ util/DateTime.cpp \ util/NDC.cpp \ util/ParserPool.cpp \ diff --git a/xmltooling/XMLToolingConfig.cpp b/xmltooling/XMLToolingConfig.cpp index e192b75..f1e929e 100644 --- a/xmltooling/XMLToolingConfig.cpp +++ b/xmltooling/XMLToolingConfig.cpp @@ -32,7 +32,6 @@ #include "signature/Signature.h" #include "soap/SOAP.h" #include "soap/SOAPTransport.h" -#include "util/CurlNetAccessor.h" #include "util/NDC.h" #include "util/ReplayCache.h" #include "util/StorageService.h" @@ -202,9 +201,6 @@ bool XMLToolingInternalConfig::init() log.debug("libcurl %s initialization complete", LIBCURL_VERSION); XMLPlatformUtils::Initialize(); - auto_ptr curler(new CurlNetAccessor()); - delete XMLPlatformUtils::fgNetAccessor; - XMLPlatformUtils::fgNetAccessor = curler.release(); log.debug("Xerces initialization complete"); #ifndef XMLTOOLING_NO_XMLSEC diff --git a/xmltooling/util/CurlNetAccessor.cpp b/xmltooling/util/CurlNetAccessor.cpp deleted file mode 100644 index 505e9d0..0000000 --- a/xmltooling/util/CurlNetAccessor.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * $Id: CurlNetAccessor.cpp 471747 2006-11-06 14:31:56Z amassari $ - */ - -#include "internal.h" -#include "util/CurlURLInputStream.h" -#include "util/CurlNetAccessor.h" - -#include -#include -#include -#include - -using namespace xmltooling; - -const XMLCh CurlNetAccessor::fgMyName[] = -{ - chLatin_C, chLatin_u, chLatin_r, chLatin_l, chLatin_N, chLatin_e, - chLatin_t, chLatin_A, chLatin_c, chLatin_c, chLatin_e, chLatin_s, - chLatin_s, chLatin_o, chLatin_r, chNull -}; - - -BinInputStream* -CurlNetAccessor::makeNew(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/) -{ - // Just create a CurlURLInputStream - // We defer any checking of the url type for curl in CurlURLInputStream - CurlURLInputStream* retStrm = - new (urlSource.getMemoryManager()) CurlURLInputStream(urlSource, httpInfo); - return retStrm; -} diff --git a/xmltooling/util/CurlNetAccessor.h b/xmltooling/util/CurlNetAccessor.h deleted file mode 100644 index 523da70..0000000 --- a/xmltooling/util/CurlNetAccessor.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * $Id: CurlNetAccessor.hpp 527149 2007-04-10 14:56:39Z amassari $ - */ - -#if !defined(XERCESC_INCLUDE_GUARD_CURLNETACCESSOR_HPP) -#define XERCESC_INCLUDE_GUARD_CURLNETACCESSOR_HPP - - -#include -#include -#include -#include - -namespace xmltooling { - -// -// This class is the wrapper for the socket based code which -// provides the ability to fetch a resource specified using -// a HTTP or FTP URL. -// - -class XMLTOOL_DLLLOCAL CurlNetAccessor : public XMLNetAccessor -{ -public : - CurlNetAccessor() {} - ~CurlNetAccessor() {} - - virtual BinInputStream* makeNew(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo=0); - virtual const XMLCh* getId() const; - -private : - static const XMLCh fgMyName[]; - - CurlNetAccessor(const CurlNetAccessor&); - CurlNetAccessor& operator=(const CurlNetAccessor&); - -}; // CurlNetAccessor - - -inline const XMLCh* CurlNetAccessor::getId() const -{ - return fgMyName; -} - -}; - -#endif // CURLNETACCESSOR_HPP - - diff --git a/xmltooling/util/CurlURLInputStream.cpp b/xmltooling/util/CurlURLInputStream.cpp deleted file mode 100644 index e03f5c4..0000000 --- a/xmltooling/util/CurlURLInputStream.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * $Id: CurlURLInputStream.cpp 471747 2006-11-06 14:31:56Z amassari $ - */ - -#include "internal.h" -#include "util/CurlURLInputStream.h" - -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace xmltooling; - -CurlURLInputStream::CurlURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/) - : fMulti(0) - , fEasy(0) - , fMemoryManager(urlSource.getMemoryManager()) - , fURLSource(urlSource) - , fURL(0) - , fTotalBytesRead(0) - , fWritePtr(0) - , fBytesRead(0) - , fBytesToRead(0) - , fDataAvailable(false) - , fBufferHeadPtr(fBuffer) - , fBufferTailPtr(fBuffer) -{ - // Allocate the curl multi handle - fMulti = curl_multi_init(); - - // Allocate the curl easy handle - fEasy = curl_easy_init(); - - // Get the text of the URL we're going to use - fURL.reset(XMLString::transcode(fURLSource.getURLText(), fMemoryManager), fMemoryManager); - - //printf("Curl trying to fetch %s\n", fURL.get()); - - // Set URL option - curl_easy_setopt(fEasy, CURLOPT_URL, fURL.get()); - curl_easy_setopt(fEasy, CURLOPT_WRITEDATA, this); // Pass this pointer to write function - curl_easy_setopt(fEasy, CURLOPT_WRITEFUNCTION, staticWriteCallback); // Our static write function - - // Add easy handle to the multi stack - curl_multi_add_handle(fMulti, fEasy); -} - - -CurlURLInputStream::~CurlURLInputStream() -{ - // Remove the easy handle from the multi stack - curl_multi_remove_handle(fMulti, fEasy); - - // Cleanup the easy handle - curl_easy_cleanup(fEasy); - - // Cleanup the multi handle - curl_multi_cleanup(fMulti); -} - - -size_t -CurlURLInputStream::staticWriteCallback(char *buffer, - size_t size, - size_t nitems, - void *outstream) -{ - return ((CurlURLInputStream*)outstream)->writeCallback(buffer, size, nitems); -} - - - -size_t -CurlURLInputStream::writeCallback(char *buffer, - size_t size, - size_t nitems) -{ - XMLSize_t cnt = size * nitems; - XMLSize_t totalConsumed = 0; - - // Consume as many bytes as possible immediately into the buffer - XMLSize_t consume = (cnt > fBytesToRead) ? fBytesToRead : cnt; - memcpy(fWritePtr, buffer, consume); - fWritePtr += consume; - fBytesRead += consume; - fTotalBytesRead += consume; - fBytesToRead -= consume; - - //printf("write callback consuming %d bytes\n", consume); - - // If bytes remain, rebuffer as many as possible into our holding buffer - buffer += consume; - totalConsumed += consume; - cnt -= consume; - if (cnt > 0) - { - XMLSize_t bufAvail = sizeof(fBuffer) - (fBufferHeadPtr - fBuffer); - consume = (cnt > bufAvail) ? bufAvail : cnt; - memcpy(fBufferHeadPtr, buffer, consume); - fBufferHeadPtr += consume; - buffer += consume; - totalConsumed += consume; - //printf("write callback rebuffering %d bytes\n", consume); - } - - // Return the total amount we've consumed. If we don't consume all the bytes - // then an error will be generated. Since our buffer size is equal to the - // maximum size that curl will write, this should never happen unless there - // is a logic error somewhere here. - return totalConsumed; -} - - - -unsigned int -CurlURLInputStream::readBytes(XMLByte* const toFill - , const unsigned int maxToRead) -{ - fBytesRead = 0; - fBytesToRead = maxToRead; - fWritePtr = toFill; - - for (bool tryAgain = true; fBytesToRead > 0 && (tryAgain || fBytesRead == 0); ) - { - // First, any buffered data we have available - XMLSize_t bufCnt = fBufferHeadPtr - fBufferTailPtr; - bufCnt = (bufCnt > fBytesToRead) ? fBytesToRead : bufCnt; - if (bufCnt > 0) - { - memcpy(fWritePtr, fBufferTailPtr, bufCnt); - fWritePtr += bufCnt; - fBytesRead += bufCnt; - fTotalBytesRead += bufCnt; - fBytesToRead -= bufCnt; - - fBufferTailPtr += bufCnt; - if (fBufferTailPtr == fBufferHeadPtr) - fBufferHeadPtr = fBufferTailPtr = fBuffer; - - //printf("consuming %d buffered bytes\n", bufCnt); - - tryAgain = true; - continue; - } - - // Ask the curl to do some work - int runningHandles = 0; - CURLMcode curlResult = curl_multi_perform(fMulti, &runningHandles); - tryAgain = (curlResult == CURLM_CALL_MULTI_PERFORM); - - // Process messages from curl - int msgsInQueue = 0; - for (CURLMsg* msg = NULL; (msg = curl_multi_info_read(fMulti, &msgsInQueue)) != NULL; ) - { - //printf("msg %d, %d from curl\n", msg->msg, msg->data.result); - - if (msg->msg != CURLMSG_DONE) - continue; - - switch (msg->data.result) - { - case CURLE_OK: - // We completed successfully. runningHandles should have dropped to zero, so we'll bail out below... - break; - - case CURLE_UNSUPPORTED_PROTOCOL: - ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_UnsupportedProto, fMemoryManager); - break; - - case CURLE_COULDNT_RESOLVE_HOST: - case CURLE_COULDNT_RESOLVE_PROXY: - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_TargetResolution, fURLSource.getHost(), fMemoryManager); - break; - - case CURLE_COULDNT_CONNECT: - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ConnSocket, fURLSource.getURLText(), fMemoryManager); - - case CURLE_RECV_ERROR: - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, fURLSource.getURLText(), fMemoryManager); - break; - - default: - ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_InternalError, fURLSource.getURLText(), fMemoryManager); - break; - } - } - - // If nothing is running any longer, bail out - if (runningHandles == 0) - break; - - // If there is no further data to read, and we haven't - // read any yet on this invocation, call select to wait for data - if (!tryAgain && fBytesRead == 0) - { - fd_set readSet[16]; - fd_set writeSet[16]; - fd_set exceptSet[16]; - int fdcnt = 16; - - // As curl for the file descriptors to wait on - (void) curl_multi_fdset(fMulti, readSet, writeSet, exceptSet, &fdcnt); - - // Wait on the file descriptors - timeval tv; - tv.tv_sec = 2; - tv.tv_usec = 0; - (void) select(fdcnt, readSet, writeSet, exceptSet, &tv); - } - } - - return fBytesRead; -} diff --git a/xmltooling/util/CurlURLInputStream.h b/xmltooling/util/CurlURLInputStream.h deleted file mode 100644 index a1a6035..0000000 --- a/xmltooling/util/CurlURLInputStream.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * $Id: CurlURLInputStream.hpp 527149 2007-04-10 14:56:39Z amassari $ - */ - -#if !defined(XERCESC_INCLUDE_GUARD_CURLURLINPUTSTREAM_HPP) -#define XERCESC_INCLUDE_GUARD_CURLURLINPUTSTREAM_HPP - -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace xmltooling { - -// -// This class implements the BinInputStream interface specified by the XML -// parser. -// - -class XMLTOOL_DLLLOCAL CurlURLInputStream : public BinInputStream -{ -public : - CurlURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo=0); - ~CurlURLInputStream(); - - unsigned int curPos() const; - unsigned int readBytes - ( - XMLByte* const toFill - , const unsigned int maxToRead - ); - - -private : - // ----------------------------------------------------------------------- - // Unimplemented constructors and operators - // ----------------------------------------------------------------------- - CurlURLInputStream(const CurlURLInputStream&); - CurlURLInputStream& operator=(const CurlURLInputStream&); - - static size_t staticWriteCallback(char *buffer, - size_t size, - size_t nitems, - void *outstream); - size_t writeCallback( char *buffer, - size_t size, - size_t nitems); - - - // ----------------------------------------------------------------------- - // Private data members - // - // fSocket - // The socket representing the connection to the remote file. - // fBytesProcessed - // Its a rolling count of the number of bytes processed off this - // input stream. - // fBuffer - // Holds the http header, plus the first part of the actual - // data. Filled at the time the stream is opened, data goes - // out to user in response to readBytes(). - // fBufferPos, fBufferEnd - // Pointers into fBuffer, showing start and end+1 of content - // that readBytes must return. - // ----------------------------------------------------------------------- - - CURLM* fMulti; - CURL* fEasy; - - MemoryManager* fMemoryManager; - - XMLURL fURLSource; - ArrayJanitor fURL; - - unsigned long fTotalBytesRead; - XMLByte* fWritePtr; - unsigned long fBytesRead; - unsigned long fBytesToRead; - bool fDataAvailable; - - // Overflow buffer for when curl writes more data to us - // than we've asked for. - XMLByte fBuffer[CURL_MAX_WRITE_SIZE]; - XMLByte* fBufferHeadPtr; - XMLByte* fBufferTailPtr; - -}; // CurlURLInputStream - - -inline unsigned int -CurlURLInputStream::curPos() const -{ - return fTotalBytesRead; -} - -}; - -#endif // CURLURLINPUTSTREAM_HPP - diff --git a/xmltooling/util/ReloadableXMLFile.cpp b/xmltooling/util/ReloadableXMLFile.cpp index 82264fe..054e3d2 100644 --- a/xmltooling/util/ReloadableXMLFile.cpp +++ b/xmltooling/util/ReloadableXMLFile.cpp @@ -26,6 +26,7 @@ #include "util/XMLConstants.h" #include "util/XMLHelper.h" +#include #include #include @@ -38,17 +39,19 @@ using namespace xmltooling; using namespace log4cpp; using namespace std; -static const XMLCh uri[] = UNICODE_LITERAL_3(u,r,i); -static const XMLCh url[] = UNICODE_LITERAL_3(u,r,l); -static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h); -static const XMLCh pathname[] = UNICODE_LITERAL_8(p,a,t,h,n,a,m,e); -static const XMLCh file[] = UNICODE_LITERAL_4(f,i,l,e); -static const XMLCh filename[] = UNICODE_LITERAL_8(f,i,l,e,n,a,m,e); -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 uri[] = UNICODE_LITERAL_3(u,r,i); +static const XMLCh url[] = UNICODE_LITERAL_3(u,r,l); +static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h); +static const XMLCh pathname[] = UNICODE_LITERAL_8(p,a,t,h,n,a,m,e); +static const XMLCh file[] = UNICODE_LITERAL_4(f,i,l,e); +static const XMLCh filename[] = UNICODE_LITERAL_8(f,i,l,e,n,a,m,e); +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 backingFilePath[] = UNICODE_LITERAL_15(b,a,c,k,i,n,g,F,i,l,e,P,a,t,h); ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e, Category& log) - : m_root(e), m_local(true), m_validate(false), m_filestamp(0), m_lock(NULL), m_log(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"); @@ -88,33 +91,47 @@ ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e, Category& log) m_local=true; } - flag=e->getAttributeNS(NULL,reloadChanges); - if (!XMLString::equals(flag,xmlconstants::XML_FALSE) && !XMLString::equals(flag,xmlconstants::XML_ZERO)) { - if (m_local) { + if (m_local) { + 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) - m_filestamp=stat_buf.st_mtime; - else - m_local=false; #else struct stat stat_buf; if (stat(m_source.c_str(), &stat_buf) == 0) +#endif m_filestamp=stat_buf.st_mtime; else - m_local=false; -#endif + 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(); + 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_lock=RWLock::create(); } - - log.debug("using external resource (%s), will %smonitor for changes", m_source.c_str(), m_lock ? "" : "not "); } - else + else { log.debug("no resource uri/path/name supplied, will load inline configuration"); + } } -pair ReloadableXMLFile::load() +pair ReloadableXMLFile::load(bool backup) { #ifdef _DEBUG NDC ndc("init"); @@ -128,11 +145,14 @@ pair ReloadableXMLFile::load() } else { // Data comes from a file we have to parse. - m_log.debug("loading configuration from external resource..."); + if (backup) + m_log.warn("using local backup of remote resource"); + else + m_log.debug("loading configuration from external resource..."); DOMDocument* doc=NULL; - auto_ptr_XMLCh widenit(m_source.c_str()); - if (m_local) { + auto_ptr_XMLCh widenit(backup ? m_backing.c_str() : m_source.c_str()); + if (m_local || backup) { LocalFileInputSource src(widenit.get()); Wrapper4InputSource dsrc(&src,false); if (m_validate) @@ -149,19 +169,35 @@ pair ReloadableXMLFile::load() doc=XMLToolingConfig::getConfig().getParser().parse(dsrc); } - m_log.infoStream() << "loaded XML resource (" << m_source << ")" << CategoryStream::ENDLINE; + m_log.infoStream() << "loaded XML resource (" << (backup ? m_backing : m_source) << ")" << CategoryStream::ENDLINE; + + 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->getDocumentElement()); + } + 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.critStream() << "Xerces error while loading resource (" << m_source << "): " + m_log.critStream() << "Xerces error while loading resource (" << (backup ? m_backing : m_source) << "): " << msg.get() << CategoryStream::ENDLINE; + if (!backup && !m_backing.empty()) + return load(true); throw XMLParserException(msg.get()); } catch (exception& e) { m_log.critStream() << "error while loading configuration from (" - << (m_source.empty() ? "inline" : m_source) << "): " << e.what() << CategoryStream::ENDLINE; + << (m_source.empty() ? "inline" : (backup ? m_backing : m_source)) << "): " << e.what() << CategoryStream::ENDLINE; + if (!backup && !m_backing.empty()) + return load(true); throw; } } @@ -202,19 +238,25 @@ Lockable* ReloadableXMLFile::lock() m_log.info("change detected, reloading local resource..."); } else { - if (isValid()) + 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_lock->unlock(); m_lock->wrlock(); - if (isValid()) { + if (now - m_filestamp < m_reloadInterval) { // Somebody else handled it, just downgrade. m_lock->unlock(); m_lock->rdlock(); return this; } - m_log.info("local copy invalid, reloading remote resource..."); + + m_filestamp = now; + m_log.info("reloading remote resource..."); } // Do this once... diff --git a/xmltooling/util/ReloadableXMLFile.h b/xmltooling/util/ReloadableXMLFile.h index 345d2aa..2b96cb1 100644 --- a/xmltooling/util/ReloadableXMLFile.h +++ b/xmltooling/util/ReloadableXMLFile.h @@ -52,7 +52,7 @@ namespace xmltooling { *
validate
*
use a validating parser
*
reloadChanges
- *
enables monitoring of resources for changes
+ *
enables monitoring of local file for changes
* * * @param e DOM to supply configuration @@ -74,17 +74,10 @@ namespace xmltooling { * @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 load(); - - /** - * Overrideable method to determine whether a remote resource remains valid. - * - * @return true iff the resource remains valid and should not be reloaded - */ - virtual bool isValid() const { - return true; + virtual std::pair load() { + return load(false); } - + /** Root of the original DOM element passed into constructor. */ const xercesc::DOMElement* m_root; @@ -96,10 +89,16 @@ namespace xmltooling { /** Resource location, may be a local path or a URI. */ std::string m_source; + + /** Path to backup copy for remote resources. */ + std::string m_backing; - /** Last modification of local resource. */ + /** Last modification of local resource or reload of remote resource. */ time_t m_filestamp; - + + /** Time in seconds to wait before trying for new copy of remote resource. */ + time_t m_reloadInterval; + /** Shared lock for guarding reloads. */ RWLock* m_lock; @@ -113,6 +112,9 @@ namespace xmltooling { if (m_lock) m_lock->unlock(); } + + private: + std::pair load(bool backup); }; }; diff --git a/xmltooling/xmltooling.vcproj b/xmltooling/xmltooling.vcproj index bf2b136..66ebadc 100644 --- a/xmltooling/xmltooling.vcproj +++ b/xmltooling/xmltooling.vcproj @@ -231,14 +231,6 @@ Name="util" > - - - - @@ -553,14 +545,6 @@ Name="util" > - - - -