Apache Celix  latest
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 <cstdint>
23 #include <memory>
24 #include <mutex>
25 #include <vector>
26 #include <functional>
27 
29 #include "celix/Constants.h"
30 #include "celix/Properties.h"
31 #include "celix_bundle_context.h"
32 #include "celix_bundle.h"
33 #include "celix_framework.h"
34 
35 namespace celix {
36 
37  enum class ServiceRegistrationState : std::uint8_t {
39  REGISTERED,
42  };
43 
44  class ServiceRegistration;
45 
55  public:
56 
71  static std::shared_ptr<ServiceRegistration> create(std::shared_ptr<celix_bundle_context_t> cCtx,
72  std::shared_ptr<void> svc,
73  const std::string& name,
74  const std::string& 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.c_str(),
81  version.c_str(), std::move(properties), registerAsync,
82  unregisterAsync, std::move(onRegisteredCallbacks), std::move(onUnregisteredCallbacks));
83  }
84 
88  const std::string& getServiceName() const { return name; }
89 
95  const std::string& getServiceVersion() const { return version; }
96 
100  const celix::Properties& getServiceProperties() const { return properties; }
101 
106  std::lock_guard<std::mutex> lck{mutex};
107  return state;
108  }
109 
113  long getServiceId() const {
114  std::lock_guard<std::mutex> lck{mutex};
115  return svcId;
116  }
117 
121  long getServiceRanking() const {
122  return properties.getAsLong(celix::SERVICE_RANKING, 0);
123  }
124 
128  void wait() const {
129  bool needWaitUnregistering = false;
130  bool needWaitRegistering = false;
131  long localId;
132  {
133  std::lock_guard<std::mutex> lck{mutex};
134  localId = svcId;
136  needWaitRegistering = true;
137  } else if (state == ServiceRegistrationState::UNREGISTERING) {
138  needWaitUnregistering = true;
139  }
140  }
141  if (needWaitRegistering) {
143  }
144  if (needWaitUnregistering) {
146  }
147  }
148 
155  void unregister() {
156  if (unregisterAsync) {
157  std::lock_guard<std::mutex> lck{mutex};
159  //not yet unregistering
161 
162  //NOTE: As long this unregister event is in the queue, the ServiceRegistration will wait in its dtor
163  celix_bundleContext_unregisterServiceAsync(cCtx.get(), svcId, this, [](void *data) {
164  auto reg = static_cast<ServiceRegistration*>(data);
165  {
166  std::lock_guard<std::mutex> lck{reg->mutex};
167  reg->state = ServiceRegistrationState::UNREGISTERED;
168  reg->svc.reset();
169  }
170  for (const auto &cb : reg->onUnregisteredCallbacks) {
171  cb(*reg);
172  }
173  });
174  }
175  } else /*sync*/ {
176  long localSvcId = -1;
177  {
178  std::lock_guard<std::mutex> lck{mutex};
181  localSvcId = svcId;
182  svcId = -1;
183  }
184  }
185  if (localSvcId >= 0) {
186  celix_bundleContext_unregisterService(cCtx.get(), localSvcId);
187  {
188  std::lock_guard<std::mutex> lck{mutex};
190  svc.reset();
191  }
192  for (const auto& cb: onUnregisteredCallbacks) {
193  cb(*this);
194  }
195  }
196  }
197  }
198 
204  std::shared_ptr<ServiceRegistration> getSelf() const {
205  std::lock_guard<std::mutex> lck{mutex};
206  return self.lock();
207  }
208 
209  private:
214  std::shared_ptr<celix_bundle_context_t> _cCtx,
215  std::shared_ptr<void> _svc,
216  const char* _name,
217  const char* _version,
218  celix::Properties _properties,
219  bool _registerAsync,
220  bool _unregisterAsync,
221  std::vector<std::function<void(ServiceRegistration&)>> _onRegisteredCallbacks,
222  std::vector<std::function<void(ServiceRegistration&)>> _onUnregisteredCallbacks) :
223  cCtx{std::move(_cCtx)},
224  name{_name},
225  version{_version},
226  properties{std::move(_properties)},
227  registerAsync{_registerAsync},
228  unregisterAsync{_unregisterAsync},
229  onRegisteredCallbacks{std::move(_onRegisteredCallbacks)},
230  onUnregisteredCallbacks{std::move(_onUnregisteredCallbacks)},
231  svc{std::move(_svc)} {}
232 
233  static std::shared_ptr<ServiceRegistration> createInternal(
234  std::shared_ptr<celix_bundle_context_t> cCtx,
235  std::shared_ptr<void> svc,
236  const char* name,
237  const char* version,
238  celix::Properties properties,
239  bool registerAsync,
240  bool unregisterAsync,
241  std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
242  std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
243  auto delCallback = [](ServiceRegistration* reg) {
244  if (reg->getState() == ServiceRegistrationState::UNREGISTERED) {
245  delete reg;
246  } else {
247  /*
248  * if not registered/unregistering -> unregister() -> new event on the Celix event thread
249  * if unregistering -> nop unregister() -> there is already a event on the Celix event thread to unregister
250  */
251  reg->unregister();
252 
253  /*
254  * Creating event on the Event loop, this will be after the unregistration is done
255  */
256  auto* fw = celix_bundleContext_getFramework(reg->cCtx.get());
257  auto* bnd = celix_bundleContext_getBundle(reg->cCtx.get());
258  long bndId = celix_bundle_getId(bnd);
260  fw,
261  -1,
262  bndId,
263  "celix::ServiceRegistration delete callback",
264  reg,
265  [](void *data) {
266  auto* r = static_cast<ServiceRegistration*>(data);
267  delete r;
268  },
269  nullptr,
270  nullptr);
271  }
272  };
273 
274  auto reg = std::shared_ptr<ServiceRegistration>{
275  new ServiceRegistration{
276  std::move(cCtx),
277  std::move(svc),
278  name,
279  version,
280  std::move(properties),
281  registerAsync,
282  unregisterAsync,
283  std::move(onRegisteredCallbacks),
284  std::move(onUnregisteredCallbacks)},
285  delCallback
286  };
287  reg->setSelf(reg);
288  reg->registerService();
289  return reg;
290  }
291 
300  void registerService() {
301  //setup registration using C api.
302  auto* cProps = celix_properties_copy(properties.getCProperties());
304  opts.svc = svc.get();
305  opts.serviceName = name.c_str();
306  opts.properties = cProps;
307  if (!version.empty()) {
308  opts.serviceVersion = version.c_str();
309  }
310 
311  if (registerAsync) {
312  opts.asyncData = static_cast<void*>(this);
313  opts.asyncCallback = [](void *data, long /*svcId*/) {
314  auto *reg = static_cast<ServiceRegistration *>(data);
315  {
316  std::lock_guard<std::mutex> lck{reg->mutex};
318  }
319  for (const auto &cb : reg->onRegisteredCallbacks) {
320  cb(*reg);
321  }
322  };
323  std::lock_guard<std::mutex> lck{mutex};
324  svcId = celix_bundleContext_registerServiceWithOptionsAsync(cCtx.get(), &opts);
325  if (svcId < 0) {
326  throw celix::ServiceRegistrationException{"Cannot register service"};
327  }
328  } else /*sync*/ {
329  long localSvcId = celix_bundleContext_registerServiceWithOptions(cCtx.get(), &opts);
330  if (localSvcId < 0) {
331  throw celix::ServiceRegistrationException{"Cannot register service"};
332  }
333  {
334  std::lock_guard<std::mutex> lck{mutex};
335  svcId = localSvcId;
337  }
338  for (const auto& cb: onRegisteredCallbacks) {
339  cb(*this);
340  }
341  }
342  }
343 
347  void setSelf(const std::shared_ptr<ServiceRegistration>& s) {
348  std::lock_guard<std::mutex> lck{mutex};
349  self = s;
350  }
351 
352  const std::shared_ptr<celix_bundle_context_t> cCtx;
353  const std::string name;
354  const std::string version;
355  const celix::Properties properties;
356  const bool registerAsync;
357  const bool unregisterAsync;
358  const std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks;
359  const std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks;
360 
361  mutable std::mutex mutex{}; //protects below
362  long svcId{-1};
363  std::shared_ptr<void> svc;
365  std::weak_ptr<ServiceRegistration> self{}; //weak ptr to self, so that callbacks can receive a shared ptr
366  };
367 
368 }
celix
Definition: Bundle.h:28
celix::ServiceRegistration::getSelf
std::shared_ptr< ServiceRegistration > getSelf() const
Returns the shared_ptr of for this object.
Definition: ServiceRegistration.h:204
celix::ServiceRegistrationState::REGISTERING
@ REGISTERING
celix::ServiceRegistrationState
ServiceRegistrationState
Definition: ServiceRegistration.h:37
celix_service_registration_options
Service Registration Options when registering services to the Celix framework.
Definition: celix_bundle_context.h:119
celix::ServiceRegistration::wait
void wait() const
If the service registration is REGISTERING or UNREGISTERING, wait until state is REGISTERED OR UNREGI...
Definition: ServiceRegistration.h:128
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:54
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:105
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:113
celix::ServiceRegistration::getServiceName
const std::string & getServiceName() const
The service name for this service registration.
Definition: ServiceRegistration.h:88
celix_service_registration_options::asyncCallback
void(* asyncCallback)(void *data, long serviceId) CELIX_OPTS_INIT
Async callback.
Definition: celix_bundle_context.h:192
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:100
FrameworkExceptions.h
celix::ServiceRegistration::getServiceRanking
long getServiceRanking() const
The service ranking for this service registration.
Definition: ServiceRegistration.h:121
celix::ServiceRegistration::unregister
void unregister()
Unregister the service from the Celix framework if the state is REGISTERED.
Definition: ServiceRegistration.h:155
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:95
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.
celix::ServiceRegistration::create
static std::shared_ptr< ServiceRegistration > create(std::shared_ptr< celix_bundle_context_t > cCtx, std::shared_ptr< void > svc, const std::string &name, const std::string &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