PDUConfigurator.cpp 7.86 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
								PDUSensor* pduSensor = new PDUSensor(sensor.second.data());
100
101
102
103

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

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

bool PDUConfigurator::readSensor(PDUSensor& sensor, boost::property_tree::iptree& config) {
133
134
135
136
137
138
139
	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()));
140
141
		} else if (boost::iequals(val.first, "path")) {
			parsePathString(sensor, val.second.data());
142
143
144
		} else if (boost::iequals(val.first, "default")) {
			//avoid unnecessary "Value not recognized" message
		} else {
145
			LOG(warning) << "  Value \"" << val.first << "\" not recognized. Omitting...";
146
147
		}
	}
148
	sensor.setCacheInterval(_cacheInterval);
149

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

154
	return true;
155
156
}

157
void PDUConfigurator::parsePathString(PDUSensor& sensor, const std::string& pathString) {
158
	LOG(debug) << "  Using " << pathString << " as XML search path";
159
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

	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));
200
					LOG(debug) << "  Attribute: " << attName << "=" << attVal;
201
				} else { //should not happen. If it does the path was malformed
202
					LOG(error) << "  Could not parse XML-path!";
203
204
205
206
207
208
209
210
211
					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));
212
				LOG(debug) << "  Subpath: " << subPath << " ; Child: " << subPathChild;
213
214
			} else {//the path contained only one node
				sensor._xmlPath.push_back(std::make_tuple("", subPath, attrs));
215
				LOG(debug) << "  Child: " << subPath;
216
217
218
219
220
221
			}
		} else { //no attributes specified. Last (sub)path
			if (subStr.front() == '.') {
				subStr.erase(0, 1);
			}
			sensor._xmlPath.push_back(std::make_tuple(subStr, "", attributesVector_t()));
222
			LOG(debug) << "  (Sub)path: " << subStr;
223
224
225
226
227
			break;
		}
	}
}