summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJackLivio <jack@livio.io>2018-08-14 14:00:00 -0400
committerGitHub <noreply@github.com>2018-08-14 14:00:00 -0400
commitd8360ad3c6721ddd9795652dd9bf9b3ae451538a (patch)
treee8bf6902d5ff4b424df8c09dd92a9504c84118f4
parent43e53192045daeff8e9e2887c8b67894725240b5 (diff)
parent086883d76c21f1e8a341cc79080f9af04b88a595 (diff)
downloadsdl_core-d8360ad3c6721ddd9795652dd9bf9b3ae451538a.tar.gz
Merge pull request #2497 from JackLivio/feature/mobile_versioning
Mobile API Versioning Implementation
-rw-r--r--src/components/application_manager/include/application_manager/application.h3
-rw-r--r--src/components/application_manager/include/application_manager/application_data_impl.h4
-rw-r--r--src/components/application_manager/include/application_manager/rpc_handler_impl.h11
-rw-r--r--src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc41
-rw-r--r--src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/register_app_interface_request_test.cc11
-rw-r--r--src/components/application_manager/src/application_data_impl.cc9
-rw-r--r--src/components/application_manager/src/rpc_handler_impl.cc49
-rw-r--r--src/components/application_manager/test/include/application_manager/mock_application.h3
-rw-r--r--src/components/formatters/include/formatters/CSmartFactory.h17
-rw-r--r--src/components/formatters/src/CSmartFactory.cc2
-rw-r--r--src/components/include/utils/semantic_version.h121
-rw-r--r--src/components/interfaces/MOBILE_API.xml2
-rw-r--r--src/components/protocol_handler/include/protocol_handler/handshake_handler.h8
-rw-r--r--src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h5
-rw-r--r--src/components/protocol_handler/include/protocol_handler/protocol_packet.h52
-rw-r--r--src/components/protocol_handler/src/handshake_handler.cc15
-rw-r--r--src/components/protocol_handler/src/protocol_handler_impl.cc43
-rw-r--r--src/components/protocol_handler/src/protocol_packet.cc43
-rw-r--r--src/components/protocol_handler/test/protocol_handler_tm_test.cc9
-rw-r--r--src/components/smart_objects/include/smart_objects/always_false_schema_item.h8
-rw-r--r--src/components/smart_objects/include/smart_objects/always_true_schema_item.h6
-rw-r--r--src/components/smart_objects/include/smart_objects/array_schema_item.h14
-rw-r--r--src/components/smart_objects/include/smart_objects/default_shema_item.h12
-rw-r--r--src/components/smart_objects/include/smart_objects/enum_schema_item.h154
-rw-r--r--src/components/smart_objects/include/smart_objects/number_schema_item.h12
-rw-r--r--src/components/smart_objects/include/smart_objects/object_schema_item.h44
-rw-r--r--src/components/smart_objects/include/smart_objects/schema_item.h12
-rw-r--r--src/components/smart_objects/include/smart_objects/smart_object.h5
-rw-r--r--src/components/smart_objects/include/smart_objects/smart_schema.h11
-rw-r--r--src/components/smart_objects/include/smart_objects/string_schema_item.h6
-rw-r--r--src/components/smart_objects/src/always_false_schema_item.cc5
-rw-r--r--src/components/smart_objects/src/always_true_schema_item.cc6
-rw-r--r--src/components/smart_objects/src/array_schema_item.cc21
-rw-r--r--src/components/smart_objects/src/object_schema_item.cc118
-rw-r--r--src/components/smart_objects/src/schema_item.cc9
-rw-r--r--src/components/smart_objects/src/smart_object.cc6
-rw-r--r--src/components/smart_objects/src/smart_schema.cc13
-rw-r--r--src/components/smart_objects/src/string_schema_item.cc6
-rw-r--r--src/components/smart_objects/test/CObjectSchemaItem_test.cc61
-rw-r--r--tools/InterfaceGenerator/MsgVersionGenerate.py34
-rwxr-xr-xtools/InterfaceGenerator/generator/Model.py58
-rwxr-xr-xtools/InterfaceGenerator/generator/generators/SmartFactoryBase.py287
-rwxr-xr-xtools/InterfaceGenerator/generator/parsers/RPCBase.py152
43 files changed, 1245 insertions, 263 deletions
diff --git a/src/components/application_manager/include/application_manager/application.h b/src/components/application_manager/include/application_manager/application.h
index 844b08071b..da5860f06b 100644
--- a/src/components/application_manager/include/application_manager/application.h
+++ b/src/components/application_manager/include/application_manager/application.h
@@ -51,6 +51,7 @@
#include "protocol_handler/protocol_handler.h"
#include "smart_objects/smart_object.h"
#include "utils/macro.h"
+#include "utils/semantic_version.h"
namespace application_manager {
@@ -115,6 +116,7 @@ class InitialApplicationData {
virtual const smart_objects::SmartObject* ngn_media_screen_name() const = 0;
virtual const mobile_api::Language::eType& language() const = 0;
virtual const mobile_api::Language::eType& ui_language() const = 0;
+ virtual const utils::SemanticVersion& msg_version() const = 0;
virtual void set_app_types(const smart_objects::SmartObject& app_types) = 0;
virtual void set_vr_synonyms(
const smart_objects::SmartObject& vr_synonyms) = 0;
@@ -125,6 +127,7 @@ class InitialApplicationData {
virtual void set_language(const mobile_api::Language::eType& language) = 0;
virtual void set_ui_language(
const mobile_api::Language::eType& ui_language) = 0;
+ virtual void set_msg_version(const utils::SemanticVersion& version) = 0;
};
/*
diff --git a/src/components/application_manager/include/application_manager/application_data_impl.h b/src/components/application_manager/include/application_manager/application_data_impl.h
index 3f60040db9..05091dbfbd 100644
--- a/src/components/application_manager/include/application_manager/application_data_impl.h
+++ b/src/components/application_manager/include/application_manager/application_data_impl.h
@@ -35,6 +35,7 @@
#include <string>
#include "utils/lock.h"
+#include "utils/semantic_version.h"
#include "smart_objects/smart_object.h"
#include "application_manager/application.h"
#include "interfaces/MOBILE_API.h"
@@ -55,6 +56,7 @@ class InitialApplicationDataImpl : public virtual Application {
const smart_objects::SmartObject* ngn_media_screen_name() const;
const mobile_api::Language::eType& language() const;
const mobile_api::Language::eType& ui_language() const;
+ const utils::SemanticVersion& msg_version() const;
void set_app_types(const smart_objects::SmartObject& app_types);
void set_vr_synonyms(const smart_objects::SmartObject& vr_synonyms);
@@ -63,6 +65,7 @@ class InitialApplicationDataImpl : public virtual Application {
void set_ngn_media_screen_name(const smart_objects::SmartObject& ngn_name);
void set_language(const mobile_api::Language::eType& language);
void set_ui_language(const mobile_api::Language::eType& ui_language);
+ void set_msg_version(const utils::SemanticVersion& version);
void set_perform_interaction_layout(
mobile_api::LayoutMode::eType layout) OVERRIDE;
@@ -77,6 +80,7 @@ class InitialApplicationDataImpl : public virtual Application {
mobile_api::Language::eType language_;
mobile_api::Language::eType ui_language_;
mobile_apis::LayoutMode::eType perform_interaction_layout_;
+ utils::SemanticVersion msg_version_;
private:
DISALLOW_COPY_AND_ASSIGN(InitialApplicationDataImpl);
diff --git a/src/components/application_manager/include/application_manager/rpc_handler_impl.h b/src/components/application_manager/include/application_manager/rpc_handler_impl.h
index 44954d41f7..8f1d454c3b 100644
--- a/src/components/application_manager/include/application_manager/rpc_handler_impl.h
+++ b/src/components/application_manager/include/application_manager/rpc_handler_impl.h
@@ -57,6 +57,7 @@
#include "interfaces/v4_protocol_v1_2_no_extra_schema.h"
#include "utils/threads/message_loop_thread.h"
+#include "utils/semantic_version.h"
namespace application_manager {
namespace rpc_handler {
@@ -142,6 +143,16 @@ class RPCHandlerImpl : public RPCHandler,
void SetTelemetryObserver(AMTelemetryObserver* observer) OVERRIDE;
#endif // TELEMETRY_MONITOR
+ /**
+ * @brief Extracts and validates the syncMsgVersion included in
+ * a RegisterAppInterfaceRequest
+ *
+ * @param output - SmartObject Message received from mobile
+ * @param messageVersion - message version to be updated
+ */
+ void GetMessageVersion(NsSmartDeviceLink::NsSmartObjects::SmartObject& output,
+ utils::SemanticVersion& message_version);
+
private:
void ProcessMessageFromMobile(const std::shared_ptr<Message> message);
void ProcessMessageFromHMI(const std::shared_ptr<Message> message);
diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc
index 78a92d360a..164c854f18 100644
--- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc
+++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/src/commands/mobile/register_app_interface_request.cc
@@ -293,12 +293,45 @@ void RegisterAppInterfaceRequest::Run() {
return;
}
+ uint16_t major =
+ msg_params[strings::sync_msg_version][strings::major_version].asUInt();
+ uint16_t minor =
+ msg_params[strings::sync_msg_version][strings::minor_version].asUInt();
+ uint16_t patch = 0;
+ // Check if patch exists since it is not mandatory.
+ if (msg_params[strings::sync_msg_version].keyExists(strings::patch_version)) {
+ patch =
+ msg_params[strings::sync_msg_version][strings::patch_version].asUInt();
+ }
+
+ utils::SemanticVersion mobile_version(major, minor, patch);
+ utils::SemanticVersion min_module_version(
+ minimum_major_version, minimum_minor_version, minimum_patch_version);
+
+ if (mobile_version < min_module_version) {
+ LOG4CXX_WARN(logger_,
+ "Application RPC Version does not meet minimum requirement");
+ SendResponse(false, mobile_apis::Result::REJECTED);
+ }
+
application = application_manager_.RegisterApplication(message_);
if (!application) {
LOG4CXX_ERROR(logger_, "Application hasn't been registered!");
return;
}
+
+ // Version negotiation
+ utils::SemanticVersion module_version(
+ major_version, minor_version, patch_version);
+ if (mobile_version < module_version) {
+ // Use mobile RPC version as negotiated version
+ application->set_msg_version(mobile_version);
+ } else {
+ // Use module version as negotiated version
+ application->set_msg_version(module_version);
+ }
+
// For resuming application need to restore hmi_app_id from resumeCtrl
resumption::ResumeCtrl& resumer = application_manager_.resume_controller();
const std::string& device_mac = application->mac_address();
@@ -585,12 +618,14 @@ void RegisterAppInterfaceRequest::SendRegisterAppInterfaceResponseToMobile(
return;
}
+ utils::SemanticVersion negotiated_version = application->msg_version();
+
response_params[strings::sync_msg_version][strings::major_version] =
- major_version; // From generated file interfaces/generated_msg_version.h
+ negotiated_version.major_version_;
response_params[strings::sync_msg_version][strings::minor_version] =
- minor_version; // From generated file interfaces/generated_msg_version.h
+ negotiated_version.minor_version_;
response_params[strings::sync_msg_version][strings::patch_version] =
- patch_version; // From generated file interfaces/generated_msg_version.h
+ negotiated_version.patch_version_;
const smart_objects::SmartObject& msg_params =
(*message_)[strings::msg_params];
diff --git a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/register_app_interface_request_test.cc b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/register_app_interface_request_test.cc
index dbaee6b2ad..2518e9c7fd 100644
--- a/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/register_app_interface_request_test.cc
+++ b/src/components/application_manager/rpc_plugins/sdl_rpc_plugin/test/commands/mobile/register_app_interface_request_test.cc
@@ -55,6 +55,7 @@
#include "utils/custom_string.h"
#include "utils/lock.h"
#include "utils/macro.h"
+#include "utils/semantic_version.h"
namespace test {
namespace components {
@@ -82,6 +83,7 @@ const std::string kMacAddress = "test_mac_address";
const std::string kAppId = "test_app_id";
const std::string kDummyString = "test_string";
const std::vector<uint32_t> kDummyDiagModes;
+const utils::SemanticVersion mock_semantic_version(1, 0, 0);
} // namespace
class RegisterAppInterfaceRequestTest
@@ -115,6 +117,12 @@ class RegisterAppInterfaceRequestTest
kHmiLanguage;
(*msg_)[am::strings::msg_params]
[am::strings::hmi_display_language_desired] = kHmiLanguage;
+ (*msg_)[am::strings::msg_params][am::strings::sync_msg_version]
+ [am::strings::major_version] = 4;
+ (*msg_)[am::strings::msg_params][am::strings::sync_msg_version]
+ [am::strings::minor_version] = 0;
+ (*msg_)[am::strings::msg_params][am::strings::sync_msg_version]
+ [am::strings::patch_version] = 0;
}
MockAppPtr CreateBasicMockedApp() {
@@ -125,6 +133,8 @@ class RegisterAppInterfaceRequestTest
ON_CALL(*mock_app, language()).WillByDefault(ReturnRef(kMobileLanguage));
ON_CALL(*mock_app, ui_language()).WillByDefault(ReturnRef(kMobileLanguage));
ON_CALL(*mock_app, policy_app_id()).WillByDefault(Return(kAppId));
+ ON_CALL(*mock_app, msg_version())
+ .WillByDefault(ReturnRef(mock_semantic_version));
return mock_app;
}
@@ -281,6 +291,7 @@ TEST_F(RegisterAppInterfaceRequestTest, Run_MinimalData_SUCCESS) {
.WillByDefault(Return(notify_upd_manager));
EXPECT_CALL(app_mngr_, RegisterApplication(msg_)).WillOnce(Return(mock_app));
+
EXPECT_CALL(mock_rpc_service_,
ManageHMICommand(HMIResultCodeIs(
hmi_apis::FunctionID::BasicCommunication_OnAppRegistered)))
diff --git a/src/components/application_manager/src/application_data_impl.cc b/src/components/application_manager/src/application_data_impl.cc
index 3cfbeb2602..ea7893ddc5 100644
--- a/src/components/application_manager/src/application_data_impl.cc
+++ b/src/components/application_manager/src/application_data_impl.cc
@@ -103,6 +103,10 @@ const mobile_api::Language::eType& InitialApplicationDataImpl::ui_language()
return ui_language_;
}
+const utils::SemanticVersion& InitialApplicationDataImpl::msg_version() const {
+ return msg_version_;
+}
+
void InitialApplicationDataImpl::set_app_types(
const smart_objects::SmartObject& app_types) {
if (app_types_) {
@@ -153,6 +157,11 @@ void InitialApplicationDataImpl::set_ui_language(
ui_language_ = ui_language;
}
+void InitialApplicationDataImpl::set_msg_version(
+ const utils::SemanticVersion& version) {
+ msg_version_ = version;
+}
+
void InitialApplicationDataImpl::set_perform_interaction_layout(
mobile_apis::LayoutMode::eType layout) {
perform_interaction_layout_ = layout;
diff --git a/src/components/application_manager/src/rpc_handler_impl.cc b/src/components/application_manager/src/rpc_handler_impl.cc
index b374147968..bf1ff78d36 100644
--- a/src/components/application_manager/src/rpc_handler_impl.cc
+++ b/src/components/application_manager/src/rpc_handler_impl.cc
@@ -194,6 +194,36 @@ void RPCHandlerImpl::SetTelemetryObserver(AMTelemetryObserver* observer) {
#endif // TELEMETRY_MONITOR
+void RPCHandlerImpl::GetMessageVersion(
+ NsSmartDeviceLink::NsSmartObjects::SmartObject& output,
+ utils::SemanticVersion& message_version) {
+ if (output.keyExists(
+ NsSmartDeviceLink::NsJSONHandler::strings::S_MSG_PARAMS) &&
+ output[NsSmartDeviceLink::NsJSONHandler::strings::S_MSG_PARAMS].keyExists(
+ strings::sync_msg_version)) {
+ // SyncMsgVersion exists, check if it is valid.
+ auto sync_msg_version =
+ output[NsSmartDeviceLink::NsJSONHandler::strings::S_MSG_PARAMS]
+ [strings::sync_msg_version];
+ uint16_t major = 0;
+ uint16_t minor = 0;
+ uint16_t patch = 0;
+ if (sync_msg_version.keyExists(strings::major_version)) {
+ major = sync_msg_version[strings::major_version].asUInt();
+ }
+ if (sync_msg_version.keyExists(strings::minor_version)) {
+ minor = sync_msg_version[strings::minor_version].asUInt();
+ }
+ if (sync_msg_version.keyExists(strings::patch_version)) {
+ patch = sync_msg_version[strings::patch_version].asUInt();
+ }
+ utils::SemanticVersion temp_version(major, minor, patch);
+ if (temp_version.isValid()) {
+ message_version = temp_version;
+ }
+ }
+}
+
bool RPCHandlerImpl::ConvertMessageToSO(
const Message& message,
NsSmartDeviceLink::NsSmartObjects::SmartObject& output) {
@@ -218,9 +248,24 @@ bool RPCHandlerImpl::ConvertMessageToSO(
rpc::ValidationReport report("RPC");
+ // Attach RPC version to SmartObject if it does not exist yet.
+ auto app_ptr = app_manager_.application(message.connection_key());
+ utils::SemanticVersion msg_version(0, 0, 0);
+ if (app_ptr &&
+ (output[NsSmartDeviceLink::NsJSONHandler::strings::S_PARAMS]
+ .keyExists(NsSmartDeviceLink::NsJSONHandler::strings::
+ S_RPC_MSG_VERSION) == false)) {
+ msg_version = app_ptr->msg_version();
+ } else if (mobile_apis::FunctionID::RegisterAppInterfaceID ==
+ static_cast<mobile_apis::FunctionID::eType>(
+ output[strings::params][strings::function_id].asInt())) {
+ GetMessageVersion(output, msg_version);
+ }
+
if (!conversion_result ||
- !mobile_so_factory().attachSchema(output, true) ||
- ((output.validate(&report) != smart_objects::Errors::OK))) {
+ !mobile_so_factory().attachSchema(output, true, msg_version) ||
+ ((output.validate(&report, msg_version) !=
+ smart_objects::Errors::OK))) {
LOG4CXX_WARN(logger_,
"Failed to parse string to smart object :"
<< message.json_message());
diff --git a/src/components/application_manager/test/include/application_manager/mock_application.h b/src/components/application_manager/test/include/application_manager/mock_application.h
index 47a39d742c..602d228147 100644
--- a/src/components/application_manager/test/include/application_manager/mock_application.h
+++ b/src/components/application_manager/test/include/application_manager/mock_application.h
@@ -38,6 +38,7 @@
#include "smart_objects/smart_object.h"
#include "utils/custom_string.h"
#include "application_manager/usage_statistics.h"
+#include "utils/semantic_version.h"
namespace test {
namespace components {
@@ -191,6 +192,7 @@ class MockApplication : public ::application_manager::Application {
const smart_objects::SmartObject*());
MOCK_CONST_METHOD0(language, const mobile_apis::Language::eType&());
MOCK_CONST_METHOD0(ui_language, const mobile_apis::Language::eType&());
+ MOCK_CONST_METHOD0(msg_version, const utils::SemanticVersion&());
MOCK_METHOD1(set_app_types,
void(const smart_objects::SmartObject& app_types));
MOCK_METHOD1(set_vr_synonyms,
@@ -203,6 +205,7 @@ class MockApplication : public ::application_manager::Application {
void(const mobile_apis::Language::eType& language));
MOCK_METHOD1(set_ui_language,
void(const mobile_apis::Language::eType& ui_language));
+ MOCK_METHOD1(set_msg_version, void(const utils::SemanticVersion& version));
// DynamicApplicationData methods
MOCK_CONST_METHOD0(help_prompt, const smart_objects::SmartObject*());
MOCK_CONST_METHOD0(timeout_prompt, const smart_objects::SmartObject*());
diff --git a/src/components/formatters/include/formatters/CSmartFactory.h b/src/components/formatters/include/formatters/CSmartFactory.h
index 9fed89253b..a459f179c0 100644
--- a/src/components/formatters/include/formatters/CSmartFactory.h
+++ b/src/components/formatters/include/formatters/CSmartFactory.h
@@ -82,6 +82,10 @@ extern const std::string S_PROTOCOL_TYPE;
extern const std::string S_CORRELATION_ID;
/**
+ * @brief String constant for RPC_MSG_VERSION.
+ */
+extern const std::string S_RPC_MSG_VERSION;
+/**
* @brief String constant for "code" param name.
*/
extern const std::string kCode;
@@ -149,8 +153,10 @@ class CSmartFactory {
*
* @return True if operation was successful or false otherwise.
*/
- bool attachSchema(NsSmartDeviceLink::NsSmartObjects::SmartObject& object,
- const bool RemoveFakeParameters);
+ bool attachSchema(
+ NsSmartDeviceLink::NsSmartObjects::SmartObject& object,
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion = utils::SemanticVersion());
/**
* @brief Attach schema to the struct SmartObject.
@@ -269,7 +275,8 @@ CSmartFactory<FunctionIdEnum, MessageTypeEnum, StructIdEnum>::CSmartFactory(
template <class FunctionIdEnum, class MessageTypeEnum, class StructIdEnum>
bool CSmartFactory<FunctionIdEnum, MessageTypeEnum, StructIdEnum>::attachSchema(
NsSmartDeviceLink::NsSmartObjects::SmartObject& object,
- const bool RemoveFakeParameters) {
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion) {
if (false == object.keyExists(strings::S_PARAMS))
return false;
if (false == object[strings::S_PARAMS].keyExists(strings::S_MESSAGE_TYPE))
@@ -295,7 +302,9 @@ bool CSmartFactory<FunctionIdEnum, MessageTypeEnum, StructIdEnum>::attachSchema(
}
object.setSchema(schemaIterator->second);
- schemaIterator->second.applySchema(object, RemoveFakeParameters);
+
+ schemaIterator->second.applySchema(
+ object, RemoveFakeParameters, MessageVersion);
return true;
}
diff --git a/src/components/formatters/src/CSmartFactory.cc b/src/components/formatters/src/CSmartFactory.cc
index 6b0808fbfa..6efd895500 100644
--- a/src/components/formatters/src/CSmartFactory.cc
+++ b/src/components/formatters/src/CSmartFactory.cc
@@ -47,6 +47,8 @@ const std::string NsSmartDeviceLink::NsJSONHandler::strings::S_PROTOCOL_TYPE(
"protocol_type");
const std::string NsSmartDeviceLink::NsJSONHandler::strings::S_CORRELATION_ID(
"correlation_id");
+const std::string NsSmartDeviceLink::NsJSONHandler::strings::S_RPC_MSG_VERSION(
+ "rpc_msg_version");
const std::string NsSmartDeviceLink::NsJSONHandler::strings::kCode("code");
const std::string NsSmartDeviceLink::NsJSONHandler::strings::kMessage(
"message");
diff --git a/src/components/include/utils/semantic_version.h b/src/components/include/utils/semantic_version.h
new file mode 100644
index 0000000000..7b9ec0eb96
--- /dev/null
+++ b/src/components/include/utils/semantic_version.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018, Livio
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Ford Motor Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SRC_COMPONENTS_INCLUDE_UTILS_SEMANTIC_VERSION_H_
+#define SRC_COMPONENTS_INCLUDE_UTILS_SEMANTIC_VERSION_H_
+
+namespace utils {
+
+struct SemanticVersion {
+ SemanticVersion(uint16_t major = 0, uint16_t minor = 0, uint16_t patch = 0) {
+ major_version_ = major;
+ minor_version_ = minor;
+ patch_version_ = patch;
+ }
+
+ SemanticVersion(const SemanticVersion& other) {
+ major_version_ = other.major_version_;
+ minor_version_ = other.minor_version_;
+ patch_version_ = other.patch_version_;
+ }
+
+ SemanticVersion(const std::string& versionString)
+ : major_version_(0), minor_version_(0), patch_version_(0) {
+ unsigned int major_int, minor_int, patch_int;
+ int readElements = sscanf(
+ versionString.c_str(), "%u.%u.%u", &major_int, &minor_int, &patch_int);
+ if (readElements != 3) {
+ // LOG4CXX_WARN(logger_,
+ // "Error while parsing version string: " << versionString);
+ } else {
+ major_version_ = static_cast<uint8_t>(major_int);
+ minor_version_ = static_cast<uint8_t>(minor_int);
+ patch_version_ = static_cast<uint8_t>(patch_int);
+ }
+ }
+
+ static inline int16_t cmp(const SemanticVersion& version1,
+ const SemanticVersion& version2) {
+ int16_t diff =
+ static_cast<int16_t>(version1.major_version_ - version2.major_version_);
+ if (diff == 0) {
+ diff = static_cast<int16_t>(version1.minor_version_ -
+ version2.minor_version_);
+ if (diff == 0) {
+ diff = static_cast<int16_t>(version1.patch_version_ -
+ version2.patch_version_);
+ }
+ }
+ return diff;
+ }
+
+ bool operator==(const SemanticVersion& other) const {
+ return SemanticVersion::cmp(*this, other) == 0;
+ }
+ bool operator<(const SemanticVersion& other) const {
+ return SemanticVersion::cmp(*this, other) < 0;
+ }
+ bool operator>(const SemanticVersion& other) const {
+ return SemanticVersion::cmp(*this, other) > 0;
+ }
+ bool operator<=(const SemanticVersion& other) const {
+ return SemanticVersion::cmp(*this, other) <= 0;
+ }
+ bool operator>=(const SemanticVersion& other) const {
+ return SemanticVersion::cmp(*this, other) >= 0;
+ }
+ static inline SemanticVersion* min(SemanticVersion& version1,
+ SemanticVersion& version2) {
+ return (version1 < version2) ? &version1 : &version2;
+ }
+
+ const std::string toString() const {
+ std::string result = "";
+ result += std::to_string(major_version_);
+ result += ".";
+ result += std::to_string(minor_version_);
+ result += ".";
+ result += std::to_string(patch_version_);
+ return result;
+ }
+
+ bool isValid() const {
+ return major_version_ > 0 || minor_version_ > 0 || patch_version_ > 0;
+ }
+
+ uint16_t major_version_ = 0;
+ uint16_t minor_version_ = 0;
+ uint16_t patch_version_ = 0;
+};
+}
+
+#endif // SRC_COMPONENTS_INCLUDE_UTILS_CALLABLE_H \ No newline at end of file
diff --git a/src/components/interfaces/MOBILE_API.xml b/src/components/interfaces/MOBILE_API.xml
index 45a484a6a4..4861fe7ba5 100644
--- a/src/components/interfaces/MOBILE_API.xml
+++ b/src/components/interfaces/MOBILE_API.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/xml" href="protocol2html.xsl"?>
-<interface name="SmartDeviceLink RAPI" version="4.5.0" date="2017-09-22">
+<interface name="SmartDeviceLink RAPI" version="4.5.0" minVersion="1.0.0" date="2017-09-22">
<enum name="Result" internal_scope="base">
<element name="SUCCESS">
<description>The request succeeded</description>
diff --git a/src/components/protocol_handler/include/protocol_handler/handshake_handler.h b/src/components/protocol_handler/include/protocol_handler/handshake_handler.h
index 8b7f28d50e..be81493e7a 100644
--- a/src/components/protocol_handler/include/protocol_handler/handshake_handler.h
+++ b/src/components/protocol_handler/include/protocol_handler/handshake_handler.h
@@ -40,6 +40,8 @@
#include "protocol_handler/session_observer.h"
#include "security_manager/security_manager_listener.h"
+#include "utils/semantic_version.h"
+
namespace protocol_handler {
class ProtocolHandlerImpl;
@@ -60,12 +62,12 @@ class HandshakeHandler : public security_manager::SecurityManagerListener {
ServiceType service_type,
const std::vector<int>& force_protected_service,
const bool is_new_service,
- ProtocolPacket::ProtocolVersion& full_version,
+ utils::SemanticVersion& full_version,
std::shared_ptr<BsonObject> payload);
HandshakeHandler(ProtocolHandlerImpl& protocol_handler,
SessionObserver& session_observer,
- ProtocolPacket::ProtocolVersion& full_version,
+ utils::SemanticVersion& full_version,
const SessionContext& context,
const uint8_t protocol_version,
std::shared_ptr<BsonObject> payload);
@@ -124,7 +126,7 @@ class HandshakeHandler : public security_manager::SecurityManagerListener {
ProtocolHandlerImpl& protocol_handler_;
SessionObserver& session_observer_;
SessionContext context_;
- ProtocolPacket::ProtocolVersion full_version_;
+ utils::SemanticVersion full_version_;
const uint8_t protocol_version_;
std::shared_ptr<BsonObject> payload_;
};
diff --git a/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h b/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h
index 58877ac611..e763be8c1b 100644
--- a/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h
+++ b/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h
@@ -45,6 +45,7 @@
#include "utils/messagemeter.h"
#include "utils/custom_string.h"
+#include "utils/semantic_version.h"
#include "protocol_handler/protocol_handler.h"
#include "protocol_handler/protocol_packet.h"
@@ -313,7 +314,7 @@ class ProtocolHandlerImpl
uint32_t hash_code,
uint8_t service_type,
bool protection,
- ProtocolPacket::ProtocolVersion& full_version);
+ utils::SemanticVersion& full_version);
/**
* \brief Sends acknowledgement of starting session to mobile application
@@ -337,7 +338,7 @@ class ProtocolHandlerImpl
uint32_t hash_code,
uint8_t service_type,
bool protection,
- ProtocolPacket::ProtocolVersion& full_version,
+ utils::SemanticVersion& full_version,
BsonObject& params);
const ProtocolHandlerSettings& get_settings() const OVERRIDE {
diff --git a/src/components/protocol_handler/include/protocol_handler/protocol_packet.h b/src/components/protocol_handler/include/protocol_handler/protocol_packet.h
index ff084beff8..de4af84915 100644
--- a/src/components/protocol_handler/include/protocol_handler/protocol_packet.h
+++ b/src/components/protocol_handler/include/protocol_handler/protocol_packet.h
@@ -64,58 +64,6 @@ class ProtocolPacket {
};
/**
- * \class ProtocolVersion
- * \brief Used for storing the full protocol version of a service
- * (major.minor.patch).
- */
- class ProtocolVersion {
- public:
- ProtocolVersion();
- ProtocolVersion(uint8_t majorVersion,
- uint8_t minorVersion,
- uint8_t patchVersion);
- ProtocolVersion(ProtocolVersion& other);
- ProtocolVersion(std::string versionString);
- uint8_t majorVersion;
- uint8_t minorVersion;
- uint8_t patchVersion;
- static inline int16_t cmp(const ProtocolVersion& version1,
- const ProtocolVersion& version2) {
- int16_t diff =
- static_cast<int16_t>(version1.majorVersion - version2.majorVersion);
- if (diff == 0) {
- diff =
- static_cast<int16_t>(version1.minorVersion - version2.minorVersion);
- if (diff == 0) {
- diff = static_cast<int16_t>(version1.patchVersion -
- version2.patchVersion);
- }
- }
- return diff;
- }
- inline bool operator==(const ProtocolVersion& other) {
- return ProtocolVersion::cmp(*this, other) == 0;
- }
- inline bool operator<(const ProtocolVersion& other) {
- return ProtocolVersion::cmp(*this, other) < 0;
- }
- bool operator>(const ProtocolVersion& other) {
- return ProtocolVersion::cmp(*this, other) > 0;
- }
- inline bool operator<=(const ProtocolVersion& other) {
- return ProtocolVersion::cmp(*this, other) <= 0;
- }
- bool operator>=(const ProtocolVersion& other) {
- return ProtocolVersion::cmp(*this, other) >= 0;
- }
- static inline ProtocolVersion* min(ProtocolVersion& version1,
- ProtocolVersion& version2) {
- return (version1 < version2) ? &version1 : &version2;
- }
- std::string to_string();
- };
-
- /**
* \class ProtocolHeader
* \brief Used for storing protocol header of a message.
*/
diff --git a/src/components/protocol_handler/src/handshake_handler.cc b/src/components/protocol_handler/src/handshake_handler.cc
index 8db551cfd6..f6ab08319e 100644
--- a/src/components/protocol_handler/src/handshake_handler.cc
+++ b/src/components/protocol_handler/src/handshake_handler.cc
@@ -54,7 +54,7 @@ HandshakeHandler::HandshakeHandler(
ServiceType service_type,
const std::vector<int>& force_protected_service,
const bool is_new_service,
- ProtocolPacket::ProtocolVersion& full_version,
+ utils::SemanticVersion& full_version,
std::shared_ptr<BsonObject> payload)
: protocol_handler_(protocol_handler)
, session_observer_(session_observer)
@@ -63,13 +63,12 @@ HandshakeHandler::HandshakeHandler(
, protocol_version_(protocol_version)
, payload_(payload) {}
-HandshakeHandler::HandshakeHandler(
- ProtocolHandlerImpl& protocol_handler,
- SessionObserver& session_observer,
- ProtocolPacket::ProtocolVersion& full_version,
- const SessionContext& context,
- const uint8_t protocol_version,
- std::shared_ptr<BsonObject> payload)
+HandshakeHandler::HandshakeHandler(ProtocolHandlerImpl& protocol_handler,
+ SessionObserver& session_observer,
+ utils::SemanticVersion& full_version,
+ const SessionContext& context,
+ const uint8_t protocol_version,
+ std::shared_ptr<BsonObject> payload)
: protocol_handler_(protocol_handler)
, session_observer_(session_observer)
, context_(context)
diff --git a/src/components/protocol_handler/src/protocol_handler_impl.cc b/src/components/protocol_handler/src/protocol_handler_impl.cc
index 872a8dc755..0e49e28397 100644
--- a/src/components/protocol_handler/src/protocol_handler_impl.cc
+++ b/src/components/protocol_handler/src/protocol_handler_impl.cc
@@ -61,8 +61,8 @@ std::string ConvertPacketDataToString(const uint8_t* data,
const size_t kStackSize = 65536;
-ProtocolPacket::ProtocolVersion defaultProtocolVersion(5, 1, 0);
-ProtocolPacket::ProtocolVersion minMultipleTransportsVersion(5, 1, 0);
+utils::SemanticVersion defaultProtocolVersion(5, 1, 0);
+utils::SemanticVersion minMultipleTransportsVersion(5, 1, 0);
ProtocolHandlerImpl::ProtocolHandlerImpl(
const ProtocolHandlerSettings& settings,
@@ -199,7 +199,7 @@ void ProtocolHandlerImpl::SendStartSessionAck(ConnectionID connection_id,
uint8_t service_type,
bool protection) {
LOG4CXX_AUTO_TRACE(logger_);
- ProtocolPacket::ProtocolVersion fullVersion;
+ utils::SemanticVersion fullVersion;
SendStartSessionAck(connection_id,
session_id,
input_protocol_version,
@@ -216,7 +216,7 @@ void ProtocolHandlerImpl::SendStartSessionAck(
uint32_t hash_id,
uint8_t service_type,
bool protection,
- ProtocolPacket::ProtocolVersion& full_version) {
+ utils::SemanticVersion& full_version) {
LOG4CXX_AUTO_TRACE(logger_);
BsonObject empty_param;
@@ -241,7 +241,7 @@ void ProtocolHandlerImpl::SendStartSessionAck(
uint32_t hash_id,
uint8_t service_type,
bool protection,
- ProtocolPacket::ProtocolVersion& full_version,
+ utils::SemanticVersion& full_version,
BsonObject& params) {
LOG4CXX_AUTO_TRACE(logger_);
@@ -252,7 +252,7 @@ void ProtocolHandlerImpl::SendStartSessionAck(
const bool proxy_supports_v5_protocol =
input_protocol_version >= PROTOCOL_VERSION_5 ||
(ServiceTypeFromByte(service_type) == kRpc &&
- full_version.majorVersion >= PROTOCOL_VERSION_5);
+ full_version.major_version_ >= PROTOCOL_VERSION_5);
if (kRpc != service_type) {
// In case if input protocol version os bigger then supported, SDL should
@@ -307,13 +307,13 @@ void ProtocolHandlerImpl::SendStartSessionAck(
&params, strings::hash_id)));
// Minimum protocol version supported by both
- ProtocolPacket::ProtocolVersion* minVersion =
- (full_version.majorVersion < PROTOCOL_VERSION_5)
+ utils::SemanticVersion* minVersion =
+ (full_version.major_version_ < PROTOCOL_VERSION_5)
? &defaultProtocolVersion
- : ProtocolPacket::ProtocolVersion::min(full_version,
- defaultProtocolVersion);
+ : utils::SemanticVersion::min(full_version,
+ defaultProtocolVersion);
char protocolVersionString[256];
- strncpy(protocolVersionString, (*minVersion).to_string().c_str(), 255);
+ strncpy(protocolVersionString, (*minVersion).toString().c_str(), 255);
const bool protocol_ver_written = bson_object_put_string(
&params, strings::protocol_version, protocolVersionString);
@@ -1608,22 +1608,22 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageStartSession(
PROTECTION_OFF);
return RESULT_OK;
}
- ProtocolPacket::ProtocolVersion* fullVersion;
+ utils::SemanticVersion* fullVersion;
std::vector<std::string> rejectedParams(0, std::string(""));
// Can't check protocol_version because the first packet is v1, but there
// could still be a payload, in which case we can get the real protocol
// version
if (packet.service_type() == kRpc && packet.data_size() != 0) {
BsonObject obj = bson_object_from_bytes(packet.data());
- fullVersion = new ProtocolPacket::ProtocolVersion(
+ fullVersion = new utils::SemanticVersion(
std::string(bson_object_get_string(&obj, "protocolVersion")));
bson_object_deinitialize(&obj);
// Constructed payloads added in Protocol v5
- if (fullVersion->majorVersion < PROTOCOL_VERSION_5) {
+ if (fullVersion->major_version_ < PROTOCOL_VERSION_5) {
rejectedParams.push_back(std::string("protocolVersion"));
}
} else {
- fullVersion = new ProtocolPacket::ProtocolVersion();
+ fullVersion = new utils::SemanticVersion();
}
if (!rejectedParams.empty()) {
SendStartSessionNAck(connection_id,
@@ -1670,11 +1670,11 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageStartSession(
#endif // ENABLE_SECURITY
if (packet.service_type() == kRpc && packet.data_size() != 0) {
BsonObject obj = bson_object_from_bytes(packet.data());
- ProtocolPacket::ProtocolVersion fullVersion(
+ utils::SemanticVersion fullVersion(
bson_object_get_string(&obj, "protocolVersion"));
bson_object_deinitialize(&obj);
- if (fullVersion.majorVersion >= PROTOCOL_VERSION_5) {
+ if (fullVersion.major_version_ >= PROTOCOL_VERSION_5) {
// Start service without protection
SendStartSessionAck(connection_id,
session_id,
@@ -1880,7 +1880,7 @@ void ProtocolHandlerImpl::NotifySessionStarted(
bson_object_deinitialize(&req_param);
}
- std::shared_ptr<ProtocolPacket::ProtocolVersion> fullVersion;
+ std::shared_ptr<utils::SemanticVersion> fullVersion;
// Can't check protocol_version because the first packet is v1, but there
// could still be a payload, in which case we can get the real protocol
@@ -1890,15 +1890,14 @@ void ProtocolHandlerImpl::NotifySessionStarted(
char* version_param =
bson_object_get_string(&request_params, strings::protocol_version);
std::string version_string(version_param == NULL ? "" : version_param);
- fullVersion =
- std::make_shared<ProtocolPacket::ProtocolVersion>(version_string);
+ fullVersion = std::make_shared<utils::SemanticVersion>(version_string);
// Constructed payloads added in Protocol v5
- if (fullVersion->majorVersion < PROTOCOL_VERSION_5) {
+ if (fullVersion->major_version_ < PROTOCOL_VERSION_5) {
rejected_params.push_back(std::string(strings::protocol_version));
}
bson_object_deinitialize(&request_params);
} else {
- fullVersion = std::make_shared<ProtocolPacket::ProtocolVersion>();
+ fullVersion = std::make_shared<utils::SemanticVersion>();
}
#ifdef ENABLE_SECURITY
diff --git a/src/components/protocol_handler/src/protocol_packet.cc b/src/components/protocol_handler/src/protocol_packet.cc
index 3cd9e7f781..d5422e11bc 100644
--- a/src/components/protocol_handler/src/protocol_packet.cc
+++ b/src/components/protocol_handler/src/protocol_packet.cc
@@ -41,6 +41,7 @@
#include "protocol_handler/protocol_packet.h"
#include "utils/macro.h"
#include "utils/byte_order.h"
+#include "utils/semantic_version.h"
namespace protocol_handler {
@@ -52,48 +53,6 @@ ProtocolPacket::ProtocolData::~ProtocolData() {
delete[] data;
}
-ProtocolPacket::ProtocolVersion::ProtocolVersion()
- : majorVersion(0), minorVersion(0), patchVersion(0) {}
-
-ProtocolPacket::ProtocolVersion::ProtocolVersion(uint8_t majorVersion,
- uint8_t minorVersion,
- uint8_t patchVersion)
- : majorVersion(majorVersion)
- , minorVersion(minorVersion)
- , patchVersion(patchVersion) {}
-
-ProtocolPacket::ProtocolVersion::ProtocolVersion(ProtocolVersion& other) {
- this->majorVersion = other.majorVersion;
- this->minorVersion = other.minorVersion;
- this->patchVersion = other.patchVersion;
-}
-
-ProtocolPacket::ProtocolVersion::ProtocolVersion(std::string versionString)
- : majorVersion(0), minorVersion(0), patchVersion(0) {
- unsigned int majorInt, minorInt, patchInt;
- int readElements = sscanf(
- versionString.c_str(), "%u.%u.%u", &majorInt, &minorInt, &patchInt);
- if (readElements != 3) {
- LOG4CXX_WARN(logger_,
- "Error while parsing version string: " << versionString);
- } else {
- majorVersion = static_cast<uint8_t>(majorInt);
- minorVersion = static_cast<uint8_t>(minorInt);
- patchVersion = static_cast<uint8_t>(patchInt);
- }
-}
-
-std::string ProtocolPacket::ProtocolVersion::to_string() {
- char versionString[256];
- snprintf(versionString,
- 255,
- "%u.%u.%u",
- static_cast<unsigned int>(majorVersion),
- static_cast<unsigned int>(minorVersion),
- static_cast<unsigned int>(patchVersion));
- return std::string(versionString);
-}
-
ProtocolPacket::ProtocolHeader::ProtocolHeader()
: version(0x00)
, protection_flag(PROTECTION_OFF)
diff --git a/src/components/protocol_handler/test/protocol_handler_tm_test.cc b/src/components/protocol_handler/test/protocol_handler_tm_test.cc
index cfda0a550a..615900c7fa 100644
--- a/src/components/protocol_handler/test/protocol_handler_tm_test.cc
+++ b/src/components/protocol_handler/test/protocol_handler_tm_test.cc
@@ -48,6 +48,7 @@
#endif // ENABLE_SECURITY
#include "transport_manager/mock_transport_manager.h"
#include "utils/mock_system_time_handler.h"
+#include "utils/semantic_version.h"
#include "utils/test_async_waiter.h"
#include <bson_object.h>
@@ -1539,7 +1540,7 @@ void ProtocolHandlerImplTest::VerifySecondaryTransportParamsInStartSessionAck(
const uint8_t input_protocol_version = 5;
const uint32_t hash_id = 123456;
- ProtocolPacket::ProtocolVersion full_version(5, 1, 0);
+ utils::SemanticVersion full_version(5, 1, 0);
char full_version_string[] = "5.1.0";
// configuration setup
@@ -2030,7 +2031,7 @@ TEST_F(ProtocolHandlerImplTest,
const uint8_t input_protocol_version = 5;
const uint32_t hash_id = 123456;
- ProtocolPacket::ProtocolVersion full_version(5, 0, 0);
+ utils::SemanticVersion full_version(5, 0, 0);
char full_version_string[] = "5.0.0";
const size_t maximum_rpc_payload_size = 1500;
@@ -2190,7 +2191,7 @@ TEST_F(ProtocolHandlerImplTest,
const uint8_t input_protocol_version = 5;
const uint32_t hash_id = 123456;
- ProtocolPacket::ProtocolVersion full_version(5, 1, 0);
+ utils::SemanticVersion full_version(5, 1, 0);
const size_t maximum_rpc_payload_size = 1500;
EXPECT_CALL(protocol_handler_settings_mock, maximum_rpc_payload_size())
@@ -2313,7 +2314,7 @@ TEST_F(ProtocolHandlerImplTest,
const uint8_t input_protocol_version = 5;
const uint32_t hash_id = 123456;
- ProtocolPacket::ProtocolVersion full_version(5, 1, 0);
+ utils::SemanticVersion full_version(5, 1, 0);
const size_t maximum_rpc_payload_size = 1500;
EXPECT_CALL(protocol_handler_settings_mock, maximum_rpc_payload_size())
diff --git a/src/components/smart_objects/include/smart_objects/always_false_schema_item.h b/src/components/smart_objects/include/smart_objects/always_false_schema_item.h
index 4510f2292a..a7b93012bb 100644
--- a/src/components/smart_objects/include/smart_objects/always_false_schema_item.h
+++ b/src/components/smart_objects/include/smart_objects/always_false_schema_item.h
@@ -54,14 +54,18 @@ class CAlwaysFalseSchemaItem : public ISchemaItem {
* @return Errors::ERROR
**/
Errors::eType validate(const SmartObject& Object) OVERRIDE;
+
/**
* @brief Validate smart object.
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
- * @return Errors::ERROR
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
+ * @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) OVERRIDE;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
private:
CAlwaysFalseSchemaItem();
diff --git a/src/components/smart_objects/include/smart_objects/always_true_schema_item.h b/src/components/smart_objects/include/smart_objects/always_true_schema_item.h
index 8a211339ba..b025723ea6 100644
--- a/src/components/smart_objects/include/smart_objects/always_true_schema_item.h
+++ b/src/components/smart_objects/include/smart_objects/always_true_schema_item.h
@@ -54,14 +54,18 @@ class CAlwaysTrueSchemaItem : public ISchemaItem {
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object) OVERRIDE;
+
/**
* @brief Validate smart object.
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) OVERRIDE;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
private:
CAlwaysTrueSchemaItem();
diff --git a/src/components/smart_objects/include/smart_objects/array_schema_item.h b/src/components/smart_objects/include/smart_objects/array_schema_item.h
index 3e8be98ee0..4dc416007a 100644
--- a/src/components/smart_objects/include/smart_objects/array_schema_item.h
+++ b/src/components/smart_objects/include/smart_objects/array_schema_item.h
@@ -38,6 +38,8 @@
#include "smart_objects/always_true_schema_item.h"
#include "smart_objects/schema_item_parameter.h"
+#include "utils/semantic_version.h"
+
namespace NsSmartDeviceLink {
namespace NsSmartObjects {
/**
@@ -74,15 +76,15 @@ class CArraySchemaItem : public ISchemaItem {
/**
* @brief Validate smart object.
- *
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
- * message if an error occurs
- *
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) OVERRIDE;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
/**
* @brief Apply schema.
@@ -93,7 +95,9 @@ class CArraySchemaItem : public ISchemaItem {
* from smart object otherwise contains false.
**/
void applySchema(SmartObject& Object,
- const bool RemoveFakeParameters) OVERRIDE;
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
/**
* @brief Unapply schema.
diff --git a/src/components/smart_objects/include/smart_objects/default_shema_item.h b/src/components/smart_objects/include/smart_objects/default_shema_item.h
index fdac77d029..7d5b33b1a6 100644
--- a/src/components/smart_objects/include/smart_objects/default_shema_item.h
+++ b/src/components/smart_objects/include/smart_objects/default_shema_item.h
@@ -55,14 +55,18 @@ class CDefaultSchemaItem : public ISchemaItem {
* @return Errors::ERROR
**/
Errors::eType validate(const SmartObject& Object) OVERRIDE;
+
/**
* @brief Validate smart object.
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
- * @return Errors::ERROR
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
+ * @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) OVERRIDE;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
/**
* @brief Set default value to an object.
@@ -113,7 +117,9 @@ Errors::eType CDefaultSchemaItem<Type>::validate(const SmartObject& Object) {
template <typename Type>
Errors::eType CDefaultSchemaItem<Type>::validate(
- const SmartObject& Object, rpc::ValidationReport* report__) {
+ const SmartObject& Object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
if (getSmartType() != Object.getType()) {
std::string validation_info = "Incorrect type, expected: " +
SmartObject::typeToString(getSmartType()) +
diff --git a/src/components/smart_objects/include/smart_objects/enum_schema_item.h b/src/components/smart_objects/include/smart_objects/enum_schema_item.h
index 450bbc6c40..41102933f3 100644
--- a/src/components/smart_objects/include/smart_objects/enum_schema_item.h
+++ b/src/components/smart_objects/include/smart_objects/enum_schema_item.h
@@ -41,9 +41,35 @@
#include "smart_objects/default_shema_item.h"
+#include "utils/semantic_version.h"
+#include <boost/optional.hpp>
+
namespace NsSmartDeviceLink {
namespace NsSmartObjects {
+struct ElementSignature {
+ boost::optional<utils::SemanticVersion> mSince;
+ boost::optional<utils::SemanticVersion> mUntil;
+ bool mRemoved;
+
+ ElementSignature(std::string since = "",
+ std::string until = "",
+ bool removed = false) {
+ utils::SemanticVersion since_struct(since);
+ utils::SemanticVersion until_struct(until);
+
+ if (since_struct.isValid()) {
+ mSince = since_struct;
+ }
+
+ if (until_struct.isValid()) {
+ mUntil = until_struct;
+ }
+
+ mRemoved = removed;
+ }
+};
+
template <typename EnumType>
class EnumConversionHelper;
/**
@@ -63,6 +89,19 @@ class TEnumSchemaItem : public CDefaultSchemaItem<EnumType> {
const std::set<EnumType>& AllowedElements,
const TSchemaItemParameter<EnumType>& DefaultValue =
TSchemaItemParameter<EnumType>());
+
+ /**
+ * @brief Create a new schema item.
+ * @param AllowedElements Set of allowed enumeration elements.
+ * @param DefaultValue Default value.
+ * @return Shared pointer to a new schema item.
+ **/
+ static std::shared_ptr<TEnumSchemaItem> createWithSignatures(
+ const std::set<EnumType>& AllowedElements,
+ const std::map<EnumType, std::vector<ElementSignature> >&
+ ElementSignatures,
+ const TSchemaItemParameter<EnumType>& DefaultValue =
+ TSchemaItemParameter<EnumType>());
/**
* @deprecated
* @brief Validate smart object.
@@ -70,14 +109,27 @@ class TEnumSchemaItem : public CDefaultSchemaItem<EnumType> {
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object) OVERRIDE;
+
/**
* @brief Validate smart object.
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) OVERRIDE;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
+ /**
+ * @brief Return the correct history signature based on message version.
+ * @param signatures Vector reference of enums history items.
+ * @param MessageVersion RPC Version of mobile app.
+ **/
+ const ElementSignature getSignature(
+ const std::vector<ElementSignature>& signatures,
+ const utils::SemanticVersion& MessageVersion);
+
/**
* @brief Apply schema.
* This implementation checks if enumeration is represented as string
@@ -88,7 +140,9 @@ class TEnumSchemaItem : public CDefaultSchemaItem<EnumType> {
* from smart object otherwise contains false.
**/
void applySchema(SmartObject& Object,
- const bool RemoveFakeParameters) OVERRIDE;
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
/**
* @brief Unapply schema.
* @param Object Object to unapply schema.
@@ -103,12 +157,18 @@ class TEnumSchemaItem : public CDefaultSchemaItem<EnumType> {
**/
TEnumSchemaItem(const std::set<EnumType>& AllowedElements,
const TSchemaItemParameter<EnumType>& DefaultValue);
+
+ TEnumSchemaItem(const std::set<EnumType>& AllowedElements,
+ const TSchemaItemParameter<EnumType>& DefaultValue,
+ const std::map<EnumType, std::vector<ElementSignature> >&
+ ElementSignatures);
SmartType getSmartType() const OVERRIDE;
EnumType getDefaultValue() const OVERRIDE;
/**
* @brief Set of allowed enumeration elements.
**/
const std::set<EnumType> mAllowedElements;
+ std::map<EnumType, std::vector<ElementSignature> > mElementSignatures;
/**
* @brief Default value.
**/
@@ -215,14 +275,52 @@ std::shared_ptr<TEnumSchemaItem<EnumType> > TEnumSchemaItem<EnumType>::create(
}
template <typename EnumType>
+std::shared_ptr<TEnumSchemaItem<EnumType> >
+TEnumSchemaItem<EnumType>::createWithSignatures(
+ const std::set<EnumType>& AllowedElements,
+ const std::map<EnumType, std::vector<ElementSignature> >& ElementSignatures,
+ const TSchemaItemParameter<EnumType>& DefaultValue) {
+ return std::shared_ptr<TEnumSchemaItem<EnumType> >(
+ new TEnumSchemaItem<EnumType>(
+ AllowedElements, DefaultValue, ElementSignatures));
+}
+
+template <typename EnumType>
Errors::eType TEnumSchemaItem<EnumType>::validate(const SmartObject& Object) {
rpc::ValidationReport report("RPC");
return validate(Object, &report);
}
template <typename EnumType>
+const ElementSignature TEnumSchemaItem<EnumType>::getSignature(
+ const std::vector<ElementSignature>& signatures,
+ const utils::SemanticVersion& MessageVersion) {
+ for (uint i = 0; i < signatures.size(); i++) {
+ ElementSignature signature = signatures[i];
+ // Check if signature matches message version
+ if (signature.mSince != boost::none &&
+ MessageVersion < signature.mSince.get()) {
+ // Msg version predates 'since' field, check next entry
+ continue;
+ }
+ if (signature.mUntil != boost::none &&
+ (MessageVersion >= signature.mUntil.get())) {
+ continue; // Msg version newer than `until` field, check next entry
+ }
+ // Found correct signature
+ return signature;
+ }
+
+ // Could not match msg version to element siganture
+ ElementSignature ret;
+ return ret;
+}
+
+template <typename EnumType>
Errors::eType TEnumSchemaItem<EnumType>::validate(
- const SmartObject& Object, rpc::ValidationReport* report__) {
+ const SmartObject& Object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
if (SmartType_Integer != Object.getType()) {
std::string validation_info;
if (SmartType_String == Object.getType()) {
@@ -236,20 +334,53 @@ Errors::eType TEnumSchemaItem<EnumType>::validate(
report__->set_validation_info(validation_info);
return Errors::INVALID_VALUE;
}
- if (mAllowedElements.find(static_cast<EnumType>(Object.asInt())) ==
- mAllowedElements.end()) {
+
+ auto elements_it =
+ mAllowedElements.find(static_cast<EnumType>(Object.asInt()));
+
+ if (elements_it == mAllowedElements.end()) {
std::stringstream stream;
stream << "Invalid enum value: " << Object.asInt();
std::string validation_info = stream.str();
report__->set_validation_info(validation_info);
return Errors::OUT_OF_RANGE;
}
+
+ // Element exists in schema. Check if version is also valid.
+ if (MessageVersion.isValid()) {
+ EnumType value = *elements_it;
+ auto signatures_it = mElementSignatures.find(value);
+ if (signatures_it != mElementSignatures.end()) {
+ if (!signatures_it->second.empty()) {
+ ElementSignature signature =
+ getSignature(signatures_it->second, MessageVersion);
+ if (signature.mRemoved) {
+ // Element was removed for this version
+ std::string validation_info = "Enum value : " + Object.asString() +
+ " removed for SyncMsgVersion " +
+ MessageVersion.toString();
+ report__->set_validation_info(validation_info);
+ return Errors::INVALID_VALUE;
+ } else if (signature.mSince == boost::none &&
+ signature.mUntil == boost::none) {
+ // Element does not exist for this version
+ std::string validation_info = "Enum value : " + Object.asString() +
+ " does not exist for SyncMsgVersion " +
+ MessageVersion.toString();
+ report__->set_validation_info(validation_info);
+ return Errors::INVALID_VALUE;
+ }
+ }
+ }
+ }
return Errors::OK;
}
template <typename EnumType>
-void TEnumSchemaItem<EnumType>::applySchema(SmartObject& Object,
- const bool RemoveFakeParameters) {
+void TEnumSchemaItem<EnumType>::applySchema(
+ SmartObject& Object,
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion) {
if (SmartType_String == Object.getType()) {
EnumType enum_val = static_cast<EnumType>(-1);
if (ConversionHelper::StringToEnum(Object.asString(), &enum_val)) {
@@ -285,6 +416,15 @@ TEnumSchemaItem<EnumType>::TEnumSchemaItem(
: CDefaultSchemaItem<EnumType>(DefaultValue)
, mAllowedElements(AllowedElements) {}
+template <typename EnumType>
+TEnumSchemaItem<EnumType>::TEnumSchemaItem(
+ const std::set<EnumType>& AllowedElements,
+ const TSchemaItemParameter<EnumType>& DefaultValue,
+ const std::map<EnumType, std::vector<ElementSignature> >& ElementSignatures)
+ : CDefaultSchemaItem<EnumType>(DefaultValue)
+ , mAllowedElements(AllowedElements)
+ , mElementSignatures(ElementSignatures) {}
+
} // namespace NsSmartObjects
} // namespace NsSmartDeviceLink
#endif // SRC_COMPONENTS_SMART_OBJECTS_INCLUDE_SMART_OBJECTS_ENUM_SCHEMA_ITEM_H_
diff --git a/src/components/smart_objects/include/smart_objects/number_schema_item.h b/src/components/smart_objects/include/smart_objects/number_schema_item.h
index 2c64538953..0f3246ef5f 100644
--- a/src/components/smart_objects/include/smart_objects/number_schema_item.h
+++ b/src/components/smart_objects/include/smart_objects/number_schema_item.h
@@ -72,14 +72,18 @@ class TNumberSchemaItem : public CDefaultSchemaItem<NumberType> {
* @return Errors::ERROR
**/
Errors::eType validate(const SmartObject& Object) OVERRIDE;
+
/**
* @brief Validate smart object.
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
- * @return Errors::ERROR
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
+ * @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) OVERRIDE;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
private:
/**
@@ -146,7 +150,9 @@ Errors::eType TNumberSchemaItem<NumberType>::validate(
template <typename NumberType>
Errors::eType TNumberSchemaItem<NumberType>::validate(
- const SmartObject& Object, rpc::ValidationReport* report__) {
+ const SmartObject& Object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
if (!isValidNumberType(Object.getType())) {
SmartType expectedType = (typeid(double) == typeid(Object.getType()))
? SmartType_Double
diff --git a/src/components/smart_objects/include/smart_objects/object_schema_item.h b/src/components/smart_objects/include/smart_objects/object_schema_item.h
index 4c0def558b..4785211694 100644
--- a/src/components/smart_objects/include/smart_objects/object_schema_item.h
+++ b/src/components/smart_objects/include/smart_objects/object_schema_item.h
@@ -37,6 +37,8 @@
#include <set>
#include "utils/macro.h"
+#include "utils/semantic_version.h"
+#include <boost/optional.hpp>
#include "smart_objects/schema_item.h"
#include "smart_objects/schema_item_parameter.h"
@@ -62,7 +64,21 @@ class CObjectSchemaItem : public ISchemaItem {
* @param IsMandatory true if member is mandatory, false
* otherwise. Defaults to true.
**/
- SMember(const ISchemaItemPtr SchemaItem, const bool IsMandatory = true);
+
+ SMember(const ISchemaItemPtr SchemaItem,
+ const bool IsMandatory = true,
+ const std::string& Since = "",
+ const std::string& Until = "",
+ const bool IsDeprecated = false,
+ const bool IsRemoved = false,
+ const std::vector<CObjectSchemaItem::SMember>& history_vector = {});
+ /**
+ * @brief Checks the version a parameter was removed (until)
+ * If the mobile's msg version is greater than or
+ **/
+ bool CheckHistoryFieldVersion(
+ const utils::SemanticVersion& MessageVersion) const;
+
/**
* @brief Member schema item.
**/
@@ -71,6 +87,11 @@ class CObjectSchemaItem : public ISchemaItem {
* @brief true if member is mandatory, false otherwise.
**/
bool mIsMandatory;
+ boost::optional<utils::SemanticVersion> mSince;
+ boost::optional<utils::SemanticVersion> mUntil;
+ bool mIsDeprecated;
+ bool mIsRemoved;
+ std::vector<CObjectSchemaItem::SMember> mHistoryVector;
};
typedef std::map<std::string, SMember> Members;
/**
@@ -89,14 +110,18 @@ class CObjectSchemaItem : public ISchemaItem {
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object) OVERRIDE;
+
/**
* @brief Validate smart object.
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) OVERRIDE;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
/**
* @brief Apply schema.
* @param Object Object to apply schema.
@@ -104,7 +129,9 @@ class CObjectSchemaItem : public ISchemaItem {
* from smart object otherwise contains false.
**/
void applySchema(SmartObject& Object,
- const bool RemoveFakeParameters) OVERRIDE;
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
/**
* @brief Unapply schema.
* @param Object Object to unapply schema.
@@ -136,7 +163,16 @@ class CObjectSchemaItem : public ISchemaItem {
* @brief Removes fake parameters from object.
* @param Object Object to remove fake parameters.
**/
- void RemoveFakeParams(SmartObject& Object);
+ void RemoveFakeParams(SmartObject& Object,
+ const utils::SemanticVersion& MessageVersion);
+
+ /**
+ * @brief Returns the correct schema item based on message version.
+ * @param member Schema member
+ * @param MmessageVersion Semantic Version of mobile message.
+ **/
+ const CObjectSchemaItem::SMember& GetCorrectMember(
+ const SMember& member, const utils::SemanticVersion& messageVersion);
/**
* @brief Map of member name to SMember structure describing the object
diff --git a/src/components/smart_objects/include/smart_objects/schema_item.h b/src/components/smart_objects/include/smart_objects/schema_item.h
index 2b15a1d47a..2e951f7f9f 100644
--- a/src/components/smart_objects/include/smart_objects/schema_item.h
+++ b/src/components/smart_objects/include/smart_objects/schema_item.h
@@ -40,6 +40,7 @@
#include <memory>
#include "utils/macro.h"
+#include "utils/semantic_version.h"
namespace NsSmartDeviceLink {
namespace NsSmartObjects {
@@ -67,11 +68,13 @@ class ISchemaItem {
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
* message if an error occurs
- *
+ * @param MessageVersion to check mobile RPC version against RPC Spec Histor
* @return NsSmartObjects::Errors::eType
**/
- virtual Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__);
+ virtual Errors::eType validate(
+ const SmartObject& Object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion = utils::SemanticVersion());
/**
* @brief Set default value to an object.
@@ -100,7 +103,8 @@ class ISchemaItem {
**/
virtual void applySchema(
NsSmartDeviceLink::NsSmartObjects::SmartObject& Object,
- const bool RemoveFakeParameters);
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion = utils::SemanticVersion());
/**
* @brief Unapply schema.
diff --git a/src/components/smart_objects/include/smart_objects/smart_object.h b/src/components/smart_objects/include/smart_objects/smart_object.h
index 6a2cbdb911..d81e18569f 100644
--- a/src/components/smart_objects/include/smart_objects/smart_object.h
+++ b/src/components/smart_objects/include/smart_objects/smart_object.h
@@ -682,9 +682,12 @@ class SmartObject FINAL {
* @brief Validates object according to attached schema.
*
* @param report__ object for reporting errors during validation
+ * @param messageVersion of the mobile app to check against RPC Spec Schema
* @return Result of validation.
*/
- Errors::eType validate(rpc::ValidationReport* report__);
+ Errors::eType validate(
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion = utils::SemanticVersion());
/**
* @brief Sets new schema
diff --git a/src/components/smart_objects/include/smart_objects/smart_schema.h b/src/components/smart_objects/include/smart_objects/smart_schema.h
index ada5646043..d3fcc0e28d 100644
--- a/src/components/smart_objects/include/smart_objects/smart_schema.h
+++ b/src/components/smart_objects/include/smart_objects/smart_schema.h
@@ -76,11 +76,13 @@ class CSmartSchema FINAL {
*
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
- *
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) const;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& messageVersion =
+ utils::SemanticVersion()) const;
/**
* @brief Set new root schema item.
@@ -97,7 +99,10 @@ class CSmartSchema FINAL {
* @param RemoveFakeParameters contains true if need to remove fake parameters
* from smart object otherwise contains false.
**/
- void applySchema(SmartObject& Object, const bool RemoveFakeParameters);
+ void applySchema(
+ SmartObject& Object,
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion = utils::SemanticVersion());
/**
* @brief The reverse SmartObject conversion using schema.
diff --git a/src/components/smart_objects/include/smart_objects/string_schema_item.h b/src/components/smart_objects/include/smart_objects/string_schema_item.h
index 50418debc0..dcaad364b2 100644
--- a/src/components/smart_objects/include/smart_objects/string_schema_item.h
+++ b/src/components/smart_objects/include/smart_objects/string_schema_item.h
@@ -66,14 +66,18 @@ class CStringSchemaItem : public CDefaultSchemaItem<std::string> {
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object) OVERRIDE;
+
/**
* @brief Validate smart object.
* @param Object Object to validate.
* @param report__ object for reporting errors during validation
+ * @param MessageVersion to check mobile RPC version against RPC Spec History
* @return NsSmartObjects::Errors::eType
**/
Errors::eType validate(const SmartObject& Object,
- rpc::ValidationReport* report__) OVERRIDE;
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion =
+ utils::SemanticVersion()) OVERRIDE;
private:
/**
diff --git a/src/components/smart_objects/src/always_false_schema_item.cc b/src/components/smart_objects/src/always_false_schema_item.cc
index 203ae11236..db16640265 100644
--- a/src/components/smart_objects/src/always_false_schema_item.cc
+++ b/src/components/smart_objects/src/always_false_schema_item.cc
@@ -47,9 +47,12 @@ Errors::eType CAlwaysFalseSchemaItem::validate(const SmartObject& object) {
}
Errors::eType CAlwaysFalseSchemaItem::validate(
- const SmartObject& object, rpc::ValidationReport* report__) {
+ const SmartObject& Object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
report__->set_validation_info("Generic error");
return Errors::ERROR;
}
+
} // namespace NsSmartObjects
} // namespace NsSmartDeviceLink
diff --git a/src/components/smart_objects/src/always_true_schema_item.cc b/src/components/smart_objects/src/always_true_schema_item.cc
index 774bcea121..0a3b8be134 100644
--- a/src/components/smart_objects/src/always_true_schema_item.cc
+++ b/src/components/smart_objects/src/always_true_schema_item.cc
@@ -43,8 +43,10 @@ Errors::eType CAlwaysTrueSchemaItem::validate(const SmartObject& object) {
return Errors::OK;
}
-Errors::eType CAlwaysTrueSchemaItem::validate(const SmartObject& object,
- rpc::ValidationReport* report__) {
+Errors::eType CAlwaysTrueSchemaItem::validate(
+ const SmartObject& Object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
return Errors::OK;
}
diff --git a/src/components/smart_objects/src/array_schema_item.cc b/src/components/smart_objects/src/array_schema_item.cc
index f006267f10..60081c5222 100644
--- a/src/components/smart_objects/src/array_schema_item.cc
+++ b/src/components/smart_objects/src/array_schema_item.cc
@@ -47,8 +47,10 @@ Errors::eType CArraySchemaItem::validate(const SmartObject& Object) {
return validate(Object, &report);
}
-Errors::eType CArraySchemaItem::validate(const SmartObject& Object,
- rpc::ValidationReport* report__) {
+Errors::eType CArraySchemaItem::validate(
+ const SmartObject& Object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
if (SmartType_Array != Object.getType()) {
std::string validation_info = "Incorrect type, expected: " +
SmartObject::typeToString(SmartType_Array) +
@@ -80,8 +82,10 @@ Errors::eType CArraySchemaItem::validate(const SmartObject& Object,
for (size_t i = 0u; i < array_len; ++i) {
std::stringstream strVal;
strVal << i;
- const Errors::eType result = mElementSchemaItem->validate(
- Object.getElement(i), &report__->ReportSubobject(strVal.str()));
+ const Errors::eType result =
+ mElementSchemaItem->validate(Object.getElement(i),
+ &report__->ReportSubobject(strVal.str()),
+ MessageVersion);
if (Errors::OK != result) {
return result;
}
@@ -89,11 +93,14 @@ Errors::eType CArraySchemaItem::validate(const SmartObject& Object,
return Errors::OK;
}
-void CArraySchemaItem::applySchema(SmartObject& Object,
- const bool RemoveFakeParameters) {
+void CArraySchemaItem::applySchema(
+ SmartObject& Object,
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion) {
if (SmartType_Array == Object.getType()) {
for (size_t i = 0U; i < Object.length(); ++i) {
- mElementSchemaItem->applySchema(Object[i], RemoveFakeParameters);
+ mElementSchemaItem->applySchema(
+ Object[i], RemoveFakeParameters, MessageVersion);
}
}
}
diff --git a/src/components/smart_objects/src/object_schema_item.cc b/src/components/smart_objects/src/object_schema_item.cc
index c79b97689d..879c280a67 100644
--- a/src/components/smart_objects/src/object_schema_item.cc
+++ b/src/components/smart_objects/src/object_schema_item.cc
@@ -47,9 +47,57 @@ namespace NsSmartObjects {
CObjectSchemaItem::SMember::SMember()
: mSchemaItem(CAlwaysFalseSchemaItem::create()), mIsMandatory(true) {}
-CObjectSchemaItem::SMember::SMember(const ISchemaItemPtr SchemaItem,
- const bool IsMandatory)
- : mSchemaItem(SchemaItem), mIsMandatory(IsMandatory) {}
+CObjectSchemaItem::SMember::SMember(
+ const ISchemaItemPtr SchemaItem,
+ const bool IsMandatory,
+ const std::string& Since,
+ const std::string& Until,
+ const bool IsDeprecated,
+ const bool IsRemoved,
+ const std::vector<CObjectSchemaItem::SMember>& history_vector)
+ : mSchemaItem(SchemaItem), mIsMandatory(IsMandatory) {
+ if (Since.size() > 0) {
+ utils::SemanticVersion since_struct(Since);
+ if (since_struct.isValid()) {
+ mSince = since_struct;
+ }
+ }
+ if (Until.size() > 0) {
+ utils::SemanticVersion until_struct(Until);
+ if (until_struct.isValid()) {
+ mUntil = until_struct;
+ }
+ }
+ mIsDeprecated = IsDeprecated;
+ mIsRemoved = IsRemoved;
+ mHistoryVector = history_vector;
+}
+
+bool CObjectSchemaItem::SMember::CheckHistoryFieldVersion(
+ const utils::SemanticVersion& MessageVersion) const {
+ if (MessageVersion.isValid()) {
+ if (mSince != boost::none) {
+ if (MessageVersion < mSince.get()) {
+ return false; // Msg version predates `since` field
+ } else {
+ if (mUntil != boost::none && (MessageVersion >= mUntil.get())) {
+ return false; // Msg version newer than `until` field
+ } else {
+ return true; // Mobile msg version falls within specified version
+ // range
+ }
+ }
+ }
+
+ if (mUntil != boost::none && (MessageVersion >= mUntil.get())) {
+ return false; // Msg version newer than `until` field
+ } else {
+ return true; // Mobile msg version falls within specified version range
+ }
+ }
+
+ return true; // Not enough version information. Default true.
+}
std::shared_ptr<CObjectSchemaItem> CObjectSchemaItem::create(
const Members& members) {
@@ -61,8 +109,10 @@ Errors::eType CObjectSchemaItem::validate(const SmartObject& object) {
return validate(object, &report);
}
-Errors::eType CObjectSchemaItem::validate(const SmartObject& object,
- rpc::ValidationReport* report__) {
+Errors::eType CObjectSchemaItem::validate(
+ const SmartObject& object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
if (SmartType_Map != object.getType()) {
std::string validation_info = "Incorrect type, expected: " +
SmartObject::typeToString(SmartType_Map) +
@@ -78,10 +128,12 @@ Errors::eType CObjectSchemaItem::validate(const SmartObject& object,
++it) {
const std::string& key = it->first;
const SMember& member = it->second;
+ const SMember& correct_member = GetCorrectMember(member, MessageVersion);
std::set<std::string>::const_iterator key_it = object_keys.find(key);
if (object_keys.end() == key_it) {
- if (member.mIsMandatory) {
+ if (correct_member.mIsMandatory == true &&
+ correct_member.mIsRemoved == false) {
std::string validation_info = "Missing mandatory parameter: " + key;
report__->set_validation_info(validation_info);
return Errors::MISSING_MANDATORY_PARAMETER;
@@ -89,8 +141,11 @@ Errors::eType CObjectSchemaItem::validate(const SmartObject& object,
continue;
}
const SmartObject& field = object.getElement(key);
- const Errors::eType result =
- member.mSchemaItem->validate(field, &report__->ReportSubobject(key));
+
+ Errors::eType result = Errors::OK;
+ // Check if MessageVersion matches schema version
+ result = correct_member.mSchemaItem->validate(
+ field, &report__->ReportSubobject(key), MessageVersion);
if (Errors::OK != result) {
return result;
}
@@ -99,14 +154,16 @@ Errors::eType CObjectSchemaItem::validate(const SmartObject& object,
return Errors::OK;
}
-void CObjectSchemaItem::applySchema(SmartObject& Object,
- const bool RemoveFakeParameters) {
+void CObjectSchemaItem::applySchema(
+ SmartObject& Object,
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion) {
if (SmartType_Map != Object.getType()) {
return;
}
if (RemoveFakeParameters) {
- RemoveFakeParams(Object);
+ RemoveFakeParams(Object, MessageVersion);
}
SmartObject default_value;
@@ -117,10 +174,12 @@ void CObjectSchemaItem::applySchema(SmartObject& Object,
if (!Object.keyExists(key)) {
if (member.mSchemaItem->setDefaultValue(default_value)) {
Object[key] = default_value;
- member.mSchemaItem->applySchema(Object[key], RemoveFakeParameters);
+ member.mSchemaItem->applySchema(
+ Object[key], RemoveFakeParameters, MessageVersion);
}
} else {
- member.mSchemaItem->applySchema(Object[key], RemoveFakeParameters);
+ member.mSchemaItem->applySchema(
+ Object[key], RemoveFakeParameters, MessageVersion);
}
}
}
@@ -173,21 +232,48 @@ size_t CObjectSchemaItem::GetMemberSize() {
CObjectSchemaItem::CObjectSchemaItem(const Members& members)
: mMembers(members) {}
-void CObjectSchemaItem::RemoveFakeParams(SmartObject& Object) {
+void CObjectSchemaItem::RemoveFakeParams(
+ SmartObject& Object, const utils::SemanticVersion& MessageVersion) {
for (SmartMap::const_iterator it = Object.map_begin();
it != Object.map_end();) {
const std::string& key = it->first;
- if (mMembers.end() == mMembers.find(key)
+ std::map<std::string, SMember>::const_iterator members_it =
+ mMembers.find(key);
+ if (mMembers.end() == members_it
// FIXME(EZamakhov): Remove illegal usage of filed in AM
&&
key.compare(connection_key) != 0 && key.compare(binary_data) != 0 &&
key.compare(app_id) != 0) {
++it;
Object.erase(key);
+
+ } else if (mMembers.end() != members_it &&
+ GetCorrectMember(members_it->second, MessageVersion)
+ .mIsRemoved) {
+ ++it;
+ Object.erase(key);
} else {
- it++;
+ ++it;
+ }
+ }
+}
+
+const CObjectSchemaItem::SMember& CObjectSchemaItem::GetCorrectMember(
+ const SMember& member, const utils::SemanticVersion& messageVersion) {
+ // Check if member is the correct version
+ if (member.CheckHistoryFieldVersion(messageVersion)) {
+ return member;
+ }
+ // Check for history tag items
+ if (!member.mHistoryVector.empty()) {
+ for (uint i = 0; i < member.mHistoryVector.size(); i++) {
+ if (member.mHistoryVector[i].CheckHistoryFieldVersion(messageVersion)) {
+ return member.mHistoryVector[i];
+ }
}
}
+ // Return member as default
+ return member;
}
} // namespace NsSmartObjects
diff --git a/src/components/smart_objects/src/schema_item.cc b/src/components/smart_objects/src/schema_item.cc
index 22735d40d5..ae7f3665bb 100644
--- a/src/components/smart_objects/src/schema_item.cc
+++ b/src/components/smart_objects/src/schema_item.cc
@@ -39,8 +39,10 @@ Errors::eType ISchemaItem::validate(const SmartObject& Object) {
return Errors::ERROR;
}
-Errors::eType ISchemaItem::validate(const SmartObject& object,
- rpc::ValidationReport* report__) {
+Errors::eType ISchemaItem::validate(
+ const SmartObject& object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
return Errors::ERROR;
}
@@ -53,7 +55,8 @@ bool ISchemaItem::hasDefaultValue(SmartObject& Object) {
}
void ISchemaItem::applySchema(SmartObject& Object,
- const bool RemoveFakeParameters) {}
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion) {}
void ISchemaItem::unapplySchema(SmartObject& Object) {}
diff --git a/src/components/smart_objects/src/smart_object.cc b/src/components/smart_objects/src/smart_object.cc
index a0925eef05..691f45f63b 100644
--- a/src/components/smart_objects/src/smart_object.cc
+++ b/src/components/smart_objects/src/smart_object.cc
@@ -878,8 +878,10 @@ Errors::eType SmartObject::validate() {
return validate(&report);
}
-Errors::eType SmartObject::validate(rpc::ValidationReport* report__) {
- return m_schema.validate(*this, report__);
+Errors::eType SmartObject::validate(
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
+ return m_schema.validate(*this, report__, MessageVersion);
}
void SmartObject::setSchema(const CSmartSchema& schema) {
diff --git a/src/components/smart_objects/src/smart_schema.cc b/src/components/smart_objects/src/smart_schema.cc
index 7509ea80f1..3ab94caf85 100644
--- a/src/components/smart_objects/src/smart_schema.cc
+++ b/src/components/smart_objects/src/smart_schema.cc
@@ -45,9 +45,11 @@ Errors::eType CSmartSchema::validate(const SmartObject& Object) const {
return validate(Object, &report);
}
-Errors::eType CSmartSchema::validate(const SmartObject& object,
- rpc::ValidationReport* report__) const {
- return mSchemaItem->validate(object, report__);
+Errors::eType CSmartSchema::validate(
+ const SmartObject& object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) const {
+ return mSchemaItem->validate(object, report__, MessageVersion);
}
void CSmartSchema::setSchemaItem(const ISchemaItemPtr schemaItem) {
@@ -55,8 +57,9 @@ void CSmartSchema::setSchemaItem(const ISchemaItemPtr schemaItem) {
}
void CSmartSchema::applySchema(SmartObject& Object,
- const bool RemoveFakeParameters) {
- mSchemaItem->applySchema(Object, RemoveFakeParameters);
+ const bool RemoveFakeParameters,
+ const utils::SemanticVersion& MessageVersion) {
+ mSchemaItem->applySchema(Object, RemoveFakeParameters, MessageVersion);
}
void CSmartSchema::unapplySchema(SmartObject& Object) {
diff --git a/src/components/smart_objects/src/string_schema_item.cc b/src/components/smart_objects/src/string_schema_item.cc
index b403607ede..f3c39eff8f 100644
--- a/src/components/smart_objects/src/string_schema_item.cc
+++ b/src/components/smart_objects/src/string_schema_item.cc
@@ -51,8 +51,10 @@ Errors::eType CStringSchemaItem::validate(const SmartObject& Object) {
return validate(Object, &report);
}
-Errors::eType CStringSchemaItem::validate(const SmartObject& Object,
- rpc::ValidationReport* report__) {
+Errors::eType CStringSchemaItem::validate(
+ const SmartObject& Object,
+ rpc::ValidationReport* report__,
+ const utils::SemanticVersion& MessageVersion) {
if (SmartType_String != Object.getType()) {
std::string validation_info = "Incorrect type, expected: " +
SmartObject::typeToString(SmartType_String) +
diff --git a/src/components/smart_objects/test/CObjectSchemaItem_test.cc b/src/components/smart_objects/test/CObjectSchemaItem_test.cc
index 523b25a8d8..5a0dcefa10 100644
--- a/src/components/smart_objects/test/CObjectSchemaItem_test.cc
+++ b/src/components/smart_objects/test/CObjectSchemaItem_test.cc
@@ -44,6 +44,7 @@
#include "smart_objects/object_schema_item.h"
#include "formatters/generic_json_formatter.h"
#include "formatters/CSmartFactory.h"
+#include "utils/semantic_version.h"
namespace formatters = NsSmartDeviceLink::NsJSONHandler::Formatters;
namespace smartobj = NsSmartDeviceLink::NsSmartObjects;
@@ -136,6 +137,36 @@ class ObjectSchemaItemTest : public ::testing::Test {
schemaMembersMap[Keys::SUCCESS] =
CObjectSchemaItem::SMember(CBoolSchemaItem::create(), false);
+ // Create fake param that has breaking history changes
+ std::vector<CObjectSchemaItem::SMember> fake_param_history_vector;
+
+ std::shared_ptr<ISchemaItem> fake_param_SchemaItem =
+ CArraySchemaItem::create(
+ CStringSchemaItem::create(TSchemaItemParameter<size_t>(1),
+ TSchemaItemParameter<size_t>(99),
+ TSchemaItemParameter<std::string>()),
+ TSchemaItemParameter<size_t>(1),
+ TSchemaItemParameter<size_t>(100));
+
+ std::shared_ptr<ISchemaItem> fake_param_history_v1_SchemaItem =
+ CArraySchemaItem::create(
+ CStringSchemaItem::create(TSchemaItemParameter<size_t>(1),
+ TSchemaItemParameter<size_t>(99),
+ TSchemaItemParameter<std::string>()),
+ TSchemaItemParameter<size_t>(1),
+ TSchemaItemParameter<size_t>(100));
+
+ fake_param_history_vector.push_back(CObjectSchemaItem::SMember(
+ fake_param_history_v1_SchemaItem, true, "", "4.5.0", false, false));
+ schemaMembersMap["fakeParam"] =
+ CObjectSchemaItem::SMember(fake_param_SchemaItem,
+ false,
+ "4.5.0",
+ "",
+ false,
+ false,
+ fake_param_history_vector);
+
CObjectSchemaItem::Members rootMembersMap;
rootMembersMap[S_PARAMS] = CObjectSchemaItem::SMember(
CObjectSchemaItem::create(paramsMembersMap), true);
@@ -160,6 +191,36 @@ TEST_F(ObjectSchemaItemTest, validation_correct) {
EXPECT_EQ(std::string(""), rpc::PrettyFormat(report));
}
+TEST_F(ObjectSchemaItemTest, validation_correct_with_new_version) {
+ SmartObject obj;
+ obj[S_PARAMS][S_FUNCTION_ID] = 0;
+ obj[S_PARAMS][S_CORRELATION_ID] = 0XFF0;
+ obj[S_PARAMS][S_PROTOCOL_VERSION] = 1;
+ obj[S_MSG_PARAMS][Keys::RESULT_CODE] = 0;
+ obj[S_MSG_PARAMS][Keys::INFO] = "0123456789";
+ obj[S_MSG_PARAMS][Keys::SUCCESS] = true;
+
+ utils::SemanticVersion messageVersion(4, 5, 0);
+ rpc::ValidationReport report("RPC");
+ EXPECT_EQ(Errors::OK, schema_item->validate(obj, &report, messageVersion));
+ EXPECT_EQ(std::string(""), rpc::PrettyFormat(report));
+}
+
+TEST_F(ObjectSchemaItemTest, validation_invalid_data_with_old_version) {
+ SmartObject obj;
+ obj[S_PARAMS][S_FUNCTION_ID] = 0;
+ obj[S_PARAMS][S_CORRELATION_ID] = 0XFF0;
+ obj[S_PARAMS][S_PROTOCOL_VERSION] = 1;
+ obj[S_MSG_PARAMS][Keys::RESULT_CODE] = 0;
+ obj[S_MSG_PARAMS][Keys::INFO] = "0123456789";
+ obj[S_MSG_PARAMS][Keys::SUCCESS] = true;
+
+ utils::SemanticVersion messageVersion(3, 0, 0);
+ rpc::ValidationReport report("RPC");
+ EXPECT_EQ(Errors::MISSING_MANDATORY_PARAMETER,
+ schema_item->validate(obj, &report, messageVersion));
+}
+
TEST_F(ObjectSchemaItemTest, validation_correct_skip_not_mandatory) {
SmartObject obj;
obj[S_PARAMS][S_FUNCTION_ID] = 1;
diff --git a/tools/InterfaceGenerator/MsgVersionGenerate.py b/tools/InterfaceGenerator/MsgVersionGenerate.py
index 86251cd419..4a24a3239f 100644
--- a/tools/InterfaceGenerator/MsgVersionGenerate.py
+++ b/tools/InterfaceGenerator/MsgVersionGenerate.py
@@ -12,14 +12,25 @@ def generate_msg_version(file_name, path_to_storage):
"""
tree = xml.etree.ElementTree.parse(file_name)
root = tree.getroot()
- if (root.tag == "interface" and "version" in root.attrib):
+ if (root.tag == "interface" and "version" and "minVersion" in root.attrib):
check_version_format(root.attrib["version"])
array = (root.attrib["version"]).split(".")
major_version = array[0]
minor_version = array[1]
patch_version = array[2]
- if (major_version.isdigit() and minor_version.isdigit() and patch_version.isdigit):
- data_for_storage = prepare_data_for_storage(major_version, minor_version, patch_version)
+
+ check_minimum_version_format(root.attrib["minVersion"])
+ minimum_version_array = (root.attrib["minVersion"]).split(".")
+ if (len(minimum_version_array) == 2):
+ minimum_version_array.append("0")
+ minimum_major_version = minimum_version_array[0]
+ minimum_minor_version = minimum_version_array[1]
+ minimum_patch_version = minimum_version_array[2]
+
+ if (major_version.isdigit() and minor_version.isdigit() and patch_version.isdigit() and
+ minimum_major_version.isdigit() and minimum_minor_version.isdigit() and minimum_patch_version.isdigit()):
+ data_for_storage = prepare_data_for_storage(major_version, minor_version, patch_version,
+ minimum_major_version, minimum_minor_version, minimum_patch_version)
store_data_to_file(path_to_storage, data_for_storage)
else:
raise RPCBase.ParseError("Attribute version has incorect value in MOBILE_API.xml")
@@ -45,7 +56,16 @@ def check_version_format(version):
raise RPCBase.ParseError("Incorrect format of version please check MOBILE_API.xml. "
"Need format of version major_version.minor_version.patch_version")
-def prepare_data_for_storage(major_version, minor_version, patch_version):
+
+def check_minimum_version_format(version):
+ """Checks correctness of format of version
+ """
+ p = re.compile('\d+\\.\d+\\.\d+|\d+\\.\d+')
+ result = p.match(version)
+ if result == None or (result.end() != len(version)):
+ raise RPCBase.ParseError("Incorrect format of version please check MOBILE_API.xml. "
+ "Need format of minVersion major_version.minor_version or major_version.minor_version.patch_version")
+def prepare_data_for_storage(major_version, minor_version, patch_version, minimum_major_version, minimum_minor_version, minimum_patch_version):
"""Prepares data to store to file.
"""
temp = Template(
@@ -80,8 +100,12 @@ def prepare_data_for_storage(major_version, minor_version, patch_version):
u'''const uint16_t major_version = $m_version;\n'''
u'''const uint16_t minor_version = $min_version;\n'''
u'''const uint16_t patch_version = $p_version;\n'''
+ u'''const uint16_t minimum_major_version = $min_major_version;\n'''
+ u'''const uint16_t minimum_minor_version = $min_minor_version;\n'''
+ u'''const uint16_t minimum_patch_version = $min_patch_version;\n'''
u'''} // namespace application_manager\n'''
u'''#endif // GENERATED_MSG_VERSION_H''')
- data_to_file = temp.substitute(m_version = major_version, min_version = minor_version, p_version = patch_version)
+ data_to_file = temp.substitute(m_version = major_version, min_version = minor_version, p_version = patch_version,
+ min_major_version = minimum_major_version, min_minor_version = minimum_minor_version, min_patch_version = minimum_patch_version)
return data_to_file
diff --git a/tools/InterfaceGenerator/generator/Model.py b/tools/InterfaceGenerator/generator/Model.py
index ee458d934a..e7cce732ed 100755
--- a/tools/InterfaceGenerator/generator/Model.py
+++ b/tools/InterfaceGenerator/generator/Model.py
@@ -124,7 +124,8 @@ class InterfaceItemBase(object):
"""
def __init__(self, name, description=None, design_description=None,
- issues=None, todos=None, platform=None, default_value=None, scope=None):
+ issues=None, todos=None, platform=None, default_value=None, scope=None,
+ since=None, until=None, deprecated=None, removed=None, history=None):
self.name = name
self.description = description if description is not None else []
self.design_description = \
@@ -134,6 +135,11 @@ class InterfaceItemBase(object):
self.platform = platform
self.default_value = default_value
self.scope = scope
+ self.since = since
+ self.until = until
+ self.deprecated = deprecated
+ self.removed = removed
+ self.history = history
class EnumElement(InterfaceItemBase):
@@ -149,13 +155,18 @@ class EnumElement(InterfaceItemBase):
def __init__(self, name, description=None, design_description=None,
issues=None, todos=None, platform=None, internal_name=None,
- value=None):
+ value=None, since=None, until=None, deprecated=None, removed=None, history=None):
super(EnumElement, self).__init__(
name, description=description,
design_description=design_description, issues=issues, todos=todos,
- platform=platform)
+ platform=platform, history=history)
self.internal_name = internal_name
self.value = value
+ self.since = since
+ self.until = until
+ self.deprecated = deprecated
+ self.removed = removed
+
@property
def primary_name(self):
@@ -180,15 +191,19 @@ class Enum(InterfaceItemBase):
def __init__(self, name, description=None, design_description=None,
issues=None, todos=None, platform=None, internal_scope=None,
- elements=None, scope=None):
+ elements=None, scope=None, since=None, until=None, deprecated=None, removed=None, history=None):
super(Enum, self).__init__(
name, description=description,
design_description=design_description, issues=issues, todos=todos,
- platform=platform, scope=scope)
+ platform=platform, scope=scope, history=history)
self.internal_scope = internal_scope
self.elements = \
elements if elements is not None else collections.OrderedDict()
+ self.since = since
+ self.until = until
+ self.deprecated = deprecated
+ self.removed = removed
class EnumSubset(InterfaceItemBase):
@@ -204,15 +219,19 @@ class EnumSubset(InterfaceItemBase):
def __init__(self, name, enum, description=None, design_description=None,
issues=None, todos=None, platform=None,
- allowed_elements=None):
+ allowed_elements=None, since=None, until=None, deprecated=None, removed=None, history=None):
super(EnumSubset, self).__init__(
name, description=description,
design_description=design_description, issues=issues, todos=todos,
- platform=platform)
+ platform=platform, history=history)
self.enum = enum
self.allowed_elements = \
allowed_elements if allowed_elements is not None else {}
+ self.since = since
+ self.until = until
+ self.deprecated = deprecated
+ self.removed = removed
class Param(InterfaceItemBase):
@@ -229,15 +248,20 @@ class Param(InterfaceItemBase):
def __init__(self, name, param_type, description=None,
design_description=None, issues=None, todos=None,
- platform=None, is_mandatory=True, default_value=None, scope=None):
+ platform=None, is_mandatory=True, default_value=None, scope=None,
+ since=None, until=None, deprecated=None, removed=None, history=None):
super(Param, self).__init__(
name, description=description,
design_description=design_description, issues=issues, todos=todos,
- platform=platform, default_value=default_value, scope=scope)
+ platform=platform, default_value=default_value, scope=scope, history=history)
self.is_mandatory = is_mandatory
self.param_type = param_type
self.default_value = default_value
+ self.since = since
+ self.until = until
+ self.deprecated = deprecated
+ self.removed=removed
class FunctionParam(Param):
@@ -251,11 +275,13 @@ class FunctionParam(Param):
def __init__(self, name, param_type, description=None,
design_description=None, issues=None, todos=None,
- platform=None, is_mandatory=True, default_value=None, scope=None):
+ platform=None, is_mandatory=True, default_value=None, scope=None,
+ since=None, until=None, deprecated=None, removed=None, history=None):
super(FunctionParam, self).__init__(
name, param_type=param_type, description=description,
design_description=design_description, issues=issues, todos=todos,
- platform=platform, is_mandatory=is_mandatory, default_value=default_value, scope=scope)
+ platform=platform, is_mandatory=is_mandatory, default_value=default_value,
+ scope=scope, since=since, until=until, deprecated=deprecated, removed=removed, history=history)
self.default_value = default_value
@@ -270,11 +296,13 @@ class Struct(InterfaceItemBase):
"""
def __init__(self, name, description=None, design_description=None,
- issues=None, todos=None, platform=None, members=None, scope=None):
+ issues=None, todos=None, platform=None, members=None, scope=None,
+ since=None, until=None, deprecated=None, removed=None, history=None):
super(Struct, self).__init__(
name, description=description,
design_description=design_description, issues=issues, todos=todos,
- platform=platform, scope=scope)
+ platform=platform, scope=scope, since=since, until=until,
+ deprecated=deprecated, removed=removed, history=history)
self.members = \
members if members is not None else collections.OrderedDict()
@@ -293,11 +321,11 @@ class Function(InterfaceItemBase):
def __init__(self, name, function_id, message_type, description=None,
design_description=None, issues=None, todos=None,
- platform=None, params=None, scope=None):
+ platform=None, params=None, scope=None, since=None, until=None, deprecated=None, removed=None, history=None):
super(Function, self).__init__(
name, description=description,
design_description=design_description, issues=issues, todos=todos,
- platform=platform, scope=scope)
+ platform=platform, scope=scope, since=since, until=until, deprecated=deprecated, removed=removed, history=history)
self.function_id = function_id
self.message_type = message_type
diff --git a/tools/InterfaceGenerator/generator/generators/SmartFactoryBase.py b/tools/InterfaceGenerator/generator/generators/SmartFactoryBase.py
index 0c500dee8e..6546b0ea89 100755
--- a/tools/InterfaceGenerator/generator/generators/SmartFactoryBase.py
+++ b/tools/InterfaceGenerator/generator/generators/SmartFactoryBase.py
@@ -505,7 +505,6 @@ class CodeGenerator(object):
String with structs implementation source code.
"""
-
processed_enums = []
return self._struct_impl_template.substitute(
namespace=namespace,
@@ -518,9 +517,46 @@ class CodeGenerator(object):
schema_items_decl=self._gen_schema_items_decls(
struct.members.values()),
schema_item_fill=self._gen_schema_items_fill(
- struct.members.values())),
+ struct.members.values(), struct.since, struct.until, struct.deprecated, struct.removed)),
1))
+
+ def _enum_has_history_present(self, enum):
+ '''
+ Check if any elements in an enum has history signature
+ '''
+ for element in enum.param_type.elements.values():
+ if ( element.history is not None or
+ element.since is not None or
+ element.until is not None or
+ element.removed is not None ):
+ return True
+ return False
+
+ def _element_has_history_present(self, element):
+ '''
+ Check if a specific element has a history signature
+ '''
+ if ( element.history is not None or
+ element.since is not None or
+ element.until is not None or
+ element.removed is not None ):
+ return True
+ return False
+
+ def _enum_param_type_has_history_present(self, param_type):
+ '''
+ Check if any elements in an enum has history signature
+ '''
+ for element in param_type.elements.values():
+ if ( element.history is not None or
+ element.since is not None or
+ element.until is not None or
+ element.removed is not None ):
+ return True
+ return False
+
+
def _gen_schema_loc_decls(self, members, processed_enums):
"""Generate local declarations of variables for schema.
@@ -540,6 +576,7 @@ class CodeGenerator(object):
for member in members:
if type(member.param_type) is Model.Enum and \
member.param_type.name not in processed_enums:
+ has_history = self._enum_has_history_present(member)
local_var = self._gen_schema_loc_emum_var_name(
member.param_type)
result = u"\n".join(
@@ -555,6 +592,46 @@ class CodeGenerator(object):
enum=member.param_type.name,
value=x.primary_name)
for x in member.param_type.elements.values()])])
+
+ if has_history == True:
+ history_result = u"\n"
+ history_result += self._impl_code_loc_decl_enum_history_set_template.substitute(
+ type=member.param_type.name)
+ history_result += u"\n"
+ history_result += u"\n".join(
+ [self._impl_code_loc_decl_enum_history_set_value_init_template.substitute(
+ enum=member.param_type.name,
+ value=x.primary_name)
+ for x in member.param_type.elements.values() if self._element_has_history_present(x)])
+ history_result += u"\n"
+ history_map_result = []
+
+ for x in member.param_type.elements.values():
+ if self._element_has_history_present(x):
+ history_map_result.append(
+ self._impl_code_loc_decl_enum_history_set_insert_template.
+ substitute(
+ enum=member.param_type.name,
+ value=x.primary_name,
+ since=x.since if x.since is not None else "",
+ until=x.until if x.until is not None else "",
+ removed=x.removed if x.removed is not None else u"false"))
+ if(x.history is not None) :
+ history_list = x.history
+ for item in history_list:
+ history_map_result.append(
+ self._impl_code_loc_decl_enum_history_set_insert_template.
+ substitute(
+ enum=member.param_type.name,
+ value=x.primary_name,
+ since=item.since if item.since is not None else "",
+ until=item.until if item.until is not None else "",
+ removed=item.removed if item.removed is not None else u"false"))
+
+ history_result += u"\n".join(history_map_result)
+ result += "\n"
+ result += history_result
+
processed_enums.append(member.param_type.name)
result = u"".join([result, u"\n\n"]) if result else u""
elif type(member.param_type) is Model.EnumSubset:
@@ -599,10 +676,40 @@ class CodeGenerator(object):
"""
- result = u"\n\n".join(
- [self._gen_schema_item_decl(x) for x in members])
+ result_array = []
+ for x in members:
+ result_array.append(self._gen_schema_item_decl(x))
+ count = 0
+ if x.history is not None:
+ history_list = x.history
+ for item in history_list:
+ item.name += "_history_v" + str(len(history_list)-count)
+ result_array.append(self._gen_schema_item_decl(item))
+ count += 1
+ result_array.append(self._gen_history_vector_decl(history_list, x.name))
+
+ result = u"\n\n".join(result_array)
+ return result
+
+ def _gen_history_vector_decl(self, history_list, name):
+ """Generate History Vector Declaration.
+
+ Generates the declaration and initialization
+ of a vector of schema items
+
+ Arguments:
+ history_list -> list of history items
+ name -> name of parent parameter name
+
+ Returns:
+ String with history array code.
+ """
+ result_array = []
+ result_array.append(self._impl_code_shared_ptr_vector_template.substitute(var_name = name))
+ result = u"\n".join(result_array)
+ return result
+
- return u"".join([result, u"\n\n"]) if result else u""
def _gen_schema_item_decl(self, member):
"""Generate schema item declaration.
@@ -696,16 +803,30 @@ class CodeGenerator(object):
code = self._impl_code_struct_item_template.substitute(
name=param.name)
elif type(param) is Model.Enum:
- code = self._impl_code_enum_item_template.substitute(
- type=param.name,
- params=u"".join(
- [self._gen_schema_loc_emum_var_name(param),
- u", ",
- self._gen_schema_item_param_values(
- [[u"".join([param.name, u"::eType"]),
- u"".join([param.name, u"::",
- default_value.primary_name]) if
- default_value is not None else None]])]))
+ if self._enum_param_type_has_history_present(param):
+ code = self._impl_code_enum_item_with_history_template.substitute(
+ type=param.name,
+ params=u"".join(
+ [self._gen_schema_loc_emum_var_name(param),
+ u", ",
+ self._impl_gen_schema_enum_history_map_template.substitute(name=param.name),
+ u", ",
+ self._gen_schema_item_param_values(
+ [[u"".join([param.name, u"::eType"]),
+ u"".join([param.name, u"::",
+ default_value.primary_name]) if
+ default_value is not None else None]])]))
+ else:
+ code = self._impl_code_enum_item_template.substitute(
+ type=param.name,
+ params=u"".join(
+ [self._gen_schema_loc_emum_var_name(param),
+ u", ",
+ self._gen_schema_item_param_values(
+ [[u"".join([param.name, u"::eType"]),
+ u"".join([param.name, u"::",
+ default_value.primary_name]) if
+ default_value is not None else None]])]))
elif type(param) is Model.EnumSubset:
code = self._impl_code_enum_item_template.substitute(
type=param.enum.name,
@@ -746,7 +867,7 @@ class CodeGenerator(object):
return result
- def _gen_schema_items_fill(self, members):
+ def _gen_schema_items_fill(self, members=None, since=None, until=None, deprecated=None, removed=None):
"""Generate schema items fill code.
Generates source code that fills new schema with items.
@@ -758,10 +879,16 @@ class CodeGenerator(object):
String with function schema items fill code.
"""
-
- result = u"\n".join(
- [self._gen_schema_item_fill(x) for x in members])
-
+ result_array = []
+ for x in members:
+ #If history, create Smember History vector first
+ if x.history is not None:
+ history_list = x.history
+ for item in history_list:
+ result_array.append(self._gen_history_vector_item_fill(item, x.name))
+ result_array.append(self._gen_schema_item_fill(x, since, until, deprecated, removed))
+
+ result = u"\n".join(result_array)
return u"".join([result, u"\n\n"]) if result else u""
def _gen_schema_params_fill(self, message_type_name):
@@ -781,7 +908,34 @@ class CodeGenerator(object):
raise GenerateError("Unexpected call to the unimplemented function.")
- def _gen_schema_item_fill(self, member):
+ def _check_member_history(self, member):
+ """
+ Checks set of rules that history items are valid
+ Raises error if rules are violated
+ """
+ if (member.since is None and
+ member.until is None and
+ member.deprecated is None and
+ member.removed is None and
+ member.history is None):
+ return
+ if (member.history is not None and member.since is None):
+ raise GenerateError("Error: Missing since version parameter for " + member.name)
+ if (member.until is not None):
+ raise GenerateError("Error: Until should only exist in history tag for " + member.name)
+ if (member.history is None):
+ if(member.until is not None or
+ member.deprecated is not None or
+ member.removed is not None):
+ raise GenerateError("Error: No history present for " + member.name)
+ if (member.deprecated is not None and member.removed is not None):
+ raise GenerateError("Error: Deprecated and removed should not be present together for " + member.name)
+ if(member.history is not None):
+ for item in member.history:
+ if item.since is None or item.until is None:
+ raise GenerateError("Error: History items require since and until parameters for " + member.name)
+
+ def _gen_schema_item_fill(self, member, since, until, deprecated, removed):
"""Generate schema item fill code.
Generates source code that fills new schema with item.
@@ -793,11 +947,62 @@ class CodeGenerator(object):
String with schema item fill code.
"""
+ self._check_member_history(member)
+
+ if (since is not None or
+ member.since is not None):
+ if member.history is not None:
+ return self._impl_code_item_fill_template_with_version_and_history_vector.substitute(
+ name=member.name,
+ var_name=self._gen_schema_item_var_name(member),
+ is_mandatory=u"true" if member.is_mandatory is True else u"false",
+ since=member.since if member.since is not None else since if since is not None else "",
+ until=member.until if member.until is not None else until if until is not None else "",
+ deprecated=member.deprecated if member.deprecated is not None else deprecated if deprecated is not None else u"false",
+ removed=member.removed if member.removed is not None else removed if removed is not None else u"false",
+ vector_name=member.name)
+ else:
+ return self._impl_code_item_fill_template_with_version.substitute(
+ name=member.name,
+ var_name=self._gen_schema_item_var_name(member),
+ is_mandatory=u"true" if member.is_mandatory is True else u"false",
+ since=member.since if member.since is not None else since if since is not None else "",
+ until=member.until if member.until is not None else until if until is not None else "",
+ deprecated=member.deprecated if member.deprecated is not None else deprecated if deprecated is not None else u"false",
+ removed=member.removed if member.removed is not None else removed if removed is not None else u"false")
+ else:
+ return self._impl_code_item_fill_template.substitute(
+ name=member.name,
+ var_name=self._gen_schema_item_var_name(member),
+ is_mandatory=u"true" if member.is_mandatory is True else u"false")
- return self._impl_code_item_fill_template.substitute(
- name=member.name,
- var_name=self._gen_schema_item_var_name(member),
- is_mandatory=u"true" if member.is_mandatory is True else u"false")
+ def _gen_history_vector_item_fill(self, member, vector_name):
+ """Generate schema item fill code.
+
+ Generates source code that fills history vector with item.
+
+ Keyword arguments:
+ member -- struct member/function parameter to process.
+
+ Returns:
+ String with schema item fill code.
+
+ """
+
+ if (member.since is not None or
+ member.until is not None or
+ member.deprecated is not None or
+ member.removed is not None):
+ return self._impl_code_append_history_vector_template.substitute(
+ vector_name=vector_name,
+ name=member.name,
+ mandatory=u"true" if member.is_mandatory is True else u"false",
+ since=member.since if member.since is not None else "",
+ until=member.until if member.until is not None else "",
+ deprecated=member.deprecated if member.deprecated is not None else u"false",
+ removed=member.removed if member.removed is not None else u"false")
+ else:
+ print "Warning! History item does not have any version history. Omitting %s" % member.name
@staticmethod
def _gen_schema_item_var_name(member):
@@ -899,7 +1104,7 @@ class CodeGenerator(object):
schema_items_decl=self._gen_schema_items_decls(
function.params.values()),
schema_item_fill=self._gen_schema_items_fill(
- function.params.values()),
+ function.params.values(), function.since, function.until, function.deprecated, function.removed),
schema_params_fill=self._gen_schema_params_fill(
function.message_type.name)),
1))
@@ -1498,13 +1703,32 @@ class CodeGenerator(object):
_impl_code_loc_decl_enum_template = string.Template(
u'''std::set<${type}::eType> ${var_name};''')
+ _impl_code_loc_decl_enum_history_set_template = string.Template(
+ u'''std::map<${type}::eType, std::vector<ElementSignature>> ${type}_element_signatures;''')
+
_impl_code_loc_decl_enum_insert_template = string.Template(
u'''${var_name}.insert(${enum}::${value});''')
+ _impl_code_loc_decl_enum_history_set_value_init_template = string.Template(
+ u'''${enum}_element_signatures[${enum}::${value}] = std::vector<ElementSignature>();'''
+ )
+
+ _impl_code_loc_decl_enum_history_set_insert_template = string.Template(
+ u'''${enum}_element_signatures[${enum}::${value}].push_back(ElementSignature("${since}", "${until}", ${removed}));''')
+
+ _impl_gen_schema_enum_history_map_template = string.Template(
+ u'''${name}_element_signatures''')
+
_impl_code_item_decl_temlate = string.Template(
u'''${comment}'''
u'''std::shared_ptr<ISchemaItem> ${var_name} = ${item_decl};''')
+ _impl_code_shared_ptr_vector_template = string.Template(
+ u'''std::vector<CObjectSchemaItem::SMember> ${var_name}_history_vector;''')
+
+ _impl_code_append_history_vector_template = string.Template(
+ u'''${vector_name}_history_vector.push_back(CObjectSchemaItem::SMember(${name}_SchemaItem, ${mandatory}, "${since}", "${until}", ${deprecated}, ${removed}));''')
+
_impl_code_integer_item_template = string.Template(
u'''TNumberSchemaItem<${type}>::create(${params})''')
@@ -1524,6 +1748,9 @@ class CodeGenerator(object):
_impl_code_enum_item_template = string.Template(
u'''TEnumSchemaItem<${type}::eType>::create(${params})''')
+ _impl_code_enum_item_with_history_template = string.Template(
+ u'''TEnumSchemaItem<${type}::eType>::createWithSignatures(${params})''')
+
_impl_code_item_param_value_template = string.Template(
u'''TSchemaItemParameter<$type>($value)''')
@@ -1531,6 +1758,14 @@ class CodeGenerator(object):
u'''schema_members["${name}"] = CObjectSchemaItem::'''
u'''SMember(${var_name}, ${is_mandatory});''')
+ _impl_code_item_fill_template_with_version = string.Template(
+ u'''schema_members["${name}"] = CObjectSchemaItem::'''
+ u'''SMember(${var_name}, ${is_mandatory}, "${since}", "${until}", ${deprecated}, ${removed});''')
+
+ _impl_code_item_fill_template_with_version_and_history_vector = string.Template(
+ u'''schema_members["${name}"] = CObjectSchemaItem::'''
+ u'''SMember(${var_name}, ${is_mandatory}, "${since}", "${until}", ${deprecated}, ${removed}, ${vector_name}_history_vector);''')
+
_function_impl_template = string.Template(
u'''CSmartSchema $namespace::$class_name::'''
u'''InitFunction_${function_id}_${message_type}(\n'''
diff --git a/tools/InterfaceGenerator/generator/parsers/RPCBase.py b/tools/InterfaceGenerator/generator/parsers/RPCBase.py
index 4853916dad..21f07e6ac5 100755
--- a/tools/InterfaceGenerator/generator/parsers/RPCBase.py
+++ b/tools/InterfaceGenerator/generator/parsers/RPCBase.py
@@ -6,7 +6,7 @@ Contains base parser for SDLRPC v1/v2 and JSON RPC XML format.
import collections
import xml.etree.ElementTree
-
+import re
from generator import Model
@@ -203,16 +203,35 @@ class Parser(object):
internal_scope = None
scope = None
+ since = None
+ until = None
+ deprecated = None
+ removed = None
+ result = None
for attribute in attributes:
if attribute == "internal_scope":
internal_scope = attributes[attribute]
elif attribute == "scope":
scope = attributes[attribute]
+ elif attribute == "since":
+ result = self._parse_version(attributes[attribute])
+ since = result
+ elif attribute == "until":
+ result = self._parse_version(attributes[attribute])
+ until = result
+ elif attribute == "deprecated":
+ deprecated = attributes[attribute]
+ elif attribute == "removed":
+ removed = attributes[attribute]
else:
raise ParseError("Unexpected attribute '" + attribute +
"' in enum '" + params["name"] + "'")
params["internal_scope"] = internal_scope
params["scope"] = scope
+ params["since"] = since
+ params["until"] = until
+ params["deprecated"] = deprecated
+ params["removed"] = removed
elements = collections.OrderedDict()
for subelement in subelements:
@@ -236,13 +255,32 @@ class Parser(object):
params, subelements, attrib = self._parse_base_item(element, prefix)
scope = None
+ since = None
+ until = None
+ deprecated = None
+ removed = None
+ result = None
for attribute in attrib:
if attribute == "scope":
scope = attrib[attribute]
+ elif attribute == "since":
+ result = self._parse_version(attrib[attribute])
+ since = result
+ elif attribute == "until":
+ result = self._parse_version(attrib[attribute])
+ until = result
+ elif attribute == "deprecated":
+ deprecated = attributes[attribute]
+ elif attribute == "removed":
+ removed = attrib[attribute]
else:
raise ParseError("Unexpected attribute '" + attribute +
"' in struct '" + params["name"] + "'")
params["scope"] = scope
+ params["since"] = since
+ params["until"] = until
+ params["deprecated"] = deprecated
+ params["removed"] = removed
members = collections.OrderedDict()
for subelement in subelements:
@@ -271,13 +309,32 @@ class Parser(object):
attributes)
scope = None
+ since = None
+ until = None
+ deprecated = None
+ removed = None
+ result = None
for attribute in attributes:
if attribute == "scope":
scope = attributes[attribute]
+ elif attribute == "since":
+ result = self._parse_version(attributes[attribute])
+ since = result
+ elif attribute == "until":
+ result = self._parse_version(attributes[attribute])
+ until = result
+ elif attribute == "deprecated":
+ deprecated = attributes[attribute]
+ elif attribute == "removed":
+ removed = attributes[attribute]
params["function_id"] = function_id
params["message_type"] = message_type
params["scope"] = scope
+ params["since"] = since
+ params["until"] = until
+ params["deprecated"] = deprecated
+ params["removed"] = removed
function_params = collections.OrderedDict()
for subelement in subelements:
@@ -359,6 +416,8 @@ class Parser(object):
issues = []
todos = []
subelements = []
+ history = None
+ warnings = []
if "name" not in element.attrib:
raise ParseError("Name is not specified for " + element.tag)
@@ -379,6 +438,12 @@ class Parser(object):
todos.append(self._parse_simple_element(subelement))
elif subelement.tag == "issue":
issues.append(self._parse_issue(subelement))
+ elif subelement.tag == "history":
+ if history is not None:
+ raise ParseError("Elements can only have one history tag: " + element.tag)
+ history = self._parse_history(subelement, prefix, element)
+ elif subelement.tag == "warning":
+ warnings.append(self._parse_simple_element(subelement))
else:
subelements.append(subelement)
@@ -386,6 +451,7 @@ class Parser(object):
params["design_description"] = design_description
params["issues"] = issues
params["todos"] = todos
+ params["history"] = history
return params, subelements, attrib
@@ -443,6 +509,11 @@ class Parser(object):
internal_name = None
value = None
+ since = None
+ until = None
+ deprecated = None
+ removed = None
+ result = None
for attribute in attributes:
if attribute == "internal_name":
internal_name = attributes[attribute]
@@ -452,9 +523,22 @@ class Parser(object):
except:
raise ParseError("Invalid value for enum element: '" +
attributes[attribute] + "'")
+ elif attribute == "since":
+ result = self._parse_version(attributes[attribute])
+ since = result
+ elif attribute == "until":
+ result = self._parse_version(attributes[attribute])
+ until = result
+ elif attribute == "deprecated":
+ deprecated = attributes[attribute]
+ elif attribute == "removed":
+ removed = attributes[attribute]
params["internal_name"] = internal_name
params["value"] = value
-
+ params["since"] = since
+ params["until"] = until
+ params["deprecated"] = deprecated
+ params["removed"] = removed
# Magic usage is correct
# pylint: disable=W0142
return Model.EnumElement(**params)
@@ -548,6 +632,25 @@ class Parser(object):
"""
params, subelements, attrib = self._parse_base_item(element, "")
+ since_version = self._extract_attrib(attrib, "since")
+ if since_version is not None:
+ result = self._parse_version(since_version)
+ params["since"] = result
+
+ until_version = self._extract_attrib(attrib, "until")
+ if until_version is not None:
+ result = self._parse_version(until_version)
+ params["until"] = result
+
+ deprecated = self._extract_attrib(attrib, "deprecated")
+ if deprecated is not None:
+ params["deprecated"] = deprecated
+
+ removed = self._extract_attrib(attrib, "removed")
+ if removed is not None:
+ params["removed"] = removed
+
+
is_mandatory = self._extract_attrib(attrib, "mandatory")
if is_mandatory is None:
raise ParseError("'mandatory' is not specified for parameter '" +
@@ -765,3 +868,48 @@ class Parser(object):
print ("Ignoring attribute '" +
name + "'")
return True
+
+ def _parse_version(self, version):
+ """
+ Validates if a version supplied is in the correct
+ format of Major.Minor.Patch. If Major.Minor format
+ is supplied, a patch version of 0 will be added to
+ the end.
+ """
+ p = re.compile('\d+\\.\d+\\.\d+|\d+\\.\d+')
+ result = p.match(version)
+ if result == None or (result.end() != len(version)):
+ raise RPCBase.ParseError("Incorrect format of version please check MOBILE_API.xml. "
+ "Need format of major_version.minor_version or major_version.minor_version.patch_version")
+
+ version_array = version.split(".")
+ if (len(version_array) == 2):
+ version_array.append("0")
+ dot_str = "."
+ return dot_str.join(version_array)
+
+ def _parse_history(self, history, prefix, parent):
+ if history.tag != "history":
+ raise ParseError("Invalid history tag: " + interface.tag)
+
+ items = []
+
+ for subelement in history:
+ if subelement.tag == "enum" and parent.tag == "enum":
+ items.append(self._parse_enum(subelement, prefix))
+ elif subelement.tag == "element" and parent.tag == "element":
+ items.append(self._parse_enum_element(subelement))
+ elif subelement.tag == "description" and parent.tag == "description":
+ items.append(self._parse_simple_element(subelement))
+ elif subelement.tag == "struct" and parent.tag == "struct":
+ items.append(self._parse_struct(subelement, prefix))
+ elif subelement.tag == "param" and parent.tag == "param":
+ items.append(self._parse_function_param(subelement, prefix))
+ elif subelement.tag == "function" and parent.tag == "function":
+ items.append(self.__parse_function(subelement, prefix))
+ else:
+ raise ParseError("A history tag must be nested within the element it notes the history for. Fix item: '" +
+ parent.attrib["name"] + "'")
+
+ return items
+