diff --git a/ThirdParty/jsoncpp b/ThirdParty/jsoncpp index 8875b448e4..384f055bde 160000 --- a/ThirdParty/jsoncpp +++ b/ThirdParty/jsoncpp @@ -1 +1 @@ -Subproject commit 8875b448e4f5bfa03a7380d2d29a71019c5ed06f +Subproject commit 384f055bdea629643abdc70fc5a9d7811427c9aa diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f5f5c1e113..a713db3b52 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -25,3 +25,5 @@ endif() if(HELICS_BUILD_CXX_SHARED_LIB) add_subdirectory(comboFederates_cpp_shared) endif() + +add_subdirectory(InteropExample) diff --git a/examples/InteropExample/CMakeLists.txt b/examples/InteropExample/CMakeLists.txt new file mode 100644 index 0000000000..5d5235235c --- /dev/null +++ b/examples/InteropExample/CMakeLists.txt @@ -0,0 +1,20 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# Copyright (c) 2017-2021, Battelle Memorial Institute; Lawrence Livermore +# National Security, LLC; Alliance for Sustainable Energy, LLC. +# See the top-level NOTICE for additional details. +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +add_executable(interopFed1 InterOpFed1.cpp) + +target_link_libraries(interopFed1 PUBLIC helics_application_api) +target_link_libraries(interopFed1 PRIVATE compile_flags_target) +set_target_properties(interopFed1 PROPERTIES FOLDER examples) + +add_executable(interopFed2 InterOpFed2.cpp) + +target_link_libraries(interopFed2 PUBLIC helics_application_api) +target_link_libraries(interopFed2 PRIVATE compile_flags_target) +set_target_properties(interopFed2 PROPERTIES FOLDER examples) diff --git a/examples/InteropExample/InterOpFed1.cpp b/examples/InteropExample/InterOpFed1.cpp new file mode 100644 index 0000000000..297ae09d6f --- /dev/null +++ b/examples/InteropExample/InterOpFed1.cpp @@ -0,0 +1,78 @@ +/* +Copyright (c) 2017-2021, +Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable +Energy, LLC. See the top-level NOTICE for additional details. All rights reserved. +SPDX-License-Identifier: BSD-3-Clause +*/ +#include "helics/application_api/BrokerApp.hpp" +#include "helics/application_api/CombinationFederate.hpp" +#include "helics/application_api/Endpoints.hpp" +#include "helics/application_api/Publications.hpp" +#include "helics/application_api/Subscriptions.hpp" + +#include + +int main(int argc, char* argv[]) +{ + helics::FederateInfo fi(argc, argv); + fi.setProperty(helics_property_time_period, 1.0); + helics::BrokerApp brk(fi.coreType, fi.brokerInitString + " -f 2"); + + auto cFed = std::make_unique("ioFed1", fi); + auto name = cFed->getName(); + + helics::data_block mbuf(256, 0); + for (int ii = 0; ii < 256; ++ii) { + mbuf[ii] = char(ii); + } + // this line actually creates an endpoint + auto& ept = cFed->registerEndpoint("ept"); + + auto& pubid = cFed->registerPublication("pub", "double"); + + auto& subid = cFed->registerSubscription("ioFed2/pub"); + + cFed->enterInitializingMode(); + cFed->enterExecutingMode(); + bool passed{true}; + for (int i = 1; i < 10; ++i) { + std::string mback = std::string(" at time ") + std::to_string(i); + std::string message = std::string("message sent from ioFed1 to ioFed2"); + message.append(mback); + ept.send("ioFed2/ept", message.data(), message.size()); + ept.send("ioFed2/ept", mbuf); + + pubid.publish(i); + + auto newTime = cFed->requestTime(i); + + if (cFed->isUpdated(subid)) { + auto val = subid.getValue(); + if (val != i) { + passed = false; + } + } else { + passed = false; + } + if (ept.pendingMessages() != 2) { + passed = false; + } else { + auto m1 = ept.getMessage(); + if (m1->data.to_string().find(mback) == std::string::npos) { + passed = false; + } + auto m2 = ept.getMessage(); + if (mbuf != m2->data) { + passed = false; + } + } + } + cFed->finalize(); + brk.waitForDisconnect(); + if (passed) { + std::cout << "Federate1 has PASSED the test"; + } else { + std::cout << "Federate1 has FAILED the test"; + } + return 0; +} diff --git a/examples/InteropExample/InterOpFed2.cpp b/examples/InteropExample/InterOpFed2.cpp new file mode 100644 index 0000000000..613b667126 --- /dev/null +++ b/examples/InteropExample/InterOpFed2.cpp @@ -0,0 +1,78 @@ +/* +Copyright (c) 2017-2021, +Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable +Energy, LLC. See the top-level NOTICE for additional details. All rights reserved. +SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "helics/application_api/CombinationFederate.hpp" +#include "helics/application_api/Endpoints.hpp" +#include "helics/application_api/Publications.hpp" +#include "helics/application_api/Subscriptions.hpp" + +#include + +int main(int argc, char* argv[]) +{ + helics::FederateInfo fi(argc, argv); + fi.setProperty(helics_property_time_period, 1.0); + + auto cFed = std::make_unique("ioFed2", fi); + auto name = cFed->getName(); + + helics::data_block mbuf(256, 0); + for (int ii = 0; ii < 256; ++ii) { + mbuf[ii] = char(ii); + } + // this line actually creates an endpoint + auto& ept = cFed->registerEndpoint("ept"); + + auto& pubid = cFed->registerPublication("pub", "double"); + + auto& subid = cFed->registerSubscription("ioFed1/pub"); + + cFed->enterInitializingMode(); + cFed->enterExecutingMode(); + bool passed{true}; + for (int i = 1; i < 10; ++i) { + std::string mback = std::string(" at time ") + std::to_string(i); + std::string message = std::string("message sent from ioFed2 to ioFed1"); + message.append(mback); + ept.send("ioFed1/ept", message.data(), message.size()); + ept.send("ioFed1/ept", mbuf); + pubid.publish(i); + + auto newTime = cFed->requestTime(i); + + if (cFed->isUpdated(subid)) { + auto val = subid.getValue(); + if (val != i) { + passed = false; + } + } else { + passed = false; + } + if (ept.pendingMessages() != 2) { + passed = false; + } else { + auto m1 = ept.getMessage(); + if (m1->data.to_string().find(mback) == std::string::npos) { + passed = false; + } + auto m2 = ept.getMessage(); + if (mbuf != m2->data) { + auto s1 = std::string(mbuf.to_string()); + auto s2 = std::string(m2->to_string()); + passed = false; + } + } + } + cFed->finalize(); + + if (passed) { + std::cout << "Federate 2 has PASSED the test"; + } else { + std::cout << "Federate 2 has FAILED the test"; + } + return 0; +} diff --git a/src/helics/application_api/ValueFederate.cpp b/src/helics/application_api/ValueFederate.cpp index 2b6b5e09ad..1a3bcd1c41 100644 --- a/src/helics/application_api/ValueFederate.cpp +++ b/src/helics/application_api/ValueFederate.cpp @@ -73,6 +73,7 @@ ValueFederate::ValueFederate() = default; ValueFederate::ValueFederate(bool /*res*/) { vfManager = std::make_unique(coreObject.get(), this, getID()); + vfManager->useJsonSerialization = useJsonSerialization; } ValueFederate::ValueFederate(ValueFederate&&) noexcept = default; diff --git a/src/helics/common/JsonProcessingFunctions.cpp b/src/helics/common/JsonProcessingFunctions.cpp index cd1ad5faa5..585bbe4121 100644 --- a/src/helics/common/JsonProcessingFunctions.cpp +++ b/src/helics/common/JsonProcessingFunctions.cpp @@ -97,6 +97,7 @@ std::string getKey(const Json::Value& element) std::string generateJsonString(const Json::Value& block) { Json::StreamWriterBuilder builder; + builder["emitUTF8"] = true; builder["commentStyle"] = "None"; builder["indentation"] = " "; // or whatever you like auto writer = std::unique_ptr(builder.newStreamWriter()); diff --git a/src/helics/core/ActionMessage.cpp b/src/helics/core/ActionMessage.cpp index 9167cdea06..2f58c675d6 100644 --- a/src/helics/core/ActionMessage.cpp +++ b/src/helics/core/ActionMessage.cpp @@ -73,7 +73,12 @@ ActionMessage::ActionMessage(const std::vector& bytes): ActionMessage() ActionMessage::ActionMessage(const char* data, size_t size): ActionMessage() { - fromByteArray(data, static_cast(size)); + auto result = fromByteArray(data, static_cast(size)); + if (result == 0U && size > 0 && data[0] == '{') { + if (!from_json_string(data)) { + messageAction = CMD_INVALID; + } + } } ActionMessage::~ActionMessage() = default; @@ -567,7 +572,7 @@ int ActionMessage::depacketize(const char* data, int buffer_size) std::size_t ActionMessage::from_string(const std::string& data) { auto result = fromByteArray(data.data(), static_cast(data.size())); - if (result == 0U && data.size() > 0 && data.front() == '{') { + if (result == 0U && !data.empty() && data.front() == '{') { if (from_json_string(data)) { return data.size(); } @@ -612,7 +617,7 @@ bool ActionMessage::from_json_string(const std::string& data) std::size_t ActionMessage::from_vector(const std::vector& data) { std::size_t bytesUsed = fromByteArray(data.data(), static_cast(data.size())); - if (bytesUsed == 0 && data.size() > 0 && data.front() == '{') { + if (bytesUsed == 0 && !data.empty() && data.front() == '{') { if (from_json_string(std::string(data.data(), data.size()))) { return data.size(); } diff --git a/src/helics/network/zmq/ZmqComms.cpp b/src/helics/network/zmq/ZmqComms.cpp index 26475aaee4..01f94e2a45 100644 --- a/src/helics/network/zmq/ZmqComms.cpp +++ b/src/helics/network/zmq/ZmqComms.cpp @@ -277,6 +277,9 @@ namespace zeromq { return (-3); } ActionMessage getPorts = generatePortRequest((serverMode) ? 2 : 1); + if (useJsonSerialization) { + setActionFlag(getPorts, use_json_serialization_flag); + } auto str = (useJsonSerialization) ? getPorts.to_json_string() : getPorts.to_string(); diff --git a/tests/helics/core/ActionMessage-tests.cpp b/tests/helics/core/ActionMessage-tests.cpp index 8c26abb833..b099ccf7ca 100644 --- a/tests/helics/core/ActionMessage-tests.cpp +++ b/tests/helics/core/ActionMessage-tests.cpp @@ -537,3 +537,35 @@ TEST(ActionMessage, jsonconversion_test_binary_strings) EXPECT_EQ(cmd.flags, cmd2.flags); EXPECT_TRUE(cmd.getStringData() == cmd2.getStringData()); } + +TEST(ActionMessage, jsonconversion_test_binary_strings2) +{ + helics::ActionMessage cmd(helics::CMD_SEND_MESSAGE); + cmd.source_id = global_federate_id{1}; + cmd.source_handle = interface_handle{2}; + cmd.dest_id = global_federate_id{3}; + cmd.dest_handle = interface_handle{4}; + setActionFlag(cmd, iteration_requested_flag); + setActionFlag(cmd, required_flag); + setActionFlag(cmd, error_flag); + cmd.actionTime = 45.7; + cmd.payload = std::string(256, '\0'); + for (int ii = 0; ii < 256; ++ii) { + cmd.payload[ii] = char(ii); + } + + cmd.setStringData("target", std::string(987, '\0'), "original_source"); + + auto cmdString = cmd.to_json_string(); + + helics::ActionMessage cmd2(cmdString); + EXPECT_TRUE(cmd.action() == cmd2.action()); + EXPECT_EQ(cmd.actionTime, cmd2.actionTime); + EXPECT_EQ(cmd.source_id, cmd2.source_id); + EXPECT_EQ(cmd.dest_id, cmd2.dest_id); + EXPECT_EQ(cmd.source_handle, cmd2.source_handle); + EXPECT_EQ(cmd.dest_handle, cmd2.dest_handle); + EXPECT_EQ(cmd.payload, cmd2.payload); + EXPECT_EQ(cmd.flags, cmd2.flags); + EXPECT_TRUE(cmd.getStringData() == cmd2.getStringData()); +}