+
+ // per-thread structure allocated to track locks and role->provider mappings
+ struct SAML_DLLLOCAL tracker_t;
+
+ class SAML_DLLLOCAL ChainingMetadataProvider
+ : public DiscoverableMetadataProvider, public ObservableMetadataProvider, public ObservableMetadataProvider::Observer {
+ public:
+ ChainingMetadataProvider(const xercesc::DOMElement* e=nullptr);
+ virtual ~ChainingMetadataProvider();
+
+ using MetadataProvider::getEntityDescriptor;
+ using MetadataProvider::getEntitiesDescriptor;
+
+ Lockable* lock();
+ void unlock();
+ void setContext(const MetadataFilterContext*);
+ void init();
+ void outputStatus(ostream&) const;
+ const XMLObject* getMetadata() const;
+ const EntitiesDescriptor* getEntitiesDescriptor(const char*, bool requireValidMetadata=true) const;
+ pair<const EntityDescriptor*,const RoleDescriptor*> getEntityDescriptor(const Criteria&) const;
+
+ const Credential* resolve(const CredentialCriteria* criteria=nullptr) const;
+ vector<const Credential*>::size_type resolve(vector<const Credential*>&, const CredentialCriteria* criteria=nullptr) const;
+
+ string getCacheTag() const {
+ Lock lock(m_trackerLock);
+ return m_feedTag;
+ }
+
+ void outputFeed(ostream& os, bool& first, bool wrapArray=true) const {
+ if (wrapArray)
+ os << '[';
+ // Lock each provider in turn and suck in its feed.
+ for (ptr_vector<MetadataProvider>::iterator m = m_providers.begin(); m != m_providers.end(); ++m) {
+ DiscoverableMetadataProvider* d = dynamic_cast<DiscoverableMetadataProvider*>(&(*m));
+ if (d) {
+ Locker locker(d);
+ d->outputFeed(os, first, false);
+ }
+ }
+ if (wrapArray)
+ os << "\n]";
+ }
+
+ void onEvent(const ObservableMetadataProvider& provider) const {
+ // Reset the cache tag for the feed.
+ Lock lock(m_trackerLock);
+ SAMLConfig::getConfig().generateRandomBytes(m_feedTag, 4);
+ m_feedTag = SAMLArtifact::toHex(m_feedTag);
+ emitChangeEvent();
+ }
+
+ protected:
+ void generateFeed() {
+ // No-op.
+ }
+
+ private:
+ bool m_firstMatch;
+ mutable auto_ptr<Mutex> m_trackerLock;
+ auto_ptr<ThreadKey> m_tlsKey;
+ mutable ptr_vector<MetadataProvider> m_providers;
+ mutable set<tracker_t*> m_trackers;
+ static void tracker_cleanup(void*);
+ Category& m_log;
+ friend struct tracker_t;
+ };
+
+ struct SAML_DLLLOCAL tracker_t {
+ tracker_t(const ChainingMetadataProvider* m) : m_metadata(m) {
+ Lock lock(m_metadata->m_trackerLock);
+ m_metadata->m_trackers.insert(this);
+ }
+
+ void lock_if(MetadataProvider* m) {
+ if (m_locked.count(m) == 0)
+ m->lock();
+ }
+
+ void unlock_if(MetadataProvider* m) {
+ if (m_locked.count(m) == 0)
+ m->unlock();
+ }
+
+ void remember(MetadataProvider* m, const EntityDescriptor* entity=nullptr) {
+ m_locked.insert(m);
+ if (entity)
+ m_objectMap.insert(pair<const XMLObject*,const MetadataProvider*>(entity,m));
+ }
+
+ const MetadataProvider* getProvider(const RoleDescriptor& role) {
+ map<const XMLObject*,const MetadataProvider*>::const_iterator i = m_objectMap.find(role.getParent());
+ return (i != m_objectMap.end()) ? i->second : nullptr;
+ }
+
+ const ChainingMetadataProvider* m_metadata;
+ set<MetadataProvider*> m_locked;
+ map<const XMLObject*,const MetadataProvider*> m_objectMap;
+ };
+