void ServiceListeners::RemoveAllListeners(const std::shared_ptr<BundleContextPrivate>& context) { { auto l = this->Lock(); US_UNUSED(l); for (ServiceListenerEntries::iterator it = serviceSet.begin(); it != serviceSet.end(); ) { if (GetPrivate(it->GetBundleContext()) == context) { RemoveFromCache_unlocked(*it); serviceSet.erase(it++); } else { ++it; } } } { auto l = bundleListenerMap.Lock(); US_UNUSED(l); bundleListenerMap.value.erase(context); } { auto l = frameworkListenerMap.Lock(); US_UNUSED(l); frameworkListenerMap.value.erase(context); } }
void ServiceListeners::SendFrameworkEvent(const FrameworkEvent& evt) { // avoid deadlocks, race conditions and other undefined behavior // by using a local snapshot of all listeners. // A lock shouldn't be held while calling into user code (e.g. callbacks). FrameworkListenerMap listener_snapshot; { auto l = frameworkListenerMap.Lock(); US_UNUSED(l); listener_snapshot = frameworkListenerMap.value; } for (auto& listeners : listener_snapshot) { for (auto& listener : listeners.second) { try { std::get<0>(listener.second)(evt); } catch (...) { // do not send a FrameworkEvent as that could cause a deadlock or an infinite loop. // Instead, log to the internal logger // @todo send this to the LogService instead when its supported. DIAG_LOG(*coreCtx->sink) << "A Framework Listener threw an exception: " << util::GetLastExceptionStr() << "\n"; } } } }
void ServiceRegistry::RemoveServiceRegistration_unlocked( const ServiceRegistrationBase& sr) { std::vector<std::string> classes; { auto l2 = sr.d->properties.Lock(); US_UNUSED(l2); assert(sr.d->properties.Value_unlocked(Constants::OBJECTCLASS).Type() == typeid(std::vector<std::string>)); classes = ref_any_cast<std::vector<std::string>>( sr.d->properties.Value_unlocked(Constants::OBJECTCLASS)); } services.erase(sr); serviceRegistrations.erase( std::remove(serviceRegistrations.begin(), serviceRegistrations.end(), sr), serviceRegistrations.end()); for (auto& clazz : classes) { std::vector<ServiceRegistrationBase>& s = classServices[clazz]; if (s.size() > 1) { s.erase(std::remove(s.begin(), s.end(), sr), s.end()); } else { classServices.erase(clazz); } } }
void ServiceRegistry::RemoveServiceRegistration( const ServiceRegistrationBase& sr) { auto l = this->Lock(); US_UNUSED(l); RemoveServiceRegistration_unlocked(sr); }
void ServiceListeners::RemoveAllListeners(ModuleContext* mc) { { US_UNUSED(Lock(this)); for (ServiceListenerEntries::iterator it = serviceSet.begin(); it != serviceSet.end(); ) { if (it->GetModuleContext() == mc) { RemoveFromCache(*it); serviceSet.erase(it++); } else { ++it; } } } { MutexLock lock(moduleListenerMapMutex); moduleListenerMap.erase(mc); } }
void ServiceRegistry::Clear() { auto l = this->Lock(); US_UNUSED(l); services.clear(); classServices.clear(); serviceRegistrations.clear(); }
void ServiceListeners::RemoveServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data) { ServiceListenerEntry entryToRemove(mc, listener, data); US_UNUSED(Lock(this)); RemoveServiceListener_unlocked(entryToRemove); }
void ServiceHooks::Close() { US_UNUSED(Lock(this)); listenerHookTracker->Close(); delete listenerHookTracker; listenerHookTracker = NULL; bOpen = false; }
ListenerToken ServiceListeners::AddFrameworkListener(const std::shared_ptr<BundleContextPrivate>& context, const FrameworkListener& listener, void* data) { auto token = MakeListenerToken(); auto l = frameworkListenerMap.Lock(); US_UNUSED(l); auto& listeners = frameworkListenerMap.value[context]; listeners[token.Id()] = std::make_tuple(listener, data); return token; }
void ServiceHooks::Open() { US_UNUSED(Lock(this)); listenerHookTracker = new ServiceTracker<ServiceListenerHook>(GetModuleContext(), this); listenerHookTracker->Open(); bOpen = true; }
void ModuleSettings::SetAutoLoadPaths(const PathList& paths) { PathList normalizedPaths; normalizedPaths.resize(paths.size()); std::transform(paths.begin(), paths.end(), normalizedPaths.begin(), RemoveTrailingPathSeparator); US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); moduleSettingsPrivate()->autoLoadPaths.clear(); moduleSettingsPrivate()->autoLoadPaths.insert(normalizedPaths.begin(), normalizedPaths.end()); }
bool ModuleSettings::IsAutoLoadingEnabled() { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); #ifdef US_ENABLE_AUTOLOADING_SUPPORT return !moduleSettingsPrivate()->autoLoadingDisabled && moduleSettingsPrivate()->autoLoadingEnabled; #else return false; #endif }
std::vector<ServiceListenerHook::ListenerInfo> ServiceListeners::GetListenerInfoCollection() const { auto l = this->Lock(); US_UNUSED(l); std::vector<ServiceListenerHook::ListenerInfo> result; result.reserve(serviceSet.size()); for (auto info : serviceSet) { result.push_back(info); } return result; }
ServiceRegistrationBase ServiceRegistry::RegisterService( BundlePrivate* bundle, const InterfaceMapConstPtr& service, const ServiceProperties& properties) { if (!service || service->empty()) { throw std::invalid_argument( "Can't register empty InterfaceMap as a service"); } // Check if we got a service factory bool isFactory = service->count("org.cppmicroservices.factory") > 0; bool isPrototypeFactory = (isFactory ? static_cast<bool>(std::dynamic_pointer_cast<PrototypeServiceFactory>( std::static_pointer_cast<ServiceFactory>( service->find("org.cppmicroservices.factory")->second))) : false); std::vector<std::string> classes; // Check if service implements claimed classes and that they exist. for (auto i : *service) { if (i.first.empty() || (!isFactory && i.second == nullptr)) { throw std::invalid_argument("Can't register as null class"); } classes.push_back(i.first); } ServiceRegistrationBase res( bundle, service, CreateServiceProperties( properties, classes, isFactory, isPrototypeFactory)); { auto l = this->Lock(); US_UNUSED(l); services.insert(std::make_pair(res, classes)); serviceRegistrations.push_back(res); for (auto& clazz : classes) { std::vector<ServiceRegistrationBase>& s = classServices[clazz]; std::vector<ServiceRegistrationBase>::iterator ip = std::lower_bound(s.begin(), s.end(), res); s.insert(ip, res); } } ServiceReferenceBase r = res.GetReference(std::string()); ServiceListeners::ServiceListenerEntries listeners; ServiceEvent registeredEvent(ServiceEvent::SERVICE_REGISTERED, r); bundle->coreCtx->listeners.GetMatchingServiceListeners(registeredEvent, listeners); bundle->coreCtx->listeners.ServiceChanged(listeners, registeredEvent); return res; }
ModuleSettings::PathList ModuleSettings::GetAutoLoadPaths() { US_UNUSED(ModuleSettingsPrivate::Lock(moduleSettingsPrivate())); ModuleSettings::PathList paths(moduleSettingsPrivate()->autoLoadPaths.begin(), moduleSettingsPrivate()->autoLoadPaths.end()); paths.insert(paths.end(), moduleSettingsPrivate()->extraPaths.begin(), moduleSettingsPrivate()->extraPaths.end()); std::sort(paths.begin(), paths.end()); paths.erase(std::unique(paths.begin(), paths.end()), paths.end()); return paths; }
void ServiceListeners::AddServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener, void* data, const std::string& filter) { US_UNUSED(Lock(this)); ServiceListenerEntry sle(mc, listener, data, filter); RemoveServiceListener_unlocked(sle); serviceSet.insert(sle); coreCtx->serviceHooks.HandleServiceListenerReg(sle); CheckSimple(sle); }
std::vector<ServiceListenerHook::ListenerInfo> ServiceListeners::GetListenerInfoCollection() const { US_UNUSED(Lock(this)); std::vector<ServiceListenerHook::ListenerInfo> result; result.reserve(serviceSet.size()); for (ServiceListenerEntries::const_iterator iter = serviceSet.begin(), iterEnd = serviceSet.end(); iter != iterEnd; ++iter) { result.push_back(*iter); } return result; }
void ServiceRegistry::UpdateServiceRegistrationOrder( const ServiceRegistrationBase& sr, const std::vector<std::string>& classes) { auto l = this->Lock(); US_UNUSED(l); for (auto& clazz : classes) { std::vector<ServiceRegistrationBase>& s = classServices[clazz]; s.erase(std::remove(s.begin(), s.end(), sr), s.end()); s.insert(std::lower_bound(s.begin(), s.end(), sr), sr); } }
void ServiceRegistry::GetRegisteredByBundle( BundlePrivate* p, std::vector<ServiceRegistrationBase>& res) const { auto l = this->Lock(); US_UNUSED(l); for (auto& sr : serviceRegistrations) { if (sr.d->bundle == p) { res.push_back(sr); } } }
void ServiceListeners::Clear() { bundleListenerMap.Lock(), bundleListenerMap.value.clear(); { auto l = this->Lock(); US_UNUSED(l); serviceSet.clear(); hashedServiceKeys.clear(); complicatedListeners.clear(); cache[0].clear(); cache[1].clear(); } frameworkListenerMap.Lock(), frameworkListenerMap.value.clear(); }
void ServiceListeners::HooksModuleStopped(ModuleContext* mc) { US_UNUSED(Lock(this)); std::vector<ServiceListenerEntry> entries; for (ServiceListenerEntries::iterator it = serviceSet.begin(); it != serviceSet.end(); ) { if (it->GetModuleContext() == mc) { entries.push_back(*it); } } coreCtx->serviceHooks.HandleServiceListenerUnreg(entries); }
void ServiceListeners::HooksBundleStopped(const std::shared_ptr<BundleContextPrivate>& context) { std::vector<ServiceListenerEntry> entries; { auto l = this->Lock(); US_UNUSED(l); for (auto& sle : serviceSet) { if (sle.GetBundleContext() == MakeBundleContext(context)) { entries.push_back(sle); } } } coreCtx->serviceHooks.HandleServiceListenerUnreg(entries); }
void ServiceRegistry::GetUsedByBundle( BundlePrivate* bundle, std::vector<ServiceRegistrationBase>& res) const { auto l = this->Lock(); US_UNUSED(l); for (std::vector<ServiceRegistrationBase>::const_iterator i = serviceRegistrations.begin(); i != serviceRegistrations.end(); ++i) { if (i->d->IsUsedByBundle(bundle)) { res.push_back(*i); } } }
ListenerToken ServiceListeners::AddServiceListener(const std::shared_ptr<BundleContextPrivate>& context, const ServiceListener& listener, void* data, const std::string& filter) { // The following condition is true only if the listener is a non-static member function. // If so, the existing listener is replaced with the new listener. if (data != nullptr) { RemoveServiceListener(context, ListenerTokenId(0), listener, data); } auto token = MakeListenerToken(); ServiceListenerEntry sle(context, listener, data, token.Id(), filter); { auto l = this->Lock(); US_UNUSED(l); serviceSet.insert(sle); CheckSimple_unlocked(sle); } coreCtx->serviceHooks.HandleServiceListenerReg(sle); return token; }
/** * Called by the deprecated RemoveFrameworkListener(name_of_callable) */ void ServiceListeners::RemoveFrameworkListener(const std::shared_ptr<BundleContextPrivate>& context, const FrameworkListener& listener, void* data) { // Note: Only the "data" part is used to compare for sameness. The listener comparison // always returns "true", because std::function objects aren't equality comparable. auto FrameworkListenerCompareListenerData = [](const FrameworkListener& listener, void* data, const std::pair<ListenerTokenId, ServiceListeners::FrameworkListenerEntry>& pair) { return data == std::get<1>(pair.second) && listener.target<void(const FrameworkEvent&)>() == std::get<0>(pair.second).target<void(const FrameworkEvent&)>(); }; auto l = frameworkListenerMap.Lock(); US_UNUSED(l); auto& listeners = frameworkListenerMap.value[context]; auto it = std::find_if(listeners.begin(), listeners.end(), std::bind(FrameworkListenerCompareListenerData, listener, data, std::placeholders::_1)); if (it != listeners.end()) { listeners.erase(it); } }
ServiceReferenceBase ServiceRegistry::Get(BundlePrivate* bundle, const std::string& clazz) const { auto l = this->Lock(); US_UNUSED(l); try { std::vector<ServiceReferenceBase> srs; Get_unlocked(clazz, "", bundle, srs); DIAG_LOG(*core->sink) << "get service ref " << clazz << " for bundle " << bundle->symbolicName << " = " << srs.size() << " refs"; if (!srs.empty()) { return srs.back(); } } catch (const std::invalid_argument&) { } return ServiceReferenceBase(); }
void ServiceListeners::GetMatchingServiceListeners(const ServiceEvent& evt, ServiceListenerEntries& set, bool lockProps) { US_UNUSED(Lock(this)); // Filter the original set of listeners ServiceListenerEntries receivers = serviceSet; coreCtx->serviceHooks.FilterServiceEventReceivers(evt, receivers); // Check complicated or empty listener filters for (std::list<ServiceListenerEntry>::const_iterator sse = complicatedListeners.begin(); sse != complicatedListeners.end(); ++sse) { if (receivers.count(*sse) == 0) continue; const LDAPExpr& ldapExpr = sse->GetLDAPExpr(); if (ldapExpr.IsNull() || ldapExpr.Evaluate(evt.GetServiceReference().d->GetProperties(), false)) { set.insert(*sse); } } //US_DEBUG << "Added " << set.size() << " out of " << n // << " listeners with complicated filters"; // Check the cache const std::vector<std::string> c(any_cast<std::vector<std::string> > (evt.GetServiceReference().d->GetProperty(ServiceConstants::OBJECTCLASS(), lockProps))); for (std::vector<std::string>::const_iterator objClass = c.begin(); objClass != c.end(); ++objClass) { AddToSet(set, receivers, OBJECTCLASS_IX, *objClass); } long service_id = any_cast<long>(evt.GetServiceReference().d->GetProperty(ServiceConstants::SERVICE_ID(), lockProps)); std::stringstream ss; ss << service_id; AddToSet(set, receivers, SERVICE_ID_IX, ss.str()); }
void ServiceListeners::RemoveServiceListener(const std::shared_ptr<BundleContextPrivate>& context, ListenerTokenId tokenId, const ServiceListener& listener, void* data) { ServiceListenerEntry sle; { auto l = this->Lock(); US_UNUSED(l); std::function<bool(const ServiceListenerEntry&)> entryExists; if (tokenId) { assert(!listener); assert(data == nullptr); entryExists = [&context, &tokenId](const ServiceListenerEntry& entry) -> bool { return entry.Contains(context, tokenId); }; } else { entryExists = [&context, &listener, &data](const ServiceListenerEntry& entry) -> bool { return entry.Contains(context, listener, data); }; } auto it = std::find_if(serviceSet.begin(), serviceSet.end(), entryExists); if (it != serviceSet.end()) { sle = *it; it->SetRemoved(true); RemoveFromCache_unlocked(*it); serviceSet.erase(it); } } if (!sle.IsNull()) { coreCtx->serviceHooks.HandleServiceListenerUnreg(sle); } }
void ServiceListeners::GetMatchingServiceListeners(const ServiceEvent& evt, ServiceListenerEntries& set) { // Filter the original set of listeners ServiceListenerEntries receivers = (this->Lock(), serviceSet); // This must not be called with any locks held coreCtx->serviceHooks.FilterServiceEventReceivers(evt, receivers); // Get a copy of the service reference and keep it until we are // done with its properties. auto ref = evt.GetServiceReference(); auto props = ref.d.load()->GetProperties(); { auto l = this->Lock(); US_UNUSED(l); // Check complicated or empty listener filters for (auto& sse : complicatedListeners) { if (receivers.count(sse) == 0) continue; const LDAPExpr& ldapExpr = sse.GetLDAPExpr(); if (ldapExpr.IsNull() || ldapExpr.Evaluate(props, false)) { set.insert(sse); } } // Check the cache const auto c = any_cast<std::vector<std::string>>(props->Value_unlocked(Constants::OBJECTCLASS)); for (auto& objClass : c) { AddToSet_unlocked(set, receivers, OBJECTCLASS_IX, objClass); } long service_id = any_cast<long>(props->Value_unlocked(Constants::SERVICE_ID)); AddToSet_unlocked(set, receivers, SERVICE_ID_IX, cppmicroservices::util::ToString((service_id))); } }
bool ServiceRegistrationBasePrivate::IsUsedByBundle(BundlePrivate* bundle) const { auto l = this->Lock(); US_UNUSED(l); return (dependents.find(bundle) != dependents.end()) || (prototypeServiceInstances.find(bundle) != prototypeServiceInstances.end()); }