iceparser.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package ArmarXCore::core
19  * @author Cedric Seehausen (usdnr at kit dot edu)
20  * @date 2016
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
25 
26 #include "iceparser.h"
27 
28 #include <algorithm>
29 #include <filesystem>
30 #include <fstream>
31 #include <iostream>
32 
33 #include <boost/regex.hpp>
34 
35 #include <Ice/Properties.h>
36 
46 
47 using namespace ScenarioManager;
48 using namespace Data_Structure;
49 using namespace Parser;
50 using namespace rapidxml;
51 using namespace armarx;
52 
54 IceParser::mergeXmlAndCfg(ApplicationInstanceWPtr wApp, bool firstLoad)
55 {
56  ApplicationInstancePtr app = wApp.lock();
57 
58  std::string configPath = app->getConfigPath();
59 
60  std::string cachePath = ArmarXDataPath::GetCachePath();
61 
62  if (!std::filesystem::exists(std::filesystem::path(configPath)))
63  {
64  std::ofstream out(configPath);
65  out.close();
66  }
67 
68  Ice::PropertiesPtr cfgProperties = IceProperties::create();
69  armarx::IceProperties* propsInternals =
70  static_cast<armarx::IceProperties*>(cfgProperties.get());
71  propsInternals->setInheritanceSolver(nullptr);
72 
73  cfgProperties->load(configPath);
74 
75 
76  std::filesystem::path xmlPath =
77  std::filesystem::path(cachePath) / std::filesystem::path("ComponentFiles") /
78  std::filesystem::path(app->getPackageName() + "." + app->getName() + ".xml");
79  if (!std::filesystem::exists(xmlPath))
80  {
81  ARMARX_INFO_S << "Could not find cached XML file at " << xmlPath;
83  result->setProperties(cfgProperties);
84  return result;
85  }
86 
87  armarx::PropertyDefinitionsPtr xmlProperties = loadFromXml(xmlPath.string(), app);
88 
89  Ice::PropertyDict dict = cfgProperties->getPropertiesForPrefix("");
90  for (auto const& property : dict)
91  {
92  //If it is no default property just set it with no Description
93  if (!app->isDefaultProperty(property.first))
94  {
95  xmlProperties->defineOptionalProperty(
96  property.first, property.second, "No Description");
97  xmlProperties->getProperties()->setProperty(property.first, property.second);
98  app->setIsDefaultProperty(property.first, false);
99  }
100  //If it is an default property set it to enabled and set the value
101  else
102  {
103  if (!firstLoad)
104  {
105  if (property.second.compare("<set value!>") &&
106  property.second.compare("::_NOT_SET_::"))
107  {
108  app->setDefaultPropertyEnabled(property.first, true);
109  xmlProperties->getProperties()->setProperty(property.first, property.second);
110  }
111  }
112  }
113  }
114 
115  return xmlProperties;
116 }
117 
118 //used to create the default ini of an ApplicationInstance
120 IceParser::loadFromXml(std::string path, ApplicationInstanceWPtr wApp)
121 {
122  ApplicationInstancePtr app = wApp.lock();
123 
124  Ice::PropertiesPtr properties = IceProperties::create();
125  armarx::IceProperties* cfgInternal = static_cast<armarx::IceProperties*>(properties.get());
126  cfgInternal->setInheritanceSolver(nullptr);
127 
129  container->setProperties(properties);
130 
131  RapidXmlReaderPtr reader;
132  try
133  {
134  auto contents = RapidXmlReader::ReadFileContents(path);
135 
136  const boost::regex e("<!-- ([a-zA-Z0-9_]+) properties -->");
137  boost::match_results<std::string::const_iterator> what;
138 
139  bool found = boost::regex_search(contents, what, e);
140  if (found && app)
141  {
142  ARMARX_CHECK(not what.empty());
143  app->setConfigDomain(what[1]);
144  }
145  else
146  {
147  if (app)
148  {
149  ARMARX_INFO << "App `" << app->getName() << "` not found.";
150  }
151  }
152 
153  reader = RapidXmlReader::FromXmlString(contents);
154  }
155  catch (...)
156  {
157  ARMARX_INFO_S << "Failed to parse " << path << std::endl;
158  ARMARX_INFO_S << "It is most likely that the file has no valid XML formatting" << std::endl;
159  return container;
160  }
161 
162  for (RapidXmlReaderNode property_node = reader->getRoot("property"); property_node.is_valid();
163  property_node = property_node.next_sibling())
164  {
165  const std::string propertyName = property_node.attribute_value("name");
166  const std::string description = property_node.first_node("description").value();
167  RapidXmlReaderNode attributes_node = property_node.first_node("attributes");
168 
169  RapidXmlReaderNode current_attribute = attributes_node.first_node("attribute");
170  RapidXmlReaderNode values = attributes_node.first_node("values");
171  Ice::StringSeq valueStrings;
172  if (values.is_valid())
173  {
174  RapidXmlReaderNode current_value = values.first_node("value");
175  while (current_value.is_valid())
176  {
177  valueStrings.push_back(current_value.value());
178  current_value = current_value.next_sibling();
179  }
180  }
181  if (!valueStrings.empty())
182  {
183  // ARMARX_INFO << propertyName << "\n:" << valueStrings;
184  }
185 
186 
187  std::string defaultValue = "";
188  //bool caseSensitive = false;
189  bool required = false;
190 
191  while (current_attribute.is_valid())
192  {
193  //if it is no attribute continue to the next sibling
194  if (current_attribute.name().compare("attribute") != 0)
195  {
196  }
197  else if (current_attribute.attribute_value("name").find("Default") != std::string::npos)
198  {
199  defaultValue = current_attribute.value();
200  }
201  else if (current_attribute.attribute_value("name").find("CaseSensitivity") !=
202  std::string::npos)
203  {
204  }
205  else if (current_attribute.attribute_value("name").find("Required") !=
206  std::string::npos)
207  {
208  if (current_attribute.value().compare("yes") == 0)
209  {
210  required = true;
211  }
212  }
213  current_attribute = current_attribute.next_sibling();
214  }
215 
216  if (required)
217  {
219  container->defineRequiredProperty<std::string>(propertyName, description);
220  prop.setCaseInsensitive(false);
221  for (auto& v : valueStrings)
222  {
223  prop.map(v, v);
224  }
225  container->getProperties()->setProperty(propertyName, "::_NOT_SET_::");
226  }
227  else
228  {
230  container->defineOptionalProperty(propertyName, defaultValue, description);
231  prop.setCaseInsensitive(false);
232  for (auto& v : valueStrings)
233  {
234  prop.map(v, v);
235  }
236  container->getProperties()->setProperty(propertyName, defaultValue);
237  }
238  //Always set default propertys disabled
239  //they get enabled by checking the cfg file (see mergeXmlAndCfg)
240  if (app)
241  {
242  app->setIsDefaultProperty(propertyName, true);
243  app->setDefaultPropertyEnabled(propertyName, false);
244  }
245  }
246 
247  return container;
248 }
249 
250 void
252 {
253  ApplicationInstancePtr appInstance = wAppInstance.lock();
254 
255  if (!appInstance->isConfigWritable())
256  {
257  return;
258  }
259 
260  PropertyDefinitionsPtr props = appInstance->getProperties();
261  armarx::IceProperties* propsInternals =
262  static_cast<armarx::IceProperties*>(props->getProperties().get());
263  propsInternals->setInheritanceSolver(nullptr);
264 
265  std::string resultStr;
266 
270  pdcFormatter.setProperties(props->getProperties());
271  resultStr = pdcFormatter.formatPropertyDefinitionContainer(props);
272 
273  Ice::PropertyDict dict = props->getProperties()->getPropertiesForPrefix("");
274 
275  //disable all not enabled default properties
276  for (auto const& property : dict)
277  {
278  if (appInstance->isDefaultProperty(property.first) &&
279  !appInstance->isDefaultPropertyEnabled(property.first))
280  {
281  disableProperty(resultStr, property.first);
282  }
283  }
284 
285  //filter Ice.Config
286  size_t begin = resultStr.rfind("# Ice.Config:");
287  size_t end = resultStr.rfind("Ice.Config = <set value!>");
288 
289  if (end == std::string::npos)
290  {
291  (end = resultStr.rfind("Ice.Config = \"\"")) != std::string::npos ? end += 15
292  : end = std::string::npos;
293  }
294  else
295  {
296  end += 25;
297  }
298  if (begin != std::string::npos && end != std::string::npos)
299  {
300  resultStr.erase(begin, end - begin);
301  }
302 
303  std::ofstream cfgFile;
304  cfgFile.open(appInstance->getConfigPath(), std::ofstream::out | std::ofstream::trunc);
305 
306  if (cfgFile.fail())
307  {
308  ARMARX_WARNING_S << "Failed to write to Cfg file at " << appInstance->getConfigPath();
309  return;
310  }
311 
312  cfgFile << resultStr;
313 
314  cfgFile.close();
315 }
316 
317 std::string
318 IceParser::getCacheDir()
319 {
320  std::string cachePath = ArmarXDataPath::GetCachePath();
321  return (std::filesystem::path(cachePath) / std::filesystem::path("ComponentFiles")).string();
322 }
323 
324 void
325 IceParser::disableProperty(std::string& result, const std::string propertyName)
326 {
327  //comment out default properties
328  if (result.find_last_of(propertyName) != std::string::npos)
329  {
330  size_t it1 = result.rfind(propertyName + " = ");
331  std::string commentedName = "# " + propertyName + " = ";
332  size_t it2 = result.find(commentedName, it1);
333 
334  if (it1 != std::string::npos && it2 == std::string::npos)
335  {
336  result.insert(it1, "# ");
337  }
338  }
339 }
340 
341 void
342 IceParser::clearXmlCacheDir()
343 {
344  std::filesystem::remove_all(std::filesystem::path(getCacheDir()));
345 }
armarx::RapidXmlReaderPtr
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
Definition: RapidXmlReader.h:67
armarx::RapidXmlReaderNode::next_sibling
RapidXmlReaderNode next_sibling(const char *name=nullptr) const
Definition: RapidXmlReader.h:450
iceparser.h
OnScopeExit.h
armarx::PropertyDefinitionContainerFormatter::setProperties
void setProperties(Ice::PropertiesPtr properties)
Definition: PropertyDefinitionContainerFormatter.h:54
PropertyDefinitionContainerFormatter.h
armarx::RapidXmlReaderNode::attribute_value
std::string attribute_value(const char *attrName) const
Definition: RapidXmlReader.h:230
ProsthesisInterface.values
values
Definition: ProsthesisInterface.py:190
RapidXmlWriter.h
armarx::PropertyDefinitionContainerFormatter
PropertyDefinitionContainerFormatter.
Definition: PropertyDefinitionContainerFormatter.h:41
PropertyDefinitionFormatter.h
ApplicationInstancePtr
std::shared_ptr< ScenarioManager::Data_Structure::ApplicationInstance > ApplicationInstancePtr
Definition: StopStrategy.h:8
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
IceInternal::Handle<::Ice::Properties >
armarx::RapidXmlReaderNode::name
std::string name() const
Definition: RapidXmlReader.h:407
rapidxml
Definition: rapidxml.hpp:62
PropertyDefinitionConfigFormatter.h
armarx::PropertyDefinitionContainerFormatter::formatPropertyDefinitionContainer
std::string formatPropertyDefinitionContainer(PropertyDefinitionsPtr container)
Definition: PropertyDefinitionContainerFormatter.h:60
armarx::RapidXmlReaderNode
Definition: RapidXmlReader.h:69
armarx::PropertyDefinitionContainer
PropertyDefinitionContainer.
Definition: PropertyDefinitionContainer.h:53
armarx::IceProperties::setInheritanceSolver
virtual void setInheritanceSolver(const InheritanceSolverPtr &inheritanceSolver)
Sets an inheritance solver in case of testing or using a non-default solver.
Definition: IceProperties.cpp:233
armarx::PropertyDefinitionConfigFormatter
PropertyDefinitionConfigFormatter.
Definition: PropertyDefinitionConfigFormatter.h:40
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:213
armarx::RapidXmlReaderNode::value
std::string value() const
Definition: RapidXmlReader.h:365
ExpressionException.h
armarx::IceProperties
IceProperties stores ice properties and resolves property inheritance.
Definition: IceProperties.h:120
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
ScenarioManager
Definition: Application.cpp:180
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
IceUtil::Handle< class PropertyDefinitionContainer >
RapidXmlReader.h
armarx::RapidXmlReaderNode::is_valid
bool is_valid() const
Definition: RapidXmlReader.h:457
ARMARX_INFO_S
#define ARMARX_INFO_S
Definition: Logging.h:202
armarx::PropertyDefinition::setCaseInsensitive
PropertyDefinition< PropertyType > & setCaseInsensitive(bool isCaseInsensitive)
Sets whether the property value matching is case insensitive.
Definition: PropertyDefinition.hpp:144
Logging.h
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:35
ArmarXDataPath.h
armarx::RapidXmlReaderNode::first_node
RapidXmlReaderNode first_node(const char *name=nullptr) const
Definition: RapidXmlReader.h:156
ScenarioManager::Data_Structure::ApplicationInstanceWPtr
std::weak_ptr< ApplicationInstance > ApplicationInstanceWPtr
Definition: ApplicationInstance.h:34
armarx::PropertyDefinition
PropertyDefinition defines a property that will be available within the PropertyUser.
Definition: PropertyDefinition.h:117
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::PropertyDefinition::map
PropertyDefinition< PropertyType > & map(const std::string &valueString, PropertyType value)
Maps a string value onto a value of the specified template type.
Definition: PropertyDefinition.hpp:93