# HG changeset patch # User Sebastien Jodogne # Date 1495658000 -7200 # Node ID f40a78cc7070c381565c3d6ca672c2117efa9be0 # Parent 4e21f6b3aa0d7b92c7a9306c885c94b3d80f6533 Oracle diff -r 4e21f6b3aa0d -r f40a78cc7070 Framework/Toolbox/IWebService.h --- a/Framework/Toolbox/IWebService.h Wed May 24 21:23:29 2017 +0200 +++ b/Framework/Toolbox/IWebService.h Wed May 24 22:33:20 2017 +0200 @@ -58,9 +58,5 @@ const std::string& uri, const std::string& body, Orthanc::IDynamicObject* payload) = 0; - - virtual void Start() = 0; - - virtual void Stop() = 0; }; } diff -r 4e21f6b3aa0d -r f40a78cc7070 Framework/Toolbox/OrthancAsynchronousWebService.h --- a/Framework/Toolbox/OrthancAsynchronousWebService.h Wed May 24 21:23:29 2017 +0200 +++ b/Framework/Toolbox/OrthancAsynchronousWebService.h Wed May 24 22:33:20 2017 +0200 @@ -50,8 +50,8 @@ const std::string& body, Orthanc::IDynamicObject* payload); - virtual void Start(); + void Start(); - virtual void Stop(); + void Stop(); }; } diff -r 4e21f6b3aa0d -r f40a78cc7070 Framework/Toolbox/OrthancSynchronousWebService.h --- a/Framework/Toolbox/OrthancSynchronousWebService.h Wed May 24 21:23:29 2017 +0200 +++ b/Framework/Toolbox/OrthancSynchronousWebService.h Wed May 24 22:33:20 2017 +0200 @@ -54,13 +54,5 @@ const std::string& uri, const std::string& body, Orthanc::IDynamicObject* payload); - - virtual void Start() - { - } - - virtual void Stop() - { - } }; } diff -r 4e21f6b3aa0d -r f40a78cc7070 Platforms/Generic/IOracleCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/IOracleCommand.h Wed May 24 22:33:20 2017 +0200 @@ -0,0 +1,42 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, 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 . + **/ + + +#pragma once + +#include "../../Resources/Orthanc/Core/IDynamicObject.h" + +namespace OrthancStone +{ + class IOracleCommand : public Orthanc::IDynamicObject + { + public: + virtual ~IOracleCommand() + { + } + + // This part of the command can be invoked simultaneously, and + // must not modify the Stone context + virtual void Execute() = 0; + + // This part of the command must be invoked in mutual exclusion + virtual void Commit() = 0; + }; +} diff -r 4e21f6b3aa0d -r f40a78cc7070 Platforms/Generic/Oracle.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/Oracle.cpp Wed May 24 22:33:20 2017 +0200 @@ -0,0 +1,208 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, 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 . + **/ + + +#include "Oracle.h" + +#include "../../Resources/Orthanc/Core/Logging.h" +#include "../../Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h" +#include "../../Resources/Orthanc/Core/OrthancException.h" + +#include + +namespace OrthancStone +{ + class Oracle::PImpl + { + private: + enum State + { + State_Init, + State_Started, + State_Stopped + }; + + boost::mutex* globalMutex_; + boost::mutex oracleMutex_; + State state_; + std::vector threads_; + Orthanc::SharedMessageQueue queue_; + + static void Worker(PImpl* that) + { + for (;;) + { + State state; + + { + boost::mutex::scoped_lock lock(that->oracleMutex_); + state = that->state_; + } + + if (state == State_Stopped) + { + break; + } + + std::auto_ptr item(that->queue_.Dequeue(100)); + if (item.get() != NULL) + { + IOracleCommand& command = dynamic_cast(*item); + command.Execute(); + + if (that->globalMutex_ != NULL) + { + boost::mutex::scoped_lock lock(*that->globalMutex_); + command.Commit(); + } + else + { + command.Commit(); + } + } + } + } + + public: + PImpl(boost::mutex* globalMutex, + unsigned int threadCount) : + globalMutex_(globalMutex), + state_(State_Init), + threads_(threadCount) + { + } + + ~PImpl() + { + if (state_ == State_Started) + { + LOG(ERROR) << "You should have manually called Oracle::Stop()"; + Stop(); + } + } + + void Submit(IOracleCommand* command) + { + std::auto_ptr protection(command); + + if (command == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + boost::mutex::scoped_lock lock(oracleMutex_); + + switch (state_) + { + case State_Init: + LOG(ERROR) << "You must call Oracle::Start()"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + + case State_Started: + queue_.Enqueue(protection.release()); + break; + + case State_Stopped: + LOG(ERROR) << "Cannot schedule a request to the Oracle after having " + << "called Oracle::Stop()"; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + } + + void Start() + { + boost::mutex::scoped_lock lock(oracleMutex_); + + if (state_ != State_Init) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + for (size_t i = 0; i < threads_.size(); i++) + { + threads_[i] = new boost::thread(Worker, this); + } + + state_ = State_Started; + } + + void Stop() + { + { + boost::mutex::scoped_lock lock(oracleMutex_); + + if (state_ != State_Started) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + state_ = State_Stopped; + } + + for (size_t i = 0; i < threads_.size(); i++) + { + if (threads_[i] != NULL) + { + if (threads_[i]->joinable()) + { + threads_[i]->join(); + } + + delete threads_[i]; + } + } + } + }; + + + Oracle::Oracle(boost::mutex& globalMutex, + unsigned int threadCount) : + pimpl_(new PImpl(&globalMutex, threadCount)) + { + } + + + Oracle::Oracle(unsigned int threadCount) : + pimpl_(new PImpl(NULL, threadCount)) + { + } + + + void Oracle::Start() + { + pimpl_->Start(); + } + + + void Oracle::Submit(IOracleCommand* command) + { + pimpl_->Submit(command); + } + + + void Oracle::Stop() + { + pimpl_->Stop(); + } +} diff -r 4e21f6b3aa0d -r f40a78cc7070 Platforms/Generic/Oracle.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/Oracle.h Wed May 24 22:33:20 2017 +0200 @@ -0,0 +1,50 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, 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 . + **/ + + +#pragma once + +#include "IOracleCommand.h" + +#include +#include + +namespace OrthancStone +{ + class Oracle : public boost::noncopyable + { + private: + class PImpl; + + boost::shared_ptr pimpl_; + + public: + Oracle(boost::mutex& globalMutex, + unsigned int threadCount); + + Oracle(unsigned int threadCount); + + void Start(); + + void Submit(IOracleCommand* command); + + void Stop(); + }; +} diff -r 4e21f6b3aa0d -r f40a78cc7070 Platforms/Generic/OracleWebService.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/OracleWebService.h Wed May 24 22:33:20 2017 +0200 @@ -0,0 +1,60 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, 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 . + **/ + + +#pragma once + +#include "../../Framework/Toolbox/IWebService.h" +#include "Oracle.h" +#include "WebServiceGetCommand.h" +#include "WebServicePostCommand.h" + +namespace OrthancStone +{ + class OracleWebService : public IWebService + { + private: + Oracle& oracle_; + Orthanc::WebServiceParameters parameters_; + + public: + OracleWebService(Oracle& oracle, + const Orthanc::WebServiceParameters& parameters) : + oracle_(oracle), + parameters_(parameters) + { + } + + virtual void ScheduleGetRequest(ICallback& callback, + const std::string& uri, + Orthanc::IDynamicObject* payload) + { + oracle_.Submit(new WebServiceGetCommand(callback, parameters_, uri, payload)); + } + + virtual void SchedulePostRequest(ICallback& callback, + const std::string& uri, + const std::string& body, + Orthanc::IDynamicObject* payload) + { + oracle_.Submit(new WebServicePostCommand(callback, parameters_, uri, body, payload)); + } + }; +} diff -r 4e21f6b3aa0d -r f40a78cc7070 Platforms/Generic/WebServiceGetCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/WebServiceGetCommand.cpp Wed May 24 22:33:20 2017 +0200 @@ -0,0 +1,59 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, 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 . + **/ + + +#include "WebServiceGetCommand.h" + +#include "../../Resources/Orthanc/Core/HttpClient.h" + +namespace OrthancStone +{ + WebServiceGetCommand::WebServiceGetCommand(IWebService::ICallback& callback, + const Orthanc::WebServiceParameters& parameters, + const std::string& uri, + Orthanc::IDynamicObject* payload /* takes ownership */) : + callback_(callback), + parameters_(parameters), + uri_(uri), + payload_(payload) + { + } + + + void WebServiceGetCommand::Execute() + { + Orthanc::HttpClient client(parameters_, uri_); + client.SetMethod(Orthanc::HttpMethod_Get); + success_ = client.Apply(answer_); + } + + + void WebServiceGetCommand::Commit() + { + if (success_) + { + callback_.NotifySuccess(uri_, answer_.c_str(), answer_.size(), payload_.release()); + } + else + { + callback_.NotifyError(uri_, payload_.release()); + } + } +} diff -r 4e21f6b3aa0d -r f40a78cc7070 Platforms/Generic/WebServiceGetCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/WebServiceGetCommand.h Wed May 24 22:33:20 2017 +0200 @@ -0,0 +1,53 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, 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 . + **/ + + +#pragma once + +#include "IOracleCommand.h" + +#include "../../Framework/Toolbox/IWebService.h" +#include "../../Resources/Orthanc/Core/WebServiceParameters.h" + +#include + +namespace OrthancStone +{ + class WebServiceGetCommand : public IOracleCommand + { + private: + IWebService::ICallback& callback_; + Orthanc::WebServiceParameters parameters_; + std::string uri_; + std::auto_ptr payload_; + bool success_; + std::string answer_; + + public: + WebServiceGetCommand(IWebService::ICallback& callback, + const Orthanc::WebServiceParameters& parameters, + const std::string& uri, + Orthanc::IDynamicObject* payload /* takes ownership */); + + virtual void Execute(); + + virtual void Commit(); + }; +} diff -r 4e21f6b3aa0d -r f40a78cc7070 Platforms/Generic/WebServicePostCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/WebServicePostCommand.cpp Wed May 24 22:33:20 2017 +0200 @@ -0,0 +1,60 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, 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 . + **/ + + +#include "WebServicePostCommand.h" + +#include "../../Resources/Orthanc/Core/HttpClient.h" + +namespace OrthancStone +{ + WebServicePostCommand::WebServicePostCommand(IWebService::ICallback& callback, + const Orthanc::WebServiceParameters& parameters, + const std::string& uri, + const std::string& body, + Orthanc::IDynamicObject* payload /* takes ownership */) : + callback_(callback), + parameters_(parameters), + uri_(uri), + body_(body), + payload_(payload) + { + } + + void WebServicePostCommand::Execute() + { + Orthanc::HttpClient client(parameters_, uri_); + client.SetMethod(Orthanc::HttpMethod_Post); + client.GetBody().swap(body_); + success_ = client.Apply(answer_); + } + + void WebServicePostCommand::Commit() + { + if (success_) + { + callback_.NotifySuccess(uri_, answer_.c_str(), answer_.size(), payload_.release()); + } + else + { + callback_.NotifyError(uri_, payload_.release()); + } + } +} diff -r 4e21f6b3aa0d -r f40a78cc7070 Platforms/Generic/WebServicePostCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/Generic/WebServicePostCommand.h Wed May 24 22:33:20 2017 +0200 @@ -0,0 +1,55 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017 Osimis, 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 . + **/ + + +#pragma once + +#include "IOracleCommand.h" + +#include "../../Framework/Toolbox/IWebService.h" +#include "../../Resources/Orthanc/Core/WebServiceParameters.h" + +#include + +namespace OrthancStone +{ + class WebServicePostCommand : public IOracleCommand + { + private: + IWebService::ICallback& callback_; + Orthanc::WebServiceParameters parameters_; + std::string uri_; + std::string body_; + std::auto_ptr payload_; + bool success_; + std::string answer_; + + public: + WebServicePostCommand(IWebService::ICallback& callback, + const Orthanc::WebServiceParameters& parameters, + const std::string& uri, + const std::string& body, + Orthanc::IDynamicObject* payload /* takes ownership */); + + virtual void Execute(); + + virtual void Commit(); + }; +} diff -r 4e21f6b3aa0d -r f40a78cc7070 Resources/CMake/OrthancStone.cmake --- a/Resources/CMake/OrthancStone.cmake Wed May 24 21:23:29 2017 +0200 +++ b/Resources/CMake/OrthancStone.cmake Wed May 24 22:33:20 2017 +0200 @@ -175,6 +175,12 @@ ## All the source files required to build Stone of Orthanc ##################################################################### +set(PLATFORM_SOURCES + ${ORTHANC_STONE_DIR}/Platforms/Generic/WebServiceGetCommand.cpp + ${ORTHANC_STONE_DIR}/Platforms/Generic/WebServicePostCommand.cpp + ${ORTHANC_STONE_DIR}/Platforms/Generic/Oracle.cpp + ) + list(APPEND ORTHANC_STONE_SOURCES ${ORTHANC_STONE_DIR}/Applications/BasicApplicationContext.cpp ${ORTHANC_STONE_DIR}/Applications/IBasicApplication.cpp @@ -229,6 +235,8 @@ ${ORTHANC_STONE_DIR}/Framework/Widgets/LayerWidget.cpp ${ORTHANC_STONE_DIR}/Framework/Widgets/WorldSceneWidget.cpp + ${PLATFORM_SOURCES} + ${ORTHANC_ROOT}/Core/ChunkedBuffer.cpp ${ORTHANC_ROOT}/Core/Compression/DeflateBaseCompressor.cpp ${ORTHANC_ROOT}/Core/Compression/GzipCompressor.cpp diff -r 4e21f6b3aa0d -r f40a78cc7070 UnitTestsSources/UnitTestsMain.cpp --- a/UnitTestsSources/UnitTestsMain.cpp Wed May 24 21:23:29 2017 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Wed May 24 22:33:20 2017 +0200 @@ -21,9 +21,13 @@ #include "gtest/gtest.h" +#include "../Platforms/Generic/OracleWebService.h" #include "../Framework/Toolbox/OrthancAsynchronousWebService.h" #include "../Framework/Toolbox/OrthancSlicesLoader.h" +#include "../Resources/Orthanc/Core/HttpClient.h" #include "../Resources/Orthanc/Core/Logging.h" +#include "../Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h" +#include "../Resources/Orthanc/Core/OrthancException.h" #include #include @@ -36,7 +40,7 @@ public: virtual void NotifyGeometryReady(const OrthancSlicesLoader& loader) { - printf(">> %d\n", loader.GetSliceCount()); + printf(">> %d\n", (int) loader.GetSliceCount()); for (size_t i = 0; i < loader.GetSliceCount(); i++) { @@ -70,23 +74,28 @@ TEST(Toto, Tutu) { + OrthancStone::Oracle oracle(4); + oracle.Start(); + Orthanc::WebServiceParameters web; - OrthancStone::OrthancAsynchronousWebService orthanc(web, 4); - orthanc.Start(); + //OrthancStone::OrthancAsynchronousWebService orthanc(web, 4); + OrthancStone::OracleWebService orthanc(oracle, web); + //orthanc.Start(); OrthancStone::Tata tata; OrthancStone::OrthancSlicesLoader loader(tata, orthanc); - //loader.ScheduleLoadSeries("c1c4cb95-05e3bd11-8da9f5bb-87278f71-0b2b43f5"); + loader.ScheduleLoadSeries("c1c4cb95-05e3bd11-8da9f5bb-87278f71-0b2b43f5"); //loader.ScheduleLoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); - loader.ScheduleLoadInstance("19816330-cb02e1cf-df3a8fe8-bf510623-ccefe9f5", 0); + //loader.ScheduleLoadInstance("19816330-cb02e1cf-df3a8fe8-bf510623-ccefe9f5", 0); /*printf(">> %d\n", loader.GetSliceCount()); loader.ScheduleLoadSliceImage(31);*/ boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - orthanc.Stop(); + //orthanc.Stop(); + oracle.Stop(); }