[cpp-sp] 02/02: Port in simplified ReloadableXMLFile class.

Scott Cantor cantor.2 at osu.edu
Tue Dec 3 19:20:53 UTC 2024


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch main
in repository cpp-sp.

View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=6938b4024a528be8002399ccfdf4ba1df5d90485

commit 6938b4024a528be8002399ccfdf4ba1df5d90485
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Dec 3 14:20:31 2024 -0500

    Port in simplified ReloadableXMLFile class.
---
 shibsp/util/ReloadableXMLFile.cpp | 166 ++++++++++++++++++++++++++++++++++++++
 shibsp/util/ReloadableXMLFile.h   | 112 +++++++++++++++++++++++++
 2 files changed, 278 insertions(+)

diff --git a/shibsp/util/ReloadableXMLFile.cpp b/shibsp/util/ReloadableXMLFile.cpp
new file mode 100644
index 00000000..443109c6
--- /dev/null
+++ b/shibsp/util/ReloadableXMLFile.cpp
@@ -0,0 +1,166 @@
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID 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.
+ */
+
+/**
+ * @file ReloadableXMLFile.cpp
+ *
+ * Base class for file-based XML configuration.
+ */
+
+#include "internal.h"
+
+#include "AgentConfig.h"
+#include "logging/Category.h"
+#include "util/PathResolver.h"
+#include "util/ReloadableXMLFile.h"
+
+#include <fstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+using namespace boost::property_tree;
+using namespace shibsp;
+using namespace std;
+
+ReloadableXMLFile::ReloadableXMLFile(const std::string& path, Category& log, bool reloadChanges, bool deprecationSupport)
+    : m_tree(nullptr), m_log(log), m_source(path), m_filestamp(0)
+#ifdef HAVE_CXX17
+        , m_lock(nullptr)
+#elif HAVE_CXX14
+        , m_lock(nullptr)
+#endif
+{
+    AgentConfig::getConfig().getPathResolver().resolve(m_source, PathResolver::SHIBSP_CFG_FILE);
+
+    log.info("using path (%s), will %smonitor for changes", m_source.c_str(), reloadChanges ? "" : "not ");
+
+    if (reloadChanges) {
+#ifdef HAVE_CXX17
+        m_lock.reset(new shared_mutex());
+#elif HAVE_CXX14
+        m_lock.reset(new shared_timed_mutex());
+#endif
+    }
+
+    m_tree = load();
+}
+
+ReloadableXMLFile::~ReloadableXMLFile()
+{
+}
+
+unique_ptr<ptree> ReloadableXMLFile::load()
+{
+    try {
+        unique_ptr<ptree> pt = unique_ptr<ptree>(new ptree());
+        xml_parser::read_xml(m_source, *pt, xml_parser::no_comments|xml_parser::trim_whitespace);
+        return pt;
+    } catch (const bad_alloc& e) {
+        m_log.crit("out of memory parsing XML configuration (%s)", m_source.c_str());
+    } catch (const xml_parser_error& e) {
+        m_log.error("failed to process XML configuration (%s): %s", m_source.c_str(), e.what());
+    }
+    return nullptr;
+}
+
+void ReloadableXMLFile::lock()
+{
+    if (m_lock) {
+        m_lock->lock();
+    }
+}
+
+bool ReloadableXMLFile::try_lock()
+{
+    if (m_lock) {
+        return m_lock->try_lock();
+    }
+}
+
+void ReloadableXMLFile::unlock()
+{
+    if (m_lock)
+        m_lock->unlock();
+}
+
+void ReloadableXMLFile::lock_shared()
+{
+    if (!m_lock) {
+        return;
+    }
+
+    m_lock->lock_shared();
+
+    // Check if we need to refresh.
+#ifdef WIN32
+    struct _stat stat_buf;
+    if (_stat(m_source.c_str(), &stat_buf) != 0) {
+        return;
+    }
+#else
+    struct stat stat_buf;
+    if (stat(m_source.c_str(), &stat_buf) != 0) {
+        return;
+    }
+#endif
+    if (m_filestamp >= stat_buf.st_mtime) {
+        return;
+    }
+
+    m_lock->unlock();
+    m_log.info("change detected...");
+
+    unique_ptr<ptree> newtree = load();
+
+    if (newtree) {
+        m_log.info("swapping in new configuration");
+        m_lock->lock();
+#ifdef WIN32
+        if (_stat(m_source.c_str(), &stat_buf) == 0) {
+#else
+        if (stat(m_source.c_str(), &stat_buf) == 0) {
+#endif
+            m_filestamp = stat_buf.st_mtime;
+        }
+        m_tree.swap(newtree);
+        m_lock->unlock();
+        m_lock->lock_shared();
+    } else {
+        m_log.info("new configuration was invalid, retaining original");
+        m_lock->lock_shared();
+    }
+}
+
+bool ReloadableXMLFile::try_lock_shared()
+{
+    if (m_lock)
+        return m_lock->try_lock_shared();
+    else
+        return true;
+}
+
+void ReloadableXMLFile::unlock_shared()
+{
+    if (m_lock)
+        m_lock->unlock_shared();
+}
diff --git a/shibsp/util/ReloadableXMLFile.h b/shibsp/util/ReloadableXMLFile.h
new file mode 100644
index 00000000..9e79c616
--- /dev/null
+++ b/shibsp/util/ReloadableXMLFile.h
@@ -0,0 +1,112 @@
+/**
+ * Licensed 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.
+ */
+
+/**
+ * @file shibsp/util/ReloadableXMLFile.h
+ * 
+ * Base class for reloadable file-based XML configuration.
+ */
+
+#ifndef __shibsp_reloadablexml_h__
+#define __shibsp_reloadablexml_h__
+
+#include <shibsp/base.h>
+
+#include <ctime>
+#include <memory>
+#include <string>
+#include <boost/property_tree/ptree_fwd.hpp>
+
+#ifdef HAVE_CXX14
+#include <shared_mutex>
+#endif
+
+namespace shibsp {
+
+    class SHIBSP_API Category;
+
+    /**
+     * Base class for file-based XML configuration.
+     */
+    class SHIBSP_API ReloadableXMLFile
+    {
+    MAKE_NONCOPYABLE(ReloadableXMLFile);
+    protected:
+        /**
+         * Base class constructor.
+         * 
+         * @param path                  path to file to use
+         * @param log                   logging object to use
+         * @param reloadChanges         whether to monitor for changes
+         * @param deprecationSupport    true iff deprecated options and settings should be accepted
+         */
+        ReloadableXMLFile(
+            const std::string& path,
+            Category& log,
+            bool reloadChanges=false,
+            bool deprecationSupport=true
+            );
+    
+        virtual ~ReloadableXMLFile();
+
+        /**
+         * Loads configuration material.
+         * 
+         * <p>This method is called to load configuration material
+         * initially and any time a change is detected. The base version
+         * performs basic parsing duties and returns the result.</p>
+         *
+         * <p>This method is not called with the object locked, so actual
+         * modification of implementation state requires explicit locking within
+         * the method override.</p>
+         * 
+         * <p>This method should NOT throw exceptions.</p>
+         * 
+         * @return a possibly empty smart pointer holding the replacement tree
+         */
+        virtual std::unique_ptr<boost::property_tree::ptree> load();
+        
+        /** The owned property tree. */
+        std::unique_ptr<boost::property_tree::ptree> m_tree;
+
+        /** Logging object. */
+        Category& m_log;
+
+        /** Resource path. */
+        std::string m_source;
+
+        /** Last modification of local resource. */
+        time_t m_filestamp;
+
+        /** Shared lock for guarding reloads. */
+#ifdef HAVE_CXX17
+        std::unique_ptr<std::shared_mutex> m_lock;
+#elif HAVE_CXX14
+        std::unique_ptr<std::shared_timed_mutex> m_lock;
+#endif
+
+    public:
+        // SharedLockable
+        void lock_shared();
+        bool try_lock_shared();
+        void unlock_shared();
+        // BasicLockable
+        void lock();
+        bool try_lock();
+        void unlock();
+    };
+
+};
+
+#endif /* __shibsp_reloadablexml_h__ */

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list