2 * Copyright 2001-2006 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * FilesystemMetadataProvider.cpp
20 * Supplies metadata from a local file, detecting and reloading changes.
24 #include "saml2/metadata/ObservableMetadataProvider.h"
27 #include <sys/types.h>
29 #include <log4cpp/Category.hh>
30 #include <xercesc/framework/LocalFileInputSource.hpp>
31 #include <xercesc/framework/Wrapper4InputSource.hpp>
32 #include <xmltooling/util/NDC.h>
33 #include <xmltooling/util/Threads.h>
35 using namespace opensaml::saml2md;
36 using namespace xmltooling;
37 using namespace log4cpp;
44 class SAML_DLLLOCAL FilesystemMetadataProvider : public ObservableMetadataProvider
47 FilesystemMetadataProvider(const DOMElement* e);
48 ~FilesystemMetadataProvider();
58 const XMLObject* getMetadata() const {
63 XMLObject* load() const;
66 const DOMElement* m_root; // survives only until init() method is done
74 MetadataProvider* SAML_DLLLOCAL FilesystemMetadataProviderFactory(const DOMElement* const & e)
76 return new FilesystemMetadataProvider(e);
82 static const XMLCh uri[] = UNICODE_LITERAL_3(u,r,i);
83 static const XMLCh url[] = UNICODE_LITERAL_3(u,r,l);
84 static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);
85 static const XMLCh pathname[] = UNICODE_LITERAL_8(p,a,t,h,n,a,m,e);
86 static const XMLCh file[] = UNICODE_LITERAL_4(f,i,l,e);
87 static const XMLCh filename[] = UNICODE_LITERAL_8(f,i,l,e,n,a,m,e);
88 static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
90 FilesystemMetadataProvider::FilesystemMetadataProvider(const DOMElement* e)
91 : ObservableMetadataProvider(e), m_root(e), m_filestamp(0), m_validate(false), m_lock(NULL), m_object(NULL)
94 NDC ndc("FilesystemMetadataProvider");
96 Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
98 // Establish source of data...
99 const XMLCh* source=e->getAttributeNS(NULL,uri);
100 if (!source || !*source) {
101 source=e->getAttributeNS(NULL,url);
102 if (!source || !*source) {
103 source=e->getAttributeNS(NULL,path);
104 if (!source || !*source) {
105 source=e->getAttributeNS(NULL,pathname);
106 if (!source || !*source) {
107 source=e->getAttributeNS(NULL,file);
108 if (!source || !*source) {
109 source=e->getAttributeNS(NULL,filename);
116 if (source && *source) {
117 const XMLCh* valflag=e->getAttributeNS(NULL,validate);
118 m_validate=(XMLString::equals(valflag,XMLConstants::XML_TRUE) || XMLString::equals(valflag,XMLConstants::XML_ONE));
120 auto_ptr_char temp(source);
122 log.debug("using external metadata file (%s)", temp.get());
125 struct _stat stat_buf;
126 if (_stat(m_source.c_str(), &stat_buf) == 0)
128 struct stat stat_buf;
129 if (stat(m_source.c_str(), &stat_buf) == 0)
131 m_filestamp=stat_buf.st_mtime;
132 m_lock=RWLock::create();
135 log.debug("no file path/name supplied, will look for metadata inline");
138 FilesystemMetadataProvider::~FilesystemMetadataProvider()
144 void FilesystemMetadataProvider::init()
150 XMLObject* FilesystemMetadataProvider::load() const
155 Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
158 XMLObject* xmlObject=NULL;
160 if (!m_source.empty()) {
161 // Data comes from a file we have to parse.
162 log.debug("loading metadata from file...");
163 auto_ptr_XMLCh widenit(m_source.c_str());
164 LocalFileInputSource src(widenit.get());
165 Wrapper4InputSource dsrc(&src,false);
166 DOMDocument* doc=NULL;
168 doc=XMLToolingConfig::getConfig().getValidatingParser().parse(dsrc);
170 doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
171 XercesJanitor<DOMDocument> docjanitor(doc);
172 log.infoStream() << "loaded and parsed XML file (" << m_source << ")" << CategoryStream::ENDLINE;
174 // Unmarshall objects, binding the document.
175 xmlObject = XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true);
176 docjanitor.release();
179 // Data comes from the DOM we were handed.
180 log.debug("loading inline metadata...");
181 DOMElement* child = XMLHelper::getFirstChildElement(m_root);
183 throw XMLToolingException("No metadata was found inline.");
184 xmlObject = XMLObjectBuilder::buildOneFromElement(child);
187 auto_ptr<XMLObject> xmlObjectPtr(xmlObject);
189 doFilters(*xmlObject);
191 xmlObjectPtr->releaseThisAndChildrenDOM();
192 xmlObjectPtr->setDocument(NULL);
193 return xmlObjectPtr.release();
195 catch (XMLException& e) {
196 auto_ptr_char msg(e.getMessage());
197 log.errorStream() << "Xerces parser error while loading metadata from ("
198 << (m_source.empty() ? "inline" : m_source) << "): " << msg.get() << CategoryStream::ENDLINE;
199 throw XMLParserException(msg.get());
201 catch (XMLToolingException& e) {
202 log.errorStream() << "error while loading metadata from ("
203 << (m_source.empty() ? "inline" : m_source) << "): " << e.what() << CategoryStream::ENDLINE;
208 Lockable* FilesystemMetadataProvider::lock()
215 // Check if we need to refresh.
217 struct _stat stat_buf;
218 if (_stat(m_source.c_str(), &stat_buf) == 0)
220 struct stat stat_buf;
221 if (stat(m_source.c_str(), &stat_buf) == 0)
224 if (m_filestamp>0 && m_filestamp<stat_buf.st_mtime) {
225 // Elevate lock and recheck.
228 if (m_filestamp>0 && m_filestamp<stat_buf.st_mtime) {
229 SharedLock lockwrap(m_lock,false); // pops write lock
231 // Update the timestamp regardless. No point in repeatedly trying.
232 m_filestamp=stat_buf.st_mtime;
233 XMLObject* newstuff = load();
239 catch(XMLToolingException& e) {
240 Category::getInstance(SAML_LOGCAT".Metadata").error("failed to reload metadata from file, sticking with what we have: %s", e.what());
252 void FilesystemMetadataProvider::index()
254 clearDescriptorIndex();
255 EntitiesDescriptor* group=dynamic_cast<EntitiesDescriptor*>(m_object);
257 MetadataProvider::index(group, SAMLTIME_MAX);
260 EntityDescriptor* site=dynamic_cast<EntityDescriptor*>(m_object);
261 MetadataProvider::index(site, SAMLTIME_MAX);