fw4spl
AppConfig.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2017.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwServices/registry/AppConfig.hpp"
8 
9 #include <fwData/Composite.hpp>
10 #include <fwData/String.hpp>
11 
12 #include <fwRuntime/ConfigurationElement.hpp>
13 #include <fwRuntime/helper.hpp>
14 #include <fwRuntime/Runtime.hpp>
15 
16 #include <boost/regex.hpp>
17 
18 namespace fwServices
19 {
20 namespace registry
21 {
22 
23 AppConfig::sptr AppConfig::s_currentAppConfig = AppConfig::New();
24 ::fwCore::mt::Mutex AppConfig::s_idMutex;
25 
26 std::string AppConfig::s_mandatoryParameterIdentifier = "@mandatory@";
27 
28 AppConfig::UidDefinitionType AppConfig::s_uidDefinitionDictionary = { { "object", "uid" },
29  { "service", "uid" },
30  { "view", "sid" },
31  { "view", "wid" },
32  { "connect", "channel" }, };
33 static const ::boost::regex s_isVariable( "\\${.*}.*" );
34 
35 //-----------------------------------------------------------------------------
36 
37 AppConfig::sptr AppConfig::getDefault()
38 {
39  return s_currentAppConfig;
40 }
41 
42 //-----------------------------------------------------------------------------
43 
45 {
46 }
47 
48 //-----------------------------------------------------------------------------
49 
51 {
52  auto extensions = ::fwRuntime::getAllExtensionsForPoint("::fwServices::registry::AppConfig");
53  for( const auto& ext : extensions )
54  {
55  // Get id
56  std::string configId = ext->findConfigurationElement("id")->getValue();
57 
58  // Get group
59  std::string group = "";
60  if ( ext->hasConfigurationElement("group") )
61  {
62  group = ext->findConfigurationElement("group")->getValue();
63  }
64  // Get desc
65  std::string desc = "No description available";
66  if ( ext->hasConfigurationElement("desc") )
67  {
68  desc = ext->findConfigurationElement("desc")->getValue();
69  }
70  unsigned long syntax = 1;
71  if ( ext->hasConfigurationElement("syntax") )
72  {
73  syntax = std::stoul( ext->findConfigurationElement("syntax")->getValue() );
74  }
75 
76  AppInfo::ParametersType parameters;
77  if ( ext->hasConfigurationElement("parameters") )
78  {
79  ::fwRuntime::ConfigurationElement::csptr parametersConfig = ext->findConfigurationElement("parameters");
80  ::fwRuntime::ConfigurationElement::Container elements = parametersConfig->getElements();
81  for( ::fwRuntime::ConfigurationElement::sptr paramConfig : elements )
82  {
83  std::string name = paramConfig->getExistingAttributeValue("name");
84 
85  if(paramConfig->hasAttribute("default"))
86  {
87  parameters[name] = paramConfig->getAttributeValue("default");
88  }
89  else
90  {
91  parameters[name] = s_mandatoryParameterIdentifier;
92  }
93 
94  }
95  }
96 
97  // Get config
98  ::fwRuntime::ConfigurationElement::csptr config = ext->findConfigurationElement("config");
99 
100  // Get bundle
101  std::shared_ptr< ::fwRuntime::Bundle> bundle = ext->getBundle();
102  std::string bundleId = bundle->getIdentifier();
103  std::string bundleVersion = bundle->getVersion().string();
104 
105  // Add app info
106  this->addAppInfo( configId, group, desc, parameters, config, bundleId, bundleVersion );
107  }
108 }
109 
110 //-----------------------------------------------------------------------------
111 
112 void AppConfig::addAppInfo( const std::string& configId,
113  const std::string& group,
114  const std::string& desc,
115  const AppInfo::ParametersType& parameters,
116  const ::fwRuntime::ConfigurationElement::csptr& config,
117  const std::string& bundleId,
118  const std::string& bundleVersion)
119 {
120  ::fwCore::mt::WriteLock lock(m_registryMutex);
121 
122  SLM_DEBUG( "New app config registering : configId = " + configId );
123  SLM_ASSERT("The app config with the id = "<< configId <<" already exist.", m_reg.find( configId ) == m_reg.end() );
124 
125  AppInfo::sptr info = AppInfo::New();
126  info->group = group;
127  info->desc = desc;
128  info->config = config;
129  info->parameters = parameters;
130  info->bundleId = bundleId;
131  info->bundleVersion = bundleVersion;
132  m_reg[configId] = info;
133 }
134 
135 //-----------------------------------------------------------------------------
136 
138 {
139 }
140 
141 //-----------------------------------------------------------------------------
142 
144 {
145  ::fwCore::mt::WriteLock lock(m_registryMutex);
146  m_reg.clear();
147 }
148 
149 //-----------------------------------------------------------------------------
150 
151 ::fwRuntime::ConfigurationElement::csptr AppConfig::getAdaptedTemplateConfig(
152  const std::string& configId,
153  const FieldAdaptorType fieldAdaptors,
154  bool autoPrefixId) const
155 {
156  ::fwCore::mt::ReadLock lock(m_registryMutex);
157  // Get config template
158  Registry::const_iterator iter = m_reg.find( configId );
159  SLM_ASSERT("The id " << configId << " is not found in the application configuration registry",
160  iter != m_reg.end());
161 
162  // Adapt config
163  ::fwRuntime::ConfigurationElement::sptr newConfig;
164 
165  FieldAdaptorType fields;
166  AppInfo::ParametersType parameters = iter->second->parameters;
167 
168  for( AppInfo::ParametersType::value_type param : parameters )
169  {
170  FieldAdaptorType::const_iterator iter = fieldAdaptors.find( param.first );
171  const std::string key = "\\$\\{" + param.first + "\\}";
172  if ( iter != fieldAdaptors.end() )
173  {
174  fields[key] = iter->second;
175  }
176  else if ( param.second != s_mandatoryParameterIdentifier)
177  {
178  fields[key] = param.second;
179  }
180  else
181  {
182  FW_RAISE("Parameter : '" << param.first << "' is needed by the app configuration id='"<< configId <<"'.");
183  }
184  }
185 
186  std::string autoPrefixName;
187  if(autoPrefixId)
188  {
189  autoPrefixName = this->getUniqueIdentifier(configId);
190  }
191 
192  UidParameterReplaceType parameterReplaceAdaptors;
193  this->collectUIDForParameterReplace(iter->second->config, parameterReplaceAdaptors);
194  newConfig = this->adaptConfig(iter->second->config, fields, parameterReplaceAdaptors, autoPrefixName);
195 
196  return newConfig;
197 }
198 
199 //-----------------------------------------------------------------------------
200 
201 ::fwRuntime::ConfigurationElement::csptr AppConfig::getAdaptedTemplateConfig( const std::string& configId,
202  ::fwData::Composite::csptr replaceFields,
203  bool autoPrefixId )
204 const
205 {
206  FieldAdaptorType fieldAdaptors = compositeToFieldAdaptor( replaceFields );
207  return this->getAdaptedTemplateConfig( configId, fieldAdaptors, autoPrefixId );
208 }
209 
210 //-----------------------------------------------------------------------------
211 
212 std::shared_ptr< ::fwRuntime::Bundle > AppConfig::getBundle(const std::string& _configId)
213 {
214  Registry::const_iterator iter = m_reg.find( _configId );
215  SLM_ASSERT("The id " << _configId << " is not found in the application configuration registry",
216  iter != m_reg.end());
217 
218  std::shared_ptr< ::fwRuntime::Bundle > bundle = ::fwRuntime::findBundle(iter->second->bundleId,
219  iter->second->bundleVersion);
220 
221  return bundle;
222 }
223 
224 //-----------------------------------------------------------------------------
225 
226 std::vector< std::string > AppConfig::getAllConfigs() const
227 {
228  ::fwCore::mt::ReadLock lock(m_registryMutex);
229  std::vector< std::string > ids;
230  for( const Registry::value_type& elem : m_reg )
231  {
232  ids.push_back( elem.first );
233  }
234  return ids;
235 }
236 
237 //-----------------------------------------------------------------------------
238 
239 std::vector< std::string > AppConfig::getConfigsFromGroup(const std::string& group) const
240 {
241  ::fwCore::mt::ReadLock lock(m_registryMutex);
242  std::vector< std::string > ids;
243  for( const Registry::value_type& elem : m_reg )
244  {
245  AppInfo::sptr info = elem.second;
246  if(info->group == group)
247  {
248  ids.push_back( elem.first );
249  }
250  }
251  return ids;
252 }
253 
254 //-----------------------------------------------------------------------------
255 
256 FieldAdaptorType AppConfig::compositeToFieldAdaptor( ::fwData::Composite::csptr fieldAdaptors ) const
257 {
258  FieldAdaptorType fields;
259  for(const ::fwData::Composite::value_type& elem : * fieldAdaptors )
260  {
261  fields[elem.first] = ::fwData::String::dynamicCast( elem.second )->value();
262  }
263 
264  return fields;
265 }
266 
267 //-----------------------------------------------------------------------------
268 
269 std::string AppConfig::getUniqueIdentifier(const std::string& serviceUid )
270 {
271  ::fwCore::mt::ScopedLock lock(s_idMutex);
272  static unsigned int srvCpt = 1;
273  std::stringstream sstr;
274 
275  if ( serviceUid.empty() )
276  {
277  sstr << "AppConfigManager_" << srvCpt;
278  }
279  else
280  {
281  sstr << serviceUid << "_" << srvCpt;
282  }
283  ++srvCpt;
284  return sstr.str();
285 }
286 
287 //-----------------------------------------------------------------------------
288 
289 void AppConfig::collectUIDForParameterReplace(::fwRuntime::ConfigurationElement::csptr _cfgElem,
290  UidParameterReplaceType& _replaceMap)
291 {
292  const auto& name = _cfgElem->getName();
293  for( const auto& attribute : _cfgElem->getAttributes() )
294  {
295  auto range = s_uidDefinitionDictionary.equal_range(name);
296 
297  for (auto it = range.first; it != range.second; ++it)
298  {
299  if(it->second == attribute.first && !::boost::regex_match(attribute.second, s_isVariable ) )
300  {
301  _replaceMap.insert(attribute.second);
302  }
303  }
304  }
305 
306  for ( const auto& subElem : _cfgElem->getElements())
307  {
308  collectUIDForParameterReplace( subElem, _replaceMap );
309  }
310 }
311 
312 //-----------------------------------------------------------------------------
313 
314 ::fwRuntime::EConfigurationElement::sptr AppConfig::adaptConfig(::fwRuntime::ConfigurationElement::csptr _cfgElem,
315  const FieldAdaptorType& _fieldAdaptors,
316  const UidParameterReplaceType& _uidParameterReplace,
317  const std::string& _autoPrefixId)
318 {
319  ::fwRuntime::EConfigurationElement::sptr result = ::fwRuntime::EConfigurationElement::New( _cfgElem->getName() );
320  result->setValue( adaptField( _cfgElem->getValue(), _fieldAdaptors ) );
321 
322  for( const auto& attribute : _cfgElem->getAttributes() )
323  {
324  // Add the config prefix for unique identifiers
325  if(!_autoPrefixId.empty())
326  {
327  if(attribute.first == "uid" ||
328  attribute.first == "sid" ||
329  attribute.first == "wid" ||
330  attribute.first == "channel" )
331  {
332  // Detect if we have a variable name
333  if ( !::boost::regex_match( attribute.second, s_isVariable ) )
334  {
335  // This is not a variable, add the prefix
336  result->setAttributeValue( attribute.first,
337  _autoPrefixId + "_" + adaptField( attribute.second, _fieldAdaptors ));
338  continue;
339  }
340  }
341  // Special case for <parameter replace="..." by="..." />
342  else if(attribute.first == "by")
343  {
344  // Detect if we have a variable name
345  if ( !::boost::regex_match( attribute.second, s_isVariable ) )
346  {
347  // Look inside the map of potential replacements
348  auto itParam = _uidParameterReplace.find(attribute.second);
349  if(itParam != _uidParameterReplace.end())
350  {
351  result->setAttributeValue( attribute.first,
352  _autoPrefixId + "_" +
353  adaptField( attribute.second, _fieldAdaptors ));
354  continue;
355  }
356  }
357  }
358 
359  }
360  result->setAttributeValue( attribute.first, adaptField( attribute.second, _fieldAdaptors ) );
361  }
362 
363  for ( const auto& subElem : _cfgElem->getElements())
364  {
365  // Add the config prefix for unique identifiers in signal and slot sources
366  if( !_autoPrefixId.empty() && (subElem->getName() == "signal" || subElem->getName() == "slot" ) )
367  {
368  // Detect if we have a variable name
369  if ( !::boost::regex_match( subElem->getValue(), s_isVariable ) )
370  {
371  // This is not a variable, add the prefix
372  auto elt = ::fwRuntime::EConfigurationElement::New( subElem->getName() );
373  elt->setValue( _autoPrefixId + "_" + subElem->getValue() );
374 
375  for (const auto& attr : subElem->getAttributes())
376  {
377  elt->setAttributeValue(attr.first, attr.second);
378  }
379 
380  result->addConfigurationElement( elt );
381  continue;
382  }
383  }
384 
385  result->addConfigurationElement( adaptConfig( subElem, _fieldAdaptors, _uidParameterReplace, _autoPrefixId ) );
386  }
387 
388  return result;
389 }
390 
391 //-----------------------------------------------------------------------------
392 
393 std::string AppConfig::adaptField( const std::string& _str, const FieldAdaptorType& _variablesMap )
394 {
395  std::string newStr = _str;
396  if(!_str.empty())
397  {
398  // Discriminate first variable expressions only, looking through all keys of the replace map is not for free
399  // However we look inside the whole string instead of only at the beginning because we want to replace "inner"
400  // variables as well, i.e. not only ${uid} but also uid${suffix}
401  if ( ::boost::regex_search(_str, s_isVariable ) )
402  {
403  // Iterate over all variables
404  for(const auto& fieldAdaptor : _variablesMap )
405  {
406  const ::boost::regex varRegex( "(.*)" + fieldAdaptor.first + "(.*)" );
407  if ( ::boost::regex_match( _str, varRegex ) )
408  {
409  const std::string varReplace("\\1" + fieldAdaptor.second + "\\2");
410  newStr = ::boost::regex_replace( newStr, varRegex, varReplace,
411  ::boost::match_default | ::boost::format_sed );
412  }
413  }
414  }
415  }
416  return newStr;
417 }
418 
419 //-----------------------------------------------------------------------------
420 
421 } // namespace registry
422 
423 } // namespace fwServices
424 
Contains fwAtomsFilter::registry details.
Namespace fwServices is dedicated to (mimic) the dynamic affectation of methods to (pure data) object...
std::vector< std::shared_ptr< ConfigurationElement > > Container
Defines the configuration element container type.
::boost::unique_lock< ReadWriteMutex > WriteLock
Defines a lock of write type for read/write mutex.
FWSERVICES_API AppConfig()
Constructor.
Definition: AppConfig.cpp:137
FWSERVICES_API void addAppInfo(const std::string &configId, const std::string &group, const std::string &desc, const AppInfo::ParametersType &parameters, const ::fwRuntime::ConfigurationElement::csptr &config, const std::string &bundleId, const std::string &bundleVersion)
Register a new config.
Definition: AppConfig.cpp:112
#define SLM_DEBUG(message)
Definition: spyLog.hpp:239
FWSERVICES_API std::vector< std::string > getAllConfigs() const
Return all configurations ( standard and template ) register in the registry.
Definition: AppConfig.cpp:226
virtual FWSERVICES_API ~AppConfig()
Destructor.
Definition: AppConfig.cpp:44
Registry m_reg
Container of <configId, AppConfig information>
Definition: AppConfig.hpp:141
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
::boost::shared_lock< ReadWriteMutex > ReadLock
Defines a lock of read type for read/write mutex.
FWSERVICES_API void clearRegistry()
Clear the registry.
Definition: AppConfig.cpp:143
FWSERVICES_API std::shared_ptr< ::fwRuntime::Bundle > getBundle(const std::string &_configId)
Retrieves the bunble from the config id.
Definition: AppConfig.cpp:212
FWSERVICES_API void parseBundleInformation()
Parses bundle information to retrieve configuration declaration.
Definition: AppConfig.cpp:50
static FWSERVICES_API AppConfig::sptr getDefault()
Return an instance of AppConfig.
Definition: AppConfig.cpp:37
static FWSERVICES_API std::string getUniqueIdentifier(const std::string &serviceUid="")
Create an unique identifier.
Definition: AppConfig.cpp:269
std::map< std::string, std::string > FieldAdaptorType
Associations of <pattern, value>.
Definition: AppConfig.hpp:42
FWSERVICES_API std::vector< std::string > getConfigsFromGroup(const std::string &group) const
Return all configurations with specified group.
Definition: AppConfig.cpp:239
FWSERVICES_API::fwRuntime::ConfigurationElement::csptr getAdaptedTemplateConfig(const std::string &configId, const FieldAdaptorType replaceFields, bool autoPrefixId) const
Return the adapted config with the identifier configId.
Definition: AppConfig.cpp:151