Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
usServiceListeners.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 "usUtils_p.h"
23 
24 #include "usServiceListeners_p.h"
25 #include "usServiceReferenceBasePrivate.h"
26 
27 #include "usCoreModuleContext_p.h"
28 #include "usModule.h"
29 #include "usModuleContext.h"
30 
31 
32 US_BEGIN_NAMESPACE
33 
34 const int ServiceListeners::OBJECTCLASS_IX = 0;
35 const int ServiceListeners::SERVICE_ID_IX = 1;
36 
37 ServiceListeners::ServiceListeners(CoreModuleContext* coreCtx)
38  : coreCtx(coreCtx)
39 {
40  hashedServiceKeys.push_back(ServiceConstants::OBJECTCLASS());
41  hashedServiceKeys.push_back(ServiceConstants::SERVICE_ID());
42 }
43 
44 void ServiceListeners::AddServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener,
45  void* data, const std::string& filter)
46 {
47  US_UNUSED(Lock(this));
48 
49  ServiceListenerEntry sle(mc, listener, data, filter);
50  RemoveServiceListener_unlocked(sle);
51 
52  serviceSet.insert(sle);
53  coreCtx->serviceHooks.HandleServiceListenerReg(sle);
54  CheckSimple(sle);
55 }
56 
57 void ServiceListeners::RemoveServiceListener(ModuleContext* mc, const ServiceListenerEntry::ServiceListener& listener,
58  void* data)
59 {
60  ServiceListenerEntry entryToRemove(mc, listener, data);
61 
62  US_UNUSED(Lock(this));
63  RemoveServiceListener_unlocked(entryToRemove);
64 }
65 
66 void ServiceListeners::RemoveServiceListener_unlocked(const ServiceListenerEntry& entryToRemove)
67 {
68  ServiceListenerEntries::const_iterator it = serviceSet.find(entryToRemove);
69  if (it != serviceSet.end())
70  {
71  it->SetRemoved(true);
72  coreCtx->serviceHooks.HandleServiceListenerUnreg(*it);
73  RemoveFromCache(*it);
74  serviceSet.erase(it);
75  }
76 }
77 
78 void ServiceListeners::AddModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data)
79 {
80  MutexLock lock(moduleListenerMapMutex);
81  ModuleListenerMap::value_type::second_type& listeners = moduleListenerMap[mc];
82  if (std::find_if(listeners.begin(), listeners.end(), std::bind1st(ModuleListenerCompare(), std::make_pair(listener, data))) == listeners.end())
83  {
84  listeners.push_back(std::make_pair(listener, data));
85  }
86 }
87 
88 void ServiceListeners::RemoveModuleListener(ModuleContext* mc, const ModuleListener& listener, void* data)
89 {
90  MutexLock lock(moduleListenerMapMutex);
91  moduleListenerMap[mc].remove_if(std::bind1st(ModuleListenerCompare(), std::make_pair(listener, data)));
92 }
93 
94 void ServiceListeners::ModuleChanged(const ModuleEvent& evt)
95 {
96  ModuleListenerMap filteredModuleListeners;
97  coreCtx->moduleHooks.FilterModuleEventReceivers(evt, filteredModuleListeners);
98 
99  for(ModuleListenerMap::iterator iter = filteredModuleListeners.begin(), end = filteredModuleListeners.end();
100  iter != end; ++iter)
101  {
102  for (ModuleListenerMap::mapped_type::iterator iter2 = iter->second.begin(), end2 = iter->second.end();
103  iter2 != end2; ++iter2)
104  {
105  try
106  {
107  (iter2->first)(evt);
108  }
109  catch (const std::exception& e)
110  {
111  US_WARN << "Module listener threw an exception: " << e.what();
112  }
113  }
114  }
115 }
116 
117 void ServiceListeners::RemoveAllListeners(ModuleContext* mc)
118 {
119  {
120  US_UNUSED(Lock(this));
121  for (ServiceListenerEntries::iterator it = serviceSet.begin();
122  it != serviceSet.end(); )
123  {
124 
125  if (it->GetModuleContext() == mc)
126  {
127  RemoveFromCache(*it);
128  serviceSet.erase(it++);
129  }
130  else
131  {
132  ++it;
133  }
134  }
135  }
136 
137  {
138  MutexLock lock(moduleListenerMapMutex);
139  moduleListenerMap.erase(mc);
140  }
141 }
142 
143 void ServiceListeners::HooksModuleStopped(ModuleContext* mc)
144 {
145  US_UNUSED(Lock(this));
146  std::vector<ServiceListenerEntry> entries;
147  for (ServiceListenerEntries::iterator it = serviceSet.begin();
148  it != serviceSet.end(); )
149  {
150  if (it->GetModuleContext() == mc)
151  {
152  entries.push_back(*it);
153  }
154  }
155  coreCtx->serviceHooks.HandleServiceListenerUnreg(entries);
156 }
157 
158 void ServiceListeners::ServiceChanged(ServiceListenerEntries& receivers,
159  const ServiceEvent& evt)
160 {
161  ServiceListenerEntries matchBefore;
162  ServiceChanged(receivers, evt, matchBefore);
163 }
164 
165 void ServiceListeners::ServiceChanged(ServiceListenerEntries& receivers,
166  const ServiceEvent& evt,
167  ServiceListenerEntries& matchBefore)
168 {
169  int n = 0;
170 
171  if (!matchBefore.empty())
172  {
173  for (ServiceListenerEntries::const_iterator l = receivers.begin();
174  l != receivers.end(); ++l)
175  {
176  matchBefore.erase(*l);
177  }
178  }
179 
180  for (ServiceListenerEntries::const_iterator l = receivers.begin();
181  l != receivers.end(); ++l)
182  {
183  if (!l->IsRemoved())
184  {
185  try
186  {
187  ++n;
188  l->CallDelegate(evt);
189  }
190  catch (...)
191  {
192  US_WARN << "Service listener"
193  << " in " << l->GetModuleContext()->GetModule()->GetName()
194  << " threw an exception!";
195  }
196  }
197  }
198 
199  //US_DEBUG << "Notified " << n << " listeners";
200 }
201 
202 void ServiceListeners::GetMatchingServiceListeners(const ServiceEvent& evt, ServiceListenerEntries& set,
203  bool lockProps)
204 {
205  US_UNUSED(Lock(this));
206 
207  // Filter the original set of listeners
208  ServiceListenerEntries receivers = serviceSet;
209  coreCtx->serviceHooks.FilterServiceEventReceivers(evt, receivers);
210 
211  // Check complicated or empty listener filters
212  for (std::list<ServiceListenerEntry>::const_iterator sse = complicatedListeners.begin();
213  sse != complicatedListeners.end(); ++sse)
214  {
215  if (receivers.count(*sse) == 0) continue;
216  const LDAPExpr& ldapExpr = sse->GetLDAPExpr();
217  if (ldapExpr.IsNull() ||
218  ldapExpr.Evaluate(evt.GetServiceReference().d->GetProperties(), false))
219  {
220  set.insert(*sse);
221  }
222  }
223 
224  //US_DEBUG << "Added " << set.size() << " out of " << n
225  // << " listeners with complicated filters";
226 
227  // Check the cache
228  const std::vector<std::string> c(any_cast<std::vector<std::string> >
229  (evt.GetServiceReference().d->GetProperty(ServiceConstants::OBJECTCLASS(), lockProps)));
230  for (std::vector<std::string>::const_iterator objClass = c.begin();
231  objClass != c.end(); ++objClass)
232  {
233  AddToSet(set, receivers, OBJECTCLASS_IX, *objClass);
234  }
235 
236  long service_id = any_cast<long>(evt.GetServiceReference().d->GetProperty(ServiceConstants::SERVICE_ID(), lockProps));
237  std::stringstream ss;
238  ss << service_id;
239  AddToSet(set, receivers, SERVICE_ID_IX, ss.str());
240 }
241 
242 std::vector<ServiceListenerHook::ListenerInfo> ServiceListeners::GetListenerInfoCollection() const
243 {
244  US_UNUSED(Lock(this));
245  std::vector<ServiceListenerHook::ListenerInfo> result;
246  result.reserve(serviceSet.size());
247  for (ServiceListenerEntries::const_iterator iter = serviceSet.begin(),
248  iterEnd = serviceSet.end(); iter != iterEnd; ++iter)
249  {
250  result.push_back(*iter);
251  }
252  return result;
253 }
254 
255 void ServiceListeners::RemoveFromCache(const ServiceListenerEntry& sle)
256 {
257  if (!sle.GetLocalCache().empty())
258  {
259  for (std::size_t i = 0; i < hashedServiceKeys.size(); ++i)
260  {
261  CacheType& keymap = cache[i];
262  std::vector<std::string>& l = sle.GetLocalCache()[i];
263  for (std::vector<std::string>::const_iterator it = l.begin();
264  it != l.end(); ++it)
265  {
266  std::list<ServiceListenerEntry>& sles = keymap[*it];
267  sles.remove(sle);
268  if (sles.empty())
269  {
270  keymap.erase(*it);
271  }
272  }
273  }
274  }
275  else
276  {
277  complicatedListeners.remove(sle);
278  }
279 }
280 
281  void ServiceListeners::CheckSimple(const ServiceListenerEntry& sle) {
282  if (sle.GetLDAPExpr().IsNull())
283  {
284  complicatedListeners.push_back(sle);
285  }
286  else
287  {
288  LDAPExpr::LocalCache local_cache;
289  if (sle.GetLDAPExpr().IsSimple(hashedServiceKeys, local_cache, false))
290  {
291  sle.GetLocalCache() = local_cache;
292  for (std::size_t i = 0; i < hashedServiceKeys.size(); ++i)
293  {
294  for (std::vector<std::string>::const_iterator it = local_cache[i].begin();
295  it != local_cache[i].end(); ++it)
296  {
297  std::list<ServiceListenerEntry>& sles = cache[i][*it];
298  sles.push_back(sle);
299  }
300  }
301  }
302  else
303  {
304  //US_DEBUG << "Too complicated filter: " << sle.GetFilter();
305  complicatedListeners.push_back(sle);
306  }
307  }
308  }
309 
310 void ServiceListeners::AddToSet(ServiceListenerEntries& set,
311  const ServiceListenerEntries& receivers,
312  int cache_ix, const std::string& val)
313 {
314  std::list<ServiceListenerEntry>& l = cache[cache_ix][val];
315  if (!l.empty())
316  {
317  //US_DEBUG << hashedServiceKeys[cache_ix] << " matches " << l.size();
318 
319  for (std::list<ServiceListenerEntry>::const_iterator entry = l.begin();
320  entry != l.end(); ++entry)
321  {
322  if (receivers.count(*entry))
323  {
324  set.insert(*entry);
325  }
326  }
327  }
328  else
329  {
330  //US_DEBUG << hashedServiceKeys[cache_ix] << " matches none";
331  }
332 }
333 
334 US_END_NAMESPACE
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
US_MODULE_LISTENER_FUNCTOR ModuleListener
US_BEGIN_NAMESPACE typedef US_SERVICE_LISTENER_FUNCTOR ServiceListener
US_Core_EXPORT const std::string & OBJECTCLASS()
US_Core_EXPORT const std::string & SERVICE_ID()