ConfiguratorTemplate.h 11.4 KB
Newer Older
1
/*
2
 * ConfiguratorTemplate.h
3
4
5
6
7
 *
 *  Created on: 13.01.2018
 *      Author: Micha Mueller
 */

8
9
#ifndef SRC_CONFIGURATORTEMPLATE_H_
#define SRC_CONFIGURATORTEMPLATE_H_
10

11
#include "ConfiguratorInterface.h"
12

13
14
#include "SensorBase.h"
#include "SensorGroupTemplate.h"
15

16
17
18
19
20
21
#include <map>

#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/info_parser.hpp>
22

23
24
#define STRCMP(node,str) boost::iequals(node.first,str)

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//TODO how to set mqttsuffix? (_mqttprefix + (mqttpart) + suffix)
#define LOOP_HEADER				BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) { \
									if (false) {}

#define S_BASE_ATTRIBUTES	bool sensorBase(S_BASE& obj, boost::property_tree::iptree& config) override { \
								LOOP_HEADER
#define S_GROUP_ATTRIBUTES	bool sensorGroup(S_GROUP& obj, boost::property_tree::iptree& config) override { \
								LOOP_HEADER
#define S_ENTITY_ATTRIBUTES	bool sensorEntity(S_ENTITY& obj, boost::property_tree::iptree& config) override { \
								LOOP_HEADER
#define ADD(name,setter)			else if (boost::iequals(val.first, name)) { obj.setter(val.second.data()); }
#define END_ATTRIBUTES			} return true; \
							}


/*
41
42
43
44
45
#define CONFIG		boost::property_tree::iptree& config
#define ATTRIBUTES	BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) { \
						if (false) {}
#define ADD(name,setter)	else if (boost::iequals(val.first, name)) { sBase.setter(val.second.data()); }
#define END			} return true;
46
*/
47

Micha Mueller's avatar
Micha Mueller committed
48
/**
49
 * Non-virtual interface template for the configurators.
Micha Mueller's avatar
Micha Mueller committed
50
 */
51
template <class SBase, class SGroup, class SEntity = void>
52
class ConfiguratorTemplate : public ConfiguratorInterface {
53
	//the template shall only be instantiated for classes which derive from SensorBase/SensorGroup
54
	static_assert(std::is_base_of<SensorBase, SBase>::value, "SBase must derive from SensorBase!");
55
	static_assert(std::is_base_of<SensorGroupTemplate, SGroup>::value, "SGroup must derive from SensorGroupTemplate!");
56

57
protected:
58
59
	typedef std::map<std::string, SGroup*> sGroupMap_t;
	typedef std::map<std::string, SEntity*> sEntityMap_t;
60

61
public:
62
63
64
	ConfiguratorTemplate() :
		_entityName("entity"),
		_groupName("group"),
65
		_baseName("sensor"),
66
67
68
		_cfgPath(""),
		_mqttPrefix(""),
		_cacheInterval(900000) {}
69

70
71
	ConfiguratorTemplate(const ConfiguratorTemplate&) = delete;

72
	virtual ~ConfiguratorTemplate() {
73
74
		for (auto g : _sensorGroups) {
			delete g;
75
		}
76
77
78
79
80
81
		for (auto tg : _templateSensorGroups) {
			delete tg;
		}
		for (auto te : _templateSensorEntitys) {
			delete te;
		}
82
		_templateSensorGroups.clear();
83
		_templateSensorEntitys.clear();
84
	}
85

86
87
	ConfiguratorTemplate& operator=(const ConfiguratorTemplate&) = delete;

Micha Mueller's avatar
Micha Mueller committed
88
89
	/**
	 * Read in the given configuration
90
	 *
Micha Mueller's avatar
Micha Mueller committed
91
	 * @param	cfgPath Path to the config-file
92
93
	 *
	 * @return	True on success, false otherwise
Micha Mueller's avatar
Micha Mueller committed
94
	 */
95
	bool readConfig(std::string cfgPath) final {
96
		_cfgPath = cfgPath;
97
98
99
100
101

		boost::property_tree::iptree cfg;
		boost::property_tree::read_info(cfgPath, cfg);

		//read global variables (if present overwrite those from global.conf)
102
103
104
105
106
107
108
109
110
		readGlobal(cfg);

		//read template stuff
		boost::optional<boost::property_tree::iptree&> templates = cfg.get_child_optional("templates");
		if (templates) {
			BOOST_FOREACH(boost::property_tree::iptree::value_type &tempVal, cfg.get_child("templates")) {
				if (boost::iequals(tempVal.first, _entityName)) {
					//TODO
				} else if (boost::iequals(tempVal.first, _groupName)) {
111
					LOG(debug) << "Template " << _groupName << " \"" << tempVal.second.data() << "\"";
112
					if (!tempVal.second.empty()) {
113
114
115
116
117
						SGroup* group = new SGroup(tempVal.second.data());
						if (readSensorGroup(*group, tempVal.second)) {
							auto ret = _templateSensorGroups.insert(std::pair<std::string, SGroup*>(group->getName(), group));
							if(!ret.second) {
								LOG(warning) << "Template " << _groupName << " " << group->getName() << " already exists! Omitting...";
118
119
							}
						} else {
120
							LOG(warning) << "Template " << _groupName << " \"" << tempVal.second.data() << "\" has bad values! Ignoring...";
121
						}
122
					}
123
				} //else if (boost::iequals(tempVal.first, _baseName)) {//TODO allow for template sensors? even useful?}
124
125
126
			}
		}

127
128
		//TODO read actual entitys/groups/bases. How to handle defaults?

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//		//read template groups
//		boost::optional<boost::property_tree::iptree&> tempSens = cfg.get_child_optional("groupTemplates");
//		if (tempSens) {
//			BOOST_FOREACH(boost::property_tree::iptree::value_type &groupVal, cfg.get_child("groupTemplates")) {
//				if (STRCMP(groupVal, "group")) {
//					LOG(debug) << "Template " << _groupName << " \"" << groupVal.second.data() << "\"";
//					if (!groupVal.second.empty()) {
//						//TODO
//						SGroup group(groupVal.second.data());
//						if(readSensorGroup(group, groupVal.second)) {
//							_templateSensorGroups.insert(std::pair<std::string, SGroup>(group.getName(), group));
//						} else {
//							LOG(warning) << "Template " << _groupName << " \"" << groupVal.second.data() << "\" has bad values! Ignoring...";
//						}
//					}
//				}
//			}
//		}
147
148
149

		//read in plugin specific stuff (including actual sensors)
		return derivedReadConfig(cfg);
150
151
152
153
	}

	/**
	 * Clear internal storage and read in the configuration again.
154
155
	 *
	 * @return	True on success, false otherwise
156
	 */
157
	bool reReadConfig() final {
Micha Mueller's avatar
Micha Mueller committed
158
159
		//bring everything to a halt
		for(auto g : _sensorGroups) {
160
			g->stop();
Micha Mueller's avatar
Micha Mueller committed
161
162
163
164
165
166
		}

		//wait until everything is halted
		for(auto g : _sensorGroups) {
			g->wait();
		}
167

Micha Mueller's avatar
Micha Mueller committed
168
		//clean up plugin specific stuff
169
170
		derivedReReadConfig();

171
		//clean up sensors/groups and templates
Micha Mueller's avatar
Micha Mueller committed
172
173
174
		for(auto g : _sensorGroups) {
			delete g;
		}
175
176
177
178
179
180
		for (auto tg : _templateSensorGroups) {
			delete tg;
		}
		for (auto te : _templateSensorEntitys) {
			delete te;
		}
Micha Mueller's avatar
Micha Mueller committed
181
		_sensorGroups.clear();
182
		_templateSensorGroups.clear();
183
		_templateSensorEntitys.clear();
184

Micha Mueller's avatar
Micha Mueller committed
185
		//back to the very beginning
186
		return readConfig(_cfgPath);
187
	}
188

189
190
191
192
193
194
195
	/**
	 * Sets internal variables with the ones provided by pluginSettings.
	 * This method should be called once after constructing a configurator
	 * to provide him with the global default values.
	 *
	 * @param pluginSettings	Struct with global default settings for the plugins.
	 */
196
	void setGlobalSettings(const pluginSettings_t& pluginSettings) final {
197
198
		_mqttPrefix = pluginSettings.mqttPrefix;
		_cacheInterval = pluginSettings.cacheInterval;
199
200

		derivedSetGlobalSettings(pluginSettings);
201
202
	}

Micha Mueller's avatar
Micha Mueller committed
203
204
205
206
207
	/**
	 * Get all sensor groups
	 *
	 * @return	Vector containing pointers to all sensor groups of this plugin
	 */
208
	std::vector<SensorGroupInterface*>& getSensorGroups() {
Micha Mueller's avatar
Micha Mueller committed
209
210
211
		return _sensorGroups;
	}

212
protected:
213
214
215
216
217
	/**
	 * Non-virtual interface method for class-internal use only.
	 * Reads and sets the common base values of a sensor (currently none),
	 * then calls the corresponding derived function to read plugin specific
	 * values.
218
	 *
219
	 * @param sBase		The sensor base for which to set the values
220
221
222
223
	 * @param config	A boost property (sub-)tree containing the sensor values
	 *
	 * @return	True on success, false otherwise
	 */
224
	bool readSensorBase(SBase& sBase, boost::property_tree::iptree& config) {
225
		return sensorBase(sBase, config);
226
227
228
229
230
231
232
233
234
235
236
237
238
	}

	/**
	 * Non-virtual interface method for class-internal use only.
	 * Reads and sets the common base values of a SensorInterface, then calls
	 * the corresponding derived function to read in plugin specific values
	 * (currently none).
	 *
	 * @param sensor	The sensor for which to set the values
	 * @param config	A boost property (sub-)tree containing the sensor values
	 *
	 * @return	True on success, false otherwise
	 */
239
240
241
	bool readSensorGroup(SGroup& sGroup, boost::property_tree::iptree& config) {
		sGroup.setCacheInterval(_cacheInterval);
		//read in values inherited from SensorGroupInterface
242
		BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
243
			//TODO handle default value here?
244
			if (STRCMP(val, "interval")) {
245
				sGroup.setInterval(stoull(val.second.data()));
246
			} else if (STRCMP(val, "minValues")) {
247
248
249
250
				sGroup.setMinValues(stoull(val.second.data()));
			} else if (STRCMP(val, "sensor")) {
				SBase* sensor = new SBase(val.second.data());
				if (readSensorBase(*sensor, val.second)) {
251
252
253
254
					auto ret = sGroup.pushBackSensor(sensor);
					if(!ret.second) {
						LOG(warning) << _baseName << " " << sensor->getName() << " already exists! Omitting...";
					}
255
				} else {
256
					LOG(warning) << _baseName << " " << sGroup.getGroupName() << "::" << sensor->getName() << " could not be read! Omitting";
257
				}
258
259
260
			}
		}

261
262
		LOG(debug) << "  Interval : " << sGroup.getInterval();
		LOG(debug) << "  minValues: " << sGroup.getMinValues();
263

264
265
266
267
268
		return sensorGroup(sGroup, config);
	}

	bool readSensorEntity(SEntity& sEntity, boost::property_tree::iptree& config) {
		return sensorEntity(sEntity, config);
269
270
	}

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
	bool readGlobal(boost::property_tree::iptree& config) {
		boost::optional<boost::property_tree::iptree&> globalVals = config.get_child_optional("global");
		if (globalVals) {
			BOOST_FOREACH(boost::property_tree::iptree::value_type &global, config.get_child("global")) {
				if (boost::iequals(global.first, "mqttprefix")) {
					_mqttPrefix = global.second.data();
					if (_mqttPrefix[_mqttPrefix.length()-1] != '/') {
						_mqttPrefix.append("/");
					}
					LOG(debug) << "  Using own MQTT-Prefix " << _mqttPrefix;
				} else if (boost::iequals(global.first, "cacheInterval")) {
					_cacheInterval = stoul(global.second.data());
					LOG(debug) << "  Using own caching interval " << _cacheInterval << " [s]";
					_cacheInterval *= 1000;
				}
			}
		}
		return global(config);
	}

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
	/**
	 * Pure virtual interface method, responsible for reading the plugin-specific
	 * configuration part.
	 *
	 * @param cfg	The (root) boost property tree from the plugins configuration file
	 *
	 * @return	True on success, false otherwise
	 */
	virtual bool derivedReadConfig(boost::property_tree::iptree& cfg) = 0;

	/**
	 * Pure virtual interface method, responsible for the plugin specific part if
	 * re-reading the config.
	 */
	virtual void derivedReReadConfig() = 0;

	/**
	 * Pure virtual interface method, responsible for setting global values specifically
	 * for its plugin.
	 *
	 * @param pluginSettings	The struct with global default plugin settings
	 */
	virtual void derivedSetGlobalSettings(const pluginSettings_t& pluginSettings) = 0;

	/**
	 * Pure virtual interface method, responsible for reading plugin-specific sensor
317
	 * base values.
318
	 *
319
320
321
322
323
	 * @param sBase		The sensor base for which to set the values
	 * @param config	A boost property (sub-)tree containing the sensor values
	 *
	 * @return	True on success, false otherwise
	 */
324
	virtual bool sensorBase(SBase& sBase, boost::property_tree::iptree& config) = 0;
325
326
327
328
329
330

	/**
	 * Pure virtual interface method, responsible for reading plugin-specific sensor
	 * group values.
	 *
	 * @param sGroup	The sensor group for which to set the values
331
332
333
334
	 * @param config	A boost property (sub-)tree containing the sensor values
	 *
	 * @return	True on success, false otherwise
	 */
335
336
337
338
	virtual bool sensorGroup(SGroup& sGroup, boost::property_tree::iptree& config) = 0;

	virtual bool sensorEntity(SEntity& sEntity, boost::property_tree::iptree& config) = 0;

339
340
	virtual bool global(boost::property_tree::iptree& config) = 0;

341
342
	std::string		_entityName;
	std::string		_groupName;
343
	std::string		_baseName;
344
345
346
347

	std::string 	_cfgPath;
	std::string		_mqttPrefix;
	unsigned int	_cacheInterval;
348
	std::vector<SensorGroupInterface*> _sensorGroups;
349
350
	sGroupMap_t		_templateSensorGroups;
	sEntityMap_t	_templateSensorEntitys;
351
352
};

353
#endif /* SRC_CONFIGURATORTEMPLATE_H_ */