comparison OrthancServer/OrthancRestApi/OrthancRestModalities.cpp @ 2573:3372c5255333 jobs

StoreScuJob, Orthanc Explorer for jobs
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 09 May 2018 17:56:14 +0200
parents 878b59270859
children 055d7d4a823f
comparison
equal deleted inserted replaced
2570:2e879c796ec7 2573:3372c5255333
42 #include "../Scheduler/StoreScuCommand.h" 42 #include "../Scheduler/StoreScuCommand.h"
43 #include "../Scheduler/StorePeerCommand.h" 43 #include "../Scheduler/StorePeerCommand.h"
44 #include "../QueryRetrieveHandler.h" 44 #include "../QueryRetrieveHandler.h"
45 #include "../ServerToolbox.h" 45 #include "../ServerToolbox.h"
46 46
47
48
49 namespace Orthanc
50 {
51 class InstancesIteratorJob : public IJob
52 {
53 private:
54 bool started_;
55 std::vector<std::string> instances_;
56 size_t position_;
57
58 public:
59 InstancesIteratorJob() :
60 started_(false),
61 position_(0)
62 {
63 }
64
65 void Reserve(size_t size)
66 {
67 if (started_)
68 {
69 throw OrthancException(ErrorCode_BadSequenceOfCalls);
70 }
71 else
72 {
73 instances_.reserve(size);
74 }
75 }
76
77 size_t GetInstancesCount() const
78 {
79 return instances_.size();
80 }
81
82 void AddInstance(const std::string& instance)
83 {
84 if (started_)
85 {
86 throw OrthancException(ErrorCode_BadSequenceOfCalls);
87 }
88 else
89 {
90 instances_.push_back(instance);
91 }
92 }
93
94 virtual void Start()
95 {
96 started_ = true;
97 }
98
99 virtual float GetProgress()
100 {
101 if (instances_.size() == 0)
102 {
103 return 0;
104 }
105 else
106 {
107 return (static_cast<float>(position_) /
108 static_cast<float>(instances_.size()));
109 }
110 }
111
112 bool IsStarted() const
113 {
114 return started_;
115 }
116
117 bool IsDone() const
118 {
119 return (position_ >= instances_.size());
120 }
121
122 void Next()
123 {
124 if (IsDone())
125 {
126 throw OrthancException(ErrorCode_BadSequenceOfCalls);
127 }
128 else
129 {
130 position_ += 1;
131 }
132 }
133
134 const std::string& GetCurrentInstance() const
135 {
136 if (IsDone())
137 {
138 throw OrthancException(ErrorCode_BadSequenceOfCalls);
139 }
140 else
141 {
142 return instances_[position_];
143 }
144 }
145 };
146
147
148 class StoreScuJob : public InstancesIteratorJob
149 {
150 private:
151 ServerContext& context_;
152 std::string localAet_;
153 RemoteModalityParameters remote_;
154 bool permissive_;
155 std::string moveOriginatorAet_;
156 uint16_t moveOriginatorId_;
157 std::auto_ptr<DicomUserConnection> connection_;
158 std::set<std::string> failedInstances_;
159
160 void Open()
161 {
162 if (connection_.get() == NULL)
163 {
164 connection_.reset(new DicomUserConnection);
165 connection_->SetLocalApplicationEntityTitle(localAet_);
166 connection_->SetRemoteModality(remote_);
167 connection_->Open();
168 }
169 }
170
171 public:
172 StoreScuJob(ServerContext& context) :
173 context_(context),
174 localAet_("ORTHANC"),
175 permissive_(false),
176 moveOriginatorId_(0) // By default, not a C-MOVE
177 {
178 }
179
180 void AddResource(const std::string& publicId)
181 {
182 typedef std::list<std::string> Instances;
183
184 Instances instances;
185 context_.GetIndex().GetChildInstances(instances, publicId);
186
187 Reserve(GetInstancesCount() + instances.size());
188
189 for (Instances::const_iterator it = instances.begin();
190 it != instances.end(); ++it)
191 {
192 AddInstance(*it);
193 }
194 }
195
196 const std::string& GetLocalAet() const
197 {
198 return localAet_;
199 }
200
201 void SetLocalAet(const std::string& aet)
202 {
203 if (IsStarted())
204 {
205 throw OrthancException(ErrorCode_BadSequenceOfCalls);
206 }
207 else
208 {
209 localAet_ = aet;
210 }
211 }
212
213 const RemoteModalityParameters& GetRemoteModality() const
214 {
215 return remote_;
216 }
217
218 void SetRemoteModality(const RemoteModalityParameters& remote)
219 {
220 if (IsStarted())
221 {
222 throw OrthancException(ErrorCode_BadSequenceOfCalls);
223 }
224 else
225 {
226 remote_ = remote;
227 }
228 }
229
230 bool IsPermissive() const
231 {
232 return permissive_;
233 }
234
235 void SetPermissive(bool permissive)
236 {
237 if (IsStarted())
238 {
239 throw OrthancException(ErrorCode_BadSequenceOfCalls);
240 }
241 else
242 {
243 permissive_ = permissive;
244 }
245 }
246
247 bool HasMoveOriginator() const
248 {
249 return moveOriginatorId_ != 0;
250 }
251
252 const std::string& GetMoveOriginatorAet() const
253 {
254 if (HasMoveOriginator())
255 {
256 return moveOriginatorAet_;
257 }
258 else
259 {
260 throw OrthancException(ErrorCode_BadSequenceOfCalls);
261 }
262 }
263
264 uint16_t GetMoveOriginatorId() const
265 {
266 if (HasMoveOriginator())
267 {
268 return moveOriginatorId_;
269 }
270 else
271 {
272 throw OrthancException(ErrorCode_BadSequenceOfCalls);
273 }
274 }
275
276 void SetMoveOriginator(const std::string& aet,
277 int id)
278 {
279 if (IsStarted())
280 {
281 throw OrthancException(ErrorCode_BadSequenceOfCalls);
282 }
283 else if (id < 0 ||
284 id >= 65536)
285 {
286 throw OrthancException(ErrorCode_ParameterOutOfRange);
287 }
288 else
289 {
290 moveOriginatorId_ = static_cast<uint16_t>(id);
291 moveOriginatorAet_ = aet;
292 }
293 }
294
295 virtual JobStepResult* ExecuteStep()
296 {
297 if (IsDone())
298 {
299 return new JobStepResult(JobStepCode_Success);
300 }
301
302 Open();
303
304 bool ok = false;
305
306 try
307 {
308 std::string dicom;
309 context_.ReadDicom(dicom, GetCurrentInstance());
310
311 if (HasMoveOriginator())
312 {
313 connection_->Store(dicom, moveOriginatorAet_, moveOriginatorId_);
314 }
315 else
316 {
317 connection_->Store(dicom);
318 }
319
320 boost::this_thread::sleep(boost::posix_time::milliseconds(300));
321
322 ok = true;
323 }
324 catch (OrthancException& e)
325 {
326 }
327
328 if (!ok)
329 {
330 if (permissive_)
331 {
332 failedInstances_.insert(GetCurrentInstance());
333 }
334 else
335 {
336 return new JobStepResult(JobStepCode_Failure);
337 }
338 }
339
340 Next();
341
342 if (IsDone())
343 {
344 return new JobStepResult(JobStepCode_Success);
345 }
346 else
347 {
348 return new JobStepResult(JobStepCode_Continue);
349 }
350 }
351
352 virtual void ReleaseResources() // For pausing jobs
353 {
354 connection_.reset(NULL);
355 }
356
357 virtual void GetJobType(std::string& target)
358 {
359 target = "C-Store";
360 }
361
362 virtual void GetPublicContent(Json::Value& value)
363 {
364 value["LocalAet"] = localAet_;
365 value["RemoteAet"] = remote_.GetApplicationEntityTitle();
366
367 if (HasMoveOriginator())
368 {
369 value["MoveOriginatorAET"] = GetMoveOriginatorAet();
370 value["MoveOriginatorID"] = GetMoveOriginatorId();
371 }
372
373 Json::Value v = Json::arrayValue;
374 for (std::set<std::string>::const_iterator it = failedInstances_.begin();
375 it != failedInstances_.end(); ++it)
376 {
377 v.append(*it);
378 }
379
380 value["FailedInstances"] = v;
381 }
382
383 virtual void GetInternalContent(Json::Value& value)
384 {
385 // TODO
386 }
387 };
388 }
389
390
391
392
47 namespace Orthanc 393 namespace Orthanc
48 { 394 {
49 /*************************************************************************** 395 /***************************************************************************
50 * DICOM C-Echo SCU 396 * DICOM C-Echo SCU
51 ***************************************************************************/ 397 ***************************************************************************/
687 std::string localAet = Toolbox::GetJsonStringField(request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle()); 1033 std::string localAet = Toolbox::GetJsonStringField(request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle());
688 bool permissive = Toolbox::GetJsonBooleanField(request, "Permissive", false); 1034 bool permissive = Toolbox::GetJsonBooleanField(request, "Permissive", false);
689 bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false); 1035 bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false);
690 std::string moveOriginatorAET = Toolbox::GetJsonStringField(request, "MoveOriginatorAet", context.GetDefaultLocalApplicationEntityTitle()); 1036 std::string moveOriginatorAET = Toolbox::GetJsonStringField(request, "MoveOriginatorAet", context.GetDefaultLocalApplicationEntityTitle());
691 int moveOriginatorID = Toolbox::GetJsonIntegerField(request, "MoveOriginatorID", 0 /* By default, not a C-MOVE */); 1037 int moveOriginatorID = Toolbox::GetJsonIntegerField(request, "MoveOriginatorID", 0 /* By default, not a C-MOVE */);
1038 int priority = Toolbox::GetJsonIntegerField(request, "Priority", 0);
692 1039
693 if (moveOriginatorID < 0 || 1040 if (moveOriginatorID < 0 ||
694 moveOriginatorID >= 65536) 1041 moveOriginatorID >= 65536)
695 { 1042 {
696 throw OrthancException(ErrorCode_ParameterOutOfRange); 1043 throw OrthancException(ErrorCode_ParameterOutOfRange);
697 } 1044 }
698 1045
699 RemoteModalityParameters p = Configuration::GetModalityUsingSymbolicName(remote); 1046 RemoteModalityParameters p = Configuration::GetModalityUsingSymbolicName(remote);
700 1047
1048 #if 1
1049 std::auto_ptr<StoreScuJob> job(new StoreScuJob(context));
1050 job->SetLocalAet(localAet);
1051 job->SetRemoteModality(p);
1052 job->SetPermissive(permissive);
1053
1054 if (moveOriginatorID != 0)
1055 {
1056 job->SetMoveOriginator(moveOriginatorAET, static_cast<uint16_t>(moveOriginatorID));
1057 }
1058
1059 for (std::list<std::string>::const_iterator
1060 it = instances.begin(); it != instances.end(); ++it)
1061 {
1062 job->AddInstance(*it);
1063 }
1064
1065 if (asynchronous)
1066 {
1067 // Asynchronous mode: Submit the job, but don't wait for its completion
1068 std::string id;
1069 context.GetJobsEngine().GetRegistry().Submit(id, job.release(), priority);
1070
1071 Json::Value v;
1072 v["ID"] = id;
1073 call.GetOutput().AnswerJson(v);
1074 }
1075 else if (context.GetJobsEngine().GetRegistry().SubmitAndWait(job.release(), priority))
1076 {
1077 // Synchronous mode: We have submitted and waited for completion
1078 call.GetOutput().AnswerBuffer("{}", "application/json");
1079 }
1080 else
1081 {
1082 call.GetOutput().SignalError(HttpStatus_500_InternalServerError);
1083 }
1084
1085 #else
701 ServerJob job; 1086 ServerJob job;
702 for (std::list<std::string>::const_iterator 1087 for (std::list<std::string>::const_iterator
703 it = instances.begin(); it != instances.end(); ++it) 1088 it = instances.begin(); it != instances.end(); ++it)
704 { 1089 {
705 std::auto_ptr<StoreScuCommand> command(new StoreScuCommand(context, localAet, p, permissive)); 1090 std::auto_ptr<StoreScuCommand> command(new StoreScuCommand(context, localAet, p, permissive));
727 } 1112 }
728 else 1113 else
729 { 1114 {
730 call.GetOutput().SignalError(HttpStatus_500_InternalServerError); 1115 call.GetOutput().SignalError(HttpStatus_500_InternalServerError);
731 } 1116 }
1117 #endif
732 } 1118 }
733 1119
734 1120
735 /*************************************************************************** 1121 /***************************************************************************
736 * DICOM C-Move SCU 1122 * DICOM C-Move SCU