Pulled out curl accessor, doesn't seem to work anyway.
Rework XML resource loader with file backup and time-based reloading.
soap/OpenSSLSOAPTransport.h
utilinclude_HEADERS = \
- util/CurlNetAccessor.h \
- util/CurlURLInputStream.h \
util/DateTime.h \
util/NDC.h \
util/ParserPool.h \
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 \
#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"
log.debug("libcurl %s initialization complete", LIBCURL_VERSION);
XMLPlatformUtils::Initialize();
- auto_ptr<XMLNetAccessor> curler(new CurlNetAccessor());
- delete XMLPlatformUtils::fgNetAccessor;
- XMLPlatformUtils::fgNetAccessor = curler.release();
log.debug("Xerces initialization complete");
#ifndef XMLTOOLING_NO_XMLSEC
+++ /dev/null
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/*\r
- * $Id: CurlNetAccessor.cpp 471747 2006-11-06 14:31:56Z amassari $\r
- */\r
-\r
-#include "internal.h"\r
-#include "util/CurlURLInputStream.h"\r
-#include "util/CurlNetAccessor.h"\r
-\r
-#include <xercesc/util/XMLUniDefs.hpp>\r
-#include <xercesc/util/XMLUni.hpp>\r
-#include <xercesc/util/XMLString.hpp>\r
-#include <xercesc/util/XMLExceptMsgs.hpp>\r
-\r
-using namespace xmltooling;\r
-\r
-const XMLCh CurlNetAccessor::fgMyName[] =\r
-{\r
- chLatin_C, chLatin_u, chLatin_r, chLatin_l, chLatin_N, chLatin_e,\r
- chLatin_t, chLatin_A, chLatin_c, chLatin_c, chLatin_e, chLatin_s,\r
- chLatin_s, chLatin_o, chLatin_r, chNull\r
-};\r
-\r
-\r
-BinInputStream*\r
-CurlNetAccessor::makeNew(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/)\r
-{\r
- // Just create a CurlURLInputStream\r
- // We defer any checking of the url type for curl in CurlURLInputStream\r
- CurlURLInputStream* retStrm =\r
- new (urlSource.getMemoryManager()) CurlURLInputStream(urlSource, httpInfo);\r
- return retStrm; \r
-}\r
+++ /dev/null
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/*\r
- * $Id: CurlNetAccessor.hpp 527149 2007-04-10 14:56:39Z amassari $\r
- */\r
-\r
-#if !defined(XERCESC_INCLUDE_GUARD_CURLNETACCESSOR_HPP)\r
-#define XERCESC_INCLUDE_GUARD_CURLNETACCESSOR_HPP\r
-\r
-\r
-#include <xercesc/util/XercesDefs.hpp>\r
-#include <xercesc/util/XMLURL.hpp>\r
-#include <xercesc/util/BinInputStream.hpp>\r
-#include <xercesc/util/XMLNetAccessor.hpp>\r
-\r
-namespace xmltooling {\r
-\r
-//\r
-// This class is the wrapper for the socket based code which\r
-// provides the ability to fetch a resource specified using\r
-// a HTTP or FTP URL.\r
-//\r
-\r
-class XMLTOOL_DLLLOCAL CurlNetAccessor : public XMLNetAccessor\r
-{\r
-public :\r
- CurlNetAccessor() {}\r
- ~CurlNetAccessor() {}\r
- \r
- virtual BinInputStream* makeNew(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo=0);\r
- virtual const XMLCh* getId() const;\r
-\r
-private :\r
- static const XMLCh fgMyName[];\r
-\r
- CurlNetAccessor(const CurlNetAccessor&);\r
- CurlNetAccessor& operator=(const CurlNetAccessor&);\r
-\r
-}; // CurlNetAccessor\r
-\r
-\r
-inline const XMLCh* CurlNetAccessor::getId() const\r
-{\r
- return fgMyName;\r
-}\r
-\r
-};\r
-\r
-#endif // CURLNETACCESSOR_HPP\r
-\r
-\r
+++ /dev/null
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/*\r
- * $Id: CurlURLInputStream.cpp 471747 2006-11-06 14:31:56Z amassari $\r
- */\r
-\r
-#include "internal.h"\r
-#include "util/CurlURLInputStream.h"\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <errno.h>\r
-#ifdef HAVE_UNISTD_H\r
-# include <unistd.h>\r
-#endif\r
-#include <sys/types.h>\r
-\r
-#include <xercesc/util/XercesDefs.hpp>\r
-#include <xercesc/util/XMLNetAccessor.hpp>\r
-#include <xercesc/util/XMLString.hpp>\r
-#include <xercesc/util/XMLExceptMsgs.hpp>\r
-#include <xercesc/util/Janitor.hpp>\r
-#include <xercesc/util/XMLUniDefs.hpp>\r
-#include <xercesc/util/TransService.hpp>\r
-#include <xercesc/util/TranscodingException.hpp>\r
-#include <xercesc/util/PlatformUtils.hpp>\r
-\r
-\r
-using namespace xmltooling;\r
-\r
-CurlURLInputStream::CurlURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo/*=0*/)\r
- : fMulti(0)\r
- , fEasy(0)\r
- , fMemoryManager(urlSource.getMemoryManager())\r
- , fURLSource(urlSource)\r
- , fURL(0)\r
- , fTotalBytesRead(0)\r
- , fWritePtr(0)\r
- , fBytesRead(0)\r
- , fBytesToRead(0)\r
- , fDataAvailable(false)\r
- , fBufferHeadPtr(fBuffer)\r
- , fBufferTailPtr(fBuffer)\r
-{\r
- // Allocate the curl multi handle\r
- fMulti = curl_multi_init();\r
- \r
- // Allocate the curl easy handle\r
- fEasy = curl_easy_init();\r
- \r
- // Get the text of the URL we're going to use\r
- fURL.reset(XMLString::transcode(fURLSource.getURLText(), fMemoryManager), fMemoryManager);\r
-\r
- //printf("Curl trying to fetch %s\n", fURL.get());\r
-\r
- // Set URL option\r
- curl_easy_setopt(fEasy, CURLOPT_URL, fURL.get());\r
- curl_easy_setopt(fEasy, CURLOPT_WRITEDATA, this); // Pass this pointer to write function\r
- curl_easy_setopt(fEasy, CURLOPT_WRITEFUNCTION, staticWriteCallback); // Our static write function\r
- \r
- // Add easy handle to the multi stack\r
- curl_multi_add_handle(fMulti, fEasy);\r
-}\r
-\r
-\r
-CurlURLInputStream::~CurlURLInputStream()\r
-{\r
- // Remove the easy handle from the multi stack\r
- curl_multi_remove_handle(fMulti, fEasy);\r
- \r
- // Cleanup the easy handle\r
- curl_easy_cleanup(fEasy);\r
- \r
- // Cleanup the multi handle\r
- curl_multi_cleanup(fMulti);\r
-}\r
-\r
-\r
-size_t\r
-CurlURLInputStream::staticWriteCallback(char *buffer,\r
- size_t size,\r
- size_t nitems,\r
- void *outstream)\r
-{\r
- return ((CurlURLInputStream*)outstream)->writeCallback(buffer, size, nitems);\r
-}\r
-\r
-\r
-\r
-size_t\r
-CurlURLInputStream::writeCallback(char *buffer,\r
- size_t size,\r
- size_t nitems)\r
-{\r
- XMLSize_t cnt = size * nitems;\r
- XMLSize_t totalConsumed = 0;\r
- \r
- // Consume as many bytes as possible immediately into the buffer\r
- XMLSize_t consume = (cnt > fBytesToRead) ? fBytesToRead : cnt;\r
- memcpy(fWritePtr, buffer, consume);\r
- fWritePtr += consume;\r
- fBytesRead += consume;\r
- fTotalBytesRead += consume;\r
- fBytesToRead -= consume;\r
-\r
- //printf("write callback consuming %d bytes\n", consume);\r
-\r
- // If bytes remain, rebuffer as many as possible into our holding buffer\r
- buffer += consume;\r
- totalConsumed += consume;\r
- cnt -= consume;\r
- if (cnt > 0)\r
- {\r
- XMLSize_t bufAvail = sizeof(fBuffer) - (fBufferHeadPtr - fBuffer);\r
- consume = (cnt > bufAvail) ? bufAvail : cnt;\r
- memcpy(fBufferHeadPtr, buffer, consume);\r
- fBufferHeadPtr += consume;\r
- buffer += consume;\r
- totalConsumed += consume;\r
- //printf("write callback rebuffering %d bytes\n", consume);\r
- }\r
- \r
- // Return the total amount we've consumed. If we don't consume all the bytes\r
- // then an error will be generated. Since our buffer size is equal to the\r
- // maximum size that curl will write, this should never happen unless there\r
- // is a logic error somewhere here.\r
- return totalConsumed;\r
-}\r
-\r
-\r
-\r
-unsigned int\r
-CurlURLInputStream::readBytes(XMLByte* const toFill\r
- , const unsigned int maxToRead)\r
-{\r
- fBytesRead = 0;\r
- fBytesToRead = maxToRead;\r
- fWritePtr = toFill;\r
- \r
- for (bool tryAgain = true; fBytesToRead > 0 && (tryAgain || fBytesRead == 0); )\r
- {\r
- // First, any buffered data we have available\r
- XMLSize_t bufCnt = fBufferHeadPtr - fBufferTailPtr;\r
- bufCnt = (bufCnt > fBytesToRead) ? fBytesToRead : bufCnt;\r
- if (bufCnt > 0)\r
- {\r
- memcpy(fWritePtr, fBufferTailPtr, bufCnt);\r
- fWritePtr += bufCnt;\r
- fBytesRead += bufCnt;\r
- fTotalBytesRead += bufCnt;\r
- fBytesToRead -= bufCnt;\r
- \r
- fBufferTailPtr += bufCnt;\r
- if (fBufferTailPtr == fBufferHeadPtr)\r
- fBufferHeadPtr = fBufferTailPtr = fBuffer;\r
- \r
- //printf("consuming %d buffered bytes\n", bufCnt);\r
-\r
- tryAgain = true;\r
- continue;\r
- }\r
- \r
- // Ask the curl to do some work\r
- int runningHandles = 0;\r
- CURLMcode curlResult = curl_multi_perform(fMulti, &runningHandles);\r
- tryAgain = (curlResult == CURLM_CALL_MULTI_PERFORM);\r
- \r
- // Process messages from curl\r
- int msgsInQueue = 0;\r
- for (CURLMsg* msg = NULL; (msg = curl_multi_info_read(fMulti, &msgsInQueue)) != NULL; )\r
- {\r
- //printf("msg %d, %d from curl\n", msg->msg, msg->data.result);\r
-\r
- if (msg->msg != CURLMSG_DONE)\r
- continue;\r
- \r
- switch (msg->data.result)\r
- {\r
- case CURLE_OK:\r
- // We completed successfully. runningHandles should have dropped to zero, so we'll bail out below...\r
- break;\r
- \r
- case CURLE_UNSUPPORTED_PROTOCOL:\r
- ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_UnsupportedProto, fMemoryManager);\r
- break;\r
-\r
- case CURLE_COULDNT_RESOLVE_HOST:\r
- case CURLE_COULDNT_RESOLVE_PROXY:\r
- ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_TargetResolution, fURLSource.getHost(), fMemoryManager);\r
- break;\r
- \r
- case CURLE_COULDNT_CONNECT:\r
- ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ConnSocket, fURLSource.getURLText(), fMemoryManager);\r
- \r
- case CURLE_RECV_ERROR:\r
- ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_ReadSocket, fURLSource.getURLText(), fMemoryManager);\r
- break;\r
-\r
- default:\r
- ThrowXMLwithMemMgr1(NetAccessorException, XMLExcepts::NetAcc_InternalError, fURLSource.getURLText(), fMemoryManager);\r
- break;\r
- }\r
- }\r
- \r
- // If nothing is running any longer, bail out\r
- if (runningHandles == 0)\r
- break;\r
- \r
- // If there is no further data to read, and we haven't\r
- // read any yet on this invocation, call select to wait for data\r
- if (!tryAgain && fBytesRead == 0)\r
- {\r
- fd_set readSet[16];\r
- fd_set writeSet[16];\r
- fd_set exceptSet[16];\r
- int fdcnt = 16;\r
- \r
- // As curl for the file descriptors to wait on\r
- (void) curl_multi_fdset(fMulti, readSet, writeSet, exceptSet, &fdcnt);\r
- \r
- // Wait on the file descriptors\r
- timeval tv;\r
- tv.tv_sec = 2;\r
- tv.tv_usec = 0;\r
- (void) select(fdcnt, readSet, writeSet, exceptSet, &tv);\r
- }\r
- }\r
- \r
- return fBytesRead;\r
-}\r
+++ /dev/null
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements. See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License. You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/*\r
- * $Id: CurlURLInputStream.hpp 527149 2007-04-10 14:56:39Z amassari $\r
- */\r
-\r
-#if !defined(XERCESC_INCLUDE_GUARD_CURLURLINPUTSTREAM_HPP)\r
-#define XERCESC_INCLUDE_GUARD_CURLURLINPUTSTREAM_HPP\r
-\r
-#include <curl/curl.h>\r
-#include <curl/multi.h>\r
-#include <curl/easy.h>\r
-\r
-#include <xercesc/util/XMLURL.hpp>\r
-#include <xercesc/util/XMLExceptMsgs.hpp>\r
-#include <xercesc/util/Janitor.hpp>\r
-#include <xercesc/util/BinInputStream.hpp>\r
-#include <xercesc/util/XMLNetAccessor.hpp>\r
-\r
-namespace xmltooling {\r
-\r
-//\r
-// This class implements the BinInputStream interface specified by the XML\r
-// parser.\r
-//\r
-\r
-class XMLTOOL_DLLLOCAL CurlURLInputStream : public BinInputStream\r
-{\r
-public :\r
- CurlURLInputStream(const XMLURL& urlSource, const XMLNetHTTPInfo* httpInfo=0);\r
- ~CurlURLInputStream();\r
-\r
- unsigned int curPos() const;\r
- unsigned int readBytes\r
- (\r
- XMLByte* const toFill\r
- , const unsigned int maxToRead\r
- );\r
-\r
-\r
-private :\r
- // -----------------------------------------------------------------------\r
- // Unimplemented constructors and operators\r
- // -----------------------------------------------------------------------\r
- CurlURLInputStream(const CurlURLInputStream&);\r
- CurlURLInputStream& operator=(const CurlURLInputStream&);\r
- \r
- static size_t staticWriteCallback(char *buffer,\r
- size_t size,\r
- size_t nitems,\r
- void *outstream);\r
- size_t writeCallback( char *buffer,\r
- size_t size,\r
- size_t nitems);\r
-\r
-\r
- // -----------------------------------------------------------------------\r
- // Private data members\r
- //\r
- // fSocket\r
- // The socket representing the connection to the remote file.\r
- // fBytesProcessed\r
- // Its a rolling count of the number of bytes processed off this\r
- // input stream.\r
- // fBuffer\r
- // Holds the http header, plus the first part of the actual\r
- // data. Filled at the time the stream is opened, data goes\r
- // out to user in response to readBytes().\r
- // fBufferPos, fBufferEnd\r
- // Pointers into fBuffer, showing start and end+1 of content\r
- // that readBytes must return.\r
- // -----------------------------------------------------------------------\r
- \r
- CURLM* fMulti;\r
- CURL* fEasy;\r
- \r
- MemoryManager* fMemoryManager;\r
- \r
- XMLURL fURLSource;\r
- ArrayJanitor<char> fURL;\r
- \r
- unsigned long fTotalBytesRead;\r
- XMLByte* fWritePtr;\r
- unsigned long fBytesRead;\r
- unsigned long fBytesToRead;\r
- bool fDataAvailable;\r
- \r
- // Overflow buffer for when curl writes more data to us\r
- // than we've asked for.\r
- XMLByte fBuffer[CURL_MAX_WRITE_SIZE];\r
- XMLByte* fBufferHeadPtr;\r
- XMLByte* fBufferTailPtr;\r
- \r
-}; // CurlURLInputStream\r
-\r
-\r
-inline unsigned int\r
-CurlURLInputStream::curPos() const\r
-{\r
- return fTotalBytesRead;\r
-}\r
-\r
-};\r
-\r
-#endif // CURLURLINPUTSTREAM_HPP\r
-\r
#include "util/XMLConstants.h"\r
#include "util/XMLHelper.h"\r
\r
+#include <fstream>\r
#include <sys/types.h>\r
#include <sys/stat.h>\r
\r
using namespace log4cpp;\r
using namespace std;\r
\r
-static const XMLCh uri[] = UNICODE_LITERAL_3(u,r,i);\r
-static const XMLCh url[] = UNICODE_LITERAL_3(u,r,l);\r
-static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);\r
-static const XMLCh pathname[] = UNICODE_LITERAL_8(p,a,t,h,n,a,m,e);\r
-static const XMLCh file[] = UNICODE_LITERAL_4(f,i,l,e);\r
-static const XMLCh filename[] = UNICODE_LITERAL_8(f,i,l,e,n,a,m,e);\r
-static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);\r
-static const XMLCh reloadChanges[] =UNICODE_LITERAL_13(r,e,l,o,a,d,C,h,a,n,g,e,s);\r
+static const XMLCh uri[] = UNICODE_LITERAL_3(u,r,i);\r
+static const XMLCh url[] = UNICODE_LITERAL_3(u,r,l);\r
+static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);\r
+static const XMLCh pathname[] = UNICODE_LITERAL_8(p,a,t,h,n,a,m,e);\r
+static const XMLCh file[] = UNICODE_LITERAL_4(f,i,l,e);\r
+static const XMLCh filename[] = UNICODE_LITERAL_8(f,i,l,e,n,a,m,e);\r
+static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);\r
+static const XMLCh reloadChanges[] = UNICODE_LITERAL_13(r,e,l,o,a,d,C,h,a,n,g,e,s);\r
+static const XMLCh reloadInterval[] = UNICODE_LITERAL_14(r,e,l,o,a,d,I,n,t,e,r,v,a,l);\r
+static const XMLCh backingFilePath[] = UNICODE_LITERAL_15(b,a,c,k,i,n,g,F,i,l,e,P,a,t,h);\r
\r
ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e, Category& log)\r
- : m_root(e), m_local(true), m_validate(false), m_filestamp(0), m_lock(NULL), m_log(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
m_local=true;\r
}\r
\r
- flag=e->getAttributeNS(NULL,reloadChanges);\r
- if (!XMLString::equals(flag,xmlconstants::XML_FALSE) && !XMLString::equals(flag,xmlconstants::XML_ZERO)) {\r
- if (m_local) {\r
+ if (m_local) {\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
- m_filestamp=stat_buf.st_mtime;\r
- else\r
- m_local=false;\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
- m_local=false;\r
-#endif\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
+ 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_lock=RWLock::create();\r
}\r
-\r
- log.debug("using external resource (%s), will %smonitor for changes", m_source.c_str(), m_lock ? "" : "not ");\r
}\r
- else\r
+ else {\r
log.debug("no resource uri/path/name supplied, will load inline configuration");\r
+ }\r
}\r
\r
-pair<bool,DOMElement*> ReloadableXMLFile::load()\r
+pair<bool,DOMElement*> ReloadableXMLFile::load(bool backup)\r
{\r
#ifdef _DEBUG\r
NDC ndc("init");\r
}\r
else {\r
// Data comes from a file we have to parse.\r
- m_log.debug("loading configuration from external resource...");\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
- auto_ptr_XMLCh widenit(m_source.c_str());\r
- if (m_local) {\r
+ auto_ptr_XMLCh widenit(backup ? m_backing.c_str() : m_source.c_str());\r
+ if (m_local || backup) {\r
LocalFileInputSource src(widenit.get());\r
Wrapper4InputSource dsrc(&src,false);\r
if (m_validate)\r
doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);\r
}\r
\r
- m_log.infoStream() << "loaded XML resource (" << m_source << ")" << CategoryStream::ENDLINE;\r
+ m_log.infoStream() << "loaded XML resource (" << (backup ? m_backing : m_source) << ")" << CategoryStream::ENDLINE;\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->getDocumentElement());\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.critStream() << "Xerces error while loading resource (" << m_source << "): "\r
+ m_log.critStream() << "Xerces error while loading resource (" << (backup ? m_backing : m_source) << "): "\r
<< msg.get() << CategoryStream::ENDLINE;\r
+ if (!backup && !m_backing.empty())\r
+ return load(true);\r
throw XMLParserException(msg.get());\r
}\r
catch (exception& e) {\r
m_log.critStream() << "error while loading configuration from ("\r
- << (m_source.empty() ? "inline" : m_source) << "): " << e.what() << CategoryStream::ENDLINE;\r
+ << (m_source.empty() ? "inline" : (backup ? m_backing : m_source)) << "): " << e.what() << CategoryStream::ENDLINE;\r
+ if (!backup && !m_backing.empty())\r
+ return load(true);\r
throw;\r
}\r
}\r
m_log.info("change detected, reloading local resource...");\r
}\r
else {\r
- if (isValid())\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_lock->unlock();\r
m_lock->wrlock();\r
- if (isValid()) {\r
+ if (now - m_filestamp < m_reloadInterval) {\r
// Somebody else handled it, just downgrade.\r
m_lock->unlock();\r
m_lock->rdlock();\r
return this;\r
}\r
- m_log.info("local copy invalid, reloading remote resource...");\r
+\r
+ m_filestamp = now;\r
+ m_log.info("reloading remote resource...");\r
}\r
\r
// Do this once...\r
* <dt>validate</dt>
* <dd>use a validating parser</dd>
* <dt>reloadChanges</dt>
- * <dd>enables monitoring of resources for changes</dd>
+ * <dd>enables monitoring of local file for changes</dd>
* </dl>
*
* @param e DOM to supply configuration
* @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();
-
- /**
- * 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<bool,xercesc::DOMElement*> load() {
+ return load(false);
}
-
+
/** Root of the original DOM element passed into constructor. */
const xercesc::DOMElement* m_root;
/** 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;
if (m_lock)
m_lock->unlock();
}
+
+ private:
+ std::pair<bool,xercesc::DOMElement*> load(bool backup);
};
};
Name="util"\r
>\r
<File\r
- RelativePath=".\util\CurlNetAccessor.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\util\CurlURLInputStream.cpp"\r
- >\r
- </File>\r
- <File\r
RelativePath=".\util\DateTime.cpp"\r
>\r
</File>\r
Name="util"\r
>\r
<File\r
- RelativePath=".\util\CurlNetAccessor.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\util\CurlURLInputStream.h"\r
- >\r
- </File>\r
- <File\r
RelativePath=".\util\DateTime.h"\r
>\r
</File>\r