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,