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
47using namespace ScenarioManager;
48using namespace Data_Structure;
49using namespace Parser;
50using namespace rapidxml;
51using namespace armarx;
52
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
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
121{
122 ApplicationInstancePtr app = wApp.lock();
123
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
250void
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
317std::string
319{
320 std::string cachePath = ArmarXDataPath::GetCachePath();
321 return (std::filesystem::path(cachePath) / std::filesystem::path("ComponentFiles")).string();
322}
323
324void
325IceParser::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
341void
343{
344 std::filesystem::remove_all(std::filesystem::path(getCacheDir()));
345}
armarx::PropertyDefinitionsPtr mergeXmlAndCfg(ScenarioManager::Data_Structure::ApplicationInstanceWPtr app, bool firstLoad=false)
Definition iceparser.cpp:54
armarx::PropertyDefinitionsPtr loadFromXml(std::string path, ScenarioManager::Data_Structure::ApplicationInstanceWPtr app=ScenarioManager::Data_Structure::ApplicationInstancePtr(nullptr))
static std::string getCacheDir()
void saveCfg(ScenarioManager::Data_Structure::ApplicationInstanceWPtr appInstance)
static std::string GetCachePath()
The base Cache directory of ArmarX.
IceProperties stores ice properties and resolves property inheritance.
virtual void setInheritanceSolver(const InheritanceSolverPtr &inheritanceSolver)
Sets an inheritance solver in case of testing or using a non-default solver.
static Ice::PropertiesPtr create(const Ice::PropertiesPtr &iceProperties=nullptr)
std::string formatPropertyDefinitionContainer(PropertyDefinitionsPtr container)
PropertyDefinition defines a property that will be available within the PropertyUser.
PropertyDefinition< PropertyType > & setCaseInsensitive(bool isCaseInsensitive)
Sets whether the property value matching is case insensitive.
PropertyDefinition< PropertyType > & map(const std::string &valueString, PropertyType value)
Maps a string value onto a value of the specified template type.
RapidXmlReaderNode first_node(const char *name=nullptr) const
std::string name() const
RapidXmlReaderNode next_sibling(const char *name=nullptr) const
std::string attribute_value(const char *attrName) const
std::string value() const
static std::string ReadFileContents(const std::string &path)
static RapidXmlReaderPtr FromXmlString(const std::string &xml)
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_INFO_S
Definition Logging.h:202
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:213
::IceInternal::Handle<::Ice::Properties > PropertiesPtr
std::weak_ptr< ApplicationInstance > ApplicationInstanceWPtr
std::shared_ptr< ApplicationInstance > ApplicationInstancePtr
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< RapidXmlReader > RapidXmlReaderPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.