Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
usServiceRegistry.cpp
Go to the documentation of this file.
1 /*=============================================================================
2 
3  Library: CppMicroServices
4 
5  Copyright (c) German Cancer Research Center,
6  Division of Medical and Biological Informatics
7 
8  Licensed under the Apache License, Version 2.0 (the "License");
9  you may not use this file except in compliance with the License.
10  You may obtain a copy of the License at
11 
12  http://www.apache.org/licenses/LICENSE-2.0
13 
14  Unless required by applicable law or agreed to in writing, software
15  distributed under the License is distributed on an "AS IS" BASIS,
16  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  See the License for the specific language governing permissions and
18  limitations under the License.
19 
20 =============================================================================*/
21 
22 #include <iterator>
23 #include <stdexcept>
24 #include <cassert>
25 
26 #include "usServiceRegistry_p.h"
27 #include "usServiceFactory.h"
29 #include "usServiceRegistry_p.h"
30 #include "usServiceRegistrationBasePrivate.h"
31 #include "usModulePrivate.h"
32 #include "usCoreModuleContext_p.h"
33 
34 
35 US_BEGIN_NAMESPACE
36 
37 ServicePropertiesImpl ServiceRegistry::CreateServiceProperties(const ServiceProperties& in,
38  const std::vector<std::string>& classes,
39  bool isFactory, bool isPrototypeFactory,
40  long sid)
41 {
42  static long nextServiceID = 1;
43  ServiceProperties props(in);
44 
45  if (!classes.empty())
46  {
47  props.insert(std::make_pair(ServiceConstants::OBJECTCLASS(), classes));
48  }
49 
50  props.insert(std::make_pair(ServiceConstants::SERVICE_ID(), sid != -1 ? sid : nextServiceID++));
51 
52  if (isPrototypeFactory)
53  {
54  props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_PROTOTYPE()));
55  }
56  else if (isFactory)
57  {
58  props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_MODULE()));
59  }
60  else
61  {
62  props.insert(std::make_pair(ServiceConstants::SERVICE_SCOPE(), ServiceConstants::SCOPE_SINGLETON()));
63  }
64 
65  return ServicePropertiesImpl(props);
66 }
67 
68 ServiceRegistry::ServiceRegistry(CoreModuleContext* coreCtx)
69  : core(coreCtx)
70 {
71 
72 }
73 
74 ServiceRegistry::~ServiceRegistry()
75 {
76  Clear();
77 }
78 
79 void ServiceRegistry::Clear()
80 {
81  services.clear();
82  serviceRegistrations.clear();
83  classServices.clear();
84  core = 0;
85 }
86 
87 ServiceRegistrationBase ServiceRegistry::RegisterService(ModulePrivate* module,
88  const InterfaceMap& service,
89  const ServiceProperties& properties)
90 {
91  if (service.empty())
92  {
93  throw std::invalid_argument("Can't register empty InterfaceMap as a service");
94  }
95 
96  // Check if we got a service factory
97  bool isFactory = service.count("org.cppmicroservices.factory") > 0;
98  bool isPrototypeFactory = (isFactory ? dynamic_cast<PrototypeServiceFactory*>(reinterpret_cast<ServiceFactory*>(service.find("org.cppmicroservices.factory")->second)) != NULL : false);
99 
100  std::vector<std::string> classes;
101  // Check if service implements claimed classes and that they exist.
102  for (InterfaceMap::const_iterator i = service.begin();
103  i != service.end(); ++i)
104  {
105  if (i->first.empty() || (!isFactory && i->second == NULL))
106  {
107  throw std::invalid_argument("Can't register as null class");
108  }
109  classes.push_back(i->first);
110  }
111 
112  ServiceRegistrationBase res(module, service,
113  CreateServiceProperties(properties, classes, isFactory, isPrototypeFactory));
114  {
115  MutexLock lock(mutex);
116  services.insert(std::make_pair(res, classes));
117  serviceRegistrations.push_back(res);
118  for (std::vector<std::string>::const_iterator i = classes.begin();
119  i != classes.end(); ++i)
120  {
121  std::vector<ServiceRegistrationBase>& s = classServices[*i];
122  std::vector<ServiceRegistrationBase>::iterator ip =
123  std::lower_bound(s.begin(), s.end(), res);
124  s.insert(ip, res);
125  }
126  }
127 
128  ServiceReferenceBase r = res.GetReference(std::string());
129  ServiceListeners::ServiceListenerEntries listeners;
130  ServiceEvent registeredEvent(ServiceEvent::REGISTERED, r);
131  module->coreCtx->listeners.GetMatchingServiceListeners(registeredEvent, listeners);
132  module->coreCtx->listeners.ServiceChanged(listeners,
133  registeredEvent);
134  return res;
135 }
136 
137 void ServiceRegistry::UpdateServiceRegistrationOrder(const ServiceRegistrationBase& sr,
138  const std::vector<std::string>& classes)
139 {
140  MutexLock lock(mutex);
141  for (std::vector<std::string>::const_iterator i = classes.begin();
142  i != classes.end(); ++i)
143  {
144  std::vector<ServiceRegistrationBase>& s = classServices[*i];
145  s.erase(std::remove(s.begin(), s.end(), sr), s.end());
146  s.insert(std::lower_bound(s.begin(), s.end(), sr), sr);
147  }
148 }
149 
150 void ServiceRegistry::Get(const std::string& clazz,
151  std::vector<ServiceRegistrationBase>& serviceRegs) const
152 {
153  MutexLock lock(mutex);
154  Get_unlocked(clazz, serviceRegs);
155 }
156 
157 void ServiceRegistry::Get_unlocked(const std::string& clazz,
158  std::vector<ServiceRegistrationBase>& serviceRegs) const
159 {
160  MapClassServices::const_iterator i = classServices.find(clazz);
161  if (i != classServices.end())
162  {
163  serviceRegs = i->second;
164  }
165 }
166 
167 ServiceReferenceBase ServiceRegistry::Get(ModulePrivate* module, const std::string& clazz) const
168 {
169  MutexLock lock(mutex);
170  try
171  {
172  std::vector<ServiceReferenceBase> srs;
173  Get_unlocked(clazz, "", module, srs);
174  US_DEBUG << "get service ref " << clazz << " for module "
175  << module->info.name << " = " << srs.size() << " refs";
176 
177  if (!srs.empty())
178  {
179  return srs.back();
180  }
181  }
182  catch (const std::invalid_argument& )
183  { }
184 
185  return ServiceReferenceBase();
186 }
187 
188 void ServiceRegistry::Get(const std::string& clazz, const std::string& filter,
189  ModulePrivate* module, std::vector<ServiceReferenceBase>& res) const
190 {
191  MutexLock lock(mutex);
192  Get_unlocked(clazz, filter, module, res);
193 }
194 
195 void ServiceRegistry::Get_unlocked(const std::string& clazz, const std::string& filter,
196  ModulePrivate* module, std::vector<ServiceReferenceBase>& res) const
197 {
198  std::vector<ServiceRegistrationBase>::const_iterator s;
199  std::vector<ServiceRegistrationBase>::const_iterator send;
200  std::vector<ServiceRegistrationBase> v;
201  LDAPExpr ldap;
202  if (clazz.empty())
203  {
204  if (!filter.empty())
205  {
206  ldap = LDAPExpr(filter);
207  LDAPExpr::ObjectClassSet matched;
208  if (ldap.GetMatchedObjectClasses(matched))
209  {
210  v.clear();
211  for(LDAPExpr::ObjectClassSet::const_iterator className = matched.begin();
212  className != matched.end(); ++className)
213  {
214  MapClassServices::const_iterator i = classServices.find(*className);
215  if (i != classServices.end())
216  {
217  std::copy(i->second.begin(), i->second.end(), std::back_inserter(v));
218  }
219  }
220  if (!v.empty())
221  {
222  s = v.begin();
223  send = v.end();
224  }
225  else
226  {
227  return;
228  }
229  }
230  else
231  {
232  s = serviceRegistrations.begin();
233  send = serviceRegistrations.end();
234  }
235  }
236  else
237  {
238  s = serviceRegistrations.begin();
239  send = serviceRegistrations.end();
240  }
241  }
242  else
243  {
244  MapClassServices::const_iterator it = classServices.find(clazz);
245  if (it != classServices.end())
246  {
247  s = it->second.begin();
248  send = it->second.end();
249  }
250  else
251  {
252  return;
253  }
254  if (!filter.empty())
255  {
256  ldap = LDAPExpr(filter);
257  }
258  }
259 
260  for (; s != send; ++s)
261  {
262  ServiceReferenceBase sri = s->GetReference(clazz);
263 
264  if (filter.empty() || ldap.Evaluate(s->d->properties, false))
265  {
266  res.push_back(sri);
267  }
268  }
269 
270  if (!res.empty())
271  {
272  if (module != NULL)
273  {
274  core->serviceHooks.FilterServiceReferences(module->moduleContext, clazz, filter, res);
275  }
276  else
277  {
278  core->serviceHooks.FilterServiceReferences(NULL, clazz, filter, res);
279  }
280  }
281 }
282 
283 void ServiceRegistry::RemoveServiceRegistration(const ServiceRegistrationBase& sr)
284 {
285  MutexLock lock(mutex);
286 
287  assert(sr.d->properties.Value(ServiceConstants::OBJECTCLASS()).Type() == typeid(std::vector<std::string>));
288  const std::vector<std::string>& classes = ref_any_cast<std::vector<std::string> >(
289  sr.d->properties.Value(ServiceConstants::OBJECTCLASS()));
290  services.erase(sr);
291  serviceRegistrations.erase(std::remove(serviceRegistrations.begin(), serviceRegistrations.end(), sr),
292  serviceRegistrations.end());
293  for (std::vector<std::string>::const_iterator i = classes.begin();
294  i != classes.end(); ++i)
295  {
296  std::vector<ServiceRegistrationBase>& s = classServices[*i];
297  if (s.size() > 1)
298  {
299  s.erase(std::remove(s.begin(), s.end(), sr), s.end());
300  }
301  else
302  {
303  classServices.erase(*i);
304  }
305  }
306 }
307 
308 void ServiceRegistry::GetRegisteredByModule(ModulePrivate* p,
309  std::vector<ServiceRegistrationBase>& res) const
310 {
311  MutexLock lock(mutex);
312 
313  for (std::vector<ServiceRegistrationBase>::const_iterator i = serviceRegistrations.begin();
314  i != serviceRegistrations.end(); ++i)
315  {
316  if (i->d->module == p)
317  {
318  res.push_back(*i);
319  }
320  }
321 }
322 
323 void ServiceRegistry::GetUsedByModule(Module* p,
324  std::vector<ServiceRegistrationBase>& res) const
325 {
326  MutexLock lock(mutex);
327 
328  for (std::vector<ServiceRegistrationBase>::const_iterator i = serviceRegistrations.begin();
329  i != serviceRegistrations.end(); ++i)
330  {
331  if (i->d->IsUsedByModule(p))
332  {
333  res.push_back(*i);
334  }
335  }
336 }
337 
338 US_END_NAMESPACE
US_Core_EXPORT const std::string & SCOPE_MODULE()
US_Core_EXPORT const std::string & SCOPE_PROTOTYPE()
std::map< std::string, void * > InterfaceMap
US_Core_EXPORT const std::string & SERVICE_SCOPE()
US_Core_EXPORT const std::string & SCOPE_SINGLETON()
US_Core_EXPORT const std::string & OBJECTCLASS()
US_UNORDERED_MAP_TYPE< std::string, Any > ServiceProperties
const ValueType & ref_any_cast(const Any &operand)
Definition: usAny.h:449
static bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4)
Definition: jsoncpp.cpp:244
US_Core_EXPORT const std::string & SERVICE_ID()