Leosac  0.8.0
Open Source Access Control
ServiceRegistry.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014-2016 Leosac
3 
4  This file is part of Leosac.
5 
6  Leosac is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Affero General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Leosac is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Affero General Public License for more details.
15 
16  You should have received a copy of the GNU Affero General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #pragma once
21 #include "tools/JSONUtils.hpp"
22 #include "tools/bs2.hpp"
23 #include "tools/log.hpp"
25 #include <boost/type_index.hpp>
26 
27 namespace Leosac
28 {
29 
30 namespace service_event
31 {
33 {
36 };
37 class Event
38 {
39  public:
41  : type_(t)
42  {
43  }
44  virtual ~Event() = default;
45  EventType type() const
46  {
47  return type_;
48  }
49 
50  private:
52 };
53 
54 class ServiceRegistered : public Event
55 {
56  public:
57  ServiceRegistered(const boost::typeindex::type_index &interface_type)
60  {
61  }
62  boost::typeindex::type_index interface_type() const
63  {
65  }
66 
67  private:
68  boost::typeindex::type_index service_interface_type_;
69 };
70 
71 class ServiceUnregistered : public Event
72 {
73  public:
74  ServiceUnregistered(const boost::typeindex::type_index &interface_type)
77  {
78  }
79  boost::typeindex::type_index interface_type() const
80  {
82  }
83 
84  private:
85  boost::typeindex::type_index service_interface_type_;
86 };
87 }
88 
111 {
112 
122  {
124  : raw_service(nullptr){};
125  boost::typeindex::type_index service_interface;
126 
127  void *raw_service;
128  std::unique_ptr<void, std::function<void(void *)>> unique_service;
129  };
130  using RegistrationInfoPtr = std::shared_ptr<RegistrationInfo>;
131 
132  public:
133  using RegistrationHandle = std::weak_ptr<void>;
134 
145  template <typename ServiceInterface>
146  RegistrationHandle register_service(std::unique_ptr<ServiceInterface> srv)
147  {
148  RegistrationInfoPtr registration;
149  {
150  std::lock_guard<std::mutex> lg(mutex_);
151 
152  auto type_index = boost::typeindex::type_id<ServiceInterface>();
153  ASSERT_LOG(!services_.count(type_index),
154  "Already has a service registered for this interface: "
155  << type_index.pretty_name());
156  registration = std::make_shared<RegistrationInfo>();
157  registration->service_interface = type_index;
158  registration->unique_service =
159  std::unique_ptr<void, std::function<void(void *)>>(
160  srv.release(), [](void *service_instance) {
161  auto typed_service_ptr =
162  static_cast<ServiceInterface *>(service_instance);
163  ASSERT_LOG(service_instance && typed_service_ptr,
164  "service_instance is null.");
165  delete typed_service_ptr;
166  });
167  services_.insert(std::make_pair(type_index, registration));
168  }
169  signal_registration(registration);
170  return registration;
171  }
172 
173  template <typename ServiceInterface>
174  RegistrationHandle register_service(ServiceInterface *srv)
175  {
176  RegistrationInfoPtr registration;
177  {
178  std::lock_guard<std::mutex> lg(mutex_);
179 
180  auto type_index = boost::typeindex::type_id<ServiceInterface>();
181  ASSERT_LOG(!services_.count(type_index),
182  "Already has a service registered for this interface: "
183  << type_index.pretty_name());
184 
185  registration = std::make_shared<RegistrationInfo>();
186  registration->service_interface = type_index;
187  registration->raw_service = srv;
188  services_.insert(std::make_pair(type_index, registration));
189  }
190  signal_registration(registration);
191  return registration;
192  }
193 
205  {
206  bool success = false;
207  RegistrationInfoPtr registration_sptr;
208  {
209  std::lock_guard<std::mutex> lg(mutex_);
210 
211  std::shared_ptr<void> registration = h.lock();
212  if (registration)
213  {
214  registration_sptr =
215  std::static_pointer_cast<RegistrationInfo>(registration);
216 
217  // We must check that the service is not currently in use. If that's
218  // the
219  // case we must prevent the unregistration of the service.
220  // The reason for this if simple: It would make sense for the service
221  // object to be deleted by its owner after a successful
222  // unregister_service() call.
223  // However, is someone else holds a reference to it, ... SEGV
224 
225  // SPTR to service: the registry itself, our registration
226  // and registration_sptr objects.
227  if (registration_sptr.use_count() > 3)
228  {
229  // Someone else has a ref to this service.
230  return false;
231  }
232 
233  // Sanity check
234  ASSERT_LOG(
235  services_.count(registration_sptr->service_interface),
236  "Trying to unregister a service using an invalid handle.");
237  services_.erase(registration_sptr->service_interface);
238  success = true;
239  }
240  }
241  if (success)
242  signal_deregistration(registration_sptr);
243  return success;
244  }
245 
255  template <typename ServiceInterface>
257  {
258  bool success = false;
259  RegistrationInfoPtr registration;
260  {
261  std::lock_guard<std::mutex> lg(mutex_);
262  boost::typeindex::type_index idx =
263  boost::typeindex::type_id<ServiceInterface>();
264  auto itr = services_.find(idx);
265  if (itr != services_.end())
266  {
267  registration = itr->second;
268 
269  // Count: One in the registry, and the registration object and the
270  // iterator
271  if (registration.use_count() > 3)
272  {
273  // Someone is using the service. Cannot unregister.
274  return false;
275  }
276  services_.erase(idx);
277  success = true;
278  }
279  }
280  if (success)
281  signal_deregistration(registration);
282  return success;
283  }
284 
289  template <typename ServiceInterface>
290  std::shared_ptr<ServiceInterface> get_service() const
291  {
292  std::lock_guard<std::mutex> lg(mutex_);
293 
294  auto type_index = boost::typeindex::type_id<ServiceInterface>();
295  auto itr = services_.find(type_index);
296  if (itr != services_.end())
297  {
298  auto &registration = itr->second;
299  ServiceInterface *service_ptr;
300  if (registration->raw_service)
301  service_ptr =
302  static_cast<ServiceInterface *>(registration->raw_service);
303  else
304  service_ptr = static_cast<ServiceInterface *>(
305  registration->unique_service.get());
306  return std::shared_ptr<ServiceInterface>(registration, service_ptr);
307  }
308  return nullptr;
309  }
310 
315  template <typename ServiceInterface>
316  long use_count() const
317  {
318  auto srv = get_service<ServiceInterface>();
319 
320  if (!srv)
321  {
322  return -1;
323  }
324 
325  auto count = srv.use_count();
326  ASSERT_LOG(count >= 2, "Hum, we are missing some shared_ptr...");
327 
328  // Don't count the pointer we just retrieved, nor the pointer
329  // stored in the registry.
330  return count - 2;
331  }
332 
348  template <typename T>
349  bs2::connection register_event_listener(T &&callable)
350  {
351  static_assert(std::is_convertible<T, EventListenerT>::value,
352  "Callable is not convertible to EventListenerT");
353  return signal_.connect(callable);
354  }
355 
356  using EventListenerT = std::function<void(const service_event::Event &)>;
357 
358  private:
360  {
361  ASSERT_LOG(reg, "RegistrationInfoPtr is null");
362  service_event::ServiceRegistered ev(reg->service_interface);
363  signal_(ev);
364  }
365 
367  {
368  ASSERT_LOG(reg, "RegistrationInfoPtr is null");
369  service_event::ServiceUnregistered ev(reg->service_interface);
370  signal_(ev);
371  }
372 
373  mutable std::mutex mutex_;
374  std::map<boost::typeindex::type_index, RegistrationInfoPtr> services_;
375  bs2::signal<void(const service_event::Event &)> signal_;
376 };
377 }
Leosac::ServiceRegistry::unregister_service
bool unregister_service(RegistrationHandle h)
Unregister a service using the RegistrationHandle that was returned from the register_service() call.
Definition: ServiceRegistry.hpp:204
Leosac::service_event::Event::Event
Event(EventType t)
Definition: ServiceRegistry.hpp:40
Leosac::service_event::Event::~Event
virtual ~Event()=default
Leosac::service_event::EventType
EventType
Definition: ServiceRegistry.hpp:32
Leosac::ServiceRegistry::RegistrationInfo
An internal registration structure.
Definition: ServiceRegistry.hpp:121
Leosac::service_event::ServiceRegistered::interface_type
boost::typeindex::type_index interface_type() const
Definition: ServiceRegistry.hpp:62
Leosac::ServiceRegistry::unregister_service
bool unregister_service()
Unregister the service for the interface ServiceInterface.
Definition: ServiceRegistry.hpp:256
Leosac::ServiceRegistry::use_count
long use_count() const
How many strong (shared) pointer points to the service that provides ServiceInterface.
Definition: ServiceRegistry.hpp:316
Leosac::service_event::ServiceRegistered::service_interface_type_
boost::typeindex::type_index service_interface_type_
Definition: ServiceRegistry.hpp:68
Leosac::service_event::Event::type
EventType type() const
Definition: ServiceRegistry.hpp:45
ASSERT_LOG
#define ASSERT_LOG(cond, msg)
Definition: log.hpp:190
Leosac::ServiceRegistry::EventListenerT
std::function< void(const service_event::Event &)> EventListenerT
Definition: ServiceRegistry.hpp:356
Leosac::ServiceRegistry::mutex_
std::mutex mutex_
Definition: ServiceRegistry.hpp:373
Leosac::ServiceRegistry::RegistrationInfo::unique_service
std::unique_ptr< void, std::function< void(void *)> > unique_service
Definition: ServiceRegistry.hpp:128
Leosac::ServiceRegistry::services_
std::map< boost::typeindex::type_index, RegistrationInfoPtr > services_
Definition: ServiceRegistry.hpp:374
bs2.hpp
Leosac::ServiceRegistry::signal_registration
void signal_registration(const RegistrationInfoPtr &reg)
Definition: ServiceRegistry.hpp:359
Leosac::ServiceRegistry::signal_
bs2::signal< void(const service_event::Event &)> signal_
Definition: ServiceRegistry.hpp:375
Leosac::ServiceRegistry::signal_deregistration
void signal_deregistration(const RegistrationInfoPtr &reg)
Definition: ServiceRegistry.hpp:366
Leosac::service_event::ServiceUnregistered::interface_type
boost::typeindex::type_index interface_type() const
Definition: ServiceRegistry.hpp:79
Leosac::service_event::ServiceUnregistered::ServiceUnregistered
ServiceUnregistered(const boost::typeindex::type_index &interface_type)
Definition: ServiceRegistry.hpp:74
Registry.hpp
Leosac::service_event::UNREGISTERED
@ UNREGISTERED
Definition: ServiceRegistry.hpp:35
Leosac
This is the header file for a generated source file, GitSHA1.cpp.
Definition: APIStatusCode.hpp:22
Leosac::service_event::ServiceUnregistered::service_interface_type_
boost::typeindex::type_index service_interface_type_
Definition: ServiceRegistry.hpp:85
Leosac::service_event::ServiceRegistered
Definition: ServiceRegistry.hpp:54
Leosac::ServiceRegistry
A class that manages services.
Definition: ServiceRegistry.hpp:110
JSONUtils.hpp
Leosac::ServiceRegistry::RegistrationInfo::service_interface
boost::typeindex::type_index service_interface
Definition: ServiceRegistry.hpp:124
Leosac::ServiceRegistry::register_service
RegistrationHandle register_service(ServiceInterface *srv)
Definition: ServiceRegistry.hpp:174
Leosac::ServiceRegistry::RegistrationInfo::RegistrationInfo
RegistrationInfo()
Definition: ServiceRegistry.hpp:123
Leosac::ServiceRegistry::RegistrationHandle
std::weak_ptr< void > RegistrationHandle
Definition: ServiceRegistry.hpp:133
Leosac::ServiceRegistry::register_event_listener
bs2::connection register_event_listener(T &&callable)
Register a service-event listener.
Definition: ServiceRegistry.hpp:349
Leosac::ServiceRegistry::register_service
RegistrationHandle register_service(std::unique_ptr< ServiceInterface > srv)
Register a service by passing an unique_ptr to it.
Definition: ServiceRegistry.hpp:146
Leosac::ServiceRegistry::get_service
std::shared_ptr< ServiceInterface > get_service() const
Retrieve the service instance implementing the ServiceInterface, or nullptr if no such service was re...
Definition: ServiceRegistry.hpp:290
log.hpp
Leosac::service_event::Event
Definition: ServiceRegistry.hpp:37
Leosac::service_event::REGISTERED
@ REGISTERED
Definition: ServiceRegistry.hpp:34
Leosac::service_event::Event::type_
EventType type_
Definition: ServiceRegistry.hpp:51
Leosac::service_event::ServiceUnregistered
Definition: ServiceRegistry.hpp:71
Leosac::ServiceRegistry::RegistrationInfo::raw_service
void * raw_service
Definition: ServiceRegistry.hpp:127
Leosac::service_event::ServiceRegistered::ServiceRegistered
ServiceRegistered(const boost::typeindex::type_index &interface_type)
Definition: ServiceRegistry.hpp:57
Leosac::ServiceRegistry::RegistrationInfoPtr
std::shared_ptr< RegistrationInfo > RegistrationInfoPtr
Definition: ServiceRegistry.hpp:130