Apache Celix  2.3.0
An implementation of the OSGi specification adapted to C and C++
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 
27 #include "celix/Constants.h"
28 #include "celix/Properties.h"
29 #include "celix/Exception.h"
30 #include "celix_bundle_context.h"
31 #include "celix_bundle.h"
32 #include "celix_framework.h"
33 
34 namespace celix {
35 
38  REGISTERED,
41  };
42 
43  class ServiceRegistration;
44 
54  public:
55 
70  static std::shared_ptr<ServiceRegistration> create(std::shared_ptr<celix_bundle_context_t> cCtx,
71  std::shared_ptr<void> svc,
72  std::string_view name,
73  std::string_view version,
74  celix::Properties properties,
75  bool registerAsync,
76  bool unregisterAsync,
77  std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks,
78  std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks) {
79  auto delCallback = [](ServiceRegistration* reg) {
80  if (reg->getState() == ServiceRegistrationState::UNREGISTERED) {
81  delete reg;
82  } else {
83  /*
84  * if not registered/unregistering -> unregister() -> new event on the Celix event thread
85  * if unregistering -> nop unregister() -> there is already a event on the Celix event thread to unregister
86  */
87  reg->unregister();
88 
89  /*
90  * Creating event on the Event loop, this will be after the unregistration is done
91  */
92  auto* fw = celix_bundleContext_getFramework(reg->cCtx.get());
93  auto* bnd = celix_bundleContext_getBundle(reg->cCtx.get());
94  long bndId = celix_bundle_getId(bnd);
96  fw,
97  -1,
98  bndId,
99  "celix::ServiceRegistration delete callback",
100  reg,
101  [](void *data) {
102  auto* r = static_cast<ServiceRegistration*>(data);
103  delete r;
104  },
105  nullptr,
106  nullptr);
107  }
108  };
109 
110  auto reg = std::shared_ptr<ServiceRegistration>{
112  std::move(cCtx),
113  std::move(svc),
114  name,
115  version,
116  std::move(properties),
117  registerAsync,
118  unregisterAsync,
119  std::move(onRegisteredCallbacks),
120  std::move(onUnregisteredCallbacks)},
121  delCallback
122  };
123  reg->setSelf(reg);
124  reg->registerService();
125  return reg;
126  }
127 
131  const std::string& getServiceName() const { return name; }
132 
138  const std::string& getServiceVersion() const { return version; }
139 
143  const celix::Properties& getServiceProperties() const { return properties; }
144 
149  std::lock_guard<std::mutex> lck{mutex};
150  return state;
151  }
152 
156  long getServiceId() const {
157  std::lock_guard<std::mutex> lck{mutex};
158  return svcId;
159  }
160 
164  long getServiceRanking() const {
165  return properties.getAsLong(celix::SERVICE_RANKING, 0);
166  }
167 
171  void wait() const {
172  bool needWaitUnregistering = false;
173  bool needWaitRegistering = false;
174  long localId;
175  {
176  std::lock_guard<std::mutex> lck{mutex};
177  localId = svcId;
179  needWaitRegistering = true;
180  } else if (state == ServiceRegistrationState::UNREGISTERING) {
181  needWaitUnregistering = true;
182  }
183  }
184  if (needWaitRegistering) {
186  }
187  if (needWaitUnregistering) {
189  }
190  }
191 
198  void unregister() {
199  if (unregisterAsync) {
200  std::lock_guard<std::mutex> lck{mutex};
202  //not yet unregistering
204 
205  //NOTE: As long this unregister event is in the queue, the ServiceRegistration will wait in its dtor
206  celix_bundleContext_unregisterServiceAsync(cCtx.get(), svcId, this, [](void *data) {
207  auto reg = static_cast<ServiceRegistration*>(data);
208  {
209  std::lock_guard<std::mutex> lck{reg->mutex};
210  reg->state = ServiceRegistrationState::UNREGISTERED;
211  reg->svc.reset();
212  }
213  for (const auto &cb : reg->onUnregisteredCallbacks) {
214  cb(*reg);
215  }
216  });
217  }
218  } else /*sync*/ {
219  long localSvcId = -1;
220  {
221  std::lock_guard<std::mutex> lck{mutex};
224  localSvcId = svcId;
225  svcId = -1;
226  }
227  }
228  if (localSvcId >= 0) {
229  celix_bundleContext_unregisterService(cCtx.get(), localSvcId);
230  {
231  std::lock_guard<std::mutex> lck{mutex};
233  svc.reset();
234  }
235  for (const auto& cb: onUnregisteredCallbacks) {
236  cb(*this);
237  }
238  }
239  }
240  }
241 
247  std::shared_ptr<ServiceRegistration> getSelf() const {
248  std::lock_guard<std::mutex> lck{mutex};
249  return self.lock();
250  }
251 
252  private:
257  std::shared_ptr<celix_bundle_context_t> _cCtx,
258  std::shared_ptr<void> _svc,
259  std::string_view _name,
260  std::string_view _version,
261  celix::Properties _properties,
262  bool _registerAsync,
263  bool _unregisterAsync,
264  std::vector<std::function<void(ServiceRegistration&)>> _onRegisteredCallbacks,
265  std::vector<std::function<void(ServiceRegistration&)>> _onUnregisteredCallbacks) :
266  cCtx{std::move(_cCtx)},
267  name{_name},
268  version{_version},
269  properties{std::move(_properties)},
270  registerAsync{_registerAsync},
271  unregisterAsync{_unregisterAsync},
272  onRegisteredCallbacks{std::move(_onRegisteredCallbacks)},
273  onUnregisteredCallbacks{std::move(_onUnregisteredCallbacks)},
274  svc{std::move(_svc)} {}
275 
276 
285  void registerService() {
286  //setup registration using C api.
287  auto* cProps = celix_properties_copy(properties.getCProperties());
289  opts.svc = svc.get();
290  opts.serviceName = name.c_str();
291  opts.properties = cProps;
292  if (!version.empty()) {
293  opts.serviceVersion = version.c_str();
294  }
295 
296  if (registerAsync) {
297  opts.asyncData = static_cast<void*>(this);
298  opts.asyncCallback = [](void *data, long /*svcId*/) {
299  auto *reg = static_cast<ServiceRegistration *>(data);
300  {
301  std::lock_guard<std::mutex> lck{reg->mutex};
303  }
304  for (const auto &cb : reg->onRegisteredCallbacks) {
305  cb(*reg);
306  }
307  };
308  std::lock_guard<std::mutex> lck{mutex};
309  svcId = celix_bundleContext_registerServiceWithOptionsAsync(cCtx.get(), &opts);
310  if (svcId < 0) {
311  throw celix::Exception{"Cannot register service"};
312  }
313  } else /*sync*/ {
314  long localSvcId = celix_bundleContext_registerServiceWithOptions(cCtx.get(), &opts);
315  if (localSvcId < 0) {
316  throw celix::Exception{"Cannot register service"};
317  }
318  {
319  std::lock_guard<std::mutex> lck{mutex};
320  svcId = localSvcId;
322  }
323  for (const auto& cb: onRegisteredCallbacks) {
324  cb(*this);
325  }
326  }
327  }
328 
332  void setSelf(const std::shared_ptr<ServiceRegistration>& s) {
333  std::lock_guard<std::mutex> lck{mutex};
334  self = s;
335  }
336 
337  const std::shared_ptr<celix_bundle_context_t> cCtx;
338  const std::string name;
339  const std::string version;
340  const celix::Properties properties;
341  const bool registerAsync;
342  const bool unregisterAsync;
343  const std::vector<std::function<void(ServiceRegistration&)>> onRegisteredCallbacks;
344  const std::vector<std::function<void(ServiceRegistration&)>> onUnregisteredCallbacks;
345 
346  mutable std::mutex mutex{}; //protects below
347  long svcId{-1};
348  std::shared_ptr<void> svc;
350  std::weak_ptr<ServiceRegistration> self{}; //weak ptr to self, so that callbacks can receive a shared ptr
351  };
352 
353 }
celix_bundleContext_registerServiceWithOptionsAsync
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_framework_fireGenericEvent
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
Definition: Bundle.h:26
celix::ServiceRegistration::getSelf
std::shared_ptr< ServiceRegistration > getSelf() const
Returns the shared_ptr of for this object.
Definition: ServiceRegistration.h:247
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:171
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:70
celix::ServiceRegistrationState::UNREGISTERING
@ UNREGISTERING
celix_bundleContext_waitForAsyncRegistration
void celix_bundleContext_waitForAsyncRegistration(celix_bundle_context_t *ctx, long serviceId)
Waits til the async service registration for the provided serviceId is done.
Constants.h
celix::ServiceRegistration
A registered service.
Definition: ServiceRegistration.h:53
celix::ServiceRegistrationState::REGISTERING
@ REGISTERING
celix_bundleContext_registerServiceWithOptions
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.
celix_bundleContext_unregisterServiceAsync
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::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:148
Exception.h
celix::ServiceRegistration::getServiceId
long getServiceId() const
The service id for this service registration.
Definition: ServiceRegistration.h:156
celix::ServiceRegistration::getServiceName
const std::string & getServiceName() const
The service name for this service registration.
Definition: ServiceRegistration.h:131
celix_service_registration_options::asyncCallback
void(* asyncCallback)(void *data, long serviceId) CELIX_OPTS_INIT
Async callback.
Definition: celix_bundle_context.h:199
celix_framework.h
celix_bundleContext_getFramework
celix_framework_t * celix_bundleContext_getFramework(const celix_bundle_context_t *ctx)
celix::ServiceRegistrationState::UNREGISTERED
@ UNREGISTERED
celix::ServiceRegistration::getServiceProperties
const celix::Properties & getServiceProperties() const
The service properties for this service registration.
Definition: ServiceRegistration.h:143
celix::ServiceRegistration::getServiceRanking
long getServiceRanking() const
The service ranking for this service registration.
Definition: ServiceRegistration.h:164
celix::ServiceRegistration::unregister
void unregister()
Unregister the service from the Celix framework if the state is REGISTERED.
Definition: ServiceRegistration.h:198
celix::ServiceRegistrationState
ServiceRegistrationState
Definition: ServiceRegistration.h:36
celix::ServiceRegistrationState::REGISTERED
@ REGISTERED
celix_bundle.h
celix::ServiceRegistration::getServiceVersion
const std::string & getServiceVersion() const
The service version for this service registration.
Definition: ServiceRegistration.h:138
celix_bundle_getId
long celix_bundle_getId(const celix_bundle_t *bnd)
Returns the bundle id.
celix::dm::Properties
celix::Properties Properties
Definition: Properties.h:25
celix::Exception
Celix runtime Exception.
Definition: Exception.h:28
celix_bundleContext_waitForAsyncUnregistration
void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t *ctx, long serviceId)
Waits til the async service unregistration for the provided serviceId is done.
celix_bundle_context.h
celix_bundleContext_getBundle
celix_bundle_t * celix_bundleContext_getBundle(const celix_bundle_context_t *ctx)
Returns the bundle for this bundle context.
celix_bundleContext_unregisterService
void celix_bundleContext_unregisterService(celix_bundle_context_t *ctx, long serviceId)
Unregister the service or service factory with service id.