Mercurial > hg > orthanc
comparison Plugins/Samples/DatabasePlugin/Database.cpp @ 1671:2f2e2ec17bc4 db-changes
sample database plugin
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 01 Oct 2015 17:44:43 +0200 |
parents | |
children | 4c5a85c3ff43 |
comparison
equal
deleted
inserted
replaced
1670:16955f8fec4d | 1671:2f2e2ec17bc4 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * | |
6 * This program is free software: you can redistribute it and/or | |
7 * modify it under the terms of the GNU General Public License as | |
8 * published by the Free Software Foundation, either version 3 of the | |
9 * License, or (at your option) any later version. | |
10 * | |
11 * In addition, as a special exception, the copyright holders of this | |
12 * program give permission to link the code of its release with the | |
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
14 * that use the same license as the "OpenSSL" library), and distribute | |
15 * the linked executables. You must obey the GNU General Public License | |
16 * in all respects for all of the code used other than "OpenSSL". If you | |
17 * modify file(s) with this exception, you may extend this exception to | |
18 * your version of the file(s), but you are not obligated to do so. If | |
19 * you do not wish to do so, delete this exception statement from your | |
20 * version. If you delete this exception statement from all source files | |
21 * in the program, then also delete it here. | |
22 * | |
23 * This program is distributed in the hope that it will be useful, but | |
24 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
26 * General Public License for more details. | |
27 * | |
28 * You should have received a copy of the GNU General Public License | |
29 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
30 **/ | |
31 | |
32 | |
33 #include "Database.h" | |
34 | |
35 #include <EmbeddedResources.h> | |
36 | |
37 #include "../../../Core/DicomFormat/DicomArray.h" | |
38 | |
39 namespace Internals | |
40 { | |
41 class SignalFileDeleted : public Orthanc::SQLite::IScalarFunction | |
42 { | |
43 private: | |
44 OrthancPlugins::DatabaseBackendOutput& output_; | |
45 | |
46 public: | |
47 SignalFileDeleted(OrthancPlugins::DatabaseBackendOutput& output) : output_(output) | |
48 { | |
49 } | |
50 | |
51 virtual const char* GetName() const | |
52 { | |
53 return "SignalFileDeleted"; | |
54 } | |
55 | |
56 virtual unsigned int GetCardinality() const | |
57 { | |
58 return 7; | |
59 } | |
60 | |
61 virtual void Compute(Orthanc::SQLite::FunctionContext& context) | |
62 { | |
63 std::string uncompressedMD5, compressedMD5; | |
64 | |
65 if (!context.IsNullValue(5)) | |
66 { | |
67 uncompressedMD5 = context.GetStringValue(5); | |
68 } | |
69 | |
70 if (!context.IsNullValue(6)) | |
71 { | |
72 compressedMD5 = context.GetStringValue(6); | |
73 } | |
74 | |
75 output_.SignalDeletedAttachment(context.GetStringValue(0), | |
76 context.GetIntValue(1), | |
77 context.GetInt64Value(2), | |
78 uncompressedMD5, | |
79 context.GetIntValue(3), | |
80 context.GetInt64Value(4), | |
81 compressedMD5); | |
82 } | |
83 }; | |
84 | |
85 | |
86 class SignalResourceDeleted : public Orthanc::SQLite::IScalarFunction | |
87 { | |
88 private: | |
89 OrthancPlugins::DatabaseBackendOutput& output_; | |
90 | |
91 public: | |
92 SignalResourceDeleted(OrthancPlugins::DatabaseBackendOutput& output) : output_(output) | |
93 { | |
94 } | |
95 | |
96 virtual const char* GetName() const | |
97 { | |
98 return "SignalResourceDeleted"; | |
99 } | |
100 | |
101 virtual unsigned int GetCardinality() const | |
102 { | |
103 return 2; | |
104 } | |
105 | |
106 virtual void Compute(Orthanc::SQLite::FunctionContext& context) | |
107 { | |
108 output_.SignalDeletedResource(context.GetStringValue(0), | |
109 static_cast<OrthancPluginResourceType>(context.GetIntValue(1))); | |
110 } | |
111 }; | |
112 } | |
113 | |
114 | |
115 class Database::SignalRemainingAncestor : public Orthanc::SQLite::IScalarFunction | |
116 { | |
117 private: | |
118 bool hasRemainingAncestor_; | |
119 std::string remainingPublicId_; | |
120 Orthanc::ResourceType remainingType_; | |
121 | |
122 public: | |
123 SignalRemainingAncestor() : | |
124 hasRemainingAncestor_(false) | |
125 { | |
126 } | |
127 | |
128 void Reset() | |
129 { | |
130 hasRemainingAncestor_ = false; | |
131 } | |
132 | |
133 virtual const char* GetName() const | |
134 { | |
135 return "SignalRemainingAncestor"; | |
136 } | |
137 | |
138 virtual unsigned int GetCardinality() const | |
139 { | |
140 return 2; | |
141 } | |
142 | |
143 virtual void Compute(Orthanc::SQLite::FunctionContext& context) | |
144 { | |
145 if (!hasRemainingAncestor_ || | |
146 remainingType_ >= context.GetIntValue(1)) | |
147 { | |
148 hasRemainingAncestor_ = true; | |
149 remainingPublicId_ = context.GetStringValue(0); | |
150 remainingType_ = static_cast<Orthanc::ResourceType>(context.GetIntValue(1)); | |
151 } | |
152 } | |
153 | |
154 bool HasRemainingAncestor() const | |
155 { | |
156 return hasRemainingAncestor_; | |
157 } | |
158 | |
159 const std::string& GetRemainingAncestorId() const | |
160 { | |
161 assert(hasRemainingAncestor_); | |
162 return remainingPublicId_; | |
163 } | |
164 | |
165 Orthanc::ResourceType GetRemainingAncestorType() const | |
166 { | |
167 assert(hasRemainingAncestor_); | |
168 return remainingType_; | |
169 } | |
170 }; | |
171 | |
172 | |
173 | |
174 Database::Database(const std::string& path) : | |
175 path_(path), | |
176 base_(db_) | |
177 { | |
178 db_.Open(path_); | |
179 Open(); | |
180 } | |
181 | |
182 | |
183 void Database::Open() | |
184 { | |
185 if (!db_.DoesTableExist("GlobalProperties")) | |
186 { | |
187 std::string query; | |
188 Orthanc::EmbeddedResources::GetFileResource(query, Orthanc::EmbeddedResources::PREPARE_DATABASE); | |
189 db_.Execute(query); | |
190 } | |
191 | |
192 signalRemainingAncestor_ = new SignalRemainingAncestor; | |
193 db_.Register(signalRemainingAncestor_); | |
194 db_.Register(new Internals::SignalFileDeleted(GetOutput())); | |
195 db_.Register(new Internals::SignalResourceDeleted(GetOutput())); | |
196 } | |
197 | |
198 | |
199 void Database::Close() | |
200 { | |
201 db_.Close(); | |
202 } | |
203 | |
204 | |
205 void Database::AddAttachment(int64_t id, | |
206 const OrthancPluginAttachment& attachment) | |
207 { | |
208 Orthanc::FileInfo info(attachment.uuid, | |
209 static_cast<Orthanc::FileContentType>(attachment.contentType), | |
210 attachment.uncompressedSize, | |
211 attachment.uncompressedHash, | |
212 static_cast<Orthanc::CompressionType>(attachment.compressionType), | |
213 attachment.compressedSize, | |
214 attachment.compressedHash); | |
215 base_.AddAttachment(id, info); | |
216 } | |
217 | |
218 | |
219 void Database::DeleteResource(int64_t id) | |
220 { | |
221 // TODO | |
222 } | |
223 | |
224 | |
225 static void Answer(OrthancPlugins::DatabaseBackendOutput& output, | |
226 const Orthanc::ServerIndexChange& change) | |
227 { | |
228 output.AnswerChange(change.GetSeq(), | |
229 static_cast<int32_t>(change.GetChangeType()), | |
230 Orthanc::Plugins::Convert(change.GetResourceType()), | |
231 change.GetPublicId(), | |
232 change.GetDate()); | |
233 } | |
234 | |
235 | |
236 static void Answer(OrthancPlugins::DatabaseBackendOutput& output, | |
237 const Orthanc::ExportedResource& resource) | |
238 { | |
239 output.AnswerExportedResource(resource.GetSeq(), | |
240 Orthanc::Plugins::Convert(resource.GetResourceType()), | |
241 resource.GetPublicId(), | |
242 resource.GetModality(), | |
243 resource.GetDate(), | |
244 resource.GetPatientId(), | |
245 resource.GetStudyInstanceUid(), | |
246 resource.GetSeriesInstanceUid(), | |
247 resource.GetSopInstanceUid()); | |
248 } | |
249 | |
250 | |
251 void Database::GetChanges(bool& done /*out*/, | |
252 int64_t since, | |
253 uint32_t maxResults) | |
254 { | |
255 typedef std::list<Orthanc::ServerIndexChange> Changes; | |
256 | |
257 Changes changes; | |
258 base_.GetChanges(changes, done, since, maxResults); | |
259 | |
260 for (Changes::const_iterator it = changes.begin(); it != changes.end(); ++it) | |
261 { | |
262 Answer(GetOutput(), *it); | |
263 } | |
264 } | |
265 | |
266 | |
267 void Database::GetExportedResources(bool& done /*out*/, | |
268 int64_t since, | |
269 uint32_t maxResults) | |
270 { | |
271 typedef std::list<Orthanc::ExportedResource> Resources; | |
272 | |
273 Resources resources; | |
274 base_.GetExportedResources(resources, done, since, maxResults); | |
275 | |
276 for (Resources::const_iterator it = resources.begin(); it != resources.end(); ++it) | |
277 { | |
278 Answer(GetOutput(), *it); | |
279 } | |
280 } | |
281 | |
282 | |
283 void Database::GetLastChange() | |
284 { | |
285 std::list<Orthanc::ServerIndexChange> change; | |
286 Orthanc::ErrorCode code = base_.GetLastChange(change); | |
287 | |
288 if (code != Orthanc::ErrorCode_Success) | |
289 { | |
290 throw OrthancPlugins::DatabaseException(static_cast<OrthancPluginErrorCode>(code)); | |
291 } | |
292 | |
293 if (!change.empty()) | |
294 { | |
295 Answer(GetOutput(), change.front()); | |
296 } | |
297 } | |
298 | |
299 | |
300 void Database::GetLastExportedResource() | |
301 { | |
302 std::list<Orthanc::ExportedResource> resource; | |
303 base_.GetLastExportedResource(resource); | |
304 | |
305 if (!resource.empty()) | |
306 { | |
307 Answer(GetOutput(), resource.front()); | |
308 } | |
309 } | |
310 | |
311 | |
312 void Database::GetMainDicomTags(int64_t id) | |
313 { | |
314 Orthanc::DicomMap tags; | |
315 base_.GetMainDicomTags(tags, id); | |
316 | |
317 Orthanc::DicomArray arr(tags); | |
318 for (size_t i = 0; i < arr.GetSize(); i++) | |
319 { | |
320 GetOutput().AnswerDicomTag(arr.GetElement(i).GetTag().GetGroup(), | |
321 arr.GetElement(i).GetTag().GetElement(), | |
322 arr.GetElement(i).GetValue().AsString()); | |
323 } | |
324 } | |
325 | |
326 | |
327 std::string Database::GetPublicId(int64_t resourceId) | |
328 { | |
329 std::string id; | |
330 if (base_.GetPublicId(id, resourceId)) | |
331 { | |
332 return id; | |
333 } | |
334 else | |
335 { | |
336 throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_UnknownResource); | |
337 } | |
338 } | |
339 | |
340 | |
341 OrthancPluginResourceType Database::GetResourceType(int64_t resourceId) | |
342 { | |
343 Orthanc::ResourceType result; | |
344 Orthanc::ErrorCode code = base_.GetResourceType(result, resourceId); | |
345 | |
346 if (code == Orthanc::ErrorCode_Success) | |
347 { | |
348 return Orthanc::Plugins::Convert(result); | |
349 } | |
350 else | |
351 { | |
352 throw OrthancPlugins::DatabaseException(static_cast<OrthancPluginErrorCode>(code)); | |
353 } | |
354 } | |
355 | |
356 | |
357 | |
358 template <typename I> | |
359 static void ConvertList(std::list<int32_t>& target, | |
360 const std::list<I>& source) | |
361 { | |
362 for (typename std::list<I>::const_iterator | |
363 it = source.begin(); it != source.end(); it++) | |
364 { | |
365 target.push_back(*it); | |
366 } | |
367 } | |
368 | |
369 | |
370 void Database::ListAvailableMetadata(std::list<int32_t>& target /*out*/, | |
371 int64_t id) | |
372 { | |
373 std::list<Orthanc::MetadataType> tmp; | |
374 base_.ListAvailableMetadata(tmp, id); | |
375 ConvertList(target, tmp); | |
376 } | |
377 | |
378 | |
379 void Database::ListAvailableAttachments(std::list<int32_t>& target /*out*/, | |
380 int64_t id) | |
381 { | |
382 std::list<Orthanc::FileContentType> tmp; | |
383 base_.ListAvailableAttachments(tmp, id); | |
384 ConvertList(target, tmp); | |
385 } | |
386 | |
387 | |
388 void Database::LogChange(const OrthancPluginChange& change) | |
389 { | |
390 int64_t id; | |
391 OrthancPluginResourceType type; | |
392 if (!LookupResource(id, type, change.publicId) || | |
393 type != change.resourceType) | |
394 { | |
395 throw OrthancPlugins::DatabaseException(OrthancPluginErrorCode_DatabasePlugin); | |
396 } | |
397 | |
398 Orthanc::ServerIndexChange tmp(change.seq, | |
399 static_cast<Orthanc::ChangeType>(change.changeType), | |
400 Orthanc::Plugins::Convert(change.resourceType), | |
401 change.publicId, | |
402 change.date); | |
403 | |
404 base_.LogChange(id, tmp); | |
405 } | |
406 | |
407 | |
408 void Database::LogExportedResource(const OrthancPluginExportedResource& resource) | |
409 { | |
410 Orthanc::ExportedResource tmp(resource.seq, | |
411 Orthanc::Plugins::Convert(resource.resourceType), | |
412 resource.publicId, | |
413 resource.modality, | |
414 resource.date, | |
415 resource.patientId, | |
416 resource.studyInstanceUid, | |
417 resource.seriesInstanceUid, | |
418 resource.sopInstanceUid); | |
419 | |
420 base_.LogExportedResource(tmp); | |
421 } | |
422 | |
423 | |
424 bool Database::LookupAttachment(int64_t id, | |
425 int32_t contentType) | |
426 { | |
427 Orthanc::FileInfo attachment; | |
428 if (base_.LookupAttachment(attachment, id, static_cast<Orthanc::FileContentType>(contentType))) | |
429 { | |
430 GetOutput().AnswerAttachment(attachment.GetUuid(), | |
431 attachment.GetContentType(), | |
432 attachment.GetUncompressedSize(), | |
433 attachment.GetUncompressedMD5(), | |
434 attachment.GetCompressionType(), | |
435 attachment.GetCompressedSize(), | |
436 attachment.GetCompressedMD5()); | |
437 return true; | |
438 } | |
439 else | |
440 { | |
441 return false; | |
442 } | |
443 } | |
444 | |
445 | |
446 bool Database::LookupParent(int64_t& parentId /*out*/, | |
447 int64_t resourceId) | |
448 { | |
449 bool found; | |
450 Orthanc::ErrorCode code = base_.LookupParent(found, parentId, resourceId); | |
451 | |
452 if (code == Orthanc::ErrorCode_Success) | |
453 { | |
454 return found; | |
455 } | |
456 else | |
457 { | |
458 throw OrthancPlugins::DatabaseException(static_cast<OrthancPluginErrorCode>(code)); | |
459 } | |
460 } | |
461 | |
462 | |
463 bool Database::LookupResource(int64_t& id /*out*/, | |
464 OrthancPluginResourceType& type /*out*/, | |
465 const char* publicId) | |
466 { | |
467 Orthanc::ResourceType tmp; | |
468 if (base_.LookupResource(id, tmp, publicId)) | |
469 { | |
470 type = Orthanc::Plugins::Convert(tmp); | |
471 return true; | |
472 } | |
473 else | |
474 { | |
475 return false; | |
476 } | |
477 } | |
478 | |
479 | |
480 void Database::StartTransaction() | |
481 { | |
482 transaction_.reset(new Orthanc::SQLite::Transaction(db_)); | |
483 transaction_->Begin(); | |
484 } | |
485 | |
486 | |
487 void Database::RollbackTransaction() | |
488 { | |
489 transaction_->Rollback(); | |
490 transaction_.reset(NULL); | |
491 } | |
492 | |
493 | |
494 void Database::CommitTransaction() | |
495 { | |
496 transaction_->Commit(); | |
497 transaction_.reset(NULL); | |
498 } | |
499 | |
500 | |
501 uint32_t Database::GetDatabaseVersion() | |
502 { | |
503 return 6; | |
504 } | |
505 | |
506 | |
507 void Database::UpgradeDatabase(uint32_t targetVersion, | |
508 OrthancPluginStorageArea* storageArea) | |
509 { | |
510 } |