Mercurial > hg > orthanc
comparison OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp @ 2642:ccc470091ea6 jobs
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 28 May 2018 16:46:54 +0200 |
parents | c691fcf66071 |
children | a21b244efb37 |
comparison
equal
deleted
inserted
replaced
2641:3ce8863398ab | 2642:ccc470091ea6 |
---|---|
32 | 32 |
33 | 33 |
34 #include "../PrecompiledHeadersServer.h" | 34 #include "../PrecompiledHeadersServer.h" |
35 #include "OrthancRestApi.h" | 35 #include "OrthancRestApi.h" |
36 | 36 |
37 #include "../../Core/DicomParsing/FromDcmtkBridge.h" | |
37 #include "../../Core/Logging.h" | 38 #include "../../Core/Logging.h" |
38 #include "../../Core/DicomParsing/FromDcmtkBridge.h" | |
39 #include "../ServerContext.h" | 39 #include "../ServerContext.h" |
40 #include "../OrthancInitialization.h" | 40 #include "../ServerJobs/ResourceModificationJob.h" |
41 | 41 |
42 #include <boost/lexical_cast.hpp> | 42 #include <boost/lexical_cast.hpp> |
43 #include <boost/algorithm/string/predicate.hpp> | 43 #include <boost/algorithm/string/predicate.hpp> |
44 | 44 |
45 namespace Orthanc | 45 namespace Orthanc |
135 std::auto_ptr<ParsedDicomFile> modified(locker.GetDicom().Clone(true)); | 135 std::auto_ptr<ParsedDicomFile> modified(locker.GetDicom().Clone(true)); |
136 modification.Apply(*modified); | 136 modification.Apply(*modified); |
137 modified->Answer(call.GetOutput()); | 137 modified->Answer(call.GetOutput()); |
138 } | 138 } |
139 | 139 |
140 | |
141 | |
142 class ResourceModificationJob : public SetOfInstancesJob | |
143 { | |
144 public: | |
145 class Output : public boost::noncopyable | |
146 { | |
147 private: | |
148 boost::mutex mutex_; | |
149 ResourceType level_; | |
150 bool isFirst_; | |
151 std::string id_; | |
152 std::string patientId_; | |
153 | |
154 public: | |
155 Output(ResourceType level) : | |
156 level_(level), | |
157 isFirst_(true) | |
158 { | |
159 if (level_ != ResourceType_Patient && | |
160 level_ != ResourceType_Study && | |
161 level_ != ResourceType_Series) | |
162 { | |
163 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
164 } | |
165 } | |
166 | |
167 ResourceType GetLevel() const | |
168 { | |
169 return level_; | |
170 } | |
171 | |
172 void Update(DicomInstanceHasher& hasher) | |
173 { | |
174 boost::mutex::scoped_lock lock(mutex_); | |
175 | |
176 if (isFirst_) | |
177 { | |
178 switch (level_) | |
179 { | |
180 case ResourceType_Series: | |
181 id_ = hasher.HashSeries(); | |
182 break; | |
183 | |
184 case ResourceType_Study: | |
185 id_ = hasher.HashStudy(); | |
186 break; | |
187 | |
188 case ResourceType_Patient: | |
189 id_ = hasher.HashPatient(); | |
190 break; | |
191 | |
192 default: | |
193 throw OrthancException(ErrorCode_InternalError); | |
194 } | |
195 | |
196 patientId_ = hasher.HashPatient(); | |
197 isFirst_ = false; | |
198 } | |
199 } | |
200 | |
201 bool Format(Json::Value& target) | |
202 { | |
203 boost::mutex::scoped_lock lock(mutex_); | |
204 | |
205 if (isFirst_) | |
206 { | |
207 return false; | |
208 } | |
209 else | |
210 { | |
211 target = Json::objectValue; | |
212 target["Type"] = EnumerationToString(level_); | |
213 target["ID"] = id_; | |
214 target["Path"] = GetBasePath(level_, id_); | |
215 target["PatientID"] = patientId_; | |
216 return true; | |
217 } | |
218 } | |
219 | |
220 bool GetIdentifier(std::string& id) | |
221 { | |
222 boost::mutex::scoped_lock lock(mutex_); | |
223 | |
224 if (isFirst_) | |
225 { | |
226 return false; | |
227 } | |
228 else | |
229 { | |
230 id = id_; | |
231 return true; | |
232 } | |
233 } | |
234 }; | |
235 | |
236 private: | |
237 ServerContext& context_; | |
238 std::auto_ptr<DicomModification> modification_; | |
239 boost::shared_ptr<Output> output_; | |
240 bool isAnonymization_; | |
241 MetadataType metadataType_; | |
242 std::string description_; | |
243 DicomInstanceOrigin origin_; | |
244 | |
245 protected: | |
246 bool HandleInstance(const std::string& instance) | |
247 { | |
248 if (modification_.get() == NULL) | |
249 { | |
250 LOG(ERROR) << "No modification was provided for this job"; | |
251 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
252 } | |
253 | |
254 | |
255 LOG(INFO) << "Modifying instance in a job: " << instance; | |
256 | |
257 std::auto_ptr<ServerContext::DicomCacheLocker> locker; | |
258 | |
259 try | |
260 { | |
261 locker.reset(new ServerContext::DicomCacheLocker(context_, instance)); | |
262 } | |
263 catch (OrthancException&) | |
264 { | |
265 LOG(WARNING) << "An instance was removed after the job was issued: " << instance; | |
266 return false; | |
267 } | |
268 | |
269 | |
270 ParsedDicomFile& original = locker->GetDicom(); | |
271 DicomInstanceHasher originalHasher = original.GetHasher(); | |
272 | |
273 | |
274 /** | |
275 * Compute the resulting DICOM instance. | |
276 **/ | |
277 | |
278 std::auto_ptr<ParsedDicomFile> modified(original.Clone(true)); | |
279 modification_->Apply(*modified); | |
280 | |
281 DicomInstanceToStore toStore; | |
282 toStore.SetOrigin(origin_); | |
283 toStore.SetParsedDicomFile(*modified); | |
284 | |
285 | |
286 /** | |
287 * Prepare the metadata information to associate with the | |
288 * resulting DICOM instance (AnonymizedFrom/ModifiedFrom). | |
289 **/ | |
290 | |
291 DicomInstanceHasher modifiedHasher = modified->GetHasher(); | |
292 | |
293 MetadataType metadataType = (isAnonymization_ ? | |
294 MetadataType_AnonymizedFrom : | |
295 MetadataType_ModifiedFrom); | |
296 | |
297 if (originalHasher.HashSeries() != modifiedHasher.HashSeries()) | |
298 { | |
299 toStore.AddMetadata(ResourceType_Series, metadataType, originalHasher.HashSeries()); | |
300 } | |
301 | |
302 if (originalHasher.HashStudy() != modifiedHasher.HashStudy()) | |
303 { | |
304 toStore.AddMetadata(ResourceType_Study, metadataType, originalHasher.HashStudy()); | |
305 } | |
306 | |
307 if (originalHasher.HashPatient() != modifiedHasher.HashPatient()) | |
308 { | |
309 toStore.AddMetadata(ResourceType_Patient, metadataType, originalHasher.HashPatient()); | |
310 } | |
311 | |
312 assert(instance == originalHasher.HashInstance()); | |
313 toStore.AddMetadata(ResourceType_Instance, metadataType, instance); | |
314 | |
315 | |
316 /** | |
317 * Store the resulting DICOM instance into the Orthanc store. | |
318 **/ | |
319 | |
320 std::string modifiedInstance; | |
321 if (context_.Store(modifiedInstance, toStore) != StoreStatus_Success) | |
322 { | |
323 LOG(ERROR) << "Error while storing a modified instance " << instance; | |
324 throw OrthancException(ErrorCode_CannotStoreInstance); | |
325 } | |
326 | |
327 // Sanity checks in debug mode | |
328 assert(modifiedInstance == modifiedHasher.HashInstance()); | |
329 | |
330 | |
331 if (output_.get() != NULL) | |
332 { | |
333 output_->Update(modifiedHasher); | |
334 } | |
335 | |
336 return true; | |
337 } | |
338 | |
339 public: | |
340 ResourceModificationJob(ServerContext& context) : | |
341 context_(context), | |
342 isAnonymization_(false) | |
343 { | |
344 } | |
345 | |
346 void SetModification(DicomModification* modification, // Takes ownership | |
347 bool isAnonymization) | |
348 { | |
349 if (modification == NULL) | |
350 { | |
351 throw OrthancException(ErrorCode_NullPointer); | |
352 } | |
353 else if (IsStarted()) | |
354 { | |
355 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
356 } | |
357 else | |
358 { | |
359 modification_.reset(modification); | |
360 isAnonymization_ = isAnonymization; | |
361 } | |
362 } | |
363 | |
364 void SetOutput(boost::shared_ptr<Output>& output) | |
365 { | |
366 if (IsStarted()) | |
367 { | |
368 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
369 } | |
370 else | |
371 { | |
372 output_ = output; | |
373 } | |
374 } | |
375 | |
376 void SetOrigin(const DicomInstanceOrigin& origin) | |
377 { | |
378 if (IsStarted()) | |
379 { | |
380 throw OrthancException(ErrorCode_BadSequenceOfCalls); | |
381 } | |
382 else | |
383 { | |
384 origin_ = origin; | |
385 } | |
386 } | |
387 | |
388 void SetOrigin(const RestApiCall& call) | |
389 { | |
390 DicomInstanceOrigin tmp; | |
391 tmp.SetRestOrigin(call); | |
392 SetOrigin(tmp); | |
393 } | |
394 | |
395 virtual void ReleaseResources() | |
396 { | |
397 } | |
398 | |
399 virtual void GetJobType(std::string& target) | |
400 { | |
401 target = "ResourceModification"; | |
402 } | |
403 | |
404 virtual void GetPublicContent(Json::Value& value) | |
405 { | |
406 SetOfInstancesJob::GetPublicContent(value); | |
407 | |
408 value["IsAnonymization"] = isAnonymization_; | |
409 } | |
410 | |
411 virtual void GetInternalContent(Json::Value& value) | |
412 { | |
413 SetOfInstancesJob::GetInternalContent(value); | |
414 | |
415 Json::Value tmp; | |
416 modification_->Serialize(tmp); | |
417 value["Modification"] = tmp; | |
418 } | |
419 }; | |
420 | |
421 | 140 |
422 | 141 |
423 static void SubmitJob(std::auto_ptr<DicomModification>& modification, | 142 static void SubmitJob(std::auto_ptr<DicomModification>& modification, |
424 bool isAnonymization, | 143 bool isAnonymization, |
425 ResourceType level, | 144 ResourceType level, |