# HG changeset patch # User Sebastien Jodogne # Date 1526740826 -7200 # Node ID 3ff4c50647ea36971232ac116708dbc73223228f # Parent f7a84b551ee4176d53339540297d838b04b1fc1f moving the old scheduler to the graveyard diff -r f7a84b551ee4 -r 3ff4c50647ea CMakeLists.txt --- a/CMakeLists.txt Sat May 19 16:29:00 2018 +0200 +++ b/CMakeLists.txt Sat May 19 16:40:26 2018 +0200 @@ -70,14 +70,6 @@ OrthancServer/OrthancRestApi/OrthancRestResources.cpp OrthancServer/OrthancRestApi/OrthancRestSystem.cpp OrthancServer/QueryRetrieveHandler.cpp - OrthancServer/Scheduler/CallSystemCommand.cpp - OrthancServer/Scheduler/DeleteInstanceCommand.cpp - OrthancServer/Scheduler/ModifyInstanceCommand.cpp - OrthancServer/Scheduler/ServerCommandInstance.cpp - OrthancServer/Scheduler/ServerJob.cpp - OrthancServer/Scheduler/ServerScheduler.cpp - OrthancServer/Scheduler/StorePeerCommand.cpp - OrthancServer/Scheduler/StoreScuCommand.cpp OrthancServer/Search/HierarchicalMatcher.cpp OrthancServer/Search/IFindConstraint.cpp OrthancServer/Search/ListConstraint.cpp diff -r f7a84b551ee4 -r 3ff4c50647ea Core/DicomNetworking/ReusableDicomUserConnection.cpp --- a/Core/DicomNetworking/ReusableDicomUserConnection.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeaders.h" -#include "ReusableDicomUserConnection.h" - -#include "../Logging.h" -#include "../OrthancException.h" - -namespace Orthanc -{ - static boost::posix_time::ptime Now() - { - return boost::posix_time::microsec_clock::local_time(); - } - - void ReusableDicomUserConnection::Open(const std::string& localAet, - const RemoteModalityParameters& remote) - { - if (connection_ != NULL && - connection_->GetLocalApplicationEntityTitle() == localAet && - connection_->GetRemoteApplicationEntityTitle() == remote.GetApplicationEntityTitle() && - connection_->GetRemoteHost() == remote.GetHost() && - connection_->GetRemotePort() == remote.GetPort() && - connection_->GetRemoteManufacturer() == remote.GetManufacturer()) - { - // The current connection can be reused - LOG(INFO) << "Reusing the previous SCU connection"; - return; - } - - Close(); - - connection_ = new DicomUserConnection(); - connection_->SetLocalApplicationEntityTitle(localAet); - connection_->SetRemoteModality(remote); - connection_->Open(); - } - - void ReusableDicomUserConnection::Close() - { - if (connection_ != NULL) - { - delete connection_; - connection_ = NULL; - } - } - - void ReusableDicomUserConnection::CloseThread(ReusableDicomUserConnection* that) - { - for (;;) - { - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - if (!that->continue_) - { - //LOG(INFO) << "Finishing the thread watching the global SCU connection"; - return; - } - - { - boost::mutex::scoped_lock lock(that->mutex_); - if (that->connection_ != NULL && - Now() >= that->lastUse_ + that->timeBeforeClose_) - { - LOG(INFO) << "Closing the global SCU connection after timeout"; - that->Close(); - } - } - } - } - - - ReusableDicomUserConnection::Locker::Locker(ReusableDicomUserConnection& that, - const std::string& localAet, - const RemoteModalityParameters& remote) : - ::Orthanc::Locker(that) - { - that.Open(localAet, remote); - connection_ = that.connection_; - } - - - DicomUserConnection& ReusableDicomUserConnection::Locker::GetConnection() - { - if (connection_ == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - return *connection_; - } - - ReusableDicomUserConnection::ReusableDicomUserConnection() : - connection_(NULL), - timeBeforeClose_(boost::posix_time::seconds(5)) // By default, close connection after 5 seconds - { - lastUse_ = Now(); - continue_ = true; - closeThread_ = boost::thread(CloseThread, this); - } - - ReusableDicomUserConnection::~ReusableDicomUserConnection() - { - if (continue_) - { - LOG(ERROR) << "INTERNAL ERROR: ReusableDicomUserConnection::Finalize() should be invoked manually to avoid mess in the destruction order!"; - Finalize(); - } - } - - void ReusableDicomUserConnection::SetMillisecondsBeforeClose(uint64_t ms) - { - boost::mutex::scoped_lock lock(mutex_); - - if (ms == 0) - { - ms = 1; - } - - timeBeforeClose_ = boost::posix_time::milliseconds(ms); - } - - void ReusableDicomUserConnection::Lock() - { - mutex_.lock(); - } - - void ReusableDicomUserConnection::Unlock() - { - if (connection_ != NULL && - connection_->GetRemoteManufacturer() == ModalityManufacturer_StoreScp) - { - // "storescp" from DCMTK has problems when reusing a - // connection. Always close. - Close(); - } - - lastUse_ = Now(); - mutex_.unlock(); - } - - - void ReusableDicomUserConnection::Finalize() - { - if (continue_) - { - continue_ = false; - - if (closeThread_.joinable()) - { - closeThread_.join(); - } - - Close(); - } - } -} - diff -r f7a84b551ee4 -r 3ff4c50647ea Core/DicomNetworking/ReusableDicomUserConnection.h --- a/Core/DicomNetworking/ReusableDicomUserConnection.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "DicomUserConnection.h" -#include "../../Core/MultiThreading/Locker.h" - -#include -#include - -namespace Orthanc -{ - class ReusableDicomUserConnection : public ILockable - { - private: - boost::mutex mutex_; - DicomUserConnection* connection_; - bool continue_; - boost::posix_time::time_duration timeBeforeClose_; - boost::posix_time::ptime lastUse_; - boost::thread closeThread_; - - void Open(const std::string& localAet, - const RemoteModalityParameters& remote); - - void Close(); - - static void CloseThread(ReusableDicomUserConnection* that); - - protected: - virtual void Lock(); - - virtual void Unlock(); - - public: - class Locker : public ::Orthanc::Locker - { - private: - DicomUserConnection* connection_; - - public: - Locker(ReusableDicomUserConnection& that, - const std::string& localAet, - const RemoteModalityParameters& remote); - - DicomUserConnection& GetConnection(); - }; - - ReusableDicomUserConnection(); - - virtual ~ReusableDicomUserConnection(); - - void SetMillisecondsBeforeClose(uint64_t ms); - - void Finalize(); - }; -} - diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/CallSystemCommand.cpp --- a/OrthancServer/Scheduler/CallSystemCommand.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" -#include "CallSystemCommand.h" - -#include "../../Core/Logging.h" -#include "../../Core/Toolbox.h" -#include "../../Core/TemporaryFile.h" - -namespace Orthanc -{ - CallSystemCommand::CallSystemCommand(ServerContext& context, - const std::string& command, - const std::vector& arguments) : - context_(context), - command_(command), - arguments_(arguments) - { - } - - bool CallSystemCommand::Apply(ListOfStrings& outputs, - const ListOfStrings& inputs) - { - for (ListOfStrings::const_iterator - it = inputs.begin(); it != inputs.end(); ++it) - { - LOG(INFO) << "Calling system command " << command_ << " on instance " << *it; - - try - { - std::string dicom; - context_.ReadDicom(dicom, *it); - - TemporaryFile tmp; - tmp.Write(dicom); - - std::vector args = arguments_; - args.push_back(tmp.GetPath()); - - SystemToolbox::ExecuteSystemCommand(command_, args); - - // Only chain with other commands if this command succeeds - outputs.push_back(*it); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Unable to call system command " << command_ - << " on instance " << *it << " in a Lua script: " << e.What(); - } - } - - return true; - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/CallSystemCommand.h --- a/OrthancServer/Scheduler/CallSystemCommand.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" -#include "../ServerContext.h" - -namespace Orthanc -{ - class CallSystemCommand : public IServerCommand - { - private: - ServerContext& context_; - std::string command_; - std::vector arguments_; - - public: - CallSystemCommand(ServerContext& context, - const std::string& command, - const std::vector& arguments); - - virtual bool Apply(ListOfStrings& outputs, - const ListOfStrings& inputs); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/DeleteInstanceCommand.cpp --- a/OrthancServer/Scheduler/DeleteInstanceCommand.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" -#include "DeleteInstanceCommand.h" - -#include "../../Core/Logging.h" - -namespace Orthanc -{ - bool DeleteInstanceCommand::Apply(ListOfStrings& outputs, - const ListOfStrings& inputs) - { - for (ListOfStrings::const_iterator - it = inputs.begin(); it != inputs.end(); ++it) - { - LOG(INFO) << "Deleting instance " << *it; - - try - { - Json::Value tmp; - context_.DeleteResource(tmp, *it, ResourceType_Instance); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Unable to delete instance " << *it << ": " << e.What(); - } - } - - return true; - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/DeleteInstanceCommand.h --- a/OrthancServer/Scheduler/DeleteInstanceCommand.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" -#include "../ServerContext.h" - -namespace Orthanc -{ - class DeleteInstanceCommand : public IServerCommand - { - private: - ServerContext& context_; - - public: - DeleteInstanceCommand(ServerContext& context) : context_(context) - { - } - - virtual bool Apply(ListOfStrings& outputs, - const ListOfStrings& inputs); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/IServerCommand.h --- a/OrthancServer/Scheduler/IServerCommand.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 -#include -#include - -namespace Orthanc -{ - class IServerCommand : public boost::noncopyable - { - public: - typedef std::list ListOfStrings; - - virtual ~IServerCommand() - { - } - - virtual bool Apply(ListOfStrings& outputs, - const ListOfStrings& inputs) = 0; - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/ModifyInstanceCommand.cpp --- a/OrthancServer/Scheduler/ModifyInstanceCommand.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" -#include "ModifyInstanceCommand.h" - -#include "../../Core/Logging.h" - -namespace Orthanc -{ - ModifyInstanceCommand::ModifyInstanceCommand(ServerContext& context, - RequestOrigin origin, - DicomModification* modification) : - context_(context), - origin_(origin), - modification_(modification) - { - modification_->SetAllowManualIdentifiers(true); - - if (modification_->IsReplaced(DICOM_TAG_PATIENT_ID)) - { - modification_->SetLevel(ResourceType_Patient); - } - else if (modification_->IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - modification_->SetLevel(ResourceType_Study); - } - else if (modification_->IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - modification_->SetLevel(ResourceType_Series); - } - else - { - modification_->SetLevel(ResourceType_Instance); - } - - if (origin_ != RequestOrigin_Lua) - { - // TODO If issued from HTTP, "remoteIp" and "username" must be provided - throw OrthancException(ErrorCode_NotImplemented); - } - } - - - ModifyInstanceCommand::~ModifyInstanceCommand() - { - if (modification_) - { - delete modification_; - } - } - - - bool ModifyInstanceCommand::Apply(ListOfStrings& outputs, - const ListOfStrings& inputs) - { - for (ListOfStrings::const_iterator - it = inputs.begin(); it != inputs.end(); ++it) - { - LOG(INFO) << "Modifying resource " << *it; - - try - { - std::auto_ptr modified; - - { - ServerContext::DicomCacheLocker lock(context_, *it); - modified.reset(lock.GetDicom().Clone(true)); - } - - modification_->Apply(*modified); - - DicomInstanceToStore toStore; - assert(origin_ == RequestOrigin_Lua); - toStore.SetLuaOrigin(); - toStore.SetParsedDicomFile(*modified); - // TODO other metadata - toStore.AddMetadata(ResourceType_Instance, MetadataType_ModifiedFrom, *it); - - std::string modifiedId; - context_.Store(modifiedId, toStore); - - // Only chain with other commands if this command succeeds - outputs.push_back(modifiedId); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Unable to modify instance " << *it << ": " << e.What(); - } - } - - return true; - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/ModifyInstanceCommand.h --- a/OrthancServer/Scheduler/ModifyInstanceCommand.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" -#include "../ServerContext.h" -#include "../../Core/DicomParsing/DicomModification.h" - -namespace Orthanc -{ - class ModifyInstanceCommand : public IServerCommand - { - private: - ServerContext& context_; - RequestOrigin origin_; - DicomModification* modification_; - - public: - ModifyInstanceCommand(ServerContext& context, - RequestOrigin origin, - DicomModification* modification); // takes the ownership - - virtual ~ModifyInstanceCommand(); - - const DicomModification& GetModification() const - { - return *modification_; - } - - virtual bool Apply(ListOfStrings& outputs, - const ListOfStrings& inputs); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/ServerCommandInstance.cpp --- a/OrthancServer/Scheduler/ServerCommandInstance.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" -#include "ServerCommandInstance.h" - -#include "../../Core/OrthancException.h" - -namespace Orthanc -{ - bool ServerCommandInstance::Execute(IListener& listener) - { - ListOfStrings outputs; - - bool success = false; - - try - { - if (command_->Apply(outputs, inputs_)) - { - success = true; - } - } - catch (OrthancException&) - { - } - - if (!success) - { - listener.SignalFailure(jobId_); - return true; - } - - for (std::list::iterator - it = next_.begin(); it != next_.end(); ++it) - { - for (ListOfStrings::const_iterator - output = outputs.begin(); output != outputs.end(); ++output) - { - (*it)->AddInput(*output); - } - } - - listener.SignalSuccess(jobId_); - return true; - } - - - ServerCommandInstance::ServerCommandInstance(IServerCommand *command, - const std::string& jobId) : - command_(command), - jobId_(jobId), - connectedToSink_(false) - { - if (command_ == NULL) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - ServerCommandInstance::~ServerCommandInstance() - { - if (command_ != NULL) - { - delete command_; - } - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/ServerCommandInstance.h --- a/OrthancServer/Scheduler/ServerCommandInstance.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../../Core/IDynamicObject.h" -#include "IServerCommand.h" - -namespace Orthanc -{ - class ServerCommandInstance : public IDynamicObject - { - friend class ServerScheduler; - - public: - class IListener - { - public: - virtual ~IListener() - { - } - - virtual void SignalSuccess(const std::string& jobId) = 0; - - virtual void SignalFailure(const std::string& jobId) = 0; - }; - - private: - typedef IServerCommand::ListOfStrings ListOfStrings; - - IServerCommand *command_; - std::string jobId_; - ListOfStrings inputs_; - std::list next_; - bool connectedToSink_; - - bool Execute(IListener& listener); - - public: - ServerCommandInstance(IServerCommand *command, - const std::string& jobId); - - virtual ~ServerCommandInstance(); - - const std::string& GetJobId() const - { - return jobId_; - } - - void AddInput(const std::string& input) - { - inputs_.push_back(input); - } - - void ConnectOutput(ServerCommandInstance& next) - { - next_.push_back(&next); - } - - void SetConnectedToSink(bool connected = true) - { - connectedToSink_ = connected; - } - - bool IsConnectedToSink() const - { - return connectedToSink_; - } - - const std::list& GetNextCommands() const - { - return next_; - } - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/ServerJob.cpp --- a/OrthancServer/Scheduler/ServerJob.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" -#include "ServerJob.h" - -#include "../../Core/OrthancException.h" -#include "../../Core/Toolbox.h" - -namespace Orthanc -{ - void ServerJob::CheckOrdering() - { - std::map index; - - unsigned int count = 0; - for (std::list::const_iterator - it = filters_.begin(); it != filters_.end(); ++it) - { - index[*it] = count++; - } - - for (std::list::const_iterator - it = filters_.begin(); it != filters_.end(); ++it) - { - const std::list& nextCommands = (*it)->GetNextCommands(); - - for (std::list::const_iterator - next = nextCommands.begin(); next != nextCommands.end(); ++next) - { - if (index.find(*next) == index.end() || - index[*next] <= index[*it]) - { - // You must reorder your calls to "ServerJob::AddCommand" - throw OrthancException(ErrorCode_BadJobOrdering); - } - } - } - } - - - size_t ServerJob::Submit(SharedMessageQueue& target, - ServerCommandInstance::IListener& listener) - { - if (submitted_) - { - // This job has already been submitted - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - CheckOrdering(); - - size_t size = filters_.size(); - - for (std::list::iterator - it = filters_.begin(); it != filters_.end(); ++it) - { - target.Enqueue(*it); - } - - filters_.clear(); - submitted_ = true; - - return size; - } - - - ServerJob::ServerJob() : - jobId_(Toolbox::GenerateUuid()), - submitted_(false), - description_("no description") - { - } - - - ServerJob::~ServerJob() - { - for (std::list::iterator - it = filters_.begin(); it != filters_.end(); ++it) - { - delete *it; - } - - for (std::list::iterator - it = payloads_.begin(); it != payloads_.end(); ++it) - { - delete *it; - } - } - - - ServerCommandInstance& ServerJob::AddCommand(IServerCommand* filter) - { - if (submitted_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - filters_.push_back(new ServerCommandInstance(filter, jobId_)); - - return *filters_.back(); - } - - - IDynamicObject& ServerJob::AddPayload(IDynamicObject* payload) - { - if (submitted_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - payloads_.push_back(payload); - - return *filters_.back(); - } - -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/ServerJob.h --- a/OrthancServer/Scheduler/ServerJob.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "ServerCommandInstance.h" -#include "../../Core/MultiThreading/SharedMessageQueue.h" - -namespace Orthanc -{ - class ServerJob - { - friend class ServerScheduler; - - private: - std::list filters_; - std::list payloads_; - std::string jobId_; - bool submitted_; - std::string description_; - - void CheckOrdering(); - - size_t Submit(SharedMessageQueue& target, - ServerCommandInstance::IListener& listener); - - public: - ServerJob(); - - ~ServerJob(); - - const std::string& GetId() const - { - return jobId_; - } - - void SetDescription(const std::string& description) - { - description_ = description; - } - - const std::string& GetDescription() const - { - return description_; - } - - ServerCommandInstance& AddCommand(IServerCommand* filter); - - // Take the ownership of a payload to a job. This payload will be - // automatically freed when the job succeeds or fails. - IDynamicObject& AddPayload(IDynamicObject* payload); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/ServerScheduler.cpp --- a/OrthancServer/Scheduler/ServerScheduler.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,359 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" -#include "ServerScheduler.h" - -#include "../../Core/OrthancException.h" -#include "../../Core/Logging.h" - -namespace Orthanc -{ - namespace - { - // Anonymous namespace to avoid clashes between compilation modules - class Sink : public IServerCommand - { - private: - ListOfStrings& target_; - - public: - explicit Sink(ListOfStrings& target) : target_(target) - { - } - - virtual bool Apply(ListOfStrings& outputs, - const ListOfStrings& inputs) - { - for (ListOfStrings::const_iterator - it = inputs.begin(); it != inputs.end(); ++it) - { - target_.push_back(*it); - } - - return true; - } - }; - } - - - ServerScheduler::JobInfo& ServerScheduler::GetJobInfo(const std::string& jobId) - { - Jobs::iterator info = jobs_.find(jobId); - - if (info == jobs_.end()) - { - throw OrthancException(ErrorCode_InternalError); - } - - return info->second; - } - - - void ServerScheduler::SignalSuccess(const std::string& jobId) - { - boost::mutex::scoped_lock lock(mutex_); - - JobInfo& info = GetJobInfo(jobId); - info.success_++; - - assert(info.failures_ == 0); - - if (info.success_ >= info.size_) - { - if (info.watched_) - { - watchedJobStatus_[jobId] = JobStatus_Success; - watchedJobFinished_.notify_all(); - } - - LOG(INFO) << "Job successfully finished (" << info.description_ << ")"; - jobs_.erase(jobId); - - availableJob_.Release(); - } - } - - - void ServerScheduler::SignalFailure(const std::string& jobId) - { - boost::mutex::scoped_lock lock(mutex_); - - JobInfo& info = GetJobInfo(jobId); - info.failures_++; - - if (info.success_ + info.failures_ >= info.size_) - { - if (info.watched_) - { - watchedJobStatus_[jobId] = JobStatus_Failure; - watchedJobFinished_.notify_all(); - } - - LOG(ERROR) << "Job has failed (" << info.description_ << ")"; - jobs_.erase(jobId); - - availableJob_.Release(); - } - } - - - void ServerScheduler::Worker(ServerScheduler* that) - { - static const int32_t TIMEOUT = 100; - - LOG(WARNING) << "The server scheduler has started"; - - while (!that->finish_) - { - std::auto_ptr object(that->queue_.Dequeue(TIMEOUT)); - if (object.get() != NULL) - { - ServerCommandInstance& filter = dynamic_cast(*object); - - // Skip the execution of this filter if its parent job has - // previously failed. - bool jobHasFailed; - { - boost::mutex::scoped_lock lock(that->mutex_); - JobInfo& info = that->GetJobInfo(filter.GetJobId()); - jobHasFailed = (info.failures_ > 0 || info.cancel_); - } - - if (jobHasFailed) - { - that->SignalFailure(filter.GetJobId()); - } - else - { - filter.Execute(*that); - } - } - } - } - - - void ServerScheduler::SubmitInternal(ServerJob& job, - bool watched) - { - availableJob_.Acquire(); - - boost::mutex::scoped_lock lock(mutex_); - - JobInfo info; - info.size_ = job.Submit(queue_, *this); - info.cancel_ = false; - info.success_ = 0; - info.failures_ = 0; - info.description_ = job.GetDescription(); - info.watched_ = watched; - - assert(info.size_ > 0); - - if (watched) - { - watchedJobStatus_[job.GetId()] = JobStatus_Running; - } - - jobs_[job.GetId()] = info; - - LOG(INFO) << "New job submitted (" << job.description_ << ")"; - } - - - ServerScheduler::ServerScheduler(unsigned int maxJobs) : availableJob_(maxJobs) - { - if (maxJobs == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - finish_ = false; - worker_ = boost::thread(Worker, this); - } - - - ServerScheduler::~ServerScheduler() - { - if (!finish_) - { - LOG(ERROR) << "INTERNAL ERROR: ServerScheduler::Finalize() should be invoked manually to avoid mess in the destruction order!"; - Stop(); - } - } - - - void ServerScheduler::Stop() - { - if (!finish_) - { - finish_ = true; - - if (worker_.joinable()) - { - worker_.join(); - } - } - } - - - void ServerScheduler::Submit(ServerJob& job) - { - if (job.filters_.empty()) - { - return; - } - - SubmitInternal(job, false); - } - - - bool ServerScheduler::SubmitAndWait(ListOfStrings& outputs, - ServerJob& job) - { - std::string jobId = job.GetId(); - - outputs.clear(); - - if (job.filters_.empty()) - { - return true; - } - - // Add a sink filter to collect all the results of the filters - // that have no next filter. - ServerCommandInstance& sink = job.AddCommand(new Sink(outputs)); - - for (std::list::iterator - it = job.filters_.begin(); it != job.filters_.end(); ++it) - { - if ((*it) != &sink && - (*it)->IsConnectedToSink()) - { - (*it)->ConnectOutput(sink); - } - } - - // Submit the job - SubmitInternal(job, true); - - // Wait for the job to complete (either success or failure) - JobStatus status; - - { - boost::mutex::scoped_lock lock(mutex_); - - assert(watchedJobStatus_.find(jobId) != watchedJobStatus_.end()); - - while (watchedJobStatus_[jobId] == JobStatus_Running) - { - watchedJobFinished_.wait(lock); - } - - status = watchedJobStatus_[jobId]; - watchedJobStatus_.erase(jobId); - } - - return (status == JobStatus_Success); - } - - - bool ServerScheduler::SubmitAndWait(ServerJob& job) - { - ListOfStrings ignoredSink; - return SubmitAndWait(ignoredSink, job); - } - - - bool ServerScheduler::IsRunning(const std::string& jobId) - { - boost::mutex::scoped_lock lock(mutex_); - return jobs_.find(jobId) != jobs_.end(); - } - - - void ServerScheduler::Cancel(const std::string& jobId) - { - boost::mutex::scoped_lock lock(mutex_); - - Jobs::iterator job = jobs_.find(jobId); - - if (job != jobs_.end()) - { - job->second.cancel_ = true; - LOG(WARNING) << "Canceling a job (" << job->second.description_ << ")"; - } - } - - - float ServerScheduler::GetProgress(const std::string& jobId) - { - boost::mutex::scoped_lock lock(mutex_); - - Jobs::iterator job = jobs_.find(jobId); - - if (job == jobs_.end() || - job->second.size_ == 0 /* should never happen */) - { - // This job is not running - return 1; - } - - if (job->second.failures_ != 0) - { - return 1; - } - - if (job->second.size_ == 1) - { - return static_cast(job->second.success_); - } - - return (static_cast(job->second.success_) / - static_cast(job->second.size_ - 1)); - } - - - void ServerScheduler::GetListOfJobs(ListOfStrings& jobs) - { - boost::mutex::scoped_lock lock(mutex_); - - jobs.clear(); - - for (Jobs::const_iterator - it = jobs_.begin(); it != jobs_.end(); ++it) - { - jobs.push_back(it->first); - } - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/ServerScheduler.h --- a/OrthancServer/Scheduler/ServerScheduler.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "ServerJob.h" - -#include "../../Core/MultiThreading/Semaphore.h" - -namespace Orthanc -{ - class ServerScheduler : public ServerCommandInstance::IListener - { - private: - struct JobInfo - { - bool watched_; - bool cancel_; - size_t size_; - size_t success_; - size_t failures_; - std::string description_; - }; - - enum JobStatus - { - JobStatus_Running = 1, - JobStatus_Success = 2, - JobStatus_Failure = 3 - }; - - typedef IServerCommand::ListOfStrings ListOfStrings; - typedef std::map Jobs; - - boost::mutex mutex_; - boost::condition_variable watchedJobFinished_; - Jobs jobs_; - SharedMessageQueue queue_; - bool finish_; - boost::thread worker_; - std::map watchedJobStatus_; - Semaphore availableJob_; - - JobInfo& GetJobInfo(const std::string& jobId); - - virtual void SignalSuccess(const std::string& jobId); - - virtual void SignalFailure(const std::string& jobId); - - static void Worker(ServerScheduler* that); - - void SubmitInternal(ServerJob& job, - bool watched); - - public: - explicit ServerScheduler(unsigned int maxjobs); - - ~ServerScheduler(); - - void Stop(); - - void Submit(ServerJob& job); - - bool SubmitAndWait(ListOfStrings& outputs, - ServerJob& job); - - bool SubmitAndWait(ServerJob& job); - - bool IsRunning(const std::string& jobId); - - void Cancel(const std::string& jobId); - - // Returns a number between 0 and 1 - float GetProgress(const std::string& jobId); - - bool IsRunning(const ServerJob& job) - { - return IsRunning(job.GetId()); - } - - void Cancel(const ServerJob& job) - { - Cancel(job.GetId()); - } - - float GetProgress(const ServerJob& job) - { - return GetProgress(job.GetId()); - } - - void GetListOfJobs(ListOfStrings& jobs); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/StorePeerCommand.cpp --- a/OrthancServer/Scheduler/StorePeerCommand.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" -#include "StorePeerCommand.h" - -#include "../../Core/Logging.h" -#include "../../Core/HttpClient.h" - -namespace Orthanc -{ - StorePeerCommand::StorePeerCommand(ServerContext& context, - const WebServiceParameters& peer, - bool ignoreExceptions) : - context_(context), - peer_(peer), - ignoreExceptions_(ignoreExceptions) - { - } - - bool StorePeerCommand::Apply(ListOfStrings& outputs, - const ListOfStrings& inputs) - { - // Configure the HTTP client - HttpClient client(peer_, "instances"); - client.SetMethod(HttpMethod_Post); - - for (ListOfStrings::const_iterator - it = inputs.begin(); it != inputs.end(); ++it) - { - LOG(INFO) << "Sending resource " << *it << " to peer \"" - << peer_.GetUrl() << "\""; - - try - { - context_.ReadDicom(client.GetBody(), *it); - - std::string answer; - if (!client.Apply(answer)) - { - LOG(ERROR) << "Unable to send resource " << *it << " to peer \"" << peer_.GetUrl() << "\""; - throw OrthancException(ErrorCode_NetworkProtocol); - } - - // Only chain with other commands if this command succeeds - outputs.push_back(*it); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Unable to forward to an Orthanc peer in (instance " - << *it << ", peer " << peer_.GetUrl() << "): " << e.What(); - - if (!ignoreExceptions_) - { - throw; - } - } - } - - return true; - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/StorePeerCommand.h --- a/OrthancServer/Scheduler/StorePeerCommand.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" -#include "../ServerContext.h" -#include "../OrthancInitialization.h" - -namespace Orthanc -{ - class StorePeerCommand : public IServerCommand - { - private: - ServerContext& context_; - WebServiceParameters peer_; - bool ignoreExceptions_; - - public: - StorePeerCommand(ServerContext& context, - const WebServiceParameters& peer, - bool ignoreExceptions); - - virtual bool Apply(ListOfStrings& outputs, - const ListOfStrings& inputs); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/StoreScuCommand.cpp --- a/OrthancServer/Scheduler/StoreScuCommand.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" -#include "StoreScuCommand.h" - -#include "../../Core/Logging.h" - -namespace Orthanc -{ - StoreScuCommand::StoreScuCommand(ServerContext& context, - const std::string& localAet, - const RemoteModalityParameters& modality, - bool ignoreExceptions) : - context_(context), - modality_(modality), - ignoreExceptions_(ignoreExceptions), - localAet_(localAet), - moveOriginatorID_(0) - { - } - - - void StoreScuCommand::SetMoveOriginator(const std::string& aet, - uint16_t id) - { - moveOriginatorAET_ = aet; - moveOriginatorID_ = id; - } - - - bool StoreScuCommand::Apply(ListOfStrings& outputs, - const ListOfStrings& inputs) - { - ReusableDicomUserConnection::Locker locker(context_.GetReusableDicomUserConnection(), localAet_, modality_); - - for (ListOfStrings::const_iterator - it = inputs.begin(); it != inputs.end(); ++it) - { - LOG(INFO) << "Sending resource " << *it << " to modality \"" - << modality_.GetApplicationEntityTitle() << "\""; - - try - { - std::string dicom; - context_.ReadDicom(dicom, *it); - - locker.GetConnection().Store(dicom, moveOriginatorAET_, moveOriginatorID_); - - // Only chain with other commands if this command succeeds - outputs.push_back(*it); - } - catch (OrthancException& e) - { - // Ignore transmission errors (e.g. if the remote modality is - // powered off) - LOG(ERROR) << "Unable to forward to a modality in (instance " - << *it << "): " << e.What(); - - if (!ignoreExceptions_) - { - throw; - } - } - } - - return true; - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/Scheduler/StoreScuCommand.h --- a/OrthancServer/Scheduler/StoreScuCommand.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" -#include "../ServerContext.h" - -namespace Orthanc -{ - class StoreScuCommand : public IServerCommand - { - private: - ServerContext& context_; - RemoteModalityParameters modality_; - bool ignoreExceptions_; - std::string localAet_; - std::string moveOriginatorAET_; - uint16_t moveOriginatorID_; - - public: - StoreScuCommand(ServerContext& context, - const std::string& localAet, - const RemoteModalityParameters& modality, - bool ignoreExceptions); - - void SetMoveOriginator(const std::string& aet, - uint16_t id); - - virtual bool Apply(ListOfStrings& outputs, - const ListOfStrings& inputs); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Sat May 19 16:29:00 2018 +0200 +++ b/OrthancServer/ServerContext.cpp Sat May 19 16:40:26 2018 +0200 @@ -45,12 +45,6 @@ #include #include - -#include "Scheduler/CallSystemCommand.h" -#include "Scheduler/DeleteInstanceCommand.h" -#include "Scheduler/ModifyInstanceCommand.h" -#include "Scheduler/StoreScuCommand.h" -#include "Scheduler/StorePeerCommand.h" #include "OrthancRestApi/OrthancRestApi.h" #include "../Plugins/Engine/OrthancPlugins.h" #include "Search/LookupResource.h" @@ -120,7 +114,6 @@ storeMD5_(true), provider_(*this), dicomCache_(provider_, DICOM_CACHE_SIZE), - scheduler_(Configuration::GetGlobalUnsignedIntegerParameter("LimitJobs", 10)), lua_(*this), #if ORTHANC_ENABLE_PLUGINS == 1 plugins_(NULL), @@ -129,9 +122,6 @@ queryRetrieveArchive_(Configuration::GetGlobalUnsignedIntegerParameter("QueryRetrieveSize", 10)), defaultLocalAet_(Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC")) { - uint64_t s = Configuration::GetGlobalUnsignedIntegerParameter("DicomAssociationCloseDelay", 5); // In seconds - scu_.SetMillisecondsBeforeClose(s * 1000); // Milliseconds are expected here - listeners_.push_back(ServerListener(lua_, "Lua")); jobsEngine_.SetWorkersCount(Configuration::GetGlobalUnsignedIntegerParameter("ConcurrentJobs", 2)); @@ -169,11 +159,8 @@ changeThread_.join(); } - scu_.Finalize(); - // Do not change the order below! jobsEngine_.Stop(); - scheduler_.Stop(); index_.Stop(); } } diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/ServerContext.h --- a/OrthancServer/ServerContext.h Sat May 19 16:29:00 2018 +0200 +++ b/OrthancServer/ServerContext.h Sat May 19 16:40:26 2018 +0200 @@ -33,22 +33,21 @@ #pragma once -#include "../Core/MultiThreading/SharedMessageQueue.h" +#include "DicomInstanceToStore.h" +#include "IServerListener.h" +#include "LuaScripting.h" +#include "OrthancHttpHandler.h" +#include "ServerIndex.h" + #include "../Core/Cache/MemoryCache.h" #include "../Core/Cache/SharedArchive.h" +#include "../Core/DicomParsing/ParsedDicomFile.h" #include "../Core/FileStorage/IStorageArea.h" +#include "../Core/JobsEngine/JobsEngine.h" #include "../Core/Lua/LuaContext.h" +#include "../Core/MultiThreading/SharedMessageQueue.h" #include "../Core/RestApi/RestApiOutput.h" #include "../Plugins/Engine/OrthancPlugins.h" -#include "DicomInstanceToStore.h" -#include "../Core/DicomNetworking/ReusableDicomUserConnection.h" -#include "IServerListener.h" -#include "LuaScripting.h" -#include "../Core/DicomParsing/ParsedDicomFile.h" -#include "Scheduler/ServerScheduler.h" -#include "ServerIndex.h" -#include "OrthancHttpHandler.h" -#include "../Core/JobsEngine/JobsEngine.h" #include #include @@ -119,8 +118,6 @@ DicomCacheProvider provider_; boost::mutex dicomCacheMutex_; MemoryCache dicomCache_; - ReusableDicomUserConnection scu_; - ServerScheduler scheduler_; JobsEngine jobsEngine_; LuaScripting lua_; @@ -240,16 +237,6 @@ return storeMD5_; } - ReusableDicomUserConnection& GetReusableDicomUserConnection() - { - return scu_; - } - - ServerScheduler& GetScheduler() - { - return scheduler_; - } - JobsEngine& GetJobsEngine() { return jobsEngine_; diff -r f7a84b551ee4 -r 3ff4c50647ea OrthancServer/main.cpp --- a/OrthancServer/main.cpp Sat May 19 16:29:00 2018 +0200 +++ b/OrthancServer/main.cpp Sat May 19 16:40:26 2018 +0200 @@ -42,7 +42,6 @@ #include "../Core/Lua/LuaFunctionCall.h" #include "../Core/DicomFormat/DicomArray.h" #include "../Core/DicomNetworking/DicomServer.h" -#include "../Core/DicomNetworking/ReusableDicomUserConnection.h" #include "OrthancInitialization.h" #include "ServerContext.h" #include "OrthancFindRequestHandler.h" diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/CMake/OrthancFrameworkConfiguration.cmake --- a/Resources/CMake/OrthancFrameworkConfiguration.cmake Sat May 19 16:29:00 2018 +0200 +++ b/Resources/CMake/OrthancFrameworkConfiguration.cmake Sat May 19 16:40:26 2018 +0200 @@ -423,13 +423,12 @@ ${ORTHANC_ROOT}/Core/DicomNetworking/DicomFindAnswers.cpp ${ORTHANC_ROOT}/Core/DicomNetworking/DicomServer.cpp ${ORTHANC_ROOT}/Core/DicomNetworking/DicomUserConnection.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/RemoteModalityParameters.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/ReusableDicomUserConnection.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/CommandDispatcher.cpp ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/FindScp.cpp ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/MoveScp.cpp ${ORTHANC_ROOT}/Core/DicomNetworking/Internals/StoreScp.cpp + ${ORTHANC_ROOT}/Core/DicomNetworking/RemoteModalityParameters.cpp + ${ORTHANC_ROOT}/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp ) else() add_definitions(-DORTHANC_ENABLE_DCMTK_NETWORKING=0) @@ -497,7 +496,6 @@ list(APPEND ORTHANC_CORE_SOURCES_INTERNAL ${ORTHANC_ROOT}/Core/Cache/SharedArchive.cpp - ${ORTHANC_ROOT}/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp ${ORTHANC_ROOT}/Core/FileStorage/FilesystemStorage.cpp ${ORTHANC_ROOT}/Core/JobsEngine/JobInfo.cpp ${ORTHANC_ROOT}/Core/JobsEngine/JobStatus.cpp diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/BagOfTasks.h --- a/Resources/Graveyard/BagOfTasks.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../ICommand.h" - -#include -#include - -namespace Orthanc -{ - class BagOfTasks : public boost::noncopyable - { - private: - typedef std::list Tasks; - - Tasks tasks_; - - public: - ~BagOfTasks() - { - for (Tasks::iterator it = tasks_.begin(); it != tasks_.end(); ++it) - { - delete *it; - } - } - - ICommand* Pop() - { - ICommand* task = tasks_.front(); - tasks_.pop_front(); - return task; - } - - void Push(ICommand* task) // Takes ownership - { - if (task != NULL) - { - tasks_.push_back(task); - } - } - - size_t GetSize() const - { - return tasks_.size(); - } - - bool IsEmpty() const - { - return tasks_.empty(); - } - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/BagOfTasksProcessor.cpp --- a/Resources/Graveyard/BagOfTasksProcessor.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeaders.h" -#include "BagOfTasksProcessor.h" - -#include "../Logging.h" -#include "../OrthancException.h" - -#include - -namespace Orthanc -{ - class BagOfTasksProcessor::Task : public IDynamicObject - { - private: - uint64_t bag_; - std::auto_ptr command_; - - public: - Task(uint64_t bag, - ICommand* command) : - bag_(bag), - command_(command) - { - } - - bool Execute() - { - try - { - return command_->Execute(); - } - catch (OrthancException& e) - { - LOG(ERROR) << "Exception while processing a bag of tasks: " << e.What(); - return false; - } - catch (std::runtime_error& e) - { - LOG(ERROR) << "Runtime exception while processing a bag of tasks: " << e.what(); - return false; - } - catch (...) - { - LOG(ERROR) << "Native exception while processing a bag of tasks"; - return false; - } - } - - uint64_t GetBag() - { - return bag_; - } - }; - - - void BagOfTasksProcessor::SignalProgress(Task& task, - Bag& bag) - { - assert(bag.done_ < bag.size_); - - bag.done_ += 1; - - if (bag.done_ == bag.size_) - { - exitStatus_[task.GetBag()] = (bag.status_ == BagStatus_Running); - bagFinished_.notify_all(); - } - } - - void BagOfTasksProcessor::Worker(BagOfTasksProcessor* that) - { - while (that->continue_) - { - std::auto_ptr obj(that->queue_.Dequeue(100)); - if (obj.get() != NULL) - { - Task& task = *dynamic_cast(obj.get()); - - { - boost::mutex::scoped_lock lock(that->mutex_); - - Bags::iterator bag = that->bags_.find(task.GetBag()); - assert(bag != that->bags_.end()); - assert(bag->second.done_ < bag->second.size_); - - if (bag->second.status_ != BagStatus_Running) - { - // Do not execute this task, as its parent bag of tasks - // has failed or is tagged as canceled - that->SignalProgress(task, bag->second); - continue; - } - } - - bool success = task.Execute(); - - { - boost::mutex::scoped_lock lock(that->mutex_); - - Bags::iterator bag = that->bags_.find(task.GetBag()); - assert(bag != that->bags_.end()); - - if (!success) - { - bag->second.status_ = BagStatus_Failed; - } - - that->SignalProgress(task, bag->second); - } - } - } - } - - - void BagOfTasksProcessor::Cancel(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - Bags::iterator it = bags_.find(bag); - if (it != bags_.end()) - { - it->second.status_ = BagStatus_Canceled; - } - } - - - bool BagOfTasksProcessor::Join(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - while (continue_) - { - ExitStatus::iterator it = exitStatus_.find(bag); - if (it == exitStatus_.end()) // The bag is still running - { - bagFinished_.wait(lock); - } - else - { - bool status = it->second; - exitStatus_.erase(it); - return status; - } - } - - return false; // The processor is stopping - } - - - float BagOfTasksProcessor::GetProgress(int64_t bag) - { - boost::mutex::scoped_lock lock(mutex_); - - Bags::const_iterator it = bags_.find(bag); - if (it == bags_.end()) - { - // The bag of tasks has finished - return 1.0f; - } - else - { - return (static_cast(it->second.done_) / - static_cast(it->second.size_)); - } - } - - - bool BagOfTasksProcessor::Handle::Join() - { - if (hasJoined_) - { - return status_; - } - else - { - status_ = that_.Join(bag_); - hasJoined_ = true; - return status_; - } - } - - - BagOfTasksProcessor::BagOfTasksProcessor(size_t countThreads) : - countBags_(0), - continue_(true) - { - if (countThreads == 0) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - threads_.resize(countThreads); - - for (size_t i = 0; i < threads_.size(); i++) - { - threads_[i] = new boost::thread(Worker, this); - } - } - - - BagOfTasksProcessor::~BagOfTasksProcessor() - { - continue_ = false; - - bagFinished_.notify_all(); // Wakes up all the pending "Join()" - - for (size_t i = 0; i < threads_.size(); i++) - { - if (threads_[i]) - { - if (threads_[i]->joinable()) - { - threads_[i]->join(); - } - - delete threads_[i]; - threads_[i] = NULL; - } - } - } - - - BagOfTasksProcessor::Handle* BagOfTasksProcessor::Submit(BagOfTasks& tasks) - { - if (tasks.GetSize() == 0) - { - return new Handle(*this, 0, true); - } - - boost::mutex::scoped_lock lock(mutex_); - - uint64_t id = countBags_; - countBags_ += 1; - - Bag bag(tasks.GetSize()); - bags_[id] = bag; - - while (!tasks.IsEmpty()) - { - queue_.Enqueue(new Task(id, tasks.Pop())); - } - - return new Handle(*this, id, false); - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/BagOfTasksProcessor.h --- a/Resources/Graveyard/BagOfTasksProcessor.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "BagOfTasks.h" -#include "SharedMessageQueue.h" - -#include -#include - -namespace Orthanc -{ - class BagOfTasksProcessor : public boost::noncopyable - { - private: - enum BagStatus - { - BagStatus_Running, - BagStatus_Canceled, - BagStatus_Failed - }; - - - struct Bag - { - size_t size_; - size_t done_; - BagStatus status_; - - Bag() : - size_(0), - done_(0), - status_(BagStatus_Failed) - { - } - - explicit Bag(size_t size) : - size_(size), - done_(0), - status_(BagStatus_Running) - { - } - }; - - class Task; - - - typedef std::map Bags; - typedef std::map ExitStatus; - - SharedMessageQueue queue_; - - boost::mutex mutex_; - uint64_t countBags_; - Bags bags_; - std::vector threads_; - ExitStatus exitStatus_; - bool continue_; - - boost::condition_variable bagFinished_; - - static void Worker(BagOfTasksProcessor* that); - - void Cancel(int64_t bag); - - bool Join(int64_t bag); - - float GetProgress(int64_t bag); - - void SignalProgress(Task& task, - Bag& bag); - - public: - class Handle : public boost::noncopyable - { - friend class BagOfTasksProcessor; - - private: - BagOfTasksProcessor& that_; - uint64_t bag_; - bool hasJoined_; - bool status_; - - Handle(BagOfTasksProcessor& that, - uint64_t bag, - bool empty) : - that_(that), - bag_(bag), - hasJoined_(empty) - { - } - - public: - ~Handle() - { - Join(); - } - - void Cancel() - { - that_.Cancel(bag_); - } - - bool Join(); - - float GetProgress() - { - return that_.GetProgress(bag_); - } - }; - - - explicit BagOfTasksProcessor(size_t countThreads); - - ~BagOfTasksProcessor(); - - Handle* Submit(BagOfTasks& tasks); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Multithreading/BagOfTasks.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Multithreading/BagOfTasks.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,84 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../ICommand.h" + +#include +#include + +namespace Orthanc +{ + class BagOfTasks : public boost::noncopyable + { + private: + typedef std::list Tasks; + + Tasks tasks_; + + public: + ~BagOfTasks() + { + for (Tasks::iterator it = tasks_.begin(); it != tasks_.end(); ++it) + { + delete *it; + } + } + + ICommand* Pop() + { + ICommand* task = tasks_.front(); + tasks_.pop_front(); + return task; + } + + void Push(ICommand* task) // Takes ownership + { + if (task != NULL) + { + tasks_.push_back(task); + } + } + + size_t GetSize() const + { + return tasks_.size(); + } + + bool IsEmpty() const + { + return tasks_.empty(); + } + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Multithreading/BagOfTasksProcessor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Multithreading/BagOfTasksProcessor.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,277 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeaders.h" +#include "BagOfTasksProcessor.h" + +#include "../Logging.h" +#include "../OrthancException.h" + +#include + +namespace Orthanc +{ + class BagOfTasksProcessor::Task : public IDynamicObject + { + private: + uint64_t bag_; + std::auto_ptr command_; + + public: + Task(uint64_t bag, + ICommand* command) : + bag_(bag), + command_(command) + { + } + + bool Execute() + { + try + { + return command_->Execute(); + } + catch (OrthancException& e) + { + LOG(ERROR) << "Exception while processing a bag of tasks: " << e.What(); + return false; + } + catch (std::runtime_error& e) + { + LOG(ERROR) << "Runtime exception while processing a bag of tasks: " << e.what(); + return false; + } + catch (...) + { + LOG(ERROR) << "Native exception while processing a bag of tasks"; + return false; + } + } + + uint64_t GetBag() + { + return bag_; + } + }; + + + void BagOfTasksProcessor::SignalProgress(Task& task, + Bag& bag) + { + assert(bag.done_ < bag.size_); + + bag.done_ += 1; + + if (bag.done_ == bag.size_) + { + exitStatus_[task.GetBag()] = (bag.status_ == BagStatus_Running); + bagFinished_.notify_all(); + } + } + + void BagOfTasksProcessor::Worker(BagOfTasksProcessor* that) + { + while (that->continue_) + { + std::auto_ptr obj(that->queue_.Dequeue(100)); + if (obj.get() != NULL) + { + Task& task = *dynamic_cast(obj.get()); + + { + boost::mutex::scoped_lock lock(that->mutex_); + + Bags::iterator bag = that->bags_.find(task.GetBag()); + assert(bag != that->bags_.end()); + assert(bag->second.done_ < bag->second.size_); + + if (bag->second.status_ != BagStatus_Running) + { + // Do not execute this task, as its parent bag of tasks + // has failed or is tagged as canceled + that->SignalProgress(task, bag->second); + continue; + } + } + + bool success = task.Execute(); + + { + boost::mutex::scoped_lock lock(that->mutex_); + + Bags::iterator bag = that->bags_.find(task.GetBag()); + assert(bag != that->bags_.end()); + + if (!success) + { + bag->second.status_ = BagStatus_Failed; + } + + that->SignalProgress(task, bag->second); + } + } + } + } + + + void BagOfTasksProcessor::Cancel(int64_t bag) + { + boost::mutex::scoped_lock lock(mutex_); + + Bags::iterator it = bags_.find(bag); + if (it != bags_.end()) + { + it->second.status_ = BagStatus_Canceled; + } + } + + + bool BagOfTasksProcessor::Join(int64_t bag) + { + boost::mutex::scoped_lock lock(mutex_); + + while (continue_) + { + ExitStatus::iterator it = exitStatus_.find(bag); + if (it == exitStatus_.end()) // The bag is still running + { + bagFinished_.wait(lock); + } + else + { + bool status = it->second; + exitStatus_.erase(it); + return status; + } + } + + return false; // The processor is stopping + } + + + float BagOfTasksProcessor::GetProgress(int64_t bag) + { + boost::mutex::scoped_lock lock(mutex_); + + Bags::const_iterator it = bags_.find(bag); + if (it == bags_.end()) + { + // The bag of tasks has finished + return 1.0f; + } + else + { + return (static_cast(it->second.done_) / + static_cast(it->second.size_)); + } + } + + + bool BagOfTasksProcessor::Handle::Join() + { + if (hasJoined_) + { + return status_; + } + else + { + status_ = that_.Join(bag_); + hasJoined_ = true; + return status_; + } + } + + + BagOfTasksProcessor::BagOfTasksProcessor(size_t countThreads) : + countBags_(0), + continue_(true) + { + if (countThreads == 0) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + threads_.resize(countThreads); + + for (size_t i = 0; i < threads_.size(); i++) + { + threads_[i] = new boost::thread(Worker, this); + } + } + + + BagOfTasksProcessor::~BagOfTasksProcessor() + { + continue_ = false; + + bagFinished_.notify_all(); // Wakes up all the pending "Join()" + + for (size_t i = 0; i < threads_.size(); i++) + { + if (threads_[i]) + { + if (threads_[i]->joinable()) + { + threads_[i]->join(); + } + + delete threads_[i]; + threads_[i] = NULL; + } + } + } + + + BagOfTasksProcessor::Handle* BagOfTasksProcessor::Submit(BagOfTasks& tasks) + { + if (tasks.GetSize() == 0) + { + return new Handle(*this, 0, true); + } + + boost::mutex::scoped_lock lock(mutex_); + + uint64_t id = countBags_; + countBags_ += 1; + + Bag bag(tasks.GetSize()); + bags_[id] = bag; + + while (!tasks.IsEmpty()) + { + queue_.Enqueue(new Task(id, tasks.Pop())); + } + + return new Handle(*this, id, false); + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Multithreading/BagOfTasksProcessor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Multithreading/BagOfTasksProcessor.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,150 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "BagOfTasks.h" +#include "SharedMessageQueue.h" + +#include +#include + +namespace Orthanc +{ + class BagOfTasksProcessor : public boost::noncopyable + { + private: + enum BagStatus + { + BagStatus_Running, + BagStatus_Canceled, + BagStatus_Failed + }; + + + struct Bag + { + size_t size_; + size_t done_; + BagStatus status_; + + Bag() : + size_(0), + done_(0), + status_(BagStatus_Failed) + { + } + + explicit Bag(size_t size) : + size_(size), + done_(0), + status_(BagStatus_Running) + { + } + }; + + class Task; + + + typedef std::map Bags; + typedef std::map ExitStatus; + + SharedMessageQueue queue_; + + boost::mutex mutex_; + uint64_t countBags_; + Bags bags_; + std::vector threads_; + ExitStatus exitStatus_; + bool continue_; + + boost::condition_variable bagFinished_; + + static void Worker(BagOfTasksProcessor* that); + + void Cancel(int64_t bag); + + bool Join(int64_t bag); + + float GetProgress(int64_t bag); + + void SignalProgress(Task& task, + Bag& bag); + + public: + class Handle : public boost::noncopyable + { + friend class BagOfTasksProcessor; + + private: + BagOfTasksProcessor& that_; + uint64_t bag_; + bool hasJoined_; + bool status_; + + Handle(BagOfTasksProcessor& that, + uint64_t bag, + bool empty) : + that_(that), + bag_(bag), + hasJoined_(empty) + { + } + + public: + ~Handle() + { + Join(); + } + + void Cancel() + { + that_.Cancel(bag_); + } + + bool Join(); + + float GetProgress() + { + return that_.GetProgress(bag_); + } + }; + + + explicit BagOfTasksProcessor(size_t countThreads); + + ~BagOfTasksProcessor(); + + Handle* Submit(BagOfTasks& tasks); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Multithreading/Mutex.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Multithreading/Mutex.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,122 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeaders.h" +#include "Mutex.h" + +#include "../OrthancException.h" + +#if defined(_WIN32) +#include +#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#include +#else +#error Support your platform here +#endif + +namespace Orthanc +{ +#if defined (_WIN32) + + struct Mutex::PImpl + { + CRITICAL_SECTION criticalSection_; + }; + + Mutex::Mutex() + { + pimpl_ = new PImpl; + ::InitializeCriticalSection(&pimpl_->criticalSection_); + } + + Mutex::~Mutex() + { + ::DeleteCriticalSection(&pimpl_->criticalSection_); + delete pimpl_; + } + + void Mutex::Lock() + { + ::EnterCriticalSection(&pimpl_->criticalSection_); + } + + void Mutex::Unlock() + { + ::LeaveCriticalSection(&pimpl_->criticalSection_); + } + + +#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) + + struct Mutex::PImpl + { + pthread_mutex_t mutex_; + }; + + Mutex::Mutex() + { + pimpl_ = new PImpl; + + if (pthread_mutex_init(&pimpl_->mutex_, NULL) != 0) + { + delete pimpl_; + throw OrthancException(ErrorCode_InternalError); + } + } + + Mutex::~Mutex() + { + pthread_mutex_destroy(&pimpl_->mutex_); + delete pimpl_; + } + + void Mutex::Lock() + { + if (pthread_mutex_lock(&pimpl_->mutex_) != 0) + { + throw OrthancException(ErrorCode_InternalError); + } + } + + void Mutex::Unlock() + { + if (pthread_mutex_unlock(&pimpl_->mutex_) != 0) + { + throw OrthancException(ErrorCode_InternalError); + } + } + +#else +#error Support your plateform here +#endif +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Multithreading/Mutex.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Multithreading/Mutex.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,57 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "ILockable.h" + +namespace Orthanc +{ + class Mutex : public ILockable + { + private: + struct PImpl; + + PImpl *pimpl_; + + protected: + virtual void Lock(); + + virtual void Unlock(); + + public: + Mutex(); + + ~Mutex(); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Multithreading/ReaderWriterLock.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Multithreading/ReaderWriterLock.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,126 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeaders.h" +#include "ReaderWriterLock.h" + +#include + +namespace Orthanc +{ + namespace + { + // Anonymous namespace to avoid clashes between compilation + // modules. + + class ReaderLockable : public ILockable + { + private: + boost::shared_mutex& lock_; + + protected: + virtual void Lock() + { + lock_.lock_shared(); + } + + virtual void Unlock() + { + lock_.unlock_shared(); + } + + public: + explicit ReaderLockable(boost::shared_mutex& lock) : lock_(lock) + { + } + }; + + + class WriterLockable : public ILockable + { + private: + boost::shared_mutex& lock_; + + protected: + virtual void Lock() + { + lock_.lock(); + } + + virtual void Unlock() + { + lock_.unlock(); + } + + public: + explicit WriterLockable(boost::shared_mutex& lock) : lock_(lock) + { + } + }; + } + + struct ReaderWriterLock::PImpl + { + boost::shared_mutex lock_; + ReaderLockable reader_; + WriterLockable writer_; + + PImpl() : reader_(lock_), writer_(lock_) + { + } + }; + + + ReaderWriterLock::ReaderWriterLock() + { + pimpl_ = new PImpl; + } + + + ReaderWriterLock::~ReaderWriterLock() + { + delete pimpl_; + } + + + ILockable& ReaderWriterLock::ForReader() + { + return pimpl_->reader_; + } + + + ILockable& ReaderWriterLock::ForWriter() + { + return pimpl_->writer_; + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Multithreading/ReaderWriterLock.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Multithreading/ReaderWriterLock.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,58 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "ILockable.h" + +#include + +namespace Orthanc +{ + class ReaderWriterLock : public boost::noncopyable + { + private: + struct PImpl; + + PImpl *pimpl_; + + public: + ReaderWriterLock(); + + virtual ~ReaderWriterLock(); + + ILockable& ForReader(); + + ILockable& ForWriter(); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Mutex.cpp --- a/Resources/Graveyard/Mutex.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeaders.h" -#include "Mutex.h" - -#include "../OrthancException.h" - -#if defined(_WIN32) -#include -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) -#include -#else -#error Support your platform here -#endif - -namespace Orthanc -{ -#if defined (_WIN32) - - struct Mutex::PImpl - { - CRITICAL_SECTION criticalSection_; - }; - - Mutex::Mutex() - { - pimpl_ = new PImpl; - ::InitializeCriticalSection(&pimpl_->criticalSection_); - } - - Mutex::~Mutex() - { - ::DeleteCriticalSection(&pimpl_->criticalSection_); - delete pimpl_; - } - - void Mutex::Lock() - { - ::EnterCriticalSection(&pimpl_->criticalSection_); - } - - void Mutex::Unlock() - { - ::LeaveCriticalSection(&pimpl_->criticalSection_); - } - - -#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) - - struct Mutex::PImpl - { - pthread_mutex_t mutex_; - }; - - Mutex::Mutex() - { - pimpl_ = new PImpl; - - if (pthread_mutex_init(&pimpl_->mutex_, NULL) != 0) - { - delete pimpl_; - throw OrthancException(ErrorCode_InternalError); - } - } - - Mutex::~Mutex() - { - pthread_mutex_destroy(&pimpl_->mutex_); - delete pimpl_; - } - - void Mutex::Lock() - { - if (pthread_mutex_lock(&pimpl_->mutex_) != 0) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - void Mutex::Unlock() - { - if (pthread_mutex_unlock(&pimpl_->mutex_) != 0) - { - throw OrthancException(ErrorCode_InternalError); - } - } - -#else -#error Support your plateform here -#endif -} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/Mutex.h --- a/Resources/Graveyard/Mutex.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "ILockable.h" - -namespace Orthanc -{ - class Mutex : public ILockable - { - private: - struct PImpl; - - PImpl *pimpl_; - - protected: - virtual void Lock(); - - virtual void Unlock(); - - public: - Mutex(); - - ~Mutex(); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/CallSystemCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/CallSystemCommand.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,85 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" +#include "CallSystemCommand.h" + +#include "../../Core/Logging.h" +#include "../../Core/Toolbox.h" +#include "../../Core/TemporaryFile.h" + +namespace Orthanc +{ + CallSystemCommand::CallSystemCommand(ServerContext& context, + const std::string& command, + const std::vector& arguments) : + context_(context), + command_(command), + arguments_(arguments) + { + } + + bool CallSystemCommand::Apply(ListOfStrings& outputs, + const ListOfStrings& inputs) + { + for (ListOfStrings::const_iterator + it = inputs.begin(); it != inputs.end(); ++it) + { + LOG(INFO) << "Calling system command " << command_ << " on instance " << *it; + + try + { + std::string dicom; + context_.ReadDicom(dicom, *it); + + TemporaryFile tmp; + tmp.Write(dicom); + + std::vector args = arguments_; + args.push_back(tmp.GetPath()); + + SystemToolbox::ExecuteSystemCommand(command_, args); + + // Only chain with other commands if this command succeeds + outputs.push_back(*it); + } + catch (OrthancException& e) + { + LOG(ERROR) << "Unable to call system command " << command_ + << " on instance " << *it << " in a Lua script: " << e.What(); + } + } + + return true; + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/CallSystemCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/CallSystemCommand.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,56 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" +#include "../ServerContext.h" + +namespace Orthanc +{ + class CallSystemCommand : public IServerCommand + { + private: + ServerContext& context_; + std::string command_; + std::vector arguments_; + + public: + CallSystemCommand(ServerContext& context, + const std::string& command, + const std::vector& arguments); + + virtual bool Apply(ListOfStrings& outputs, + const ListOfStrings& inputs); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/DeleteInstanceCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/DeleteInstanceCommand.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,62 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" +#include "DeleteInstanceCommand.h" + +#include "../../Core/Logging.h" + +namespace Orthanc +{ + bool DeleteInstanceCommand::Apply(ListOfStrings& outputs, + const ListOfStrings& inputs) + { + for (ListOfStrings::const_iterator + it = inputs.begin(); it != inputs.end(); ++it) + { + LOG(INFO) << "Deleting instance " << *it; + + try + { + Json::Value tmp; + context_.DeleteResource(tmp, *it, ResourceType_Instance); + } + catch (OrthancException& e) + { + LOG(ERROR) << "Unable to delete instance " << *it << ": " << e.What(); + } + } + + return true; + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/DeleteInstanceCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/DeleteInstanceCommand.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,54 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" +#include "../ServerContext.h" + +namespace Orthanc +{ + class DeleteInstanceCommand : public IServerCommand + { + private: + ServerContext& context_; + + public: + DeleteInstanceCommand(ServerContext& context) : context_(context) + { + } + + virtual bool Apply(ListOfStrings& outputs, + const ListOfStrings& inputs); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/IServerCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/IServerCommand.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,54 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 +#include +#include + +namespace Orthanc +{ + class IServerCommand : public boost::noncopyable + { + public: + typedef std::list ListOfStrings; + + virtual ~IServerCommand() + { + } + + virtual bool Apply(ListOfStrings& outputs, + const ListOfStrings& inputs) = 0; + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ModifyInstanceCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ModifyInstanceCommand.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,124 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" +#include "ModifyInstanceCommand.h" + +#include "../../Core/Logging.h" + +namespace Orthanc +{ + ModifyInstanceCommand::ModifyInstanceCommand(ServerContext& context, + RequestOrigin origin, + DicomModification* modification) : + context_(context), + origin_(origin), + modification_(modification) + { + modification_->SetAllowManualIdentifiers(true); + + if (modification_->IsReplaced(DICOM_TAG_PATIENT_ID)) + { + modification_->SetLevel(ResourceType_Patient); + } + else if (modification_->IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) + { + modification_->SetLevel(ResourceType_Study); + } + else if (modification_->IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) + { + modification_->SetLevel(ResourceType_Series); + } + else + { + modification_->SetLevel(ResourceType_Instance); + } + + if (origin_ != RequestOrigin_Lua) + { + // TODO If issued from HTTP, "remoteIp" and "username" must be provided + throw OrthancException(ErrorCode_NotImplemented); + } + } + + + ModifyInstanceCommand::~ModifyInstanceCommand() + { + if (modification_) + { + delete modification_; + } + } + + + bool ModifyInstanceCommand::Apply(ListOfStrings& outputs, + const ListOfStrings& inputs) + { + for (ListOfStrings::const_iterator + it = inputs.begin(); it != inputs.end(); ++it) + { + LOG(INFO) << "Modifying resource " << *it; + + try + { + std::auto_ptr modified; + + { + ServerContext::DicomCacheLocker lock(context_, *it); + modified.reset(lock.GetDicom().Clone(true)); + } + + modification_->Apply(*modified); + + DicomInstanceToStore toStore; + assert(origin_ == RequestOrigin_Lua); + toStore.SetLuaOrigin(); + toStore.SetParsedDicomFile(*modified); + // TODO other metadata + toStore.AddMetadata(ResourceType_Instance, MetadataType_ModifiedFrom, *it); + + std::string modifiedId; + context_.Store(modifiedId, toStore); + + // Only chain with other commands if this command succeeds + outputs.push_back(modifiedId); + } + catch (OrthancException& e) + { + LOG(ERROR) << "Unable to modify instance " << *it << ": " << e.What(); + } + } + + return true; + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ModifyInstanceCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ModifyInstanceCommand.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,64 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" +#include "../ServerContext.h" +#include "../../Core/DicomParsing/DicomModification.h" + +namespace Orthanc +{ + class ModifyInstanceCommand : public IServerCommand + { + private: + ServerContext& context_; + RequestOrigin origin_; + DicomModification* modification_; + + public: + ModifyInstanceCommand(ServerContext& context, + RequestOrigin origin, + DicomModification* modification); // takes the ownership + + virtual ~ModifyInstanceCommand(); + + const DicomModification& GetModification() const + { + return *modification_; + } + + virtual bool Apply(ListOfStrings& outputs, + const ListOfStrings& inputs); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ReusableDicomUserConnection.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ReusableDicomUserConnection.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,188 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeaders.h" +#include "ReusableDicomUserConnection.h" + +#include "../Logging.h" +#include "../OrthancException.h" + +namespace Orthanc +{ + static boost::posix_time::ptime Now() + { + return boost::posix_time::microsec_clock::local_time(); + } + + void ReusableDicomUserConnection::Open(const std::string& localAet, + const RemoteModalityParameters& remote) + { + if (connection_ != NULL && + connection_->GetLocalApplicationEntityTitle() == localAet && + connection_->GetRemoteApplicationEntityTitle() == remote.GetApplicationEntityTitle() && + connection_->GetRemoteHost() == remote.GetHost() && + connection_->GetRemotePort() == remote.GetPort() && + connection_->GetRemoteManufacturer() == remote.GetManufacturer()) + { + // The current connection can be reused + LOG(INFO) << "Reusing the previous SCU connection"; + return; + } + + Close(); + + connection_ = new DicomUserConnection(); + connection_->SetLocalApplicationEntityTitle(localAet); + connection_->SetRemoteModality(remote); + connection_->Open(); + } + + void ReusableDicomUserConnection::Close() + { + if (connection_ != NULL) + { + delete connection_; + connection_ = NULL; + } + } + + void ReusableDicomUserConnection::CloseThread(ReusableDicomUserConnection* that) + { + for (;;) + { + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); + if (!that->continue_) + { + //LOG(INFO) << "Finishing the thread watching the global SCU connection"; + return; + } + + { + boost::mutex::scoped_lock lock(that->mutex_); + if (that->connection_ != NULL && + Now() >= that->lastUse_ + that->timeBeforeClose_) + { + LOG(INFO) << "Closing the global SCU connection after timeout"; + that->Close(); + } + } + } + } + + + ReusableDicomUserConnection::Locker::Locker(ReusableDicomUserConnection& that, + const std::string& localAet, + const RemoteModalityParameters& remote) : + ::Orthanc::Locker(that) + { + that.Open(localAet, remote); + connection_ = that.connection_; + } + + + DicomUserConnection& ReusableDicomUserConnection::Locker::GetConnection() + { + if (connection_ == NULL) + { + throw OrthancException(ErrorCode_InternalError); + } + + return *connection_; + } + + ReusableDicomUserConnection::ReusableDicomUserConnection() : + connection_(NULL), + timeBeforeClose_(boost::posix_time::seconds(5)) // By default, close connection after 5 seconds + { + lastUse_ = Now(); + continue_ = true; + closeThread_ = boost::thread(CloseThread, this); + } + + ReusableDicomUserConnection::~ReusableDicomUserConnection() + { + if (continue_) + { + LOG(ERROR) << "INTERNAL ERROR: ReusableDicomUserConnection::Finalize() should be invoked manually to avoid mess in the destruction order!"; + Finalize(); + } + } + + void ReusableDicomUserConnection::SetMillisecondsBeforeClose(uint64_t ms) + { + boost::mutex::scoped_lock lock(mutex_); + + if (ms == 0) + { + ms = 1; + } + + timeBeforeClose_ = boost::posix_time::milliseconds(ms); + } + + void ReusableDicomUserConnection::Lock() + { + mutex_.lock(); + } + + void ReusableDicomUserConnection::Unlock() + { + if (connection_ != NULL && + connection_->GetRemoteManufacturer() == ModalityManufacturer_StoreScp) + { + // "storescp" from DCMTK has problems when reusing a + // connection. Always close. + Close(); + } + + lastUse_ = Now(); + mutex_.unlock(); + } + + + void ReusableDicomUserConnection::Finalize() + { + if (continue_) + { + continue_ = false; + + if (closeThread_.joinable()) + { + closeThread_.join(); + } + + Close(); + } + } +} + diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ReusableDicomUserConnection.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ReusableDicomUserConnection.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,89 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "DicomUserConnection.h" +#include "../../Core/MultiThreading/Locker.h" + +#include +#include + +namespace Orthanc +{ + class ReusableDicomUserConnection : public ILockable + { + private: + boost::mutex mutex_; + DicomUserConnection* connection_; + bool continue_; + boost::posix_time::time_duration timeBeforeClose_; + boost::posix_time::ptime lastUse_; + boost::thread closeThread_; + + void Open(const std::string& localAet, + const RemoteModalityParameters& remote); + + void Close(); + + static void CloseThread(ReusableDicomUserConnection* that); + + protected: + virtual void Lock(); + + virtual void Unlock(); + + public: + class Locker : public ::Orthanc::Locker + { + private: + DicomUserConnection* connection_; + + public: + Locker(ReusableDicomUserConnection& that, + const std::string& localAet, + const RemoteModalityParameters& remote); + + DicomUserConnection& GetConnection(); + }; + + ReusableDicomUserConnection(); + + virtual ~ReusableDicomUserConnection(); + + void SetMillisecondsBeforeClose(uint64_t ms); + + void Finalize(); + }; +} + diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ServerCommandInstance.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ServerCommandInstance.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,99 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" +#include "ServerCommandInstance.h" + +#include "../../Core/OrthancException.h" + +namespace Orthanc +{ + bool ServerCommandInstance::Execute(IListener& listener) + { + ListOfStrings outputs; + + bool success = false; + + try + { + if (command_->Apply(outputs, inputs_)) + { + success = true; + } + } + catch (OrthancException&) + { + } + + if (!success) + { + listener.SignalFailure(jobId_); + return true; + } + + for (std::list::iterator + it = next_.begin(); it != next_.end(); ++it) + { + for (ListOfStrings::const_iterator + output = outputs.begin(); output != outputs.end(); ++output) + { + (*it)->AddInput(*output); + } + } + + listener.SignalSuccess(jobId_); + return true; + } + + + ServerCommandInstance::ServerCommandInstance(IServerCommand *command, + const std::string& jobId) : + command_(command), + jobId_(jobId), + connectedToSink_(false) + { + if (command_ == NULL) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + ServerCommandInstance::~ServerCommandInstance() + { + if (command_ != NULL) + { + delete command_; + } + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ServerCommandInstance.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ServerCommandInstance.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,105 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../../Core/IDynamicObject.h" +#include "IServerCommand.h" + +namespace Orthanc +{ + class ServerCommandInstance : public IDynamicObject + { + friend class ServerScheduler; + + public: + class IListener + { + public: + virtual ~IListener() + { + } + + virtual void SignalSuccess(const std::string& jobId) = 0; + + virtual void SignalFailure(const std::string& jobId) = 0; + }; + + private: + typedef IServerCommand::ListOfStrings ListOfStrings; + + IServerCommand *command_; + std::string jobId_; + ListOfStrings inputs_; + std::list next_; + bool connectedToSink_; + + bool Execute(IListener& listener); + + public: + ServerCommandInstance(IServerCommand *command, + const std::string& jobId); + + virtual ~ServerCommandInstance(); + + const std::string& GetJobId() const + { + return jobId_; + } + + void AddInput(const std::string& input) + { + inputs_.push_back(input); + } + + void ConnectOutput(ServerCommandInstance& next) + { + next_.push_back(&next); + } + + void SetConnectedToSink(bool connected = true) + { + connectedToSink_ = connected; + } + + bool IsConnectedToSink() const + { + return connectedToSink_; + } + + const std::list& GetNextCommands() const + { + return next_; + } + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ServerJob.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ServerJob.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,147 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" +#include "ServerJob.h" + +#include "../../Core/OrthancException.h" +#include "../../Core/Toolbox.h" + +namespace Orthanc +{ + void ServerJob::CheckOrdering() + { + std::map index; + + unsigned int count = 0; + for (std::list::const_iterator + it = filters_.begin(); it != filters_.end(); ++it) + { + index[*it] = count++; + } + + for (std::list::const_iterator + it = filters_.begin(); it != filters_.end(); ++it) + { + const std::list& nextCommands = (*it)->GetNextCommands(); + + for (std::list::const_iterator + next = nextCommands.begin(); next != nextCommands.end(); ++next) + { + if (index.find(*next) == index.end() || + index[*next] <= index[*it]) + { + // You must reorder your calls to "ServerJob::AddCommand" + throw OrthancException(ErrorCode_BadJobOrdering); + } + } + } + } + + + size_t ServerJob::Submit(SharedMessageQueue& target, + ServerCommandInstance::IListener& listener) + { + if (submitted_) + { + // This job has already been submitted + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + + CheckOrdering(); + + size_t size = filters_.size(); + + for (std::list::iterator + it = filters_.begin(); it != filters_.end(); ++it) + { + target.Enqueue(*it); + } + + filters_.clear(); + submitted_ = true; + + return size; + } + + + ServerJob::ServerJob() : + jobId_(Toolbox::GenerateUuid()), + submitted_(false), + description_("no description") + { + } + + + ServerJob::~ServerJob() + { + for (std::list::iterator + it = filters_.begin(); it != filters_.end(); ++it) + { + delete *it; + } + + for (std::list::iterator + it = payloads_.begin(); it != payloads_.end(); ++it) + { + delete *it; + } + } + + + ServerCommandInstance& ServerJob::AddCommand(IServerCommand* filter) + { + if (submitted_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + + filters_.push_back(new ServerCommandInstance(filter, jobId_)); + + return *filters_.back(); + } + + + IDynamicObject& ServerJob::AddPayload(IDynamicObject* payload) + { + if (submitted_) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + + payloads_.push_back(payload); + + return *filters_.back(); + } + +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ServerJob.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ServerJob.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,83 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "ServerCommandInstance.h" +#include "../../Core/MultiThreading/SharedMessageQueue.h" + +namespace Orthanc +{ + class ServerJob + { + friend class ServerScheduler; + + private: + std::list filters_; + std::list payloads_; + std::string jobId_; + bool submitted_; + std::string description_; + + void CheckOrdering(); + + size_t Submit(SharedMessageQueue& target, + ServerCommandInstance::IListener& listener); + + public: + ServerJob(); + + ~ServerJob(); + + const std::string& GetId() const + { + return jobId_; + } + + void SetDescription(const std::string& description) + { + description_ = description; + } + + const std::string& GetDescription() const + { + return description_; + } + + ServerCommandInstance& AddCommand(IServerCommand* filter); + + // Take the ownership of a payload to a job. This payload will be + // automatically freed when the job succeeds or fails. + IDynamicObject& AddPayload(IDynamicObject* payload); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ServerScheduler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ServerScheduler.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,359 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" +#include "ServerScheduler.h" + +#include "../../Core/OrthancException.h" +#include "../../Core/Logging.h" + +namespace Orthanc +{ + namespace + { + // Anonymous namespace to avoid clashes between compilation modules + class Sink : public IServerCommand + { + private: + ListOfStrings& target_; + + public: + explicit Sink(ListOfStrings& target) : target_(target) + { + } + + virtual bool Apply(ListOfStrings& outputs, + const ListOfStrings& inputs) + { + for (ListOfStrings::const_iterator + it = inputs.begin(); it != inputs.end(); ++it) + { + target_.push_back(*it); + } + + return true; + } + }; + } + + + ServerScheduler::JobInfo& ServerScheduler::GetJobInfo(const std::string& jobId) + { + Jobs::iterator info = jobs_.find(jobId); + + if (info == jobs_.end()) + { + throw OrthancException(ErrorCode_InternalError); + } + + return info->second; + } + + + void ServerScheduler::SignalSuccess(const std::string& jobId) + { + boost::mutex::scoped_lock lock(mutex_); + + JobInfo& info = GetJobInfo(jobId); + info.success_++; + + assert(info.failures_ == 0); + + if (info.success_ >= info.size_) + { + if (info.watched_) + { + watchedJobStatus_[jobId] = JobStatus_Success; + watchedJobFinished_.notify_all(); + } + + LOG(INFO) << "Job successfully finished (" << info.description_ << ")"; + jobs_.erase(jobId); + + availableJob_.Release(); + } + } + + + void ServerScheduler::SignalFailure(const std::string& jobId) + { + boost::mutex::scoped_lock lock(mutex_); + + JobInfo& info = GetJobInfo(jobId); + info.failures_++; + + if (info.success_ + info.failures_ >= info.size_) + { + if (info.watched_) + { + watchedJobStatus_[jobId] = JobStatus_Failure; + watchedJobFinished_.notify_all(); + } + + LOG(ERROR) << "Job has failed (" << info.description_ << ")"; + jobs_.erase(jobId); + + availableJob_.Release(); + } + } + + + void ServerScheduler::Worker(ServerScheduler* that) + { + static const int32_t TIMEOUT = 100; + + LOG(WARNING) << "The server scheduler has started"; + + while (!that->finish_) + { + std::auto_ptr object(that->queue_.Dequeue(TIMEOUT)); + if (object.get() != NULL) + { + ServerCommandInstance& filter = dynamic_cast(*object); + + // Skip the execution of this filter if its parent job has + // previously failed. + bool jobHasFailed; + { + boost::mutex::scoped_lock lock(that->mutex_); + JobInfo& info = that->GetJobInfo(filter.GetJobId()); + jobHasFailed = (info.failures_ > 0 || info.cancel_); + } + + if (jobHasFailed) + { + that->SignalFailure(filter.GetJobId()); + } + else + { + filter.Execute(*that); + } + } + } + } + + + void ServerScheduler::SubmitInternal(ServerJob& job, + bool watched) + { + availableJob_.Acquire(); + + boost::mutex::scoped_lock lock(mutex_); + + JobInfo info; + info.size_ = job.Submit(queue_, *this); + info.cancel_ = false; + info.success_ = 0; + info.failures_ = 0; + info.description_ = job.GetDescription(); + info.watched_ = watched; + + assert(info.size_ > 0); + + if (watched) + { + watchedJobStatus_[job.GetId()] = JobStatus_Running; + } + + jobs_[job.GetId()] = info; + + LOG(INFO) << "New job submitted (" << job.description_ << ")"; + } + + + ServerScheduler::ServerScheduler(unsigned int maxJobs) : availableJob_(maxJobs) + { + if (maxJobs == 0) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + finish_ = false; + worker_ = boost::thread(Worker, this); + } + + + ServerScheduler::~ServerScheduler() + { + if (!finish_) + { + LOG(ERROR) << "INTERNAL ERROR: ServerScheduler::Finalize() should be invoked manually to avoid mess in the destruction order!"; + Stop(); + } + } + + + void ServerScheduler::Stop() + { + if (!finish_) + { + finish_ = true; + + if (worker_.joinable()) + { + worker_.join(); + } + } + } + + + void ServerScheduler::Submit(ServerJob& job) + { + if (job.filters_.empty()) + { + return; + } + + SubmitInternal(job, false); + } + + + bool ServerScheduler::SubmitAndWait(ListOfStrings& outputs, + ServerJob& job) + { + std::string jobId = job.GetId(); + + outputs.clear(); + + if (job.filters_.empty()) + { + return true; + } + + // Add a sink filter to collect all the results of the filters + // that have no next filter. + ServerCommandInstance& sink = job.AddCommand(new Sink(outputs)); + + for (std::list::iterator + it = job.filters_.begin(); it != job.filters_.end(); ++it) + { + if ((*it) != &sink && + (*it)->IsConnectedToSink()) + { + (*it)->ConnectOutput(sink); + } + } + + // Submit the job + SubmitInternal(job, true); + + // Wait for the job to complete (either success or failure) + JobStatus status; + + { + boost::mutex::scoped_lock lock(mutex_); + + assert(watchedJobStatus_.find(jobId) != watchedJobStatus_.end()); + + while (watchedJobStatus_[jobId] == JobStatus_Running) + { + watchedJobFinished_.wait(lock); + } + + status = watchedJobStatus_[jobId]; + watchedJobStatus_.erase(jobId); + } + + return (status == JobStatus_Success); + } + + + bool ServerScheduler::SubmitAndWait(ServerJob& job) + { + ListOfStrings ignoredSink; + return SubmitAndWait(ignoredSink, job); + } + + + bool ServerScheduler::IsRunning(const std::string& jobId) + { + boost::mutex::scoped_lock lock(mutex_); + return jobs_.find(jobId) != jobs_.end(); + } + + + void ServerScheduler::Cancel(const std::string& jobId) + { + boost::mutex::scoped_lock lock(mutex_); + + Jobs::iterator job = jobs_.find(jobId); + + if (job != jobs_.end()) + { + job->second.cancel_ = true; + LOG(WARNING) << "Canceling a job (" << job->second.description_ << ")"; + } + } + + + float ServerScheduler::GetProgress(const std::string& jobId) + { + boost::mutex::scoped_lock lock(mutex_); + + Jobs::iterator job = jobs_.find(jobId); + + if (job == jobs_.end() || + job->second.size_ == 0 /* should never happen */) + { + // This job is not running + return 1; + } + + if (job->second.failures_ != 0) + { + return 1; + } + + if (job->second.size_ == 1) + { + return static_cast(job->second.success_); + } + + return (static_cast(job->second.success_) / + static_cast(job->second.size_ - 1)); + } + + + void ServerScheduler::GetListOfJobs(ListOfStrings& jobs) + { + boost::mutex::scoped_lock lock(mutex_); + + jobs.clear(); + + for (Jobs::const_iterator + it = jobs_.begin(); it != jobs_.end(); ++it) + { + jobs.push_back(it->first); + } + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/ServerScheduler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/ServerScheduler.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,123 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "ServerJob.h" + +#include "../../Core/MultiThreading/Semaphore.h" + +namespace Orthanc +{ + class ServerScheduler : public ServerCommandInstance::IListener + { + private: + struct JobInfo + { + bool watched_; + bool cancel_; + size_t size_; + size_t success_; + size_t failures_; + std::string description_; + }; + + enum JobStatus + { + JobStatus_Running = 1, + JobStatus_Success = 2, + JobStatus_Failure = 3 + }; + + typedef IServerCommand::ListOfStrings ListOfStrings; + typedef std::map Jobs; + + boost::mutex mutex_; + boost::condition_variable watchedJobFinished_; + Jobs jobs_; + SharedMessageQueue queue_; + bool finish_; + boost::thread worker_; + std::map watchedJobStatus_; + Semaphore availableJob_; + + JobInfo& GetJobInfo(const std::string& jobId); + + virtual void SignalSuccess(const std::string& jobId); + + virtual void SignalFailure(const std::string& jobId); + + static void Worker(ServerScheduler* that); + + void SubmitInternal(ServerJob& job, + bool watched); + + public: + explicit ServerScheduler(unsigned int maxjobs); + + ~ServerScheduler(); + + void Stop(); + + void Submit(ServerJob& job); + + bool SubmitAndWait(ListOfStrings& outputs, + ServerJob& job); + + bool SubmitAndWait(ServerJob& job); + + bool IsRunning(const std::string& jobId); + + void Cancel(const std::string& jobId); + + // Returns a number between 0 and 1 + float GetProgress(const std::string& jobId); + + bool IsRunning(const ServerJob& job) + { + return IsRunning(job.GetId()); + } + + void Cancel(const ServerJob& job) + { + Cancel(job.GetId()); + } + + float GetProgress(const ServerJob& job) + { + return GetProgress(job.GetId()); + } + + void GetListOfJobs(ListOfStrings& jobs); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/StorePeerCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/StorePeerCommand.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,92 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" +#include "StorePeerCommand.h" + +#include "../../Core/Logging.h" +#include "../../Core/HttpClient.h" + +namespace Orthanc +{ + StorePeerCommand::StorePeerCommand(ServerContext& context, + const WebServiceParameters& peer, + bool ignoreExceptions) : + context_(context), + peer_(peer), + ignoreExceptions_(ignoreExceptions) + { + } + + bool StorePeerCommand::Apply(ListOfStrings& outputs, + const ListOfStrings& inputs) + { + // Configure the HTTP client + HttpClient client(peer_, "instances"); + client.SetMethod(HttpMethod_Post); + + for (ListOfStrings::const_iterator + it = inputs.begin(); it != inputs.end(); ++it) + { + LOG(INFO) << "Sending resource " << *it << " to peer \"" + << peer_.GetUrl() << "\""; + + try + { + context_.ReadDicom(client.GetBody(), *it); + + std::string answer; + if (!client.Apply(answer)) + { + LOG(ERROR) << "Unable to send resource " << *it << " to peer \"" << peer_.GetUrl() << "\""; + throw OrthancException(ErrorCode_NetworkProtocol); + } + + // Only chain with other commands if this command succeeds + outputs.push_back(*it); + } + catch (OrthancException& e) + { + LOG(ERROR) << "Unable to forward to an Orthanc peer in (instance " + << *it << ", peer " << peer_.GetUrl() << "): " << e.What(); + + if (!ignoreExceptions_) + { + throw; + } + } + } + + return true; + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/StorePeerCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/StorePeerCommand.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,57 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" +#include "../ServerContext.h" +#include "../OrthancInitialization.h" + +namespace Orthanc +{ + class StorePeerCommand : public IServerCommand + { + private: + ServerContext& context_; + WebServiceParameters peer_; + bool ignoreExceptions_; + + public: + StorePeerCommand(ServerContext& context, + const WebServiceParameters& peer, + bool ignoreExceptions); + + virtual bool Apply(ListOfStrings& outputs, + const ListOfStrings& inputs); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/StoreScuCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/StoreScuCommand.cpp Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,99 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeadersServer.h" +#include "StoreScuCommand.h" + +#include "../../Core/Logging.h" + +namespace Orthanc +{ + StoreScuCommand::StoreScuCommand(ServerContext& context, + const std::string& localAet, + const RemoteModalityParameters& modality, + bool ignoreExceptions) : + context_(context), + modality_(modality), + ignoreExceptions_(ignoreExceptions), + localAet_(localAet), + moveOriginatorID_(0) + { + } + + + void StoreScuCommand::SetMoveOriginator(const std::string& aet, + uint16_t id) + { + moveOriginatorAET_ = aet; + moveOriginatorID_ = id; + } + + + bool StoreScuCommand::Apply(ListOfStrings& outputs, + const ListOfStrings& inputs) + { + ReusableDicomUserConnection::Locker locker(context_.GetReusableDicomUserConnection(), localAet_, modality_); + + for (ListOfStrings::const_iterator + it = inputs.begin(); it != inputs.end(); ++it) + { + LOG(INFO) << "Sending resource " << *it << " to modality \"" + << modality_.GetApplicationEntityTitle() << "\""; + + try + { + std::string dicom; + context_.ReadDicom(dicom, *it); + + locker.GetConnection().Store(dicom, moveOriginatorAET_, moveOriginatorID_); + + // Only chain with other commands if this command succeeds + outputs.push_back(*it); + } + catch (OrthancException& e) + { + // Ignore transmission errors (e.g. if the remote modality is + // powered off) + LOG(ERROR) << "Unable to forward to a modality in (instance " + << *it << "): " << e.What(); + + if (!ignoreExceptions_) + { + throw; + } + } + } + + return true; + } +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/OldScheduler/StoreScuCommand.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/OldScheduler/StoreScuCommand.h Sat May 19 16:40:26 2018 +0200 @@ -0,0 +1,63 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "IServerCommand.h" +#include "../ServerContext.h" + +namespace Orthanc +{ + class StoreScuCommand : public IServerCommand + { + private: + ServerContext& context_; + RemoteModalityParameters modality_; + bool ignoreExceptions_; + std::string localAet_; + std::string moveOriginatorAET_; + uint16_t moveOriginatorID_; + + public: + StoreScuCommand(ServerContext& context, + const std::string& localAet, + const RemoteModalityParameters& modality, + bool ignoreExceptions); + + void SetMoveOriginator(const std::string& aet, + uint16_t id); + + virtual bool Apply(ListOfStrings& outputs, + const ListOfStrings& inputs); + }; +} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/ReaderWriterLock.cpp --- a/Resources/Graveyard/ReaderWriterLock.cpp Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "../PrecompiledHeaders.h" -#include "ReaderWriterLock.h" - -#include - -namespace Orthanc -{ - namespace - { - // Anonymous namespace to avoid clashes between compilation - // modules. - - class ReaderLockable : public ILockable - { - private: - boost::shared_mutex& lock_; - - protected: - virtual void Lock() - { - lock_.lock_shared(); - } - - virtual void Unlock() - { - lock_.unlock_shared(); - } - - public: - explicit ReaderLockable(boost::shared_mutex& lock) : lock_(lock) - { - } - }; - - - class WriterLockable : public ILockable - { - private: - boost::shared_mutex& lock_; - - protected: - virtual void Lock() - { - lock_.lock(); - } - - virtual void Unlock() - { - lock_.unlock(); - } - - public: - explicit WriterLockable(boost::shared_mutex& lock) : lock_(lock) - { - } - }; - } - - struct ReaderWriterLock::PImpl - { - boost::shared_mutex lock_; - ReaderLockable reader_; - WriterLockable writer_; - - PImpl() : reader_(lock_), writer_(lock_) - { - } - }; - - - ReaderWriterLock::ReaderWriterLock() - { - pimpl_ = new PImpl; - } - - - ReaderWriterLock::~ReaderWriterLock() - { - delete pimpl_; - } - - - ILockable& ReaderWriterLock::ForReader() - { - return pimpl_->reader_; - } - - - ILockable& ReaderWriterLock::ForWriter() - { - return pimpl_->writer_; - } -} diff -r f7a84b551ee4 -r 3ff4c50647ea Resources/Graveyard/ReaderWriterLock.h --- a/Resources/Graveyard/ReaderWriterLock.h Sat May 19 16:29:00 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 "ILockable.h" - -#include - -namespace Orthanc -{ - class ReaderWriterLock : public boost::noncopyable - { - private: - struct PImpl; - - PImpl *pimpl_; - - public: - ReaderWriterLock(); - - virtual ~ReaderWriterLock(); - - ILockable& ForReader(); - - ILockable& ForWriter(); - }; -} diff -r f7a84b551ee4 -r 3ff4c50647ea UnitTestsSources/MultiThreadingTests.cpp --- a/UnitTestsSources/MultiThreadingTests.cpp Sat May 19 16:29:00 2018 +0200 +++ b/UnitTestsSources/MultiThreadingTests.cpp Sat May 19 16:40:26 2018 +0200 @@ -35,11 +35,10 @@ #include "gtest/gtest.h" #include "../Core/JobsEngine/JobsEngine.h" -#include "../Core/MultiThreading/Locker.h" +#include "../Core/MultiThreading/SharedMessageQueue.h" #include "../Core/OrthancException.h" #include "../Core/SystemToolbox.h" #include "../Core/Toolbox.h" -#include "../OrthancServer/Scheduler/ServerScheduler.h" using namespace Orthanc; @@ -107,139 +106,6 @@ -#include "../Core/DicomNetworking/ReusableDicomUserConnection.h" - -TEST(ReusableDicomUserConnection, DISABLED_Basic) -{ - ReusableDicomUserConnection c; - c.SetMillisecondsBeforeClose(200); - printf("START\n"); fflush(stdout); - - { - RemoteModalityParameters remote("STORESCP", "localhost", 2000, ModalityManufacturer_Generic); - ReusableDicomUserConnection::Locker lock(c, "ORTHANC", remote); - lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676281"); - } - - printf("**\n"); fflush(stdout); - SystemToolbox::USleep(1000000); - printf("**\n"); fflush(stdout); - - { - RemoteModalityParameters remote("STORESCP", "localhost", 2000, ModalityManufacturer_Generic); - ReusableDicomUserConnection::Locker lock(c, "ORTHANC", remote); - lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676277"); - } - - SystemToolbox::ServerBarrier(); - printf("DONE\n"); fflush(stdout); -} - - - -class Tutu : public IServerCommand -{ -private: - int factor_; - -public: - Tutu(int f) : factor_(f) - { - } - - virtual bool Apply(ListOfStrings& outputs, - const ListOfStrings& inputs) - { - for (ListOfStrings::const_iterator - it = inputs.begin(); it != inputs.end(); ++it) - { - int a = boost::lexical_cast(*it); - int b = factor_ * a; - - printf("%d * %d = %d\n", a, factor_, b); - - //if (a == 84) { printf("BREAK\n"); return false; } - - outputs.push_back(boost::lexical_cast(b)); - } - - SystemToolbox::USleep(30000); - - return true; - } -}; - - -static void Tata(ServerScheduler* s, ServerJob* j, bool* done) -{ - typedef IServerCommand::ListOfStrings ListOfStrings; - - while (!(*done)) - { - ListOfStrings l; - s->GetListOfJobs(l); - for (ListOfStrings::iterator it = l.begin(); it != l.end(); ++it) - { - printf(">> %s: %0.1f\n", it->c_str(), 100.0f * s->GetProgress(*it)); - } - SystemToolbox::USleep(3000); - } -} - - -TEST(MultiThreading, ServerScheduler) -{ - ServerScheduler scheduler(10); - - ServerJob job; - ServerCommandInstance& f2 = job.AddCommand(new Tutu(2)); - ServerCommandInstance& f3 = job.AddCommand(new Tutu(3)); - ServerCommandInstance& f4 = job.AddCommand(new Tutu(4)); - ServerCommandInstance& f5 = job.AddCommand(new Tutu(5)); - f2.AddInput(boost::lexical_cast(42)); - //f3.AddInput(boost::lexical_cast(42)); - //f4.AddInput(boost::lexical_cast(42)); - f2.ConnectOutput(f3); - f3.ConnectOutput(f4); - f4.ConnectOutput(f5); - - f3.SetConnectedToSink(true); - f5.SetConnectedToSink(true); - - job.SetDescription("tutu"); - - bool done = false; - boost::thread t(Tata, &scheduler, &job, &done); - - - //scheduler.Submit(job); - - IServerCommand::ListOfStrings l; - scheduler.SubmitAndWait(l, job); - - ASSERT_EQ(2u, l.size()); - ASSERT_EQ(42 * 2 * 3, boost::lexical_cast(l.front())); - ASSERT_EQ(42 * 2 * 3 * 4 * 5, boost::lexical_cast(l.back())); - - for (IServerCommand::ListOfStrings::iterator i = l.begin(); i != l.end(); i++) - { - printf("** %s\n", i->c_str()); - } - - //SystemToolbox::ServerBarrier(); - //SystemToolbox::USleep(3000000); - - scheduler.Stop(); - - done = true; - if (t.joinable()) - { - t.join(); - } -} - - - class DummyJob : public Orthanc::IJob { private: