view Framework/Deprecated/Toolbox/OrthancApiClient.cpp @ 874:debb70fa10b5 am-dev

correct handling of deleted observers in OrthancApiClient
author Alain Mazy <alain@mazy.be>
date Wed, 03 Jul 2019 10:11:22 +0200
parents 4fe4b221a31f
children 861c080ef47b
line wrap: on
line source

/**
 * Stone of Orthanc
 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
 * Department, University Hospital of Liege, Belgium
 * Copyright (C) 2017-2019 Osimis S.A., Belgium
 *
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 **/

#include "OrthancApiClient.h"

#include "../Toolbox/MessagingToolbox.h"

#include <Core/OrthancException.h>

namespace Deprecated
{
  const Orthanc::IDynamicObject& OrthancApiClient::JsonResponseReadyMessage::GetPayload() const
  {
    if (HasPayload())
    {
      return *payload_;
    }
    else
    {
      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
    }
  }
  
  
  const Orthanc::IDynamicObject& OrthancApiClient::BinaryResponseReadyMessage::GetPayload() const
  {
    if (HasPayload())
    {
      return *payload_;
    }
    else
    {
      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
    }
  }
  
  
  const Orthanc::IDynamicObject& OrthancApiClient::EmptyResponseReadyMessage::GetPayload() const
  {
    if (HasPayload())
    {
      return *payload_;
    }
    else
    {
      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
    }
  }
  
  
  class OrthancApiClient::WebServicePayload : public Orthanc::IDynamicObject
  {
  private:
    std::auto_ptr< OrthancStone::MessageHandler<EmptyResponseReadyMessage> >             emptyHandler_;
    std::auto_ptr< OrthancStone::MessageHandler<JsonResponseReadyMessage> >              jsonHandler_;
    std::auto_ptr< OrthancStone::MessageHandler<BinaryResponseReadyMessage> >            binaryHandler_;
    std::auto_ptr< OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage> >  failureHandler_;
    std::auto_ptr< Orthanc::IDynamicObject >                               userPayload_;
    OrthancStone::MessageBroker&                                                         broker_;
    void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const
    {
      if (failureHandler_.get() != NULL)
      {
        failureHandler_->Apply(IWebService::HttpRequestErrorMessage
                               (message.GetUri(), userPayload_.get()));
      }
    }
    
  public:
    WebServicePayload(OrthancStone::MessageBroker& broker,
                      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* handler,
                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                      Orthanc::IDynamicObject* userPayload) :
      emptyHandler_(handler),
      failureHandler_(failureHandler),
      userPayload_(userPayload),
      broker_(broker)

    {
      if (handler == NULL)
      {
        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
      }
    }

    WebServicePayload(OrthancStone::MessageBroker& broker,
                      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* handler,
                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                      Orthanc::IDynamicObject* userPayload) :
      binaryHandler_(handler),
      failureHandler_(failureHandler),
      userPayload_(userPayload),
      broker_(broker)
    {
      if (handler == NULL)
      {
        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
      }
    }

    WebServicePayload(OrthancStone::MessageBroker& broker,
                      OrthancStone::MessageHandler<JsonResponseReadyMessage>* handler,
                      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureHandler,
                      Orthanc::IDynamicObject* userPayload) :
      jsonHandler_(handler),
      failureHandler_(failureHandler),
      userPayload_(userPayload),
      broker_(broker)
    {
      if (handler == NULL)
      {
        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
      }
    }

    void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const
    {
      if (emptyHandler_.get() != NULL)
      {
        if (broker_.IsActive(*(emptyHandler_->GetObserver())))
        {
          emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage
                               (message.GetUri(), userPayload_.get()));
        }
      }
      else if (binaryHandler_.get() != NULL)
      {
        if (broker_.IsActive(*(binaryHandler_->GetObserver())))
        {
          binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage
                                (message.GetUri(), message.GetAnswer(),
                                 message.GetAnswerSize(), userPayload_.get()));
        }
      }
      else if (jsonHandler_.get() != NULL)
      {
        if (broker_.IsActive(*(jsonHandler_->GetObserver())))
        {
          Json::Value response;
          if (MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize()))
          {
            jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage
                                (message.GetUri(), response, userPayload_.get()));
          }
          else
          {
            NotifyConversionError(message);
          }
        }
      }
      else
      {
        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
      }
    }

    void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const
    {
      if (failureHandler_.get() != NULL)
      {
        failureHandler_->Apply(IWebService::HttpRequestErrorMessage
                               (message.GetUri(), userPayload_.get()));
      }
    }
  };


  OrthancApiClient::OrthancApiClient(OrthancStone::MessageBroker& broker,
                                     IWebService& web,
                                     const std::string& baseUrl) :
    IObservable(broker),
    IObserver(broker),
    web_(web),
    baseUrl_(baseUrl)
  {
  }


  void OrthancApiClient::GetJsonAsync(
      const std::string& uri,
      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
      Orthanc::IDynamicObject* payload)
  {
    IWebService::HttpHeaders emptyHeaders;
    web_.GetAsync(baseUrl_ + uri,
                  emptyHeaders,
                  new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                  (*this, &OrthancApiClient::NotifyHttpSuccess),
                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                  (*this, &OrthancApiClient::NotifyHttpError));
  }


  void OrthancApiClient::GetBinaryAsync(
      const std::string& uri,
      const std::string& contentType,
      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
      Orthanc::IDynamicObject* payload)
  {
    IWebService::HttpHeaders headers;
    headers["Accept"] = contentType;
    GetBinaryAsync(uri, headers, successCallback, failureCallback, payload);
  }

  void OrthancApiClient::GetBinaryAsync(
      const std::string& uri,
      const IWebService::HttpHeaders& headers,
      OrthancStone::MessageHandler<BinaryResponseReadyMessage>* successCallback,
      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
      Orthanc::IDynamicObject* payload)
  {
    // printf("GET [%s] [%s]\n", baseUrl_.c_str(), uri.c_str());

    web_.GetAsync(baseUrl_ + uri, headers,
                  new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                  (*this, &OrthancApiClient::NotifyHttpSuccess),
                  new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                  (*this, &OrthancApiClient::NotifyHttpError));
  }

  
  void OrthancApiClient::PostBinaryAsyncExpectJson(
      const std::string& uri,
      const std::string& body,
      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
      Orthanc::IDynamicObject* payload)
  {
    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
                   new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                   (*this, &OrthancApiClient::NotifyHttpSuccess),
                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                   (*this, &OrthancApiClient::NotifyHttpError));

  }

  void OrthancApiClient::PostBinaryAsync(
      const std::string& uri,
      const std::string& body)
  {
    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, NULL, NULL, NULL);
  }

  void OrthancApiClient::PostBinaryAsync(
      const std::string& uri,
      const std::string& body,
      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
      Orthanc::IDynamicObject* payload   /* takes ownership */)
  {
    web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body,
                   new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                   (*this, &OrthancApiClient::NotifyHttpSuccess),
                   new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                   (*this, &OrthancApiClient::NotifyHttpError));
  }

  void OrthancApiClient::PostJsonAsyncExpectJson(
      const std::string& uri,
      const Json::Value& data,
      OrthancStone::MessageHandler<JsonResponseReadyMessage>* successCallback,
      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
      Orthanc::IDynamicObject* payload)
  {
    std::string body;
    MessagingToolbox::JsonToString(body, data);
    return PostBinaryAsyncExpectJson(uri, body, successCallback, failureCallback, payload);
  }

  void OrthancApiClient::PostJsonAsync(
      const std::string& uri,
      const Json::Value& data)
  {
    std::string body;
    MessagingToolbox::JsonToString(body, data);
    return PostBinaryAsync(uri, body);
  }

  void OrthancApiClient::PostJsonAsync(
      const std::string& uri,
      const Json::Value& data,
      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
      Orthanc::IDynamicObject* payload   /* takes ownership */)
  {
    std::string body;
    MessagingToolbox::JsonToString(body, data);
    return PostBinaryAsync(uri, body, successCallback, failureCallback, payload);
  }

  void OrthancApiClient::DeleteAsync(
      const std::string& uri,
      OrthancStone::MessageHandler<EmptyResponseReadyMessage>* successCallback,
      OrthancStone::MessageHandler<IWebService::HttpRequestErrorMessage>* failureCallback,
      Orthanc::IDynamicObject* payload)
  {
    web_.DeleteAsync(baseUrl_ + uri, IWebService::HttpHeaders(),
                     new WebServicePayload(IObservable::GetBroker(), successCallback, failureCallback, payload),
                     new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestSuccessMessage>
                     (*this, &OrthancApiClient::NotifyHttpSuccess),
                     new OrthancStone::Callable<OrthancApiClient, IWebService::HttpRequestErrorMessage>
                     (*this, &OrthancApiClient::NotifyHttpError));
  }


  void OrthancApiClient::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message)
  {
    if (message.HasPayload())
    {
      dynamic_cast<const WebServicePayload&>(message.GetPayload()).HandleSuccess(message);
    }
    else
    {
      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
    }
  }

  void OrthancApiClient::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message)
  {
    if (message.HasPayload())
    {
      dynamic_cast<const WebServicePayload&>(message.GetPayload()).HandleFailure(message);
    }
    else
    {
      throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
    }
  }
}