comparison OrthancServer/ServerJobs/ResourceModificationJob.cpp @ 2642:ccc470091ea6 jobs

reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 28 May 2018 16:46:54 +0200
parents
children e1893d31652a
comparison
equal deleted inserted replaced
2641:3ce8863398ab 2642:ccc470091ea6
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-2018 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 "ResourceModificationJob.h"
36
37 #include "../../Core/Logging.h"
38
39 namespace Orthanc
40 {
41 ResourceModificationJob::Output::Output(ResourceType level) :
42 level_(level),
43 isFirst_(true)
44 {
45 if (level_ != ResourceType_Patient &&
46 level_ != ResourceType_Study &&
47 level_ != ResourceType_Series)
48 {
49 throw OrthancException(ErrorCode_ParameterOutOfRange);
50 }
51 }
52
53
54 void ResourceModificationJob::Output::Update(DicomInstanceHasher& hasher)
55 {
56 boost::mutex::scoped_lock lock(mutex_);
57
58 if (isFirst_)
59 {
60 switch (level_)
61 {
62 case ResourceType_Series:
63 id_ = hasher.HashSeries();
64 break;
65
66 case ResourceType_Study:
67 id_ = hasher.HashStudy();
68 break;
69
70 case ResourceType_Patient:
71 id_ = hasher.HashPatient();
72 break;
73
74 default:
75 throw OrthancException(ErrorCode_InternalError);
76 }
77
78 patientId_ = hasher.HashPatient();
79 isFirst_ = false;
80 }
81 }
82
83
84 bool ResourceModificationJob::Output::Format(Json::Value& target)
85 {
86 boost::mutex::scoped_lock lock(mutex_);
87
88 if (isFirst_)
89 {
90 return false;
91 }
92 else
93 {
94 target = Json::objectValue;
95 target["Type"] = EnumerationToString(level_);
96 target["ID"] = id_;
97 target["Path"] = GetBasePath(level_, id_);
98 target["PatientID"] = patientId_;
99 return true;
100 }
101 }
102
103
104 bool ResourceModificationJob::Output::GetIdentifier(std::string& id)
105 {
106 boost::mutex::scoped_lock lock(mutex_);
107
108 if (isFirst_)
109 {
110 return false;
111 }
112 else
113 {
114 id = id_;
115 return true;
116 }
117 }
118
119
120 bool ResourceModificationJob::HandleInstance(const std::string& instance)
121 {
122 if (modification_.get() == NULL)
123 {
124 LOG(ERROR) << "No modification was provided for this job";
125 throw OrthancException(ErrorCode_BadSequenceOfCalls);
126 }
127
128
129 LOG(INFO) << "Modifying instance in a job: " << instance;
130
131 std::auto_ptr<ServerContext::DicomCacheLocker> locker;
132
133 try
134 {
135 locker.reset(new ServerContext::DicomCacheLocker(context_, instance));
136 }
137 catch (OrthancException&)
138 {
139 LOG(WARNING) << "An instance was removed after the job was issued: " << instance;
140 return false;
141 }
142
143
144 ParsedDicomFile& original = locker->GetDicom();
145 DicomInstanceHasher originalHasher = original.GetHasher();
146
147
148 /**
149 * Compute the resulting DICOM instance.
150 **/
151
152 std::auto_ptr<ParsedDicomFile> modified(original.Clone(true));
153 modification_->Apply(*modified);
154
155 DicomInstanceToStore toStore;
156 toStore.SetOrigin(origin_);
157 toStore.SetParsedDicomFile(*modified);
158
159
160 /**
161 * Prepare the metadata information to associate with the
162 * resulting DICOM instance (AnonymizedFrom/ModifiedFrom).
163 **/
164
165 DicomInstanceHasher modifiedHasher = modified->GetHasher();
166
167 MetadataType metadataType = (isAnonymization_ ?
168 MetadataType_AnonymizedFrom :
169 MetadataType_ModifiedFrom);
170
171 if (originalHasher.HashSeries() != modifiedHasher.HashSeries())
172 {
173 toStore.AddMetadata(ResourceType_Series, metadataType, originalHasher.HashSeries());
174 }
175
176 if (originalHasher.HashStudy() != modifiedHasher.HashStudy())
177 {
178 toStore.AddMetadata(ResourceType_Study, metadataType, originalHasher.HashStudy());
179 }
180
181 if (originalHasher.HashPatient() != modifiedHasher.HashPatient())
182 {
183 toStore.AddMetadata(ResourceType_Patient, metadataType, originalHasher.HashPatient());
184 }
185
186 assert(instance == originalHasher.HashInstance());
187 toStore.AddMetadata(ResourceType_Instance, metadataType, instance);
188
189
190 /**
191 * Store the resulting DICOM instance into the Orthanc store.
192 **/
193
194 std::string modifiedInstance;
195 if (context_.Store(modifiedInstance, toStore) != StoreStatus_Success)
196 {
197 LOG(ERROR) << "Error while storing a modified instance " << instance;
198 throw OrthancException(ErrorCode_CannotStoreInstance);
199 }
200
201 // Sanity checks in debug mode
202 assert(modifiedInstance == modifiedHasher.HashInstance());
203
204
205 if (output_.get() != NULL)
206 {
207 output_->Update(modifiedHasher);
208 }
209
210 return true;
211 }
212
213
214
215 void ResourceModificationJob::SetModification(DicomModification* modification,
216 bool isAnonymization)
217 {
218 if (modification == NULL)
219 {
220 throw OrthancException(ErrorCode_NullPointer);
221 }
222 else if (IsStarted())
223 {
224 throw OrthancException(ErrorCode_BadSequenceOfCalls);
225 }
226 else
227 {
228 modification_.reset(modification);
229 isAnonymization_ = isAnonymization;
230 }
231 }
232
233
234 void ResourceModificationJob::SetOutput(boost::shared_ptr<Output>& output)
235 {
236 if (IsStarted())
237 {
238 throw OrthancException(ErrorCode_BadSequenceOfCalls);
239 }
240 else
241 {
242 output_ = output;
243 }
244 }
245
246
247 void ResourceModificationJob::SetOrigin(const DicomInstanceOrigin& origin)
248 {
249 if (IsStarted())
250 {
251 throw OrthancException(ErrorCode_BadSequenceOfCalls);
252 }
253 else
254 {
255 origin_ = origin;
256 }
257 }
258
259
260 void ResourceModificationJob::SetOrigin(const RestApiCall& call)
261 {
262 DicomInstanceOrigin tmp;
263 tmp.SetRestOrigin(call);
264 SetOrigin(tmp);
265 }
266
267
268 void ResourceModificationJob::GetPublicContent(Json::Value& value)
269 {
270 SetOfInstancesJob::GetPublicContent(value);
271
272 value["IsAnonymization"] = isAnonymization_;
273 }
274
275
276 void ResourceModificationJob::GetInternalContent(Json::Value& value)
277 {
278 SetOfInstancesJob::GetInternalContent(value);
279
280 Json::Value tmp;
281 modification_->Serialize(tmp);
282 value["Modification"] = tmp;
283 }
284 }