Apache Celix  2.4.0
Apache Celix is a framework for C, C++14 and C++17 to develop dynamic modular software applications using component and in-process service-oriented programming.
ServiceRegistration.h
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #pragma once
21 
22 #include <memory>
23 #include <mutex>
24 #include <vector>
25 #include <functional>
26 
28 #include "celix/Constants.h"
29 #include "celix/Properties.h"
30 #include "celix_bundle_context.h"
31 #include "celix_bundle.h"
32 #include "celix_framework.h"
33 
34 namespace celix {
35 
36  enum class ServiceRegistrationState : std::uint8_t {
38  REGISTERED,
41  };
42 
43  class ServiceRegistration;
44 
54  public:
55 
70 #if __cplusplus >= 201703L //C++17 or higher
71  static std::shared_ptr<ServiceRegistration> create(std::shared_ptr<celix_bundle_context_t> cCtx,
72  std::shared_ptr<void> svc,
73  std::string_view name,
74  std::string_view version,
75  celix::Properties properties,
76  bool registerAsync,
77  bool unregisterAsync,
78  std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
79  std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
80  return createInternal(std::move(cCtx), std::move(svc), name.data(),
81  version.data(), std::move(properties), registerAsync,
82  unregisterAsync, std::move(onRegisteredCallbacks), std::move(onUnregisteredCallbacks));
83  }
84 #else
85  static std::shared_ptr<ServiceRegistration> create(std::shared_ptr<celix_bundle_context_t> cCtx,
86  std::shared_ptr<void> svc,
87  const std::string& name,
88  const std::string& version,
89  celix::Properties properties,
90  bool registerAsync,
91  bool unregisterAsync,
92  std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
93  std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
94  return createInternal(std::move(cCtx), std::move(svc), name.c_str(),
95  version.c_str(), std::move(properties), registerAsync,
96  unregisterAsync, std::move(onRegisteredCallbacks), std::move(onUnregisteredCallbacks));
97  }
98 #endif
99 
103  const std::string& getServiceName() const { return name; }
104 
110  const std::string& getServiceVersion() const { return version; }
111 
115  const celix::Properties& getServiceProperties() const { return properties; }
116 
121  std::lock_guard<std::mutex> lck{mutex};
122  return state;
123  }
124 
128  long getServiceId() const {
129  std::lock_guard<std::mutex> lck{mutex};
130  return svcId;
131  }
132 
136  long getServiceRanking() const {
137  return properties.getAsLong(celix::SERVICE_RANKING, 0);
138  }
139 
143  void wait() const {
144  bool needWaitUnregistering = false;
145  bool needWaitRegistering = false;
146  long localId;
147  {
148  std::lock_guard<std::mutex> lck{mutex};
149  localId = svcId;
151  needWaitRegistering = true;
152  } else if (state == ServiceRegistrationState::UNREGISTERING) {
153  needWaitUnregistering = true;
154  }
155  }
156  if (needWaitRegistering) {
158  }
159  if (needWaitUnregistering) {
161  }
162  }
163 
170  void unregister() {
171  if (unregisterAsync) {
172  std::lock_guard<std::mutex> lck{mutex};
174  //not yet unregistering
176 
177  //NOTE: As long this unregister event is in the queue, the ServiceRegistration will wait in its dtor
178  celix_bundleContext_unregisterServiceAsync(cCtx.get(), svcId, this, [](void *data) {
179  auto reg = static_cast<ServiceRegistration*>(data);
180  {
181  std::lock_guard<std::mutex> lck{reg->mutex};
182  reg->state = ServiceRegistrationState::UNREGISTERED;
183  reg->svc.reset();
184  }
185  for (const auto &cb : reg->onUnregisteredCallbacks) {
186  cb(*reg);
187  }
188  });
189  }
190  } else /*sync*/ {
191  long localSvcId = -1;
192  {
193  std::lock_guard<std::mutex> lck{mutex};
196  localSvcId = svcId;
197  svcId = -1;
198  }
199  }
200  if (localSvcId >= 0) {
201  celix_bundleContext_unregisterService(cCtx.get(), localSvcId);
202  {
203  std::lock_guard<std::mutex> lck{mutex};
205  svc.reset();
206  }
207  for (const auto& cb: onUnregisteredCallbacks) {
208  cb(*this);
209  }
210  }
211  }
212  }
213 
219  std::shared_ptr<ServiceRegistration> getSelf() const {
220  std::lock_guard<std::mutex> lck{mutex};
221  return self.lock();
222  }
223 
224  private:
229  std::shared_ptr<celix_bundle_context_t> _cCtx,
230  std::shared_ptr<void> _svc,
231  const char* _name,
232  const char* _version,
233  celix::Properties _properties,
234  bool _registerAsync,
235  bool _unregisterAsync,
236  std::vector<std::function<void(ServiceRegistration&)>> _onRegisteredCallbacks,
237  std::vector<std::function<void(ServiceRegistration&)>> _onUnregisteredCallbacks) :
238  cCtx{std::move(_cCtx)},
239  name{_name},
240  version{_version},
241  properties{std::move(_properties)},
242  registerAsync{_registerAsync},
243  unregisterAsync{_unregisterAsync},
244  onRegisteredCallbacks{std::move(_onRegisteredCallbacks)},
245  onUnregisteredCallbacks{std::move(_onUnregisteredCallbacks)},
246  svc{std::move(_svc)} {}
247 
248  static std::shared_ptr<ServiceRegistration> createInternal(
249  std::shared_ptr<celix_bundle_context_t> cCtx,
250  std::shared_ptr<void> svc,
251  const char* name,
252  const char* version,
253  celix::Properties properties,
254  bool registerAsync,
255  bool unregisterAsync,
256  std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
257  std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
258  auto delCallback = [](ServiceRegistration* reg) {
259  if (reg->getState() == ServiceRegistrationState::UNREGISTERED) {
260  delete reg;
261  } else {
262  /*
263  * if not registered/unregistering -> unregister() -> new event on the Celix event thread
264  * if unregistering -> nop unregister() -> there is already a event on the Celix event thread to unregister
265  */
266  reg->unregister();
267 
268  /*
269  * Creating event on the Event loop, this will be after the unregistration is done
270  */
271  auto* fw = celix_bundleContext_getFramework(reg->cCtx.get());
272  auto* bnd = celix_bundleContext_getBundle(reg->cCtx.get());
273  long bndId = celix_bundle_getId(bnd);
275  fw,
276  -1,
277  bndId,
278  "celix::ServiceRegistration delete callback",
279  reg,
280  [](void *data) {
281  auto* r = static_cast<ServiceRegistration*>(data);
282  delete r;
283  },
284  nullptr,
285  nullptr);
286  }
287  };
288 
289  auto reg = std::shared_ptr<ServiceRegistration>{
290  new ServiceRegistration{
291  std::move(cCtx),
292  std::move(svc),
293  name,
294  version,
295  std::move(properties),
296  registerAsync,
297  unregisterAsync,
298  std::move(onRegisteredCallbacks),
299  std::move(onUnregisteredCallbacks)},
300  delCallback
301  };
302  reg->setSelf(reg);
303  reg->registerService();
304  return reg;
305  }
306 
315  void registerService() {
316  //setup registration using C api.
317  auto* cProps = celix_properties_copy(properties.getCProperties());
319  opts.svc = svc.get();
320  opts.serviceName = name.c_str();
321  opts.properties = cProps;
322  if (!version.empty()) {
323  opts.serviceVersion = version.c_str();
324  }
325 
326  if (registerAsync) {
327  opts.asyncData = static_cast<void*>(this);
328  opts.asyncCallback = [](void *data, long /*svcId*/) {
329  auto *reg = static_cast<ServiceRegistration *>(data);
330  {
331  std::lock_guard<std::mutex> lck{reg->mutex};
333  }
334  for (const auto &cb : reg->onRegisteredCallbacks) {
335  cb(*reg);
336  }
337  };
338  std::lock_guard<std::mutex> lck{mutex};
339  svcId = celix_bundleContext_registerServiceWithOptionsAsync(cCtx.get(), &opts);
340  if (svcId < 0) {
341  throw celix::ServiceRegistrationException{"Cannot register service"};
342  }
343  } else /*sync*/ {
344  long localSvcId = celix_bundleContext_registerServiceWithOptions(cCtx.get(), &opts);
345  if (localSvcId < 0) {
346  throw celix::ServiceRegistrationException{"Cannot register service"};
347  }
348  {
349  std::lock_guard<std::mutex> lck{mutex};
350  svcId = localSvcId;
352  }
353  for (const auto& cb: onRegisteredCallbacks) {
354  cb(*this);
355  }
356  }
357  }
358 
362  void setSelf(const std::shared_ptr<ServiceRegistration>& s) {
363  std::lock_guard<std::mutex> lck{mutex};
364  self = s;
365  }
366 
367  const std::shared_ptr<celix_bundle_context_t> cCtx;
368  const std::string name;
369  const std::string version;
370  const celix::Properties properties;
371  const bool registerAsync;
372  const bool unregisterAsync;
373  const std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks;
374  const std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks;
375 
376  mutable std::mutex mutex{}; //protects below
377  long svcId{-1};
378  std::shared_ptr<void> svc;
380  std::weak_ptr<ServiceRegistration> self{}; //weak ptr to self, so that callbacks can receive a shared ptr
381  };
382 
383 }
celix
Definition: Bundle.h:27
celix::ServiceRegistration::getSelf
std::shared_ptr< ServiceRegistration > getSelf() const
Returns the shared_ptr of for this object.
Definition: ServiceRegistration.h:219
celix::ServiceRegistrationState::REGISTERING
@ REGISTERING
celix::ServiceRegistrationState
ServiceRegistrationState
Definition: ServiceRegistration.h:36
celix_service_registration_options
Service Registration Options when registering services to the Celix framework.
Definition: celix_bundle_context.h:124
celix::ServiceRegistration::wait
void wait() const
If the service registration is REGISTERING or UNREGISTERING, wait until state is REGISTERED OR UNREGI...
Definition: ServiceRegistration.h:143
celix::ServiceRegistration::create
static std::shared_ptr< ServiceRegistration > create(std::shared_ptr< celix_bundle_context_t > cCtx, std::shared_ptr< void > svc, std::string_view name, std::string_view version, celix::Properties properties, bool registerAsync, bool unregisterAsync, std::vector< std::function< void(ServiceRegistration &)>> onRegisteredCallbacks, std::vector< std::function< void(ServiceRegistration &)>> onUnregisteredCallbacks)
Definition: ServiceRegistration.h:71
celix_bundleContext_registerServiceWithOptions
CELIX_FRAMEWORK_EXPORT long celix_bundleContext_registerServiceWithOptions(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts)
Register a service to the Celix framework using the provided service registration options.
Constants.h
celix::ServiceRegistration
A registered service.
Definition: ServiceRegistration.h:53
celix_bundleContext_getBundle
CELIX_FRAMEWORK_EXPORT celix_bundle_t * celix_bundleContext_getBundle(const celix_bundle_context_t *ctx)
Returns the bundle for this bundle context.
celix::SERVICE_RANKING
constexpr const char *const SERVICE_RANKING
Service property (named "service.ranking") identifying a service's ranking number (of type long).
Definition: Constants.h:91
celix::ServiceRegistration::getState
ServiceRegistrationState getState() const
The state of the service registration.
Definition: ServiceRegistration.h:120
celix::ServiceRegistrationState::UNREGISTERING
@ UNREGISTERING
celix_framework_fireGenericEvent
CELIX_FRAMEWORK_EXPORT long celix_framework_fireGenericEvent(celix_framework_t *fw, long eventId, long bndId, const char *eventName, void *processData, void(*processCallback)(void *data), void *doneData, void(*doneCallback)(void *doneData))
Fire a generic event. The event will be added to the event loop and handled on the event loop thread.
celix::ServiceRegistration::getServiceId
long getServiceId() const
The service id for this service registration.
Definition: ServiceRegistration.h:128
celix::ServiceRegistration::getServiceName
const std::string & getServiceName() const
The service name for this service registration.
Definition: ServiceRegistration.h:103
celix_service_registration_options::asyncCallback
void(* asyncCallback)(void *data, long serviceId) CELIX_OPTS_INIT
Async callback.
Definition: celix_bundle_context.h:204
celix::ServiceRegistrationException
Celix Service Registration Exception.
Definition: FrameworkExceptions.h:28
celix_framework.h
The Celix Framework API.
celix_bundleContext_unregisterService
CELIX_FRAMEWORK_EXPORT void celix_bundleContext_unregisterService(celix_bundle_context_t *ctx, long serviceId)
Unregister the service or service factory with service id.
celix::ServiceRegistration::getServiceProperties
const celix::Properties & getServiceProperties() const
The service properties for this service registration.
Definition: ServiceRegistration.h:115
FrameworkExceptions.h
celix::ServiceRegistration::getServiceRanking
long getServiceRanking() const
The service ranking for this service registration.
Definition: ServiceRegistration.h:136
celix::ServiceRegistration::unregister
void unregister()
Unregister the service from the Celix framework if the state is REGISTERED.
Definition: ServiceRegistration.h:170
celix_bundleContext_unregisterServiceAsync
CELIX_FRAMEWORK_EXPORT void celix_bundleContext_unregisterServiceAsync(celix_bundle_context_t *ctx, long serviceId, void *doneData, void(*doneCallback)(void *doneData))
Unregister the service or service factory with service id.
celix_bundleContext_waitForAsyncUnregistration
CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t *ctx, long serviceId)
Waits til the async service unregistration for the provided serviceId is done.
celix_bundleContext_waitForAsyncRegistration
CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncRegistration(celix_bundle_context_t *ctx, long serviceId)
Waits til the async service registration for the provided serviceId is done.
celix_bundle_getId
CELIX_FRAMEWORK_EXPORT long celix_bundle_getId(const celix_bundle_t *bnd)
Return the bundle id.
celix_bundle.h
celix::ServiceRegistration::getServiceVersion
const std::string & getServiceVersion() const
The service version for this service registration.
Definition: ServiceRegistration.h:110
celix::ServiceRegistrationState::UNREGISTERED
@ UNREGISTERED
celix::dm::Properties
celix::Properties Properties
Definition: Properties.h:25
celix::ServiceRegistrationState::REGISTERED
@ REGISTERED
celix_bundleContext_getFramework
CELIX_FRAMEWORK_EXPORT celix_framework_t * celix_bundleContext_getFramework(const celix_bundle_context_t *ctx)
celix_bundle_context.h
celix_bundleContext_registerServiceWithOptionsAsync
CELIX_FRAMEWORK_EXPORT long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts)
Register a service to the Celix framework using the provided service registration options.