Multi-line svn commit, see body.
authorScott Cantor <cantor.2@osu.edu>
Fri, 4 May 2007 03:15:06 +0000 (03:15 +0000)
committerScott Cantor <cantor.2@osu.edu>
Fri, 4 May 2007 03:15:06 +0000 (03:15 +0000)
Pulled out curl accessor, doesn't seem to work anyway.
Rework XML resource loader with file backup and time-based reloading.

xmltooling/Makefile.am
xmltooling/XMLToolingConfig.cpp
xmltooling/util/CurlNetAccessor.cpp [deleted file]
xmltooling/util/CurlNetAccessor.h [deleted file]
xmltooling/util/CurlURLInputStream.cpp [deleted file]
xmltooling/util/CurlURLInputStream.h [deleted file]
xmltooling/util/ReloadableXMLFile.cpp
xmltooling/util/ReloadableXMLFile.h
xmltooling/xmltooling.vcproj

index a930ab2..080f2cf 100644 (file)
@@ -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 \
index e192b75..f1e929e 100644 (file)
@@ -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<XMLNetAccessor> 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 (file)
index 505e9d0..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*\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
diff --git a/xmltooling/util/CurlNetAccessor.h b/xmltooling/util/CurlNetAccessor.h
deleted file mode 100644 (file)
index 523da70..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*\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
diff --git a/xmltooling/util/CurlURLInputStream.cpp b/xmltooling/util/CurlURLInputStream.cpp
deleted file mode 100644 (file)
index e03f5c4..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*\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
diff --git a/xmltooling/util/CurlURLInputStream.h b/xmltooling/util/CurlURLInputStream.h
deleted file mode 100644 (file)
index a1a6035..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*\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
index 82264fe..054e3d2 100644 (file)
@@ -26,6 +26,7 @@
 #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
@@ -38,17 +39,19 @@ using namespace xmltooling;
 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
@@ -88,33 +91,47 @@ ReloadableXMLFile::ReloadableXMLFile(const DOMElement* e, Category& log)
             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
@@ -128,11 +145,14 @@ pair<bool,DOMElement*> ReloadableXMLFile::load()
         }\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
@@ -149,19 +169,35 @@ pair<bool,DOMElement*> ReloadableXMLFile::load()
                     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
@@ -202,19 +238,25 @@ Lockable* ReloadableXMLFile::lock()
         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
index 345d2aa..2b96cb1 100644 (file)
@@ -52,7 +52,7 @@ namespace xmltooling {
          *  <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
@@ -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<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;
         
@@ -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<bool,xercesc::DOMElement*> load(bool backup);
     };
 
 };
index bf2b136..66ebadc 100644 (file)
                                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