# HG changeset patch # User Sebastien Jodogne # Date 1537277898 -7200 # Node ID 807169f85ba93ceeb2142532a2ee26377441aae4 # Parent a0b729ac0549715f631022997c00d402f9def3e6 OrthancPluginGetPeerUserProperty() diff -r a0b729ac0549 -r 807169f85ba9 Core/HttpClient.cpp --- a/Core/HttpClient.cpp Mon Sep 17 12:08:49 2018 +0200 +++ b/Core/HttpClient.cpp Tue Sep 18 15:38:18 2018 +0200 @@ -401,7 +401,7 @@ SetUrl(service.GetUrl() + uri); - for (WebServiceParameters::HttpHeaders::const_iterator + for (WebServiceParameters::Dictionary::const_iterator it = service.GetHttpHeaders().begin(); it != service.GetHttpHeaders().end(); ++it) { diff -r a0b729ac0549 -r 807169f85ba9 Core/WebServiceParameters.cpp --- a/Core/WebServiceParameters.cpp Mon Sep 17 12:08:49 2018 +0200 +++ b/Core/WebServiceParameters.cpp Tue Sep 18 15:38:18 2018 +0200 @@ -58,6 +58,20 @@ static const char* KEY_USERNAME = "Username"; + static bool IsReservedKey(const std::string& key) + { + return (key == KEY_CERTIFICATE_FILE || + key == KEY_CERTIFICATE_KEY_FILE || + key == KEY_CERTIFICATE_KEY_PASSWORD || + key == KEY_HTTP_HEADERS || + key == KEY_PASSWORD || + key == KEY_PKCS11 || + key == KEY_URL || + key == KEY_URL_2 || + key == KEY_USERNAME); + } + + WebServiceParameters::WebServiceParameters() : pkcs11Enabled_(false) { @@ -237,6 +251,7 @@ pkcs11Enabled_ = false; } + headers_.clear(); if (peer.isMember(KEY_HTTP_HEADERS)) @@ -263,6 +278,27 @@ } } } + + + userProperties_.clear(); + + const Json::Value::Members members = peer.getMemberNames(); + + for (Json::Value::Members::const_iterator it = members.begin(); + it != members.end(); ++it) + { + if (!IsReservedKey(*it)) + { + if (peer[*it].type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + else + { + userProperties_[*it] = peer[*it].asString(); + } + } + } } @@ -298,7 +334,7 @@ { target.clear(); - for (HttpHeaders::const_iterator it = headers_.begin(); + for (Dictionary::const_iterator it = headers_.begin(); it != headers_.end(); ++it) { target.insert(it->first); @@ -309,7 +345,7 @@ bool WebServiceParameters::LookupHttpHeader(std::string& value, const std::string& key) const { - HttpHeaders::const_iterator found = headers_.find(key); + Dictionary::const_iterator found = headers_.find(key); if (found == headers_.end()) { @@ -323,13 +359,58 @@ } + void WebServiceParameters::AddUserProperty(const std::string& key, + const std::string& value) + { + if (IsReservedKey(key)) + { + LOG(ERROR) << "Cannot use this reserved key to name an user property: " << key; + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + else + { + userProperties_[key] = value; + } + } + + + void WebServiceParameters::ListUserProperties(std::set& target) const + { + target.clear(); + + for (Dictionary::const_iterator it = userProperties_.begin(); + it != userProperties_.end(); ++it) + { + target.insert(it->first); + } + } + + + bool WebServiceParameters::LookupUserProperty(std::string& value, + const std::string& key) const + { + Dictionary::const_iterator found = userProperties_.find(key); + + if (found == userProperties_.end()) + { + return false; + } + else + { + value = found->second; + return true; + } + } + + bool WebServiceParameters::IsAdvancedFormatNeeded() const { return (!certificateFile_.empty() || !certificateKeyFile_.empty() || !certificateKeyPassword_.empty() || pkcs11Enabled_ || - !headers_.empty()); + !headers_.empty() || + !userProperties_.empty()); } @@ -373,11 +454,17 @@ value[KEY_PKCS11] = pkcs11Enabled_; value[KEY_HTTP_HEADERS] = Json::objectValue; - for (HttpHeaders::const_iterator it = headers_.begin(); + for (Dictionary::const_iterator it = headers_.begin(); it != headers_.end(); ++it) { value[KEY_HTTP_HEADERS][it->first] = it->second; } + + for (Dictionary::const_iterator it = userProperties_.begin(); + it != userProperties_.end(); ++it) + { + value[it->first] = it->second; + } } else { diff -r a0b729ac0549 -r 807169f85ba9 Core/WebServiceParameters.h --- a/Core/WebServiceParameters.h Mon Sep 17 12:08:49 2018 +0200 +++ b/Core/WebServiceParameters.h Tue Sep 18 15:38:18 2018 +0200 @@ -47,7 +47,7 @@ class WebServiceParameters { public: - typedef std::map HttpHeaders; + typedef std::map Dictionary; private: std::string url_; @@ -57,7 +57,8 @@ std::string certificateKeyFile_; std::string certificateKeyPassword_; bool pkcs11Enabled_; - HttpHeaders headers_; + Dictionary headers_; + Dictionary userProperties_; void FromSimpleFormat(const Json::Value& peer); @@ -135,7 +136,7 @@ headers_.clear(); } - const HttpHeaders& GetHttpHeaders() const + const Dictionary& GetHttpHeaders() const { return headers_; } @@ -145,6 +146,24 @@ bool LookupHttpHeader(std::string& value, const std::string& key) const; + void AddUserProperty(const std::string& key, + const std::string& value); + + void ClearUserProperties() + { + userProperties_.clear(); + } + + const Dictionary& GetUserProperties() const + { + return userProperties_; + } + + void ListUserProperties(std::set& target) const; + + bool LookupUserProperty(std::string& value, + const std::string& key) const; + bool IsAdvancedFormatNeeded() const; void Unserialize(const Json::Value& peer); diff -r a0b729ac0549 -r 807169f85ba9 Plugins/Engine/OrthancPlugins.cpp --- a/Plugins/Engine/OrthancPlugins.cpp Mon Sep 17 12:08:49 2018 +0200 +++ b/Plugins/Engine/OrthancPlugins.cpp Tue Sep 18 15:38:18 2018 +0200 @@ -2872,6 +2872,37 @@ } } + case _OrthancPluginService_GetPeerUserProperty: + { + const _OrthancPluginGetPeerProperty& p = + *reinterpret_cast(parameters); + + if (p.peers == NULL || + p.userProperty == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + else + { + const WebServiceParameters::Dictionary& properties = + reinterpret_cast(p.peers)->GetPeerParameters(p.peerIndex).GetUserProperties(); + + WebServiceParameters::Dictionary::const_iterator found = + properties.find(p.userProperty); + + if (found == properties.end()) + { + *(p.target) = NULL; + } + else + { + *(p.target) = found->second.c_str(); + } + + return true; + } + } + case _OrthancPluginService_CallPeerApi: CallPeerApi(parameters); return true; diff -r a0b729ac0549 -r 807169f85ba9 Plugins/Include/orthanc/OrthancCPlugin.h --- a/Plugins/Include/orthanc/OrthancCPlugin.h Mon Sep 17 12:08:49 2018 +0200 +++ b/Plugins/Include/orthanc/OrthancCPlugin.h Tue Sep 18 15:38:18 2018 +0200 @@ -527,6 +527,7 @@ _OrthancPluginService_GetPeerName = 8004, _OrthancPluginService_GetPeerUrl = 8005, _OrthancPluginService_CallPeerApi = 8006, + _OrthancPluginService_GetPeerUserProperty = 8007, /* Primitives for handling jobs (new in 1.4.2) */ _OrthancPluginService_CreateJob = 9000, @@ -6000,6 +6001,7 @@ const char** target; const OrthancPluginPeers* peers; uint32_t peerIndex; + const char* userProperty; } _OrthancPluginGetPeerProperty; /** @@ -6031,6 +6033,7 @@ params.target = ⌖ params.peers = peers; params.peerIndex = peerIndex; + params.userProperty = NULL; if (context->InvokeService(context, _OrthancPluginService_GetPeerName, ¶ms) != OrthancPluginErrorCode_Success) { @@ -6071,6 +6074,7 @@ params.target = ⌖ params.peers = peers; params.peerIndex = peerIndex; + params.userProperty = NULL; if (context->InvokeService(context, _OrthancPluginService_GetPeerUrl, ¶ms) != OrthancPluginErrorCode_Success) { @@ -6085,6 +6089,53 @@ + /** + * @brief Get some user-defined property of an Orthanc peer. + * + * This function returns some user-defined property of some Orthanc + * peer. An user-defined property is a property that is associated + * with the peer in the Orthanc configuration file, but that is not + * recognized by the Orthanc core. + * + * This function is thread-safe: Several threads sharing the same + * OrthancPluginPeers object can simultaneously call this function. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param peers The data structure describing the Orthanc peers. + * @param peerIndex The index of the peer of interest. + * This value must be lower than OrthancPluginGetPeersCount(). + * @param userProperty The user property of interest. + * @result The value of the user property, or NULL if it is not defined. + * @ingroup Toolbox + **/ + ORTHANC_PLUGIN_INLINE const char* OrthancPluginGetPeerUserProperty( + OrthancPluginContext* context, + const OrthancPluginPeers* peers, + uint32_t peerIndex, + const char* userProperty) + { + const char* target = NULL; + + _OrthancPluginGetPeerProperty params; + memset(¶ms, 0, sizeof(params)); + params.target = ⌖ + params.peers = peers; + params.peerIndex = peerIndex; + params.userProperty = userProperty; + + if (context->InvokeService(context, _OrthancPluginService_GetPeerUserProperty, ¶ms) != OrthancPluginErrorCode_Success) + { + /* No such user property */ + return NULL; + } + else + { + return target; + } + } + + + typedef struct { OrthancPluginMemoryBuffer* answerBody; diff -r a0b729ac0549 -r 807169f85ba9 Plugins/Samples/Common/OrthancPluginCppWrapper.cpp --- a/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Mon Sep 17 12:08:49 2018 +0200 +++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Tue Sep 18 15:38:18 2018 +0200 @@ -1288,6 +1288,22 @@ #if HAS_ORTHANC_PLUGIN_PEERS == 1 + size_t OrthancPeers::GetPeerIndex(const std::string& name) const + { + size_t index; + if (LookupName(index, name)) + { + return index; + } + else + { + std::string s = "Inexistent peer: " + name; + OrthancPluginLogError(context_, s.c_str()); + ORTHANC_PLUGINS_THROW_EXCEPTION(UnknownResource); + } + } + + OrthancPeers::OrthancPeers(OrthancPluginContext* context) : context_(context), peers_(NULL), @@ -1391,20 +1407,42 @@ std::string OrthancPeers::GetPeerUrl(const std::string& name) const { - size_t index; - if (LookupName(index, name)) + return GetPeerUrl(GetPeerIndex(name)); + } + + + bool OrthancPeers::LookupUserProperty(std::string& value, + size_t index, + const std::string& key) const + { + if (index >= index_.size()) { - return GetPeerUrl(index); + ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); } else { - std::string s = "Inexistent peer: " + name; - OrthancPluginLogError(context_, s.c_str()); - ORTHANC_PLUGINS_THROW_EXCEPTION(UnknownResource); + const char* s = OrthancPluginGetPeerUserProperty(context_, peers_, static_cast(index), key.c_str()); + if (s == NULL) + { + return false; + } + else + { + value.assign(s); + return true; + } } } + bool OrthancPeers::LookupUserProperty(std::string& value, + const std::string& peer, + const std::string& key) const + { + return LookupUserProperty(value, GetPeerIndex(peer), key); + } + + bool OrthancPeers::DoGet(MemoryBuffer& target, size_t index, const std::string& uri) const diff -r a0b729ac0549 -r 807169f85ba9 Plugins/Samples/Common/OrthancPluginCppWrapper.h --- a/Plugins/Samples/Common/OrthancPluginCppWrapper.h Mon Sep 17 12:08:49 2018 +0200 +++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.h Tue Sep 18 15:38:18 2018 +0200 @@ -553,6 +553,8 @@ Index index_; uint32_t timeout_; + size_t GetPeerIndex(const std::string& name) const; + public: OrthancPeers(OrthancPluginContext* context); @@ -582,6 +584,14 @@ return index_.size(); } + bool LookupUserProperty(std::string& value, + size_t index, + const std::string& key) const; + + bool LookupUserProperty(std::string& value, + const std::string& peer, + const std::string& key) const; + bool DoGet(MemoryBuffer& target, size_t index, const std::string& uri) const; diff -r a0b729ac0549 -r 807169f85ba9 UnitTestsSources/RestApiTests.cpp --- a/UnitTestsSources/RestApiTests.cpp Mon Sep 17 12:08:49 2018 +0200 +++ b/UnitTestsSources/RestApiTests.cpp Tue Sep 18 15:38:18 2018 +0200 @@ -603,3 +603,43 @@ ASSERT_FALSE(p2.LookupHttpHeader(s, "nope")); } } + + +TEST(WebServiceParameters, UserProperties) +{ + Json::Value v = Json::nullValue; + + { + WebServiceParameters p; + p.SetUrl("http://localhost:8042/"); + ASSERT_FALSE(p.IsAdvancedFormatNeeded()); + + ASSERT_THROW(p.AddUserProperty("Url", "nope"), OrthancException); + p.AddUserProperty("Hello", "world"); + p.AddUserProperty("a", "b"); + ASSERT_TRUE(p.IsAdvancedFormatNeeded()); + + p.Serialize(v, false, true); + + p.ClearUserProperties(); + ASSERT_FALSE(p.IsAdvancedFormatNeeded()); + } + + { + WebServiceParameters p(v); + ASSERT_TRUE(p.IsAdvancedFormatNeeded()); + ASSERT_TRUE(p.GetHttpHeaders().empty()); + + std::set tmp; + p.ListUserProperties(tmp); + ASSERT_EQ(2u, tmp.size()); + ASSERT_NE(tmp.find("a"), tmp.end()); + ASSERT_NE(tmp.find("Hello"), tmp.end()); + ASSERT_EQ(tmp.find("hello"), tmp.end()); + + std::string s; + ASSERT_TRUE(p.LookupUserProperty(s, "a")); ASSERT_TRUE(s == "b"); + ASSERT_TRUE(p.LookupUserProperty(s, "Hello")); ASSERT_TRUE(s == "world"); + ASSERT_FALSE(p.LookupUserProperty(s, "hello")); + } +}