[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