ApplicationInstance.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 Dennis Weigelt
20 * @date 2016
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
25
26#include "ApplicationInstance.h"
27
28#include <filesystem>
29
35
36#include "../parser/iceparser.h"
37
38
39using namespace ScenarioManager;
40using namespace armarx;
41
42const std::string Data_Structure::ApplicationStatus::Stopped = "Stopped";
43const std::string Data_Structure::ApplicationStatus::Running = "Running";
44const std::string Data_Structure::ApplicationStatus::Waiting = "Waiting";
45const std::string Data_Structure::ApplicationStatus::Mixed = "Mixed";
46const std::string Data_Structure::ApplicationStatus::Unknown = "Unknown";
47const std::string Data_Structure::ApplicationStatus::Inactive = "Inactive";
48const std::string Data_Structure::ApplicationStatus::Missing = "Missing";
49
50const char*
52{
53 switch (intent)
54 {
55 case Intent::Start:
56 return "Start";
57 case Intent::Stop:
58 return "Stop";
59 case Intent::Restart:
60 return "Restart";
61 case Intent::None:
62 break;
63 }
64 return "None";
65}
66
67std::string
68Data_Structure::ApplicationStatus::Aggregate(const std::vector<std::string>& stati)
69{
70 bool sawMissing = false;
71 bool sawUnknown = false;
72 // The single definite status seen so far (Running, Stopped or Inactive), if any.
73 const std::string* definite = nullptr;
74
75 for (const std::string& status : stati)
76 {
77 if (status == Waiting)
78 {
79 return Waiting;
80 }
81 if (status == Missing)
82 {
83 sawMissing = true;
84 continue;
85 }
86 if (status == Unknown || status == Mixed)
87 {
88 sawUnknown = true;
89 continue;
90 }
91
92 if (definite == nullptr)
93 {
94 definite = &status;
95 }
96 else if (*definite != status)
97 {
98 return Mixed;
99 }
100 }
101
102 if (definite != nullptr)
103 {
104 return *definite;
105 }
106 if (sawUnknown)
107 {
108 return Unknown;
109 }
110 if (sawMissing)
111 {
112 return Missing;
113 }
114 return Unknown;
115}
116
117std::string
119{
120 return configDomain;
121}
122
123void
125{
126 ARMARX_CHECK_EXPRESSION(!value.empty());
127 configDomain = value;
128}
129
130bool
132{
133 return this->readOnly;
134}
135
137 std::string executablePath,
138 std::string instanceName,
139 std::string configPath,
140 std::string packageName,
141 ScenarioPtr scenario,
142 std::string node,
143 bool enabled) :
144 Application(executableName, executablePath, packageName),
145 instanceName(instanceName),
146 configPath(configPath),
147 status(ApplicationStatus::Unknown),
148 nodeName(node),
149 scenario(scenario),
150 pid(-1),
151 pendingIntent(Intent::None),
152 enabled(enabled)
153{
154}
155
157 std::string instanceName,
158 std::string configPath,
159 ScenarioPtr scenario,
160 std::string node,
161 bool enabled) :
162 Application(application),
163 instanceName(instanceName),
164 configPath(configPath),
165 status(ApplicationStatus::Unknown),
166 nodeName(node),
167 scenario(scenario),
168 pid(-1),
169 pendingIntent(Intent::None),
170 enabled(enabled)
171{
172}
173
179
180std::string
182{
183 return this->instanceName;
184}
185
186void
188{
189 this->instanceName = newName;
190}
191
192std::string
194{
195 return this->configPath;
196}
197
198void
200{
201 this->configPath = configPath;
202}
203
204void
206{
207 std::filesystem::path scenariosFolder(scenario->getPackage()->getScenarioPath());
208 std::filesystem::path scenarioFolder = scenariosFolder / scenario->getName();
209 std::filesystem::path scenarioCfgFolder = scenarioFolder / "config";
210
211 std::filesystem::path configPath = scenarioCfgFolder;
212
213 if (!this->instanceName.empty() && this->instanceName != R"("")" &&
214 this->instanceName != R"(" ")")
215 {
216 configPath = configPath / (this->getName() + "." + this->getInstanceName() + ".cfg");
217 }
218 else
219 {
220 configPath = configPath / (this->getName() + ".cfg");
221 ;
222 }
223
224 if (configPath != this->configPath)
225 {
226 std::filesystem::remove(std::filesystem::path(this->configPath));
227 }
228 this->configPath = configPath.string();
229}
230
231std::string
233{
234 return this->status;
235}
236
237bool
239{
240 bool result = status != this->status;
241 if (result)
242 {
243 this->status = status;
244 }
245 return result;
246}
247
248int
250{
251 return this->pid;
252}
253
254void
256{
257 this->pid = pid;
258}
259
260bool
262{
263 int expected = expectedPid;
264 return pid.compare_exchange_strong(expected, -1);
265}
266
267bool
269{
270 int expected = -1;
271 return pid.compare_exchange_strong(expected, newPid);
272}
273
274void
275Data_Structure::ApplicationInstance::modifyProperty(std::string name, std::string value)
276{
277 // Take a snapshot of the container instead of using the member directly: a lifecycle worker
278 // may swap in a freshly loaded one at any moment.
280 if (!props->isPropertySet(name))
281 {
282 props->defineOptionalProperty(name, std::string("::NOT_DEFINED::"), "Custom Property");
283 }
284 props->getProperties()->setProperty(name, value);
285}
286
287void
288Data_Structure::ApplicationInstance::addProperty(std::string name, std::string value)
289{
291 if (!props->isPropertySet(name))
292 {
293 props->defineOptionalProperty(name, std::string("::NOT_DEFINED::"), "Custom Property");
294 }
295 props->getProperties()->setProperty(name, value);
296}
297
298void
300{
301 Parser::IceParser parser;
302 parser.saveCfg(shared_from_this());
303}
304
305void
307{
308 if (!isReadOnly())
309 {
310 return;
311 }
312
313 if (!std::filesystem::is_symlink(configPath))
314 {
315 ARMARX_WARNING << "Make local called on non-linked application";
316 return;
317 }
318
319 std::filesystem::remove(configPath);
320 this->save();
321 // Reload to register status changes
322 this->load();
323}
324
325void
327{
328 deleteConfig();
329 load(true);
330 auto target_path = other.configPath.lexically_relative(configPath.parent_path());
331 std::filesystem::create_symlink(target_path, configPath);
332 load();
333}
334
335void
337{
338 deleteConfig();
339 load(true);
340 std::filesystem::copy_file(
341 other.configPath, configPath, std::filesystem::copy_options::overwrite_existing);
342 load();
343}
344
345void
347{
348 if (std::filesystem::exists(this->configPath))
349 {
350 std::filesystem::remove(this->configPath);
351 }
352}
353
354void
356{
357 if (!std::filesystem::exists(configPath))
358 {
359 ARMARX_WARNING_S << "Cannot find ApplicationInstance Config at:" << configPath;
360 }
361 else
362 {
363 Parser::IceParser parser;
364 setProperties(parser.mergeXmlAndCfg(shared_from_this(), firstLoad));
365 }
366
367 // If the config file is a symlink, put app into read-only mode
368 this->readOnly = std::filesystem::is_symlink(configPath);
369}
370
371bool
373{
374 std::ofstream ofs;
375
376 ofs.open(configPath.c_str(), std::ofstream::out | std::ofstream::app);
377 ARMARX_DEBUG << configPath << " is writeable: " << ofs.is_open();
378
379 return ofs.is_open();
380}
381
384{
385 return pendingIntent;
386}
387
388void
390{
391 pendingIntent = intent;
392}
393
394std::string
396{
397 return nodeName;
398}
399
400std::string
402{
403 return nodeName.empty() && scenario ? scenario->getNodeName() : nodeName;
404}
405
406void
408{
409 this->nodeName = nodeName;
410}
411
412bool
417
418void
420{
421 this->enabled = enabled;
422}
ApplicationInstance(std::string executableName, std::string executablePath, std::string instanceName, std::string configPath, std::string packageName, ScenarioPtr scenarioName, std::string node, bool enabled)
Constructor that sets the base data of this ApplicationInstance.
void setInstanceName(std::string newName)
Sets the name of this ApplicationInstance.
void setPid(int pid)
Sets the pid of this ApplicationInstance.
void addProperty(std::string name, std::string value)
Adds a new property with the specified name and value to this ApplicationInstance.
void setConfigPath(std::string configPath)
Sets the config path of this ApplicationInstance.
bool adoptPidIfUnset(int newPid)
Sets the pid to newPid, but only if no pid is currently known (i.e.
Intent getPendingIntent() const
The intent this application is currently moving towards, or None when idle.
void modifyProperty(std::string name, std::string value)
Changes the value of the specified property.
void makeLocal()
Make a local copy of this instance if it is linked and nothing otherwise.
void save()
Saves the IceProperties to the configPath.
void copyFrom(ApplicationInstance &other)
copyFrom Copy the other instance configuration to this one.
void linkFrom(ApplicationInstance &other)
linkFrom Link this instance configuration from the other instance.
bool compareAndResetPid(int expectedPid)
Sets the pid to -1, but only if it is still expectedPid.
void load(bool firstLoad=false)
Loades the IceProperties from the configPath Firstload determins if properties that equal their defau...
bool setStatus(const std::string &status)
Sets the status of this ApplicationInstance.
void setProperties(armarx::PropertyDefinitionsPtr properties)
Sets the properties of this application.
Application(std::string name, std::string executablePath, std::string packageName)
Constructor that sets the name and the path to the executable of the application.
armarx::PropertyDefinitionsPtr getProperties()
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:182
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
#define ARMARX_WARNING_S
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:211
std::shared_ptr< Scenario > ScenarioPtr
Definition Scenario.h:35
Intent
What the ScenarioManager is currently trying to do with an application.
const char * ToString(Intent intent)
Human readable name of an intent, for logging.
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
static std::string Aggregate(const std::vector< std::string > &stati)
Combines the stati of several applications into the status of their common parent (a scenario or the ...