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 
30 
38 #include <Ice/Properties.h>
39 
40 #include <boost/regex.hpp>
41 
42 #include <filesystem>
43 #include <iostream>
44 #include <algorithm>
45 #include <fstream>
46 
47 using namespace ScenarioManager;
48 using namespace Data_Structure;
49 using namespace Parser;
50 using namespace rapidxml;
51 using namespace armarx;
52 
53 armarx::PropertyDefinitionsPtr IceParser::mergeXmlAndCfg(ApplicationInstanceWPtr wApp, bool firstLoad)
54 {
55  ApplicationInstancePtr app = wApp.lock();
56 
57  std::string configPath = app->getConfigPath();
58 
59  std::string cachePath = ArmarXDataPath::GetCachePath();
60 
61  if (!std::filesystem::exists(std::filesystem::path(configPath)))
62  {
63  std::ofstream out(configPath);
64  out.close();
65  }
66 
67  Ice::PropertiesPtr cfgProperties = IceProperties::create();
68  armarx::IceProperties* propsInternals = static_cast<armarx::IceProperties*>(cfgProperties.get());
69  propsInternals->setInheritanceSolver(nullptr);
70 
71  cfgProperties->load(configPath);
72 
73 
74  std::filesystem::path xmlPath = std::filesystem::path(cachePath) / std::filesystem::path("ComponentFiles") / std::filesystem::path(app->getPackageName() + "." + app->getName() + ".xml");
75  if (!std::filesystem::exists(xmlPath))
76  {
77  ARMARX_INFO_S << "Could not find cached XML file at " << xmlPath;
79  result->setProperties(cfgProperties);
80  return result;
81  }
82 
83  armarx::PropertyDefinitionsPtr xmlProperties = loadFromXml(xmlPath.string(), app);
84 
85  Ice::PropertyDict dict = cfgProperties->getPropertiesForPrefix("");
86  for (auto const& property : dict)
87  {
88  //If it is no default property just set it with no Description
89  if (!app->isDefaultProperty(property.first))
90  {
91  xmlProperties->defineOptionalProperty(property.first, property.second, "No Description");
92  xmlProperties->getProperties()->setProperty(property.first, property.second);
93  app->setIsDefaultProperty(property.first, false);
94  }
95  //If it is an default property set it to enabled and set the value
96  else
97  {
98  if (!firstLoad)
99  {
100  if (property.second.compare("<set value!>") &&
101  property.second.compare("::_NOT_SET_::"))
102  {
103  app->setDefaultPropertyEnabled(property.first, true);
104  xmlProperties->getProperties()->setProperty(property.first, property.second);
105  }
106  }
107  }
108 
109  }
110 
111  return xmlProperties;
112 }
113 
114 //used to create the default ini of an ApplicationInstance
115 armarx::PropertyDefinitionsPtr IceParser::loadFromXml(std::string path, ApplicationInstanceWPtr wApp)
116 {
117  ApplicationInstancePtr app = wApp.lock();
118 
119  Ice::PropertiesPtr properties = IceProperties::create();
120  armarx::IceProperties* cfgInternal = static_cast<armarx::IceProperties*>(properties.get());
121  cfgInternal->setInheritanceSolver(nullptr);
122 
124  container->setProperties(properties);
125 
126  RapidXmlReaderPtr reader;
127  try
128  {
129  auto contents = RapidXmlReader::ReadFileContents(path);
130 
131  const boost::regex e("<!-- ([a-zA-Z0-9_]+) properties -->");
132  boost::match_results<std::string::const_iterator> what;
133 
134  bool found = boost::regex_search(contents, what, e);
135  if (found && app)
136  {
137  ARMARX_CHECK(not what.empty());
138  app->setConfigDomain(what[1]);
139  }
140  else
141  {
142  if(app)
143  {
144  ARMARX_INFO << "App `" << app->getName() << "` not found.";
145  }
146  }
147 
148  reader = RapidXmlReader::FromXmlString(contents);
149  }
150  catch (...)
151  {
152  ARMARX_INFO_S << "Failed to parse " << path << std::endl;
153  ARMARX_INFO_S << "It is most likely that the file has no valid XML formatting" << std::endl;
154  return container;
155  }
156 
157  for (RapidXmlReaderNode property_node = reader->getRoot("property"); property_node.is_valid(); property_node = property_node.next_sibling())
158  {
159  const std::string propertyName = property_node.attribute_value("name");
160  const std::string description = property_node.first_node("description").value();
161  RapidXmlReaderNode attributes_node = property_node.first_node("attributes");
162 
163  RapidXmlReaderNode current_attribute = attributes_node.first_node("attribute");
164  RapidXmlReaderNode values = attributes_node.first_node("values");
165  Ice::StringSeq valueStrings;
166  if (values.is_valid())
167  {
168  RapidXmlReaderNode current_value = values.first_node("value");
169  while (current_value.is_valid())
170  {
171  valueStrings.push_back(current_value.value());
172  current_value = current_value.next_sibling();
173  }
174  }
175  if (!valueStrings.empty())
176  {
177  // ARMARX_INFO << propertyName << "\n:" << valueStrings;
178  }
179 
180 
181  std::string defaultValue = "";
182  //bool caseSensitive = false;
183  bool required = false;
184 
185  while (current_attribute.is_valid())
186  {
187  //if it is no attribute continue to the next sibling
188  if (current_attribute.name().compare("attribute") != 0)
189  {
190 
191  }
192  else if (current_attribute.attribute_value("name").find("Default") != std::string::npos)
193  {
194  defaultValue = current_attribute.value();
195  }
196  else if (current_attribute.attribute_value("name").find("CaseSensitivity") != std::string::npos)
197  {
198  }
199  else if (current_attribute.attribute_value("name").find("Required") != std::string::npos)
200  {
201  if (current_attribute.value().compare("yes") == 0)
202  {
203  required = true;
204  }
205  }
206  current_attribute = current_attribute.next_sibling();
207  }
208 
209  if (required)
210  {
211  armarx::PropertyDefinition<std::string>& prop = container->defineRequiredProperty<std::string>(propertyName, description);
212  prop.setCaseInsensitive(false);
213  for (auto& v : valueStrings)
214  {
215  prop.map(v, v);
216  }
217  container->getProperties()->setProperty(propertyName, "::_NOT_SET_::");
218  }
219  else
220  {
221  armarx::PropertyDefinition<std::string>& prop = container->defineOptionalProperty(propertyName, defaultValue, description);
222  prop.setCaseInsensitive(false);
223  for (auto& v : valueStrings)
224  {
225  prop.map(v, v);
226  }
227  container->getProperties()->setProperty(propertyName, defaultValue);
228 
229  }
230  //Always set default propertys disabled
231  //they get enabled by checking the cfg file (see mergeXmlAndCfg)
232  if (app)
233  {
234  app->setIsDefaultProperty(propertyName, true);
235  app->setDefaultPropertyEnabled(propertyName, false);
236  }
237  }
238 
239  return container;
240 }
241 
242 void IceParser::saveCfg(ScenarioManager::Data_Structure::ApplicationInstanceWPtr wAppInstance)
243 {
244  ApplicationInstancePtr appInstance = wAppInstance.lock();
245 
246  if (!appInstance->isConfigWritable())
247  {
248  return;
249  }
250 
251  PropertyDefinitionsPtr props = appInstance->getProperties();
252  armarx::IceProperties* propsInternals = static_cast<armarx::IceProperties*>(props->getProperties().get());
253  propsInternals->setInheritanceSolver(nullptr);
254 
255  std::string resultStr;
256 
259  pdcFormatter.setProperties(props->getProperties());
260  resultStr = pdcFormatter.formatPropertyDefinitionContainer(props);
261 
262  Ice::PropertyDict dict = props->getProperties()->getPropertiesForPrefix("");
263 
264  //disable all not enabled default properties
265  for (auto const& property : dict)
266  {
267  if (appInstance->isDefaultProperty(property.first) && !appInstance->isDefaultPropertyEnabled(property.first))
268  {
269  disableProperty(resultStr, property.first);
270  }
271  }
272 
273  //filter Ice.Config
274  size_t begin = resultStr.rfind("# Ice.Config:");
275  size_t end = resultStr.rfind("Ice.Config = <set value!>");
276 
277  if (end == std::string::npos)
278  {
279  (end = resultStr.rfind("Ice.Config = \"\"")) != std::string::npos ? end += 15 : end = std::string::npos;
280  }
281  else
282  {
283  end += 25;
284  }
285  if (begin != std::string::npos && end != std::string::npos)
286  {
287  resultStr.erase(begin, end - begin);
288  }
289 
290  std::ofstream cfgFile;
291  cfgFile.open(appInstance->getConfigPath(), std::ofstream::out | std::ofstream::trunc);
292 
293  if (cfgFile.fail())
294  {
295  ARMARX_WARNING_S << "Failed to write to Cfg file at " << appInstance->getConfigPath();
296  return;
297  }
298 
299  cfgFile << resultStr;
300 
301  cfgFile.close();
302 }
303 
304 std::string IceParser::getCacheDir()
305 {
306  std::string cachePath = ArmarXDataPath::GetCachePath();
307  return (std::filesystem::path(cachePath) / std::filesystem::path("ComponentFiles")).string();
308 }
309 
310 void IceParser::disableProperty(std::string& result, const std::string propertyName)
311 {
312  //comment out default properties
313  if (result.find_last_of(propertyName) != std::string::npos)
314  {
315  size_t it1 = result.rfind(propertyName + " = ");
316  std::string commentedName = "# " + propertyName + " = ";
317  size_t it2 = result.find(commentedName, it1);
318 
319  if (it1 != std::string::npos && it2 == std::string::npos)
320  {
321  result.insert(it1, "# ");
322  }
323  }
324 }
325 
326 void IceParser::clearXmlCacheDir()
327 {
328  std::filesystem::remove_all(std::filesystem::path(getCacheDir()));
329 }
armarx::RapidXmlReaderPtr
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
Definition: RapidXmlReader.h:66
armarx::RapidXmlReaderNode::next_sibling
RapidXmlReaderNode next_sibling(const char *name=nullptr) const
Definition: RapidXmlReader.h:386
iceparser.h
OnScopeExit.h
armarx::PropertyDefinitionContainerFormatter::setProperties
void setProperties(Ice::PropertiesPtr properties)
Definition: PropertyDefinitionContainerFormatter.h:52
PropertyDefinitionContainerFormatter.h
armarx::RapidXmlReaderNode::attribute_value
std::string attribute_value(const char *attrName) const
Definition: RapidXmlReader.h:198
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:7
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:349
rapidxml
Definition: rapidxml.hpp:58
PropertyDefinitionConfigFormatter.h
armarx::PropertyDefinitionContainerFormatter::formatPropertyDefinitionContainer
std::string formatPropertyDefinitionContainer(PropertyDefinitionsPtr container)
Definition: PropertyDefinitionContainerFormatter.h:57
armarx::RapidXmlReaderNode
Definition: RapidXmlReader.h:68
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:217
armarx::PropertyDefinitionConfigFormatter
PropertyDefinitionConfigFormatter.
Definition: PropertyDefinitionConfigFormatter.h:40
ARMARX_WARNING_S
#define ARMARX_WARNING_S
Definition: Logging.h:206
armarx::RapidXmlReaderNode::value
std::string value() const
Definition: RapidXmlReader.h:313
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:166
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:174
IceUtil::Handle< class PropertyDefinitionContainer >
RapidXmlReader.h
armarx::RapidXmlReaderNode::is_valid
bool is_valid() const
Definition: RapidXmlReader.h:392
ARMARX_INFO_S
#define ARMARX_INFO_S
Definition: Logging.h:195
armarx::PropertyDefinition::setCaseInsensitive
PropertyDefinition< PropertyType > & setCaseInsensitive(bool isCaseInsensitive)
Sets whether the property value matching is case insensitive.
Definition: PropertyDefinition.hpp:150
Logging.h
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:34
ArmarXDataPath.h
armarx::RapidXmlReaderNode::first_node
RapidXmlReaderNode first_node(const char *name=nullptr) const
Definition: RapidXmlReader.h:140
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:107
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
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:95