PDUConfigurator.cpp 7.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
/*
 * PDUConfigurator.cpp
 *
 *  Created on: 24.02.2018
 *      Author: Micha Mueller
 */

#include "PDUConfigurator.h"

10
#include <iostream>
11
#include <sstream>
12

13
14
15
16
#include <boost/foreach.hpp>
#include <boost/property_tree/info_parser.hpp>
#include <boost/algorithm/string.hpp>

17
18
using namespace std;

19
20
21
22
23
24
25
26
27
28
29
PDUConfigurator::PDUConfigurator() {
	// TODO Auto-generated constructor stub

}

PDUConfigurator::~PDUConfigurator() {
	for (auto s : _sensors) {
		delete s;
	}
}

30
bool PDUConfigurator::readConfig(std::string cfgPath) {
31
32
33
34
35
36
37
38
39
40
41
42
	boost::property_tree::iptree cfg;
	boost::property_tree::read_info(cfgPath, cfg);

	//read global variables (if present overwrite those from global.conf)
	boost::optional<boost::property_tree::iptree&> globalVals = cfg.get_child_optional("global");
	if (globalVals) {
		BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("global")) {
			if(boost::iequals(global.first, "mqttprefix")) {
				_mqttPrefix = global.second.data();
				if (_mqttPrefix[_mqttPrefix.length()-1] != '/') {
					_mqttPrefix.append("/");
				}
43
				LOG(debug) << "  Using own MQTT-Prefix " << _mqttPrefix;
44
45
46
47
			} else if (boost::iequals(global.first, "cacheInterval")) {
				_cacheInterval = stoul(global.second.data());
				LOG(debug) << "  Using own caching interval " << _cacheInterval << " [s]";
				_cacheInterval *= 1000;
48
			} else {
49
				LOG(error) << "  Value \"" << global.first << "\" not recognized. Omitting...";
50
51
52
53
54
55
56
			}
		}
	}

	//read template sensors
	BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("SensorTemplate")) {
		if (boost::iequals(sensor.first, "sensor")) {
57
			LOG(debug) << "Template Sensor \"" << sensor.second.data() << "\"";
58
59
60
61
62
			if (!sensor.second.empty()) {
				PDUSensor pduSensor(sensor.second.data());
				if(readSensor(pduSensor, sensor.second)) {
					_templateSensors.insert(sensorMap_t::value_type(pduSensor.getName(), pduSensor));
				} else {
63
					LOG(warning) << "Template sensor \"" << sensor.second.data() << "\" has bad values! Ignoring...";
64
65
66
67
68
69
70
71
				}
			}
		}
	}

	//read one pdu at a time
	BOOST_FOREACH(boost::property_tree::iptree::value_type &pdu, cfg.get_child("pdus")) {
		if (boost::iequals(pdu.first, "pdu")) {
72
			LOG(debug) << "PDU \"" << pdu.second.data() << "\"";
73
74
75
76
77
78
79
			if (!pdu.second.empty()) {
				//create PDU at end of list
				_pdus.push_back(PDUUnit());
				PDUUnit& pduUnit = _pdus.back();

				//read PDU-values
				BOOST_FOREACH(boost::property_tree::iptree::value_type &val, pdu.second) {
80
81
					if (boost::iequals(val.first, "TTL")) {
						pduUnit.setTTL(stoull(val.second.data()));
82
						LOG(debug) << "  TTL	" << pduUnit.getTTL();
83
					} else if (boost::iequals(val.first, "host")) {
84
85
86
87
88
89
90
						std::string host = val.second.data();
						size_t pos = host.find(':');
						if (pos != string::npos) {
							pduUnit.setHost(host);
						} else {
							pduUnit.setHost(host + ":443");
						}
91
92
93
94
						LOG(debug) << "  Host	" << pduUnit.getHost();
					} else if (boost::iequals(val.first, "request")) {
						pduUnit.setRequest(val.second.data());
						LOG(debug) << "  Request:	\n" << pduUnit.getRequest();
95
96
					} else if (boost::iequals(val.first, "sensors")) {
						BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, val.second) {
97
							LOG(debug) << "Sensor \"" << sensor.second.data() << "\"";
98
							if (!sensor.second.empty()) {
99
100
								std::string name = pdu.second.data() + "_" + sensor.second.data();
								PDUSensor* pduSensor = new PDUSensor(name);
101
102
103
104

								//first check if default sensor is given
								boost::optional<boost::property_tree::iptree&> defaultC = sensor.second.get_child_optional("default");
								if(defaultC) {
105
									LOG(debug) << "  Using \"" << defaultC.get().data() << "\" as default.";
106
107
									sensorMap_t::iterator it = _templateSensors.find(defaultC.get().data());
									if(it != _templateSensors.end()) {
108
										*pduSensor = it->second;
109
										pduSensor->setName(name);
110
									} else {
111
										LOG(warning) << "  Template sensor \"" << defaultC.get().data() << "\" not found! Using standard values.";
112
113
114
115
									}
								}

								//read remaining values
116
								if(readSensor(*pduSensor, sensor.second)) {
117
									//set pointer to corresponding pdu
118
119
									pduSensor->setPdu(&pduUnit);
									_sensors.push_back(pduSensor);
120
								} else {
Micha Mueller's avatar
Micha Mueller committed
121
									LOG(warning) << "  Sensor \"" << sensor.second.data() << "\" has bad values! Ignoring...";
122
123
124
125
126
127
128
129
								}
							}
						}
					}
				}
			}
		}
	}
130
	return true;
131
132
133
}

bool PDUConfigurator::readSensor(PDUSensor& sensor, boost::property_tree::iptree& config) {
134
135
136
137
138
139
140
	BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
		if (boost::iequals(val.first, "interval")) {
			sensor.setInterval(stoull(val.second.data()));
		} else if (boost::iequals(val.first, "mqttsuffix")) {
			sensor.setMqtt(_mqttPrefix + val.second.data());
		} else if (boost::iequals(val.first, "minValues")) {
			sensor.setMinValues(stoull(val.second.data()));
141
142
		} else if (boost::iequals(val.first, "path")) {
			parsePathString(sensor, val.second.data());
143
144
145
		} else if (boost::iequals(val.first, "default")) {
			//avoid unnecessary "Value not recognized" message
		} else {
146
			LOG(warning) << "  Value \"" << val.first << "\" not recognized. Omitting...";
147
148
		}
	}
149
	sensor.setCacheInterval(_cacheInterval);
150

151
152
153
	LOG(debug) << "  MQTT     : " << sensor.getMqtt();
	LOG(debug) << "  Interval : " << sensor.getInterval();
	LOG(debug) << "  minValues: " << sensor.getMinValues();
Micha Mueller's avatar
Micha Mueller committed
154

155
	return true;
156
157
}

158
void PDUConfigurator::parsePathString(PDUSensor& sensor, const std::string& pathString) {
159
	LOG(debug) << "  Using " << pathString << " as XML search path";
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

	std::vector<std::string> subStrings;

	std::stringstream pathStream(pathString);
	std::string item;
	//split into parts if a attribute (indicated by '(' ')') was defined
	while (std::getline(pathStream, item, ')')) {
		subStrings.push_back(item);
	}

	for (auto subStr : subStrings) {
		//extract the attributes from the path-parts
		if (subStr.find('(') != std::string::npos) { //attribute specified
			std::stringstream pathWithAttributesSStream(subStr);

			//split into path and attributes string
			std::string subPath, attributeString;
			std::getline(pathWithAttributesSStream, subPath, '(');
			std::getline(pathWithAttributesSStream, attributeString);

			if (subPath.front() == '.') {
				subPath.erase(0, 1);
			}

			//now further split the attributes string as multiple attributes could be defined
			std::vector<std::string> attributes;
			std::stringstream attributeStream(attributeString);
			while (std::getline(attributeStream, item, ',')) {
				attributes.push_back(item);
			}
			attributesVector_t attrs;
			for (auto att : attributes) {
				//part attributes into name and value
				if (att.find('=') != std::string::npos) {
					std::stringstream attStream(att);

					std::string attName, attVal;
					std::getline(attStream, attName, '=');
					std::getline(attStream, attVal);

					attrs.push_back(std::make_pair(attName, attVal));
201
					LOG(debug) << "  Attribute: " << attName << "=" << attVal;
202
				} else { //should not happen. If it does the path was malformed
203
					LOG(error) << "  Could not parse XML-path!";
204
205
206
207
208
209
210
211
212
					return;
				}
			}
			//split of the last child in the path. Required to iterate over multiple nodes which only differ in the attributes with BOOST_FOREACH
			auto index = subPath.find_last_of('.');
			if (index != std::string::npos) {
				std::string subPathChild(subPath.substr(++index));
				subPath.erase(--index);
				sensor._xmlPath.push_back(std::make_tuple(subPath, subPathChild, attrs));
213
				LOG(debug) << "  Subpath: " << subPath << " ; Child: " << subPathChild;
214
215
			} else {//the path contained only one node
				sensor._xmlPath.push_back(std::make_tuple("", subPath, attrs));
216
				LOG(debug) << "  Child: " << subPath;
217
218
219
220
221
222
			}
		} else { //no attributes specified. Last (sub)path
			if (subStr.front() == '.') {
				subStr.erase(0, 1);
			}
			sensor._xmlPath.push_back(std::make_tuple(subStr, "", attributesVector_t()));
223
			LOG(debug) << "  (Sub)path: " << subStr;
224
225
226
227
228
			break;
		}
	}
}