+
+ // per-thread structure allocated to track locks and role->provider mappings
+ struct SAML_DLLLOCAL tracker_t;
+
+ class SAML_DLLLOCAL ChainingMetadataProvider
+ : 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 init();
+ const XMLObject* getMetadata() const;
+ const EntitiesDescriptor* getEntitiesDescriptor(const char* name, bool requireValidMetadata=true) const;
+ pair<const EntityDescriptor*,const RoleDescriptor*> getEntityDescriptor(const Criteria& criteria) const;
+ void onEvent(const ObservableMetadataProvider& provider) const;
+
+ const Credential* resolve(const CredentialCriteria* criteria=nullptr) const;
+ vector<const Credential*>::size_type resolve(vector<const Credential*>& results, const CredentialCriteria* criteria=nullptr) const;
+
+ private:
+ bool m_firstMatch;
+ mutable Mutex* m_trackerLock;
+ ThreadKey* m_tlsKey;
+ 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;
+ };
+