1 /** 2 * Orthanc - A Lightweight, RESTful DICOM Store 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 4 * Department, University Hospital of Liege, Belgium 5 * Copyright (C) 2017-2020 Osimis S.A., Belgium 6 * 7 * This program is free software: you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation, either version 3 of the 10 * License, or (at your option) any later version. 11 * 12 * In addition, as a special exception, the copyright holders of this 13 * program give permission to link the code of its release with the 14 * OpenSSL project's "OpenSSL" library (or with modified versions of it 15 * that use the same license as the "OpenSSL" library), and distribute 16 * the linked executables. You must obey the GNU General Public License 17 * in all respects for all of the code used other than "OpenSSL". If you 18 * modify file(s) with this exception, you may extend this exception to 19 * your version of the file(s), but you are not obligated to do so. If 20 * you do not wish to do so, delete this exception statement from your 21 * version. If you delete this exception statement from all source files 22 * in the program, then also delete it here. 23 * 24 * This program is distributed in the hope that it will be useful, but 25 * WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 * General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with this program. If not, see <http://www.gnu.org/licenses/>. 31 **/ 32 33 34 #include "PrecompiledHeadersServer.h" 35 #include "StorageCommitmentReports.h" 36 37 #include "../../OrthancFramework/Sources/OrthancException.h" 38 39 namespace Orthanc 40 { MarkAsComplete()41 void StorageCommitmentReports::Report::MarkAsComplete() 42 { 43 if (isComplete_) 44 { 45 throw OrthancException(ErrorCode_BadSequenceOfCalls); 46 } 47 else 48 { 49 isComplete_ = true; 50 } 51 } 52 AddSuccess(const std::string & sopClassUid,const std::string & sopInstanceUid)53 void StorageCommitmentReports::Report::AddSuccess(const std::string& sopClassUid, 54 const std::string& sopInstanceUid) 55 { 56 if (isComplete_) 57 { 58 throw OrthancException(ErrorCode_BadSequenceOfCalls); 59 } 60 else 61 { 62 Success success; 63 success.sopClassUid_ = sopClassUid; 64 success.sopInstanceUid_ = sopInstanceUid; 65 success_.push_back(success); 66 } 67 } 68 AddFailure(const std::string & sopClassUid,const std::string & sopInstanceUid,StorageCommitmentFailureReason reason)69 void StorageCommitmentReports::Report::AddFailure(const std::string& sopClassUid, 70 const std::string& sopInstanceUid, 71 StorageCommitmentFailureReason reason) 72 { 73 if (isComplete_) 74 { 75 throw OrthancException(ErrorCode_BadSequenceOfCalls); 76 } 77 else 78 { 79 Failure failure; 80 failure.sopClassUid_ = sopClassUid; 81 failure.sopInstanceUid_ = sopInstanceUid; 82 failure.reason_ = reason; 83 failures_.push_back(failure); 84 } 85 } 86 87 GetStatus() const88 StorageCommitmentReports::Report::Status StorageCommitmentReports::Report::GetStatus() const 89 { 90 if (!isComplete_) 91 { 92 return Status_Pending; 93 } 94 else if (failures_.empty()) 95 { 96 return Status_Success; 97 } 98 else 99 { 100 return Status_Failure; 101 } 102 } 103 104 Format(Json::Value & json) const105 void StorageCommitmentReports::Report::Format(Json::Value& json) const 106 { 107 static const char* const FIELD_STATUS = "Status"; 108 static const char* const FIELD_SOP_CLASS_UID = "SOPClassUID"; 109 static const char* const FIELD_SOP_INSTANCE_UID = "SOPInstanceUID"; 110 static const char* const FIELD_FAILURE_REASON = "FailureReason"; 111 static const char* const FIELD_DESCRIPTION = "Description"; 112 static const char* const FIELD_REMOTE_AET = "RemoteAET"; 113 static const char* const FIELD_SUCCESS = "Success"; 114 static const char* const FIELD_FAILURES = "Failures"; 115 116 117 json = Json::objectValue; 118 json[FIELD_REMOTE_AET] = remoteAet_; 119 120 bool pending; 121 122 switch (GetStatus()) 123 { 124 case Status_Pending: 125 json[FIELD_STATUS] = "Pending"; 126 pending = true; 127 break; 128 129 case Status_Success: 130 json[FIELD_STATUS] = "Success"; 131 pending = false; 132 break; 133 134 case Status_Failure: 135 json[FIELD_STATUS] = "Failure"; 136 pending = false; 137 break; 138 139 default: 140 throw OrthancException(ErrorCode_InternalError); 141 } 142 143 if (!pending) 144 { 145 { 146 Json::Value success = Json::arrayValue; 147 for (std::list<Success>::const_iterator 148 it = success_.begin(); it != success_.end(); ++it) 149 { 150 Json::Value item = Json::objectValue; 151 item[FIELD_SOP_CLASS_UID] = it->sopClassUid_; 152 item[FIELD_SOP_INSTANCE_UID] = it->sopInstanceUid_; 153 success.append(item); 154 } 155 156 json[FIELD_SUCCESS] = success; 157 } 158 159 { 160 Json::Value failures = Json::arrayValue; 161 for (std::list<Failure>::const_iterator 162 it = failures_.begin(); it != failures_.end(); ++it) 163 { 164 Json::Value item = Json::objectValue; 165 item[FIELD_SOP_CLASS_UID] = it->sopClassUid_; 166 item[FIELD_SOP_INSTANCE_UID] = it->sopInstanceUid_; 167 item[FIELD_FAILURE_REASON] = it->reason_; 168 item[FIELD_DESCRIPTION] = EnumerationToString(it->reason_); 169 failures.append(item); 170 } 171 172 json[FIELD_FAILURES] = failures; 173 } 174 } 175 } 176 177 GetSuccessSopInstanceUids(std::vector<std::string> & target) const178 void StorageCommitmentReports::Report::GetSuccessSopInstanceUids( 179 std::vector<std::string>& target) const 180 { 181 target.clear(); 182 target.reserve(success_.size()); 183 184 for (std::list<Success>::const_iterator 185 it = success_.begin(); it != success_.end(); ++it) 186 { 187 target.push_back(it->sopInstanceUid_); 188 } 189 } 190 191 ~StorageCommitmentReports()192 StorageCommitmentReports::~StorageCommitmentReports() 193 { 194 while (!content_.IsEmpty()) 195 { 196 Report* report = NULL; 197 content_.RemoveOldest(report); 198 199 assert(report != NULL); 200 delete report; 201 } 202 } 203 204 Store(const std::string & transactionUid,Report * report)205 void StorageCommitmentReports::Store(const std::string& transactionUid, 206 Report* report) 207 { 208 std::unique_ptr<Report> protection(report); 209 210 boost::mutex::scoped_lock lock(mutex_); 211 212 { 213 Report* previous = NULL; 214 if (content_.Contains(transactionUid, previous)) 215 { 216 assert(previous != NULL); 217 delete previous; 218 219 content_.Invalidate(transactionUid); 220 } 221 } 222 223 assert(maxSize_ == 0 || 224 content_.GetSize() <= maxSize_); 225 226 if (maxSize_ != 0 && 227 content_.GetSize() == maxSize_) 228 { 229 assert(!content_.IsEmpty()); 230 231 Report* oldest = NULL; 232 content_.RemoveOldest(oldest); 233 234 assert(oldest != NULL); 235 delete oldest; 236 } 237 238 assert(maxSize_ == 0 || 239 content_.GetSize() < maxSize_); 240 241 content_.Add(transactionUid, protection.release()); 242 } 243 244 Accessor(StorageCommitmentReports & that,const std::string & transactionUid)245 StorageCommitmentReports::Accessor::Accessor(StorageCommitmentReports& that, 246 const std::string& transactionUid) : 247 lock_(that.mutex_), 248 transactionUid_(transactionUid) 249 { 250 if (that.content_.Contains(transactionUid, report_)) 251 { 252 that.content_.MakeMostRecent(transactionUid); 253 } 254 else 255 { 256 report_ = NULL; 257 } 258 } 259 260 const StorageCommitmentReports::Report& GetReport() const261 StorageCommitmentReports::Accessor::GetReport() const 262 { 263 if (report_ == NULL) 264 { 265 throw OrthancException(ErrorCode_BadSequenceOfCalls); 266 } 267 else 268 { 269 return *report_; 270 } 271 } 272 } 273