Skip to content
This repository was archived by the owner on Jul 18, 2023. It is now read-only.

Commit 7c3acc5

Browse files
authored
Merge pull request #235 from mtconnect/update_schema_version_on_device_xml_reload
Update schema version on device xml reload
2 parents b86c48b + e25bc67 commit 7c3acc5

30 files changed

+386
-247
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ set(AGENT_VERSION_MAJOR 2)
33
set(AGENT_VERSION_MINOR 0)
44
set(AGENT_VERSION_PATCH 0)
55
set(AGENT_VERSION_BUILD 12)
6-
set(AGENT_VERSION_RC "_RC24")
6+
set(AGENT_VERSION_RC "_RC25")
77

88
# This minimum version is to support Visual Studio 2017 and C++ feature checking and FetchContent
99
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)

src/agent.cpp

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <boost/range/any_range.hpp>
2727
#include <boost/range/functions.hpp>
2828
#include <boost/range/metafunctions.hpp>
29+
#include <boost/range/numeric.hpp>
2930
#include <boost/uuid/uuid.hpp>
3031
#include <boost/uuid/uuid_generators.hpp>
3132
#include <boost/uuid/uuid_io.hpp>
@@ -76,9 +77,8 @@ namespace mtconnect {
7677
m_context(context),
7778
m_strand(m_context),
7879
m_xmlParser(make_unique<parser::XmlParser>()),
79-
m_version(
80-
GetOption<string>(options, config::SchemaVersion)
81-
.value_or(to_string(AGENT_VERSION_MAJOR) + "." + to_string(AGENT_VERSION_MINOR))),
80+
m_schemaVersion(
81+
GetOption<string>(options, config::SchemaVersion)),
8282
m_deviceXmlPath(deviceXmlPath),
8383
m_circularBuffer(GetOption<int>(options, config::BufferSize).value_or(17),
8484
GetOption<int>(options, config::CheckpointFrequency).value_or(1000)),
@@ -102,8 +102,14 @@ namespace mtconnect {
102102
uint32_t(GetOption<int>(options, mtconnect::configuration::JsonVersion).value_or(2));
103103

104104
// Create the Printers
105-
m_printers["xml"] = make_unique<printer::XmlPrinter>(m_version, m_pretty);
106-
m_printers["json"] = make_unique<printer::JsonPrinter>(jsonVersion, m_version, m_pretty);
105+
m_printers["xml"] = make_unique<printer::XmlPrinter>(m_pretty);
106+
m_printers["json"] = make_unique<printer::JsonPrinter>(jsonVersion, m_pretty);
107+
108+
if (m_schemaVersion)
109+
{
110+
for (auto &[k, pr] : m_printers)
111+
pr->setSchemaVersion(*m_schemaVersion);
112+
}
107113
}
108114

109115
void Agent::initialize(pipeline::PipelineContextPtr context)
@@ -114,19 +120,27 @@ namespace mtconnect {
114120
m_loopback =
115121
std::make_shared<source::LoopbackSource>("AgentSource", m_strand, context, m_options);
116122

117-
int major, minor;
118-
char c;
119-
stringstream vstr(m_version);
120-
vstr >> major >> c >> minor;
123+
auto devices = loadXMLDeviceFile(m_deviceXmlPath);
124+
if (!m_schemaVersion)
125+
{
126+
m_schemaVersion.emplace(StrDefaultSchemaVersion());
127+
}
128+
129+
auto version = IntSchemaVersion(*m_schemaVersion);
130+
for (auto &[k, pr] : m_printers)
131+
pr->setSchemaVersion(*m_schemaVersion);
121132

122133
auto disableAgentDevice = GetOption<bool>(m_options, config::DisableAgentDevice);
123-
if (!(disableAgentDevice && *disableAgentDevice) && (major > 1 || (major == 1 && minor >= 7)))
134+
if (!(disableAgentDevice && *disableAgentDevice) && version >= SCHEMA_VERSION(1, 7))
124135
{
125136
createAgentDevice();
126137
}
127-
loadXMLDeviceFile(m_deviceXmlPath);
128-
loadCachedProbe();
138+
139+
// For the DeviceAdded event for each device
140+
for (auto device : devices)
141+
addDevice(device);
129142

143+
loadCachedProbe();
130144
m_initialized = true;
131145
}
132146

@@ -277,13 +291,21 @@ namespace mtconnect {
277291
}
278292
}
279293

280-
void Agent::reloadDevices(const std::string &deviceFile)
294+
bool Agent::reloadDevices(const std::string &deviceFile)
281295
{
282296
try
283297
{
284298
// Load the configuration for the Agent
285299
auto devices = m_xmlParser->parseFile(
286300
deviceFile, dynamic_cast<printer::XmlPrinter *>(m_printers["xml"].get()));
301+
302+
if (m_xmlParser->getSchemaVersion() &&
303+
IntSchemaVersion(*m_xmlParser->getSchemaVersion()) != IntSchemaVersion(*m_schemaVersion))
304+
{
305+
LOG(info) << "Got version: " << *(m_xmlParser->getSchemaVersion());
306+
LOG(warning) << "Schema version does not match agent schema version, restarting the agent";
307+
return false;
308+
}
287309

288310
// Fir the DeviceAdded event for each device
289311
bool changed = false;
@@ -293,6 +315,8 @@ namespace mtconnect {
293315
}
294316
if (changed)
295317
loadCachedProbe();
318+
319+
return true;
296320
}
297321
catch (runtime_error &e)
298322
{
@@ -430,7 +454,7 @@ namespace mtconnect {
430454
if (!fs::exists(backup))
431455
fs::rename(file, backup);
432456

433-
printer::XmlPrinter printer(m_version, true);
457+
printer::XmlPrinter printer(true);
434458

435459
std::list<DevicePtr> list;
436460
copy_if(m_deviceIndex.begin(), m_deviceIndex.end(), back_inserter(list),
@@ -576,7 +600,7 @@ namespace mtconnect {
576600

577601
// Create the Agent Device
578602
ErrorList errors;
579-
Properties ps {{"uuid", uuid}, {"id", id}, {"name", "Agent"s}, {"mtconnectVersion", m_version}};
603+
Properties ps {{"uuid", uuid}, {"id", id}, {"name", "Agent"s}, {"mtconnectVersion", *m_schemaVersion}};
580604
m_agentDevice =
581605
dynamic_pointer_cast<AgentDevice>(AgentDevice::getFactory()->make("Agent", ps, errors));
582606
if (!errors.empty())
@@ -592,7 +616,7 @@ namespace mtconnect {
592616
// Device management and Initialization
593617
// ----------------------------------------------
594618

595-
void Agent::loadXMLDeviceFile(const std::string &configXmlPath)
619+
std::list<device_model::DevicePtr> Agent::loadXMLDeviceFile(const std::string &configXmlPath)
596620
{
597621
NAMED_SCOPE("Agent::loadXMLDeviceFile");
598622

@@ -602,9 +626,16 @@ namespace mtconnect {
602626
auto devices = m_xmlParser->parseFile(
603627
configXmlPath, dynamic_cast<printer::XmlPrinter *>(m_printers["xml"].get()));
604628

605-
// Fir the DeviceAdded event for each device
606-
for (auto device : devices)
607-
addDevice(device);
629+
if (!m_schemaVersion && m_xmlParser->getSchemaVersion())
630+
{
631+
m_schemaVersion = m_xmlParser->getSchemaVersion();
632+
}
633+
else if (!m_schemaVersion && !m_xmlParser->getSchemaVersion())
634+
{
635+
m_schemaVersion = StrDefaultSchemaVersion();
636+
}
637+
638+
return devices;
608639
}
609640
catch (runtime_error &e)
610641
{
@@ -620,14 +651,15 @@ namespace mtconnect {
620651
cerr << f.what() << endl;
621652
throw f;
622653
}
654+
655+
return {};
623656
}
624657

625658
void Agent::verifyDevice(DevicePtr device)
626659
{
627660
NAMED_SCOPE("Agent::verifyDevice");
628-
629-
auto xmlPrinter = dynamic_cast<printer::XmlPrinter *>(m_printers["xml"].get());
630-
const auto &schemaVersion = xmlPrinter->getSchemaVersion();
661+
662+
auto version = IntSchemaVersion(*m_schemaVersion);
631663

632664
// Add the devices to the device map and create availability and
633665
// asset changed events if they don't exist
@@ -644,11 +676,7 @@ namespace mtconnect {
644676
device->addDataItem(di, errors);
645677
}
646678

647-
int major, minor;
648-
char c;
649-
stringstream ss(schemaVersion);
650-
ss >> major >> c >> minor;
651-
if (!device->getAssetChanged() && (major > 1 || (major == 1 && minor >= 2)))
679+
if (!device->getAssetChanged() && version >= SCHEMA_VERSION(1, 2))
652680
{
653681
entity::ErrorList errors;
654682
// Create asset change data item and add it to the device.
@@ -659,14 +687,14 @@ namespace mtconnect {
659687
device->addDataItem(di, errors);
660688
}
661689

662-
if (device->getAssetChanged() && (major > 1 || (major == 1 && minor >= 5)))
690+
if (device->getAssetChanged() && version >= SCHEMA_VERSION(1, 5))
663691
{
664692
auto di = device->getAssetChanged();
665693
if (!di->isDiscrete())
666694
di->makeDiscrete();
667695
}
668696

669-
if (!device->getAssetRemoved() && (major > 1 || (major == 1 && minor >= 3)))
697+
if (!device->getAssetRemoved() && version >= SCHEMA_VERSION(1, 3))
670698
{
671699
// Create asset removed data item and add it to the device.
672700
entity::ErrorList errors;
@@ -677,7 +705,7 @@ namespace mtconnect {
677705
device->addDataItem(di, errors);
678706
}
679707

680-
if (!device->getAssetCount() && (major >= 2))
708+
if (!device->getAssetCount() && version >= SCHEMA_VERSION(2, 0))
681709
{
682710
entity::ErrorList errors;
683711
auto di = DataItem::make({{"type", "ASSET_COUNT"s},

src/agent.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ namespace mtconnect {
129129
const auto &getSources() const { return m_sources; }
130130
const auto &getSinks() const { return m_sinks; }
131131

132+
const auto &getSchemaVersion() const { return m_schemaVersion; }
133+
132134
// Get device from device map
133135
DevicePtr getDeviceByName(const std::string &name);
134136
DevicePtr getDeviceByName(const std::string &name) const;
@@ -157,7 +159,7 @@ namespace mtconnect {
157159
// Add the a device from a configuration file
158160
void addDevice(DevicePtr device);
159161
void deviceChanged(DevicePtr device, const std::string &oldUuid, const std::string &oldName);
160-
void reloadDevices(const std::string &deviceFile);
162+
bool reloadDevices(const std::string &deviceFile);
161163

162164
// Message when adapter has connected and disconnected
163165
void connecting(const std::string &adapter);
@@ -221,7 +223,7 @@ namespace mtconnect {
221223

222224
// Initialization methods
223225
void createAgentDevice();
224-
void loadXMLDeviceFile(const std::string &config);
226+
std::list<device_model::DevicePtr> loadXMLDeviceFile(const std::string &config);
225227
void verifyDevice(DevicePtr device);
226228
void initializeDataItems(DevicePtr device,
227229
std::optional<std::set<std::string>> skip = std::nullopt);
@@ -296,7 +298,7 @@ namespace mtconnect {
296298
std::unordered_map<std::string, WeakDataItemPtr> m_dataItemMap;
297299

298300
// Xml Config
299-
std::string m_version;
301+
std::optional<std::string> m_schemaVersion;
300302
std::string m_deviceXmlPath;
301303
bool m_versionDeviceXml = false;
302304

src/configuration/agent_config.cpp

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <boost/log/utility/setup/common_attributes.hpp>
3131
#include <boost/log/utility/setup/console.hpp>
3232
#include <boost/log/utility/setup/file.hpp>
33+
#include <boost/filesystem.hpp>
3334

3435
#ifdef __APPLE__
3536
#include <mach-o/dyld.h>
@@ -85,6 +86,7 @@
8586

8687
using namespace std;
8788
namespace fs = std::filesystem;
89+
namespace bfs = boost::filesystem;
8890
namespace pt = boost::property_tree;
8991
namespace logr = boost::log;
9092
namespace dll = boost::dll;
@@ -276,18 +278,34 @@ namespace mtconnect::configuration {
276278
LOG(warning)
277279
<< "Detected change in configuration files. Will reload when youngest file is at least "
278280
<< m_monitorDelay.count() << " seconds old";
281+
282+
if (devTime != *m_deviceTime)
283+
{
284+
auto t = bfs::last_write_time(m_devicesFile);
285+
LOG(warning) << "Dected change in Devices file: " << m_devicesFile;
286+
LOG(warning) << "... File changed at: " << put_time(localtime(&t), "%F %T");
287+
}
288+
289+
if (cfgTime != *m_configTime)
290+
{
291+
auto t = bfs::last_write_time(m_devicesFile);
292+
LOG(warning) << "Dected change in Config file: " << m_configFile;
293+
LOG(warning) << "... File changed at: " << put_time(localtime(&t), "%F %T");
294+
}
279295

280296
auto delta = min(now - cfgTime, now - devTime);
281297
if (delta < m_monitorDelay)
282298
{
283-
LOG(warning) << "Changed, waiting " << int32_t((m_monitorDelay - delta).count());
299+
LOG(warning) << "... Waiting " << int32_t((m_monitorDelay - delta).count()) << " seconds";
300+
scheduleMonitorTimer();
284301
}
285302
else
286303
{
287304
if (cfgTime != *m_configTime)
288305
{
289306
LOG(warning)
290-
<< "Monitor thread has detected change in configuration files, restarting agent.";
307+
<< "Monitor thread has detected change in configuration files.";
308+
LOG(warning) << ".... Restarting agent: " << m_configFile;
291309

292310
m_agent->stop();
293311

@@ -311,21 +329,34 @@ namespace mtconnect::configuration {
311329
}
312330
},
313331
true);
314-
315-
return;
316332
}
317-
318-
// Handle device changed by delivering the device file to the agent
319-
if (devTime != *m_deviceTime)
333+
else if (devTime != *m_deviceTime)
320334
{
335+
// Handle device changed by delivering the device file to the agent
336+
LOG(warning) << "Monitor thread has detected change in devices files.";
337+
LOG(warning) << "... Reloading Devices File: " << m_devicesFile;
338+
321339
m_context->pause([this](AsyncContext &context) {
322-
m_agent->reloadDevices(m_devicesFile);
323-
m_deviceTime.reset();
340+
if (!m_agent->reloadDevices(m_devicesFile))
341+
{
342+
m_configTime.emplace(m_configTime->min());
343+
using namespace chrono;
344+
using namespace chrono_literals;
345+
346+
using boost::placeholders::_1;
347+
348+
m_monitorTimer.expires_from_now(100ms);
349+
m_monitorTimer.async_wait(boost::bind(&AgentConfiguration::monitorFiles, this, _1));
350+
}
351+
else
352+
{
353+
m_deviceTime.reset();
354+
scheduleMonitorTimer();
355+
}
324356
});
325357
}
326358
}
327359

328-
scheduleMonitorTimer();
329360
return;
330361
}
331362

@@ -624,8 +655,7 @@ namespace mtconnect::configuration {
624655
{configuration::MaxCachedFileSize, "20k"s},
625656
{configuration::MinCompressFileSize, "100k"s},
626657
{configuration::ServiceName, "MTConnect Agent"s},
627-
{configuration::SchemaVersion,
628-
to_string(AGENT_VERSION_MAJOR) + "."s + to_string(AGENT_VERSION_MINOR)},
658+
{configuration::SchemaVersion, ""s},
629659
{configuration::LogStreams, false},
630660
{configuration::ShdrVersion, 1},
631661
{configuration::WorkerThreads, 1},
@@ -685,20 +715,20 @@ namespace mtconnect::configuration {
685715
}
686716

687717
// Check for schema version
688-
m_version = get<string>(options[configuration::SchemaVersion]);
689718
auto port = get<int>(options[configuration::Port]);
690719
LOG(info) << "Starting agent on port " << int(port);
691720

692721
// Make the Agent
693722
m_agent = make_unique<Agent>(getAsyncContext(), m_devicesFile, options);
694-
723+
695724
// Make the PipelineContext
696725
m_pipelineContext = std::make_shared<pipeline::PipelineContext>();
697726
m_pipelineContext->m_contract = m_agent->makePipelineContract();
698727

699728
loadSinks(config, options);
700729

701730
m_agent->initialize(m_pipelineContext);
731+
m_version = *m_agent->getSchemaVersion();
702732

703733
DevicePtr device;
704734
if (get<bool>(options[configuration::PreserveUUID]))

src/mqtt/mqtt_server_impl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ namespace mtconnect {
114114
// It makes sure wp.lock() never return nullptr in the handlers below
115115
// including close_handler and error_handler.
116116
ep.start_session(std::make_tuple(std::move(spep), std::move(g)));
117-
ep.set_connect_handler([this, &server, wp](MQTT_NS::buffer client_id,
117+
ep.set_connect_handler([this, wp](MQTT_NS::buffer client_id,
118118
MQTT_NS::optional<MQTT_NS::buffer> username,
119119
MQTT_NS::optional<MQTT_NS::buffer> password,
120120
MQTT_NS::optional<MQTT_NS::will>,

0 commit comments

Comments
 (0)