From 9e5e604e0711ebe514713afa793c8920c1f4067d Mon Sep 17 00:00:00 2001 From: "Jonathan Thorpe (Sony)" Date: Mon, 7 Oct 2024 16:01:56 +0100 Subject: [PATCH] Initial implementation of backup and restore --- .../nmos-cpp-node/node_implementation.cpp | 154 +++++++++++++++--- Development/nmos/configuration_api.cpp | 110 ++----------- Development/nmos/control_protocol_handlers.h | 4 +- .../nmos/control_protocol_resource.cpp | 117 +++++++++++-- Development/nmos/control_protocol_resource.h | 16 ++ Development/nmos/control_protocol_state.cpp | 10 +- Development/nmos/control_protocol_state.h | 2 +- Development/nmos/control_protocol_typedefs.h | 17 +- Development/nmos/control_protocol_utils.cpp | 138 ++++++++++++++-- Development/nmos/control_protocol_utils.h | 9 + Development/nmos/json_fields.h | 8 +- 11 files changed, 418 insertions(+), 167 deletions(-) diff --git a/Development/nmos-cpp-node/node_implementation.cpp b/Development/nmos-cpp-node/node_implementation.cpp index 18a14358..ce5c1ed9 100644 --- a/Development/nmos-cpp-node/node_implementation.cpp +++ b/Development/nmos-cpp-node/node_implementation.cpp @@ -1,5 +1,6 @@ #include "node_implementation.h" +#include #include #include #include @@ -1719,7 +1720,7 @@ nmos::control_protocol_property_changed_handler make_node_implementation_control }; } -void get_object_property_holder(const nmos::resources& resources, slog::base_gate& gate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, const nmos::resource& resource, bool recurse, web::json::value& object_properties_holders) +web::json::value make_property_value_holders(const nmos::resource& resource, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor) { using web::json::value; @@ -1727,6 +1728,7 @@ void get_object_property_holder(const nmos::resources& resources, slog::base_gat nmos::nc_class_id class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)); + // Get properties for object while (!class_id.empty()) { // find the relevant nc_property_descriptor @@ -1740,33 +1742,54 @@ void get_object_property_holder(const nmos::resources& resources, slog::base_gat } class_id.pop_back(); } + return property_value_holders; +} + +web::json::value get_role_path(const nmos::resources& resources, const nmos::resource& resource) +{ + // Find role path for object + // Hmmm do we not have a library function to do this? + + using web::json::value; + + auto role_path = value::array(); + web::json::push_back(role_path, nmos::fields::nc::role(resource.data)); - auto role_path = nmos::fields::nc::role(resource.data); auto oid = nmos::fields::nc::id(resource.data); nmos::resource found_resource = resource; while (utility::s2us(std::to_string(nmos::root_block_oid)) != oid.as_string()) { - auto owner = nmos::fields::nc::owner(found_resource.data); - const auto& found = nmos::find_resource(resources, utility::s2us(std::to_string(owner))); + const auto& found = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::owner(found_resource.data)))); if (resources.end() == found) { break; } found_resource = (*found); - role_path = nmos::fields::nc::role(found_resource.data) + U(".") + role_path; + web::json::push_back(role_path, nmos::fields::nc::role(found_resource.data)); oid = nmos::fields::nc::id(found_resource.data); } - auto object_properties_holder = web::json::value_of({ - { nmos::fields::nc::path, role_path }, - { nmos::fields::nc::values, property_value_holders} - }, true); + std::reverse(role_path.as_array().begin(), role_path.as_array().end()); + + return role_path; +} + +void get_object_property_holder(const nmos::resources& resources, slog::base_gate& gate, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, const nmos::resource& resource, bool recurse, web::json::value& object_properties_holders) +{ + using web::json::value; + + // Get property_value_holders for this resource + const value property_value_holders = make_property_value_holders(resource, get_control_protocol_class_descriptor); + + const auto role_path = get_role_path(resources, resource); + + auto object_properties_holder = nmos::details::make_nc_object_properties_holder(role_path, property_value_holders); web::json::push_back(object_properties_holders, object_properties_holder); - // Recurse into members + // Recurse into members...if we want to...and the object has them if (recurse && nmos::is_nc_block(nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)))) { if (resource.data.has_field(nmos::fields::nc::members)) @@ -1775,8 +1798,8 @@ void get_object_property_holder(const nmos::resources& resources, slog::base_gat for (const auto& member : members) { - const auto& oid = nmos::fields::nc::oid(member); - const auto& found = find_resource(resources, utility::s2us(std::to_string(oid))); + const auto& found = find_resource(resources, utility::s2us(std::to_string(nmos::fields::nc::oid(member)))); + if (resources.end() != found) { get_object_property_holder(resources, gate, get_control_protocol_class_descriptor, *found, recurse, object_properties_holders); @@ -1788,6 +1811,40 @@ void get_object_property_holder(const nmos::resources& resources, slog::base_gat return; } +std::size_t generate_validation_fingerprint(const nmos::resources& resources, const nmos::resource& resource) +{ + // Generate a hash based on structure of the Device Model + size_t hash(0); + + nmos::nc_class_id class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)); + + boost::hash_combine(hash, class_id); + boost::hash_combine(hash, nmos::fields::nc::role(resource.data)); + + // Recurse into members...if we want to...and the object has them + if (nmos::is_nc_block(nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource.data)))) + { + if (resource.data.has_field(nmos::fields::nc::members)) + { + const auto& members = nmos::fields::nc::members(resource.data); + + // Generate hash for block members + for (const auto& member : members) + { + const auto& oid = nmos::fields::nc::oid(member); + const auto& found = find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != found) + { + size_t sub_hash = generate_validation_fingerprint(resources, *found); + boost::hash_combine(hash, sub_hash); + } + } + } + } + + return hash; +} + // Example Device Configuration callback for creating a back-up dataset nmos::get_properties_by_path_handler make_node_implementation_get_properties_by_path_handler(const nmos::resources& resources, slog::base_gate& gate) { @@ -1804,36 +1861,87 @@ nmos::get_properties_by_path_handler make_node_implementation_get_properties_by_ get_object_property_holder(resources, gate, get_control_protocol_class_descriptor, resource, recurse, object_properties_holders); - auto bulk_values_holder = value_of({ - { nmos::fields::nc::validation_fingerprint, U("your-fingerprint-here")}, - { nmos::fields::nc::values, object_properties_holders} - }, true); + size_t validation_fingerprint = generate_validation_fingerprint(resources, resource); + + auto bulk_values_holder = nmos::details::make_nc_bulk_values_holder(utility::string_t(std::to_wstring(validation_fingerprint)), object_properties_holders); return nmos::details::make_nc_method_result({ nmos::nc_method_status::ok }, bulk_values_holder); }; } +web::json::value apply_backup_data_set(nmos::resources& resources, nmos::experimental::control_protocol_state& control_protocol_state, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, const web::json::value& property_traits_, bool validate) +{ + auto object_properties_set_validation_values = web::json::value::array(); + + for (const auto& object_properties_value : nmos::fields::nc::values(backup_data_set)) + { + const auto& role_path = nmos::fields::nc::path(object_properties_value); + const auto& found = nmos::find_control_protocol_resource_by_role_path(resources, role_path); + + if (resources.end() != found) + { + auto property_restore_notices = web::json::value::array(); + + nmos::nc_class_id class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(found->data)); + + for (const auto& property_value : nmos::fields::nc::values(object_properties_value)) + { + const auto& property_id = nmos::details::parse_nc_property_id(nmos::fields::nc::id(property_value)); + + const auto& property_traits = nmos::fields::nc::property_traits(nmos::find_decorated_property_descriptor(property_id, class_id, get_control_protocol_class_descriptor)); + const auto& filtered_traits = boost::copy_range>(property_traits.as_array() + | boost::adaptors::filtered([](const web::json::value& property_trait) + { + return property_trait.as_integer() == nmos::nc_property_trait::general; + }) + ); + if (filtered_traits.size()) + { + if (!validate) + { + // modify control protocol resources + const auto& value = nmos::fields::nc::value(property_value); + + modify_control_protocol_resource(resources, found->id, [&](nmos::resource& resource) + { + resource.data[nmos::fields::nc::name(property_value)] = value; + + }, nmos::make_property_changed_event(nmos::fields::nc::oid(resource.data), { { property_id, nmos::nc_property_change_type::type::value_changed, value } })); + } + } + else + { + const auto& property_restore_notice = nmos::details::make_nc_property_restore_notice(property_id, nmos::fields::nc::name(property_value), nmos::nc_property_restore_notice_type::warning, U("Property not configurable")); + web::json::push_back(property_restore_notices, property_restore_notice); + } + } + const auto& object_properties_set_validation = nmos::details::make_nc_object_properties_set_validation(role_path, nmos::nc_restore_validation_status::ok, property_restore_notices, U("OK")); + web::json::push_back(object_properties_set_validation_values, object_properties_set_validation); + } + } + + return nmos::details::make_nc_method_result({ nmos::nc_method_status::ok }, object_properties_set_validation_values); +} + // Example Device Configuration callback for validating a back-up dataset -nmos::validate_set_properties_by_path_handler make_node_implementation_validate_set_properties_by_path_handler(const nmos::resources& resources, slog::base_gate& gate) +nmos::validate_set_properties_by_path_handler make_node_implementation_validate_set_properties_by_path_handler(nmos::resources& resources, slog::base_gate& gate) { - return [&resources, &gate](nmos::experimental::control_protocol_state& control_protocol_state, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, const web::json::array& included_property_traits) + return [&resources, &gate](nmos::experimental::control_protocol_state& control_protocol_state, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, const web::json::value& property_traits) { slog::log(gate, SLOG_FLF) << nmos::stash_category(impl::categories::node_implementation) << "Do validate_set_properties_by_path"; - // Can this backup be restored? - return nmos::details::make_nc_method_result({ nmos::nc_method_status::ok }); + return apply_backup_data_set(resources, control_protocol_state, get_control_protocol_class_descriptor, resource, backup_data_set, recurse, property_traits, true); }; } // Example Device Configuration callback for restoring a back-up dataset nmos::set_properties_by_path_handler make_node_implementation_set_properties_by_path_handler(nmos::resources& resources, slog::base_gate& gate) { - return [&resources, &gate](nmos::experimental::control_protocol_state& control_protocol_state, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, const nmos::resource& resource, const web::json::value& data_set, bool recurse, const web::json::array& included_property_traits) + return [&resources, &gate](nmos::experimental::control_protocol_state& control_protocol_state, nmos::get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, nmos::get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor, const nmos::resource& resource, const web::json::value& backup_data_set, bool recurse, const web::json::value& property_traits) { slog::log(gate, SLOG_FLF) << nmos::stash_category(impl::categories::node_implementation) << "Do set_properties_by_path"; - // Implement restore of device model here - return nmos::details::make_nc_method_result({ nmos::nc_method_status::ok }); + return apply_backup_data_set(resources, control_protocol_state, get_control_protocol_class_descriptor, resource, backup_data_set, recurse, property_traits, false); }; } diff --git a/Development/nmos/configuration_api.cpp b/Development/nmos/configuration_api.cpp index 0bd66255..87a07bc1 100644 --- a/Development/nmos/configuration_api.cpp +++ b/Development/nmos/configuration_api.cpp @@ -1,6 +1,5 @@ #include "nmos/configuration_api.h" -#include #include #include #include "cpprest/json_validator.h" @@ -84,85 +83,6 @@ namespace nmos } } - web::json::value get_nc_block_member_descriptor(const resources& resources, const nmos::resource& parent_nc_block_resource, std::list& role_path_segments) - { - if (parent_nc_block_resource.data.has_field(nmos::fields::nc::members)) - { - const auto& members = nmos::fields::nc::members(parent_nc_block_resource.data); - - const auto role_path_segement = role_path_segments.front(); - role_path_segments.pop_front(); - // find the role_path_segment member - auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& member) - { - return role_path_segement == nmos::fields::nc::role(member); - }); - - if (members.end() != member_found) - { - if (role_path_segments.empty()) - { - // NcBlockMemberDescriptor - return *member_found; - } - - // get the role_path_segement member resource - if (is_nc_block(nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(*member_found)))) - { - // get resource based on the oid - const auto& oid = nmos::fields::nc::oid(*member_found); - const auto& found = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != found) - { - return get_nc_block_member_descriptor(resources, *found, role_path_segments); - } - } - } - } - return web::json::value{}; - } - - resources::const_iterator find_resource(const resources& resources, std::list& role_path_segments) - { - auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::root_block_oid))); - if (resources.end() != resource) - { - const auto role = nmos::fields::nc::role(resource->data); - if (role_path_segments.size() && role == role_path_segments.front()) - { - role_path_segments.pop_front(); - - if (role_path_segments.size()) - { - const auto& block_member_descriptor = details::get_nc_block_member_descriptor(resources, *resource, role_path_segments); - if (!block_member_descriptor.is_null()) - { - const auto& oid = nmos::fields::nc::oid(block_member_descriptor); - const auto& found = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); - if (resources.end() != found) - { - return found; - } - } - } - else - { - return resource; - } - } - } - return resources.end(); - } - - resources::const_iterator find_resource(const resources& resources, const utility::string_t& role_path) - { - // tokenize the role_path with the '.' delimiter - std::list role_path_segments; - boost::algorithm::split(role_path_segments, role_path, [](utility::char_t c) { return '.' == c; }); - - return find_resource(resources, role_path_segments); - } - nc_property_id parse_formatted_property_id(const utility::string_t& property_id) { // Assume that property_id is in form "p" as validated by the propertyId regular expression pattern @@ -272,7 +192,7 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { @@ -294,7 +214,7 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { std::set properties_routes; @@ -333,7 +253,7 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { std::set methods_routes; @@ -379,7 +299,7 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { nc_class_id class_id = nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)); @@ -435,7 +355,7 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { // find the relevant nc_property_descriptor @@ -466,7 +386,7 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { // find the relevant nc_property_descriptor @@ -498,7 +418,7 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { // find the relevant nc_property_descriptor @@ -540,7 +460,7 @@ namespace nmos auto& resources = model.control_protocol_resources; auto& arguments = nmos::fields::nc::arguments(body); - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { auto method = get_control_protocol_method_descriptor(details::parse_nc_class_id(nmos::fields::nc::class_id(resource->data)), details::parse_formatted_method_id(method_id)); @@ -614,7 +534,7 @@ namespace nmos auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); if (resources.end() != resource) { // find the relevant nc_property_descriptor @@ -653,8 +573,8 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); - const auto& bulk_properties_manager = details::find_resource(resources, nmos::bulk_properties_manager_role); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); + const auto& bulk_properties_manager = find_control_protocol_resource_by_role_path(resources, nmos::bulk_properties_manager_role); if (resources.end() != resource && resources.end() != bulk_properties_manager) { @@ -721,8 +641,8 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); - const auto& bulk_properties_manager = details::find_resource(resources, nmos::bulk_properties_manager_role); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); + const auto& bulk_properties_manager = find_control_protocol_resource_by_role_path(resources, nmos::bulk_properties_manager_role); if (resources.end() != resource && resources.end() != bulk_properties_manager) { return details::extract_json(req, gate_).then([res, resources, resource, get_control_protocol_method_descriptor, version, &gate_](value body) mutable @@ -794,8 +714,8 @@ namespace nmos auto lock = model.read_lock(); auto& resources = model.control_protocol_resources; - const auto& resource = details::find_resource(resources, role_path); - const auto& bulk_properties_manager = details::find_resource(resources, nmos::bulk_properties_manager_role); + const auto& resource = find_control_protocol_resource_by_role_path(resources, role_path); + const auto& bulk_properties_manager = find_control_protocol_resource_by_role_path(resources, nmos::bulk_properties_manager_role); if (resources.end() != resource && resources.end() != bulk_properties_manager) { return details::extract_json(req, gate_).then([res, resources, resource, get_control_protocol_method_descriptor, version, &gate_](value body) mutable diff --git a/Development/nmos/control_protocol_handlers.h b/Development/nmos/control_protocol_handlers.h index 241fad9b..563b29af 100644 --- a/Development/nmos/control_protocol_handlers.h +++ b/Development/nmos/control_protocol_handlers.h @@ -39,8 +39,8 @@ namespace nmos // Device Configuration handlers // these callbacks should not throw exceptions typedef std::function get_properties_by_path_handler; - typedef std::function validate_set_properties_by_path_handler; - typedef std::function set_properties_by_path_handler; + typedef std::function validate_set_properties_by_path_handler; + typedef std::function set_properties_by_path_handler; namespace experimental { diff --git a/Development/nmos/control_protocol_resource.cpp b/Development/nmos/control_protocol_resource.cpp index 1f7d069f..253afe48 100644 --- a/Development/nmos/control_protocol_resource.cpp +++ b/Development/nmos/control_protocol_resource.cpp @@ -819,6 +819,20 @@ namespace nmos return data; } + // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertychangedeventdata + web::json::value make_nc_property_changed_event_data(const nc_property_changed_event_data& property_changed_event_data) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::property_id, details::make_nc_property_id(property_changed_event_data.property_id) }, + { nmos::fields::nc::change_type, property_changed_event_data.change_type }, + { nmos::fields::nc::value, property_changed_event_data.value }, + { nmos::fields::nc::sequence_item_index, property_changed_event_data.sequence_item_index } + }, true + ); + } + // TODO: add link web::json::value make_nc_bulk_properties_manager(nc_oid oid, nc_oid owner, const web::json::value &user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints) { @@ -829,12 +843,24 @@ namespace nmos return data; } + web::json::value make_nc_bulk_values_holder(const utility::string_t& validation_fingerprint, const web::json::value& object_properties_holders) + { + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::validation_fingerprint, validation_fingerprint }, + { nmos::fields::nc::values, object_properties_holders } + }, true + ); + } + // TODO: add link web::json::value make_nc_property_value_holder(const nc_property_id& property_id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, const web::json::value& property_traits, const web::json::value& property_value) { - using web::json::value; + using web::json::value; + using web::json::value_of; - return web::json::value_of({ + return value_of({ { nmos::fields::nc::id, make_nc_property_id(property_id)}, { nmos::fields::nc::name, value::string(name)}, { nmos::fields::nc::type_name, value::string(type_name)}, @@ -844,17 +870,47 @@ namespace nmos }, true); } - // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncpropertychangedeventdata - web::json::value make_nc_property_changed_event_data(const nc_property_changed_event_data& property_changed_event_data) + // TODO: add link + web::json::value make_nc_object_properties_holder(const web::json::value& role_path, const web::json::value& property_value_holders) { using web::json::value_of; return value_of({ - { nmos::fields::nc::property_id, details::make_nc_property_id(property_changed_event_data.property_id) }, - { nmos::fields::nc::change_type, property_changed_event_data.change_type }, - { nmos::fields::nc::value, property_changed_event_data.value }, - { nmos::fields::nc::sequence_item_index, property_changed_event_data.sequence_item_index } - }); + { nmos::fields::nc::path, role_path }, + { nmos::fields::nc::values, property_value_holders} + }, true + ); + + } + + // TODO: add link + web::json::value make_nc_property_restore_notice(const nc_property_id& property_id, const nc_name& name, nc_property_restore_notice_type::type notice_type, const utility::string_t& notice_message) + { + using web::json::value; + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::id, make_nc_property_id(property_id)}, + { nmos::fields::nc::name, value::string(name)}, + { nmos::fields::nc::notice_type, value::number(notice_type)}, + { nmos::fields::nc::notice_message, value::string(notice_message)} + }, true + ); + } + + // TODO: add link + web::json::value make_nc_object_properties_set_validation(const web::json::value& role_path, nc_restore_validation_status::status status, const web::json::value& notices, const utility::string_t& status_message) + { + using web::json::value; + using web::json::value_of; + + return value_of({ + { nmos::fields::nc::path, role_path}, + { nmos::fields::nc::status, value::number(status)}, + { nmos::fields::nc::notices, notices }, + { nmos::fields::nc::status_message, value::string(status_message)} + }, true + ); } } @@ -1287,7 +1343,7 @@ namespace nmos web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("The values offered (this may include read-only values and also paths which are not the target role path)"), nmos::fields::nc::data_set, U("NcBulkValuesHolder"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If set the descriptor would contain all inherited elements"), nmos::fields::nc::path, U("NcRolePath"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If true will validate properties on target path and all the nested paths"), nmos::fields::nc::recurse, U("NcBoolean"), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If populated (not an empty collection) will include the properties matching any of the specified traits in the restore validation. When not populated only properties without traits are validated for restore"), nmos::fields::nc::included_property_traits, U("NcPropertyTrait"), false, true, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If populated (not an empty collection) will include the properties matching any of the specified traits in the restore validation. When not populated only properties without traits are validated for restore"), nmos::fields::nc::property_traits, U("NcPropertyTrait"), true, true, value::null())); web::json::push_back(methods, details::make_nc_method_descriptor(U("Validate bulk properties for setting by given paths"), nc_bulk_properties_manager_validate_set_properties_by_path_method_id, U("ValidateSetPropertiesByPath"), U("NcMethodResultObjectPropertiesSetValidation"), parameters, false)); } { @@ -1295,7 +1351,7 @@ namespace nmos web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("The values offered (this may include read-only values and also paths which are not the target role path)"), nmos::fields::nc::data_set, U("NcBulkValuesHolder"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If set the descriptor would contain all inherited elements"), nmos::fields::nc::path, U("NcRolePath"), false, false, value::null())); web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If true will validate properties on target path and all the nested paths"), nmos::fields::nc::recurse, U("NcBoolean"), false, false, value::null())); - web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If populated (not an empty collection) will include the properties matching any of the specified traits in the restore validation. When not populated only properties without traits are validated for restore"), nmos::fields::nc::included_property_traits, U("NcPropertyTrait"), false, true, value::null())); + web::json::push_back(parameters, details::make_nc_parameter_descriptor(U("If populated (not an empty collection) will include the properties matching any of the specified traits in the restore validation. When not populated only properties without traits are validated for restore"), nmos::fields::nc::property_traits, U("NcPropertyTrait"), true, true, value::null())); web::json::push_back(methods, details::make_nc_method_descriptor(U("Set bulk properties for setting by given paths"), nc_bulk_properties_manager_set_properties_by_path_method_id, U("SetPropertiesByPath"), U("NcMethodResultObjectPropertiesSetValidation"), parameters, false)); } @@ -2147,10 +2203,12 @@ namespace nmos using web::json::value; auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Property is general"), U("General"), 0)); web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Property is instance specific"), U("InstanceSpecific"), 1)); web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Property is ephemeral"), U("Ephemeral"), 2)); web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Property is immutable"), U("Immutable"), 3)); web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Property value is generated by the device"), U("DeviceGenerated"), 4)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Property value is structural (affects the device model structure)"), U("Structural"), 5)); return details::make_nc_datatype_descriptor_enum(U("Property trait enumeration"), U("NcPropertyTrait"), items, value::null()); } // TODO: add link @@ -2162,7 +2220,7 @@ namespace nmos web::json::push_back(fields, details::make_nc_field_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Property name"), nmos::fields::nc::name, U("NcString"), false, false, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Property type name. If null it means the type is any"), nmos::fields::nc::type_name, U("NcName"), true, false, value::null())); - web::json::push_back(fields, details::make_nc_field_descriptor(U("Is the property ReadOnly?"), nmos::fields::nc::is_read_only, U("NcBoolean"), true, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Is the property ReadOnly?"), nmos::fields::nc::is_read_only, U("NcBoolean"), false, false, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Describes the property traits as a collection of unique items"), nmos::fields::nc::traits, U("NcPropertyTrait"), false, true, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Property value"), nmos::fields::nc::value, true, false, value::null())); @@ -2196,15 +2254,37 @@ namespace nmos using web::json::value; auto items = value::array(); - web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore was successful"), U("Ok"), 200)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Excluded from restore due to data provided in the request"), U("Excluded"), 204)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore failed because relevant backup data set provided is invalid"), U("InvalidData"), 400)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore failed because the role path is not found in the device model or the device cannot create the role path from the data set"), U("NotFound"), 404)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore failed because of missing dependency information in the relevant backup data set"), U("MissingDependency"), 424)); - web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore failed due to an internal device error preventing the restore from happening"), U("DeviceError"), 500)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore was successful"), U("Ok"), nc_restore_validation_status::ok)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Excluded from restore due to data provided in the request"), U("Excluded"), nc_restore_validation_status::excluded)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore failed"), U("Failed"), nc_restore_validation_status::failed)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore failed because the role path is not found in the device model or the device cannot create the role path from the data set"), U("NotFound"), nc_restore_validation_status::not_found)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Restore failed due to an internal device error preventing the restore from happening"), U("DeviceError"), nc_restore_validation_status::device_error)); return details::make_nc_datatype_descriptor_enum(U("Restore validation status enumeration"), U("NcRestoreValidationStatus"), items, value::null()); } // TODO: add link + web::json::value make_nc_property_restore_notice_type_datatype() + { + using web::json::value; + + auto items = value::array(); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Warning property restore notice"), U("Warning"), nc_property_restore_notice_type::warning)); + web::json::push_back(items, details::make_nc_enum_item_descriptor(U("Error property restore notice"), U("Error"), nc_property_restore_notice_type::error)); + return details::make_nc_datatype_descriptor_enum(U("Property restore notice type enumeration"), U("NcPropertyRestoreNoticeType"), items, value::null()); + } + // TODO: add link + web::json::value make_nc_property_restore_notice_datatype() + { + using web::json::value; + + auto fields = value::array(); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Property id"), nmos::fields::nc::id, U("NcPropertyId"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Property name"), nmos::fields::nc::name, U("NcName"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Property restore notice type"), nmos::fields::nc::notice_type, U("NcPropertyRestoreNoticeType"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Property restore notice message"), nmos::fields::nc::notice_message, U("NcString"), false, false, value::null())); + + return details::make_nc_datatype_descriptor_struct(U("Property restore notice descriptor"), U("NcPropertyRestoreNotice"), fields, value::null()); + } + // TODO: add link web::json::value make_nc_object_properties_set_validation_datatype() { using web::json::value; @@ -2212,6 +2292,7 @@ namespace nmos auto fields = value::array(); web::json::push_back(fields, details::make_nc_field_descriptor(U("Object role path"), nmos::fields::nc::path, U("NcRolePath"), false, false, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Validation status"), nmos::fields::nc::status, U("NcRestoreValidationStatus"), false, false, value::null())); + web::json::push_back(fields, details::make_nc_field_descriptor(U("Validation property notices"), nmos::fields::nc::notices, U("NcPropertyRestoreNotice"), false, true, value::null())); web::json::push_back(fields, details::make_nc_field_descriptor(U("Validation status message"), nmos::fields::nc::status_message, U("NcString"), true, false, value::null())); return details::make_nc_datatype_descriptor_struct(U("Object properties set validation descriptor"), U("NcObjectPropertiesSetValidation"), fields, value::null()); diff --git a/Development/nmos/control_protocol_resource.h b/Development/nmos/control_protocol_resource.h index f085d9f7..4b1a1547 100644 --- a/Development/nmos/control_protocol_resource.h +++ b/Development/nmos/control_protocol_resource.h @@ -195,8 +195,20 @@ namespace nmos // TODO: add link web::json::value make_nc_bulk_properties_manager(nc_oid oid, nc_oid owner, const web::json::value& user_label, const utility::string_t& description, const web::json::value& touchpoints, const web::json::value& runtime_property_constraints); + // TODO: add link + web::json::value make_nc_bulk_values_holder(const utility::string_t& validation_fingerprint, const web::json::value& object_properties_holders); + // TODO: add link web::json::value make_nc_property_value_holder(const nc_property_id& property_id, const nc_name& name, const utility::string_t& type_name, bool is_read_only, const web::json::value& property_traits, const web::json::value& property_value); + + // TODO: add link + web::json::value make_nc_object_properties_holder(const web::json::value& role_path, const web::json::value& property_value_holders); + + // TODO: add link + web::json::value make_nc_property_restore_notice(const nc_property_id& property_id, const nc_name& name, nc_property_restore_notice_type::type notice_type, const utility::string_t& notice_message); + + // TODO: add link + web::json::value make_nc_object_properties_set_validation(const web::json::value& role_path, nc_restore_validation_status::status status, const web::json::value& notices, const utility::string_t& status_message); } // command message response @@ -454,6 +466,10 @@ namespace nmos // web::json::value make_nc_restore_validation_status_datatype(); // + web::json::value make_nc_property_restore_notice_type_datatype(); + // + web::json::value make_nc_property_restore_notice_datatype(); + // web::json::value make_nc_object_properties_set_validation_datatype(); // web::json::value make_nc_method_result_bulk_values_holder_datatype(); diff --git a/Development/nmos/control_protocol_state.cpp b/Development/nmos/control_protocol_state.cpp index beb156c7..7c4f54cd 100644 --- a/Development/nmos/control_protocol_state.cpp +++ b/Development/nmos/control_protocol_state.cpp @@ -206,7 +206,7 @@ namespace nmos return [&control_protocol_state, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, validate_set_properties_by_path](nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) { bool recurse = nmos::fields::nc::recurse(arguments); - const auto& included_property_traits = nmos::fields::nc::included_property_traits(arguments); + const auto& property_traits = nmos::fields::nc::property_traits(arguments); const auto& data_set = nmos::fields::nc::data_set(arguments); if (data_set.is_null()) @@ -217,7 +217,7 @@ namespace nmos auto result = nmos::details::make_nc_method_result_error({ nmos::nc_method_status::method_not_implemented }, U("not implemented")); if (validate_set_properties_by_path) { - result = validate_set_properties_by_path(control_protocol_state, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, resource, data_set, recurse, included_property_traits); + result = validate_set_properties_by_path(control_protocol_state, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, resource, data_set, recurse, property_traits); const auto& status = nmos::fields::nc::status(result); if (!web::http::is_error_status_code((web::http::status_code)status) && is_deprecated) @@ -233,7 +233,7 @@ namespace nmos return [&control_protocol_state, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, set_properties_by_path](nmos::resources& resources, const nmos::resource& resource, const web::json::value& arguments, bool is_deprecated, slog::base_gate& gate) { bool recurse = nmos::fields::nc::recurse(arguments); - const auto& included_property_traits = nmos::fields::nc::included_property_traits(arguments); + const auto& property_traits = nmos::fields::nc::property_traits(arguments); const auto& data_set = nmos::fields::nc::data_set(arguments); if (data_set.is_null()) @@ -244,7 +244,7 @@ namespace nmos auto result = nmos::details::make_nc_method_result_error({ nmos::nc_method_status::method_not_implemented }, U("not implemented")); if (set_properties_by_path) { - result = set_properties_by_path(control_protocol_state, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, resource, data_set, recurse, included_property_traits); + result = set_properties_by_path(control_protocol_state, get_control_protocol_class_descriptor, get_control_protocol_datatype_descriptor, resource, data_set, recurse, property_traits); const auto& status = nmos::fields::nc::status(result); if (!web::http::is_error_status_code((web::http::status_code)status) && is_deprecated) @@ -486,6 +486,8 @@ namespace nmos { U("NcObjectPropertiesHolder"), {make_nc_object_properties_holder_datatype()}}, { U("NcBulkValuesHolder"), {make_nc_bulk_values_holder_datatype()}}, { U("NcRestoreValidationStatus"), {make_nc_restore_validation_status_datatype()}}, + { U("NcPropertyRestoreNoticeType"), {make_nc_property_restore_notice_type_datatype()}}, + { U("NcPropertyRestoreNotice"), {make_nc_property_restore_notice_datatype()}}, { U("NcObjectPropertiesSetValidation"), {make_nc_object_properties_set_validation_datatype()}}, { U("NcMethodResultBulkValuesHolder"), {make_nc_method_result_bulk_values_holder_datatype()}}, { U("NcMethodResultObjectPropertiesSetValidation"), {make_nc_method_result_object_properties_set_validation_datatype()}} diff --git a/Development/nmos/control_protocol_state.h b/Development/nmos/control_protocol_state.h index 0e7cc227..4ea4d01e 100644 --- a/Development/nmos/control_protocol_state.h +++ b/Development/nmos/control_protocol_state.h @@ -45,7 +45,7 @@ namespace nmos for (auto descriptor : decorated_property_descriptors.as_array()) { auto filtered = web::json::value::object(); for (auto item : descriptor.as_object()) { - if (item.first != U("property_traits")) { + if (item.first != nmos::fields::nc::property_traits.key) { filtered[item.first] = item.second; } } diff --git a/Development/nmos/control_protocol_typedefs.h b/Development/nmos/control_protocol_typedefs.h index 6ec79986..79a28d3d 100644 --- a/Development/nmos/control_protocol_typedefs.h +++ b/Development/nmos/control_protocol_typedefs.h @@ -142,17 +142,26 @@ namespace nmos // NcRestoreValidationStatus namespace nc_restore_validation_status { - enum staus + enum status { ok = 200, // Restore was successful - excluded = 204, // Excluded from restore due to data provided in the request - invalid_data = 400, // Restore failed because relevant backup data set provided is invalid + excluded = 210, // Excluded from restore due to data provided in the request + failed = 400, // Restore failed because relevant backup data set provided is invalid not_found = 404, // Restore failed because the role path is not found in the device model or the device cannot create the role path from the data set - missing_dependency = 424, // Restore failed because of missing dependency information in the relevant backup data set device_error = 500 // Restore failed due to an internal device error preventing the restore from happening }; } + // NcPropertyRestoreNoticeType + namespace nc_property_restore_notice_type + { + enum type + { + warning = 300, // Warning property restore notice + error = 400 // Error property restore notice + }; + }; + // NcElementId // See https://specs.amwa.tv/ms-05-02/branches/v1.0.x/docs/Framework.html#ncelementid struct nc_element_id diff --git a/Development/nmos/control_protocol_utils.cpp b/Development/nmos/control_protocol_utils.cpp index 19d054ef..d5d9fb1d 100644 --- a/Development/nmos/control_protocol_utils.cpp +++ b/Development/nmos/control_protocol_utils.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "bst/regex.h" #include "cpprest/json_utils.h" @@ -344,6 +345,70 @@ namespace nmos // do level 1 property constraints & level 0 datatype constraints validation constraints_validation(data, value::null(), property_constraints, params); } + + web::json::value get_nc_block_member_descriptor(const resources& resources, const nmos::resource& parent_nc_block_resource, web::json::value& role_path_segments) + { + if (parent_nc_block_resource.data.has_field(nmos::fields::nc::members)) + { + const auto& members = nmos::fields::nc::members(parent_nc_block_resource.data); + + + const auto role_path_segement = web::json::front(role_path_segments); + role_path_segments.erase(0); + // find the role_path_segment member + auto member_found = std::find_if(members.begin(), members.end(), [&](const web::json::value& member) + { + return role_path_segement.as_string() == nmos::fields::nc::role(member); + }); + + if (members.end() != member_found) + { + if (role_path_segments.size() == 0) + { + // NcBlockMemberDescriptor + return *member_found; + } + + // get the role_path_segement member resource + if (is_nc_block(nmos::details::parse_nc_class_id(nmos::fields::nc::class_id(*member_found)))) + { + // get resource based on the oid + const auto& oid = nmos::fields::nc::oid(*member_found); + const auto& found = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != found) + { + return get_nc_block_member_descriptor(resources, *found, role_path_segments); + } + } + } + } + return web::json::value{}; + } + + typedef std::function get_property_descriptors_handler; + + // generic find control class property descriptor in property_descriptor_ array (NcPropertyDescriptor) + web::json::value find_property_descriptor(const nc_property_id& property_id, const nc_class_id& class_id_, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor, const get_property_descriptors_handler& get_property_descriptors) + { + using web::json::value; + + auto class_id = class_id_; + + while (!class_id.empty()) + { + const auto& control_class = get_control_protocol_class_descriptor(class_id); + const auto& property_descriptors = get_property_descriptors(control_class); + auto found = std::find_if(property_descriptors.as_array().begin(), property_descriptors.as_array().end(), [&property_id](const web::json::value& property_descriptor) + { + return (property_id == nmos::details::parse_nc_property_id(nmos::fields::nc::id(property_descriptor))); + }); + if (property_descriptors.as_array().end() != found) { return *found; } + + class_id.pop_back(); + } + + return value::null(); + } } // is the given class_id a NcBlock @@ -392,24 +457,13 @@ namespace nmos // find control class property descriptor (NcPropertyDescriptor) web::json::value find_property_descriptor(const nc_property_id& property_id, const nc_class_id& class_id_, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor) { - using web::json::value; - - auto class_id = class_id_; - - while (!class_id.empty()) - { - const auto& control_class = get_control_protocol_class_descriptor(class_id); - auto& property_descriptors = control_class.property_descriptors.as_array(); - auto found = std::find_if(property_descriptors.begin(), property_descriptors.end(), [&property_id](const web::json::value& property_descriptor) - { - return (property_id == nmos::details::parse_nc_property_id(nmos::fields::nc::id(property_descriptor))); - }); - if (property_descriptors.end() != found) { return *found; } - - class_id.pop_back(); - } + return details::find_property_descriptor(property_id, class_id_, get_control_protocol_class_descriptor, [](const nmos::experimental::control_class_descriptor& class_descriptor) { return class_descriptor.property_descriptors; }); + } - return value::null(); + // find control class property descriptor (NcPropertyDescriptor) with additional configuration API property traits + web::json::value find_decorated_property_descriptor(const nc_property_id& property_id, const nc_class_id& class_id_, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor) + { + return details::find_property_descriptor(property_id, class_id_, get_control_protocol_class_descriptor, [](const nmos::experimental::control_class_descriptor& class_descriptor) { return class_descriptor.decorated_property_descriptors; }); } // get block member descriptors @@ -647,4 +701,54 @@ namespace nmos details::method_parameter_constraints_validation(arguments.at(name), constraints, { nmos::details::get_datatype_descriptor(type_name, get_control_protocol_datatype_descriptor), get_control_protocol_datatype_descriptor }); } } + + resources::const_iterator find_control_protocol_resource_by_role_path(const resources& resources, const web::json::value& role_path_) + { + web::json::value role_path = role_path_; + auto resource = nmos::find_resource(resources, utility::s2us(std::to_string(nmos::root_block_oid))); + if (resources.end() != resource) + { + const auto role = nmos::fields::nc::role(resource->data); + + if (role_path.size() && role == web::json::front(role_path).as_string()) + { + role_path.erase(0); + + if (role_path.size()) + { + const auto& block_member_descriptor = details::get_nc_block_member_descriptor(resources, *resource, role_path); + if (!block_member_descriptor.is_null()) + { + const auto& oid = nmos::fields::nc::oid(block_member_descriptor); + const auto& found = nmos::find_resource(resources, utility::s2us(std::to_string(oid))); + if (resources.end() != found) + { + return found; + } + } + } + else + { + return resource; + } + } + } + return resources.end(); + } + + + resources::const_iterator find_control_protocol_resource_by_role_path(const resources& resources, const utility::string_t& role_path_) + { + // tokenize the role_path with the '.' delimiter + std::list role_path_segments; + boost::algorithm::split(role_path_segments, role_path_, [](utility::char_t c) { return '.' == c; }); + + web::json::value role_path = web::json::value::array(); + + for (auto item : role_path_segments) + { + web::json::push_back(role_path, utility::string_t(item.c_str())); + } + return find_control_protocol_resource_by_role_path(resources, role_path); + } } diff --git a/Development/nmos/control_protocol_utils.h b/Development/nmos/control_protocol_utils.h index 6d706085..c91ac93e 100644 --- a/Development/nmos/control_protocol_utils.h +++ b/Development/nmos/control_protocol_utils.h @@ -59,6 +59,9 @@ namespace nmos // find control class property descriptor (NcPropertyDescriptor) web::json::value find_property_descriptor(const nc_property_id& property_id, const nc_class_id& class_id, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor); + // find control class property descriptor (NcPropertyDescriptor) with additional configuration API property traits + web::json::value find_decorated_property_descriptor(const nc_property_id& property_id, const nc_class_id& class_id_, get_control_protocol_class_descriptor_handler get_control_protocol_class_descriptor); + // get block memeber descriptors void get_member_descriptors(const resources& resources, const resource& resource, bool recurse, web::json::array& descriptors); @@ -77,6 +80,12 @@ namespace nmos // find the control protocol resource which is assoicated with the given IS-04/IS-05/IS-08 resource id resources::const_iterator find_control_protocol_resource(resources& resources, type type, const id& id); + // find resource based on role path. + resources::const_iterator find_control_protocol_resource_by_role_path(const resources& resources, const web::json::value& role_path); + + // find resource based on role path. Roles in role path string must be delimited with a '.' + resources::const_iterator find_control_protocol_resource_by_role_path(const resources& resources, const utility::string_t& role_path); + // method parameters constraints validation, may throw nmos::control_protocol_exception void method_parameters_contraints_validation(const web::json::value& arguments, const web::json::value& nc_method_descriptor, get_control_protocol_datatype_descriptor_handler get_control_protocol_datatype_descriptor); } diff --git a/Development/nmos/json_fields.h b/Development/nmos/json_fields.h index e353d878..1e035811 100644 --- a/Development/nmos/json_fields.h +++ b/Development/nmos/json_fields.h @@ -291,7 +291,6 @@ namespace nmos const web::json::field_as_array events{ U("events") }; // sequence const web::json::field_as_integer type{ U("type") }; // NcDatatypeType const web::json::field_as_value constraints{ U("constraints") }; // NcParameterConstraints - const web::json::field_as_value property_traits{ U("property_traits") }; // sequence const web::json::field_as_integer organization_id{ U("organizationId") }; const web::json::field_as_string website{ U("website") }; const web::json::field_as_string key{ U("key") }; @@ -313,7 +312,7 @@ namespace nmos const web::json::field_as_array fields{ U("fields") }; // sequence const web::json::field_as_integer generic_state{ U("generic") }; // NcDeviceGenericState const web::json::field_as_string device_specific_details{ U("deviceSpecificDetails") }; - const web::json::field_as_array path{ U("path") }; // NcRolePath + const web::json::field_as_value path{ U("path") }; // NcRolePath const web::json::field_as_bool case_sensitive{ U("caseSensitive") }; const web::json::field_as_bool match_whole_string{ U("matchWholeString") }; const web::json::field_as_bool include_derived{ U("includeDerived") }; @@ -342,7 +341,10 @@ namespace nmos const web::json::field_as_string status_message{ U("statusMessage") }; const web::json::field_as_value data_set{ U("dataSet") }; // NcBulkValuesHolder const web::json::field_as_value traits{ U("traits") }; - const web::json::field_as_array included_property_traits{ U("includedPropertyTraits") }; + const web::json::field_as_value property_traits{ U("propertyTraits") }; // sequence + const web::json::field_as_value notice_type{ U("noticeType") }; // NcPropertyRestoreNotice + const web::json::field_as_value notice_message{ U("noticeMessage") }; // NcPropertyRestoreNotice + const web::json::field_as_value notices{ U("notices") }; // NcObjectPropertiesSetValidation } // NMOS Parameter Registers