# HG changeset patch # User Sebastien Jodogne # Date 1354122224 -3600 # Node ID 96b7918a6a185f425200f8070592a25fbd141718 # Parent 9960642f0f45e192aee3eaec0bfff90690d3e03e start of the refactoring of the Orthanc REST API diff -r 9960642f0f45 -r 96b7918a6a18 CMakeLists.txt --- a/CMakeLists.txt Wed Nov 28 17:22:07 2012 +0100 +++ b/CMakeLists.txt Wed Nov 28 18:03:44 2012 +0100 @@ -140,6 +140,7 @@ OrthancServer/Internals/StoreScp.cpp OrthancServer/OrthancInitialization.cpp OrthancServer/OrthancRestApi.cpp + OrthancServer/OrthancRestApi2.cpp OrthancServer/ServerIndex.cpp OrthancServer/ToDcmtkBridge.cpp OrthancServer/DatabaseWrapper.cpp diff -r 9960642f0f45 -r 96b7918a6a18 Core/RestApi/RestApi.cpp --- a/Core/RestApi/RestApi.cpp Wed Nov 28 17:22:07 2012 +0100 +++ b/Core/RestApi/RestApi.cpp Wed Nov 28 18:03:44 2012 +0100 @@ -32,6 +32,8 @@ #include "RestApi.h" +#include + namespace Orthanc { bool RestApi::IsGetAccepted(const UriComponents& uri) @@ -164,7 +166,7 @@ RestApiOutput restOutput(output); RestApiPath::Components components; UriComponents trailing; - + if (method == "GET") { for (GetHandlers::const_iterator it = getHandlers_.begin(); @@ -172,10 +174,11 @@ { if (it->first->Match(components, trailing, uri)) { + LOG(INFO) << "REST GET call on: " << Toolbox::FlattenUri(uri); ok = true; GetCall call; call.output_ = &restOutput; - call.context_ = context_.get(); + call.context_ = this; call.httpHeaders_ = &headers; call.uriComponents_ = &components; call.trailing_ = &trailing; @@ -192,10 +195,11 @@ { if (it->first->Match(components, trailing, uri)) { + LOG(INFO) << "REST PUT call on: " << Toolbox::FlattenUri(uri); ok = true; PutCall call; call.output_ = &restOutput; - call.context_ = context_.get(); + call.context_ = this; call.httpHeaders_ = &headers; call.uriComponents_ = &components; call.trailing_ = &trailing; @@ -212,10 +216,11 @@ { if (it->first->Match(components, trailing, uri)) { + LOG(INFO) << "REST POST call on: " << Toolbox::FlattenUri(uri); ok = true; PostCall call; call.output_ = &restOutput; - call.context_ = context_.get(); + call.context_ = this; call.httpHeaders_ = &headers; call.uriComponents_ = &components; call.trailing_ = &trailing; @@ -232,10 +237,11 @@ { if (it->first->Match(components, trailing, uri)) { + LOG(INFO) << "REST DELETE call on: " << Toolbox::FlattenUri(uri); ok = true; DeleteCall call; call.output_ = &restOutput; - call.context_ = context_.get(); + call.context_ = this; call.httpHeaders_ = &headers; call.uriComponents_ = &components; call.trailing_ = &trailing; @@ -246,6 +252,7 @@ if (!ok) { + LOG(INFO) << "REST method " << method << " not allowed on: " << Toolbox::FlattenUri(uri); output.SendMethodNotAllowedError(GetAcceptedMethods(uri)); } } diff -r 9960642f0f45 -r 96b7918a6a18 Core/RestApi/RestApi.h --- a/Core/RestApi/RestApi.h Wed Nov 28 17:22:07 2012 +0100 +++ b/Core/RestApi/RestApi.h Wed Nov 28 18:03:44 2012 +0100 @@ -32,7 +32,6 @@ #pragma once -#include "../IDynamicObject.h" #include "../HttpServer/HttpHandler.h" #include "RestApiPath.h" #include "RestApiOutput.h" @@ -48,7 +47,7 @@ private: RestApiOutput* output_; - IDynamicObject* context_; + RestApi* context_; const HttpHandler::Arguments* httpHeaders_; const RestApiPath::Components* uriComponents_; const UriComponents* trailing_; @@ -59,9 +58,9 @@ return *output_; } - IDynamicObject* GetContext() + RestApi& GetContext() { - return context_; + return *context_; } const HttpHandler::Arguments& GetHttpHeaders() const @@ -149,9 +148,6 @@ typedef std::list< std::pair > PostHandlers; typedef std::list< std::pair > DeleteHandlers; - // CAUTION: PLEASE INTRODUCE MUTEX BETWEEN CONTEXTS !!! - std::auto_ptr context_; - GetHandlers getHandlers_; PutHandlers putHandlers_; PostHandlers postHandlers_; @@ -169,11 +165,6 @@ { } - void SetContext(IDynamicObject* context) // This takes the ownership - { - context_.reset(context); - } - ~RestApi(); virtual bool IsServedUri(const UriComponents& uri); diff -r 9960642f0f45 -r 96b7918a6a18 Core/RestApi/RestApiOutput.cpp --- a/Core/RestApi/RestApiOutput.cpp Wed Nov 28 17:22:07 2012 +0100 +++ b/Core/RestApi/RestApiOutput.cpp Wed Nov 28 18:03:44 2012 +0100 @@ -34,9 +34,25 @@ namespace Orthanc { + RestApiOutput::RestApiOutput(HttpOutput& output) : + output_(output) + { + existingResource_ = false; + } + + + RestApiOutput::~RestApiOutput() + { + if (!existingResource_) + { + output_.SendHeader(Orthanc_HttpStatus_400_BadRequest); + } + } + void RestApiOutput::AnswerFile(HttpFileSender& sender) { sender.Send(output_); + existingResource_ = true; } void RestApiOutput::AnswerJson(const Json::Value& value) @@ -44,16 +60,19 @@ Json::StyledWriter writer; std::string s = writer.write(value); output_.AnswerBufferWithContentType(s, "application/json"); + existingResource_ = true; } void RestApiOutput::AnswerBuffer(const std::string& buffer, const std::string& contentType) { output_.AnswerBufferWithContentType(buffer, contentType); + existingResource_ = true; } void RestApiOutput::Redirect(const char* path) { output_.Redirect(path); + existingResource_ = true; } } diff -r 9960642f0f45 -r 96b7918a6a18 Core/RestApi/RestApiOutput.h --- a/Core/RestApi/RestApiOutput.h Wed Nov 28 17:22:07 2012 +0100 +++ b/Core/RestApi/RestApiOutput.h Wed Nov 28 18:03:44 2012 +0100 @@ -43,11 +43,12 @@ { private: HttpOutput& output_; + bool existingResource_; public: - RestApiOutput(HttpOutput& output) : output_(output) - { - } + RestApiOutput(HttpOutput& output); + + ~RestApiOutput(); void AnswerFile(HttpFileSender& sender); diff -r 9960642f0f45 -r 96b7918a6a18 OrthancServer/OrthancRestApi.cpp --- a/OrthancServer/OrthancRestApi.cpp Wed Nov 28 17:22:07 2012 +0100 +++ b/OrthancServer/OrthancRestApi.cpp Wed Nov 28 18:03:44 2012 +0100 @@ -419,27 +419,6 @@ Json::Value result(Json::objectValue); - // Version information ------------------------------------------------------ - - if (uri.size() == 1 && uri[0] == "system") - { - if (method == "GET") - { - result = Json::Value(Json::objectValue); - result["Version"] = ORTHANC_VERSION; - result["Name"] = GetGlobalStringParameter("Name", ""); - result["TotalCompressedSize"] = boost::lexical_cast(index_.GetTotalCompressedSize()); - result["TotalUncompressedSize"] = boost::lexical_cast(index_.GetTotalUncompressedSize()); - existingResource = true; - } - else - { - output.SendMethodNotAllowedError("GET,POST"); - return; - } - } - - // List all the instances --------------------------------------------------- if (uri.size() == 1 && uri[0] == "instances") @@ -710,73 +689,8 @@ } - - // Changes API -------------------------------------------------------------- - - if (uri.size() == 1 && uri[0] == "changes") - { - if (method == "GET") - { - const static unsigned int MAX_RESULTS = 100; - - //std::string filter = GetArgument(getArguments, "filter", ""); - int64_t since; - unsigned int limit; - try - { - since = boost::lexical_cast(GetArgument(getArguments, "since", "0")); - limit = boost::lexical_cast(GetArgument(getArguments, "limit", "0")); - } - catch (boost::bad_lexical_cast) - { - output.SendHeader(Orthanc_HttpStatus_400_BadRequest); - return; - } - - if (limit == 0 || limit > MAX_RESULTS) - { - limit = MAX_RESULTS; - } - - if (!index_.GetChanges(result, since, limit)) - { - output.SendHeader(Orthanc_HttpStatus_400_BadRequest); - return; - } - - existingResource = true; - } - else - { - output.SendMethodNotAllowedError("GET"); - return; - } - } - - // DICOM bridge ------------------------------------------------------------- - if (uri.size() == 1 && - uri[0] == "modalities") - { - if (method == "GET") - { - result = Json::Value(Json::arrayValue); - existingResource = true; - - for (Modalities::const_iterator it = modalities_.begin(); - it != modalities_.end(); it++) - { - result.append(*it); - } - } - else - { - output.SendMethodNotAllowedError("GET"); - return; - } - } - if ((uri.size() == 2 || uri.size() == 3) && uri[0] == "modalities") diff -r 9960642f0f45 -r 96b7918a6a18 OrthancServer/OrthancRestApi2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/OrthancRestApi2.cpp Wed Nov 28 18:03:44 2012 +0100 @@ -0,0 +1,133 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012 Medical Physics Department, CHU of Liege, + * Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "OrthancRestApi2.h" + +#include "OrthancInitialization.h" +#include "FromDcmtkBridge.h" +#include "../Core/Uuid.h" +#include "../Core/HttpServer/FilesystemHttpSender.h" + +#include +#include +#include + + +#define RETRIEVE_CONTEXT(call) \ + OrthancRestApi2& context = dynamic_cast(call.GetContext()) + + +namespace Orthanc +{ + // System information ------------------------------------------------------- + + static void GetSystemInformation(RestApi::GetCall& call) + { + RETRIEVE_CONTEXT(call); + + Json::Value result = Json::objectValue; + result["Version"] = ORTHANC_VERSION; + result["Name"] = GetGlobalStringParameter("Name", ""); + result["TotalCompressedSize"] = boost::lexical_cast(context.GetIndex().GetTotalCompressedSize()); + result["TotalUncompressedSize"] = boost::lexical_cast(context.GetIndex().GetTotalUncompressedSize()); + call.GetOutput().AnswerJson(result); + } + + + // Changes API -------------------------------------------------------------- + + static void GetChanges(RestApi::GetCall& call) + { + RETRIEVE_CONTEXT(call); + + static const unsigned int MAX_RESULTS = 100; + ServerIndex& index = context.GetIndex(); + + //std::string filter = GetArgument(getArguments, "filter", ""); + int64_t since; + unsigned int limit; + try + { + since = boost::lexical_cast(call.GetArgument("since", "0")); + limit = boost::lexical_cast(call.GetArgument("limit", "0")); + } + catch (boost::bad_lexical_cast) + { + return; + } + + if (limit == 0 || limit > MAX_RESULTS) + { + limit = MAX_RESULTS; + } + + Json::Value result; + if (index.GetChanges(result, since, limit)) + { + call.GetOutput().AnswerJson(result); + } + } + + + + + // DICOM bridge ------------------------------------------------------------- + + static void ListModalities(RestApi::GetCall& call) + { + RETRIEVE_CONTEXT(call); + + Json::Value result = Json::arrayValue; + + for (OrthancRestApi2::Modalities::const_iterator + it = context.GetModalities().begin(); + it != context.GetModalities().end(); it++) + { + result.append(*it); + } + + call.GetOutput().AnswerJson(result); + } + + + OrthancRestApi2::OrthancRestApi2(ServerIndex& index, + const std::string& path) : + index_(index), + storage_(path) + { + GetListOfDicomModalities(modalities_); + + Register("/system", GetSystemInformation); + Register("/changes", GetChanges); + Register("/modalities", ListModalities); + } +} diff -r 9960642f0f45 -r 96b7918a6a18 OrthancServer/OrthancRestApi2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/OrthancRestApi2.h Wed Nov 28 18:03:44 2012 +0100 @@ -0,0 +1,71 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012 Medical Physics Department, CHU of Liege, + * Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "ServerIndex.h" +#include "../Core/RestApi/RestApi.h" + +#include + +namespace Orthanc +{ + class OrthancRestApi2 : public RestApi + { + public: + typedef std::set Modalities; + + private: + ServerIndex& index_; + FileStorage storage_; + Modalities modalities_; + + public: + OrthancRestApi2(ServerIndex& index, + const std::string& path); + + ServerIndex& GetIndex() + { + return index_; + } + + FileStorage& GetStorage() + { + return storage_; + } + + Modalities& GetModalities() + { + return modalities_; + } + }; +} diff -r 9960642f0f45 -r 96b7918a6a18 OrthancServer/main.cpp --- a/OrthancServer/main.cpp Wed Nov 28 17:22:07 2012 +0100 +++ b/OrthancServer/main.cpp Wed Nov 28 18:03:44 2012 +0100 @@ -31,6 +31,7 @@ #include "OrthancRestApi.h" +#include "OrthancRestApi2.h" #include #include @@ -258,6 +259,7 @@ httpServer.RegisterHandler(new FilesystemHttpHandler("/app", ORTHANC_PATH "/OrthancExplorer")); #endif + httpServer.RegisterHandler(new OrthancRestApi2(index, storageDirectory.string())); httpServer.RegisterHandler(new OrthancRestApi(index, storageDirectory.string())); // GO !!! diff -r 9960642f0f45 -r 96b7918a6a18 UnitTests/RestApi.cpp --- a/UnitTests/RestApi.cpp Wed Nov 28 17:22:07 2012 +0100 +++ b/UnitTests/RestApi.cpp Wed Nov 28 18:03:44 2012 +0100 @@ -50,6 +50,7 @@ +#if 0 #include "../Core/HttpServer/MongooseServer.h" @@ -82,3 +83,5 @@ /*LOG(WARNING) << "REST has started"; Toolbox::ServerBarrier();*/ } + +#endif