comparison Plugins/Engine/OrthancPlugins.cpp @ 1199:a843ee8bb903 db-changes

separated thread for change callbacks in plugins
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 23 Oct 2014 14:29:45 +0200
parents 1169528a9a5f
children f1c01451a8ee
comparison
equal deleted inserted replaced
1198:1169528a9a5f 1199:a843ee8bb903
37 #include "../../Core/Toolbox.h" 37 #include "../../Core/Toolbox.h"
38 #include "../../Core/HttpServer/HttpOutput.h" 38 #include "../../Core/HttpServer/HttpOutput.h"
39 #include "../../Core/ImageFormats/PngWriter.h" 39 #include "../../Core/ImageFormats/PngWriter.h"
40 #include "../../OrthancServer/ServerToolbox.h" 40 #include "../../OrthancServer/ServerToolbox.h"
41 #include "../../OrthancServer/OrthancInitialization.h" 41 #include "../../OrthancServer/OrthancInitialization.h"
42 #include "../../Core/MultiThreading/SharedMessageQueue.h"
42 43
43 #include <boost/thread.hpp> 44 #include <boost/thread.hpp>
44 #include <boost/regex.hpp> 45 #include <boost/regex.hpp>
45 #include <glog/logging.h> 46 #include <glog/logging.h>
46 47
47 namespace Orthanc 48 namespace Orthanc
48 { 49 {
50 static OrthancPluginResourceType Convert(ResourceType type)
51 {
52 switch (type)
53 {
54 case ResourceType_Patient:
55 return OrthancPluginResourceType_Patient;
56
57 case ResourceType_Study:
58 return OrthancPluginResourceType_Study;
59
60 case ResourceType_Series:
61 return OrthancPluginResourceType_Series;
62
63 case ResourceType_Instance:
64 return OrthancPluginResourceType_Instance;
65
66 default:
67 throw OrthancException(ErrorCode_ParameterOutOfRange);
68 }
69 }
70
71
72 static OrthancPluginChangeType Convert(ChangeType type)
73 {
74 switch (type)
75 {
76 case ChangeType_CompletedSeries:
77 return OrthancPluginChangeType_CompletedSeries;
78
79 case ChangeType_Deleted:
80 return OrthancPluginChangeType_Deleted;
81
82 case ChangeType_NewChildInstance:
83 return OrthancPluginChangeType_NewChildInstance;
84
85 case ChangeType_NewInstance:
86 return OrthancPluginChangeType_NewInstance;
87
88 case ChangeType_NewPatient:
89 return OrthancPluginChangeType_NewPatient;
90
91 case ChangeType_NewSeries:
92 return OrthancPluginChangeType_NewSeries;
93
94 case ChangeType_NewStudy:
95 return OrthancPluginChangeType_NewStudy;
96
97 case ChangeType_StablePatient:
98 return OrthancPluginChangeType_StablePatient;
99
100 case ChangeType_StableSeries:
101 return OrthancPluginChangeType_StableSeries;
102
103 case ChangeType_StableStudy:
104 return OrthancPluginChangeType_StableStudy;
105
106 default:
107 throw OrthancException(ErrorCode_ParameterOutOfRange);
108 }
109 }
110
111
49 namespace 112 namespace
50 { 113 {
51 // Anonymous namespace to avoid clashes between compilation modules 114 // Anonymous namespace to avoid clashes between compilation modules
52 class StringHttpOutput : public IHttpOutputStream 115 class StringHttpOutput : public IHttpOutputStream
53 { 116 {
71 virtual void Send(bool isHeader, const void* buffer, size_t length) 134 virtual void Send(bool isHeader, const void* buffer, size_t length)
72 { 135 {
73 if (!isHeader) 136 if (!isHeader)
74 { 137 {
75 buffer_.AddChunk(reinterpret_cast<const char*>(buffer), length); 138 buffer_.AddChunk(reinterpret_cast<const char*>(buffer), length);
139 }
140 }
141 };
142
143
144 class PendingChange : public IDynamicObject
145 {
146 private:
147 OrthancPluginChangeType changeType_;
148 OrthancPluginResourceType resourceType_;
149 std::string publicId_;
150
151 public:
152 PendingChange(const ServerIndexChange& change)
153 {
154 changeType_ = Convert(change.GetChangeType());
155 resourceType_ = Convert(change.GetResourceType());
156 publicId_ = change.GetPublicId();
157 }
158
159 void Submit(std::list<OrthancPluginOnChangeCallback>& callbacks)
160 {
161 for (std::list<OrthancPluginOnChangeCallback>::const_iterator
162 callback = callbacks.begin();
163 callback != callbacks.end(); ++callback)
164 {
165 (*callback) (changeType_, resourceType_, publicId_.c_str());
76 } 166 }
77 } 167 }
78 }; 168 };
79 } 169 }
80 170
93 OnStoredCallbacks onStoredCallbacks_; 183 OnStoredCallbacks onStoredCallbacks_;
94 OnChangeCallbacks onChangeCallbacks_; 184 OnChangeCallbacks onChangeCallbacks_;
95 bool hasStorageArea_; 185 bool hasStorageArea_;
96 _OrthancPluginRegisterStorageArea storageArea_; 186 _OrthancPluginRegisterStorageArea storageArea_;
97 boost::mutex callbackMutex_; 187 boost::mutex callbackMutex_;
188 SharedMessageQueue pendingChanges_;
189 boost::thread changeThread_;
190 bool done_;
98 191
99 PImpl(ServerContext& context) : 192 PImpl(ServerContext& context) :
100 context_(context), 193 context_(context),
101 restApi_(NULL), 194 restApi_(NULL),
102 hasStorageArea_(false) 195 hasStorageArea_(false),
196 done_(false)
103 { 197 {
104 memset(&storageArea_, 0, sizeof(storageArea_)); 198 memset(&storageArea_, 0, sizeof(storageArea_));
105 } 199 }
200
201
202 static void ChangeThread(PImpl* that)
203 {
204 while (!that->done_)
205 {
206 std::auto_ptr<IDynamicObject> obj(that->pendingChanges_.Dequeue(500));
207
208 if (obj.get() != NULL)
209 {
210 boost::mutex::scoped_lock lock(that->callbackMutex_);
211 PendingChange& change = *dynamic_cast<PendingChange*>(obj.get());
212 change.Submit(that->onChangeCallbacks_);
213 }
214 }
215 }
106 }; 216 };
107 217
108 218
219
109 static char* CopyString(const std::string& str) 220 static char* CopyString(const std::string& str)
110 { 221 {
111 char *result = reinterpret_cast<char*>(malloc(str.size() + 1)); 222 char *result = reinterpret_cast<char*>(malloc(str.size() + 1));
112 if (result == NULL) 223 if (result == NULL)
113 { 224 {
125 236
126 return result; 237 return result;
127 } 238 }
128 239
129 240
130 static OrthancPluginResourceType Convert(ResourceType type)
131 {
132 switch (type)
133 {
134 case ResourceType_Patient:
135 return OrthancPluginResourceType_Patient;
136
137 case ResourceType_Study:
138 return OrthancPluginResourceType_Study;
139
140 case ResourceType_Series:
141 return OrthancPluginResourceType_Series;
142
143 case ResourceType_Instance:
144 return OrthancPluginResourceType_Instance;
145
146 default:
147 throw OrthancException(ErrorCode_ParameterOutOfRange);
148 }
149 }
150
151
152 static OrthancPluginChangeType Convert(ChangeType type)
153 {
154 switch (type)
155 {
156 case ChangeType_CompletedSeries:
157 return OrthancPluginChangeType_CompletedSeries;
158
159 case ChangeType_Deleted:
160 return OrthancPluginChangeType_Deleted;
161
162 case ChangeType_NewChildInstance:
163 return OrthancPluginChangeType_NewChildInstance;
164
165 case ChangeType_NewInstance:
166 return OrthancPluginChangeType_NewInstance;
167
168 case ChangeType_NewPatient:
169 return OrthancPluginChangeType_NewPatient;
170
171 case ChangeType_NewSeries:
172 return OrthancPluginChangeType_NewSeries;
173
174 case ChangeType_NewStudy:
175 return OrthancPluginChangeType_NewStudy;
176
177 case ChangeType_StablePatient:
178 return OrthancPluginChangeType_StablePatient;
179
180 case ChangeType_StableSeries:
181 return OrthancPluginChangeType_StableSeries;
182
183 case ChangeType_StableStudy:
184 return OrthancPluginChangeType_StableStudy;
185
186 default:
187 throw OrthancException(ErrorCode_ParameterOutOfRange);
188 }
189 }
190
191
192 OrthancPlugins::OrthancPlugins(ServerContext& context) 241 OrthancPlugins::OrthancPlugins(ServerContext& context)
193 { 242 {
194 pimpl_.reset(new PImpl(context)); 243 pimpl_.reset(new PImpl(context));
244 pimpl_->changeThread_ = boost::thread(PImpl::ChangeThread, pimpl_.get());
195 } 245 }
196 246
197 247
198 OrthancPlugins::~OrthancPlugins() 248 OrthancPlugins::~OrthancPlugins()
199 { 249 {
250 Stop();
251
200 for (PImpl::RestCallbacks::iterator it = pimpl_->restCallbacks_.begin(); 252 for (PImpl::RestCallbacks::iterator it = pimpl_->restCallbacks_.begin();
201 it != pimpl_->restCallbacks_.end(); ++it) 253 it != pimpl_->restCallbacks_.end(); ++it)
202 { 254 {
203 // Delete the regular expression associated with this callback 255 // Delete the regular expression associated with this callback
204 delete it->first; 256 delete it->first;
205 } 257 }
206 } 258 }
259
260
261 void OrthancPlugins::Stop()
262 {
263 if (!pimpl_->done_)
264 {
265 pimpl_->done_ = true;
266 pimpl_->changeThread_.join();
267 }
268 }
269
207 270
208 271
209 static void ArgumentsToPlugin(std::vector<const char*>& keys, 272 static void ArgumentsToPlugin(std::vector<const char*>& keys,
210 std::vector<const char*>& values, 273 std::vector<const char*>& values,
211 const HttpHandler::Arguments& arguments) 274 const HttpHandler::Arguments& arguments)
365 428
366 429
367 430
368 void OrthancPlugins::SignalChange(const ServerIndexChange& change) 431 void OrthancPlugins::SignalChange(const ServerIndexChange& change)
369 { 432 {
370 OrthancPluginChangeType c;
371 OrthancPluginResourceType r;
372
373 try 433 try
374 { 434 {
375 c = Convert(change.GetChangeType()); 435 pimpl_->pendingChanges_.Enqueue(new PendingChange(change));
376 r = Convert(change.GetResourceType());
377 } 436 }
378 catch (OrthancException&) 437 catch (OrthancException&)
379 { 438 {
380 // This change type or resource type is not supported by the plugin SDK 439 // This change type or resource type is not supported by the plugin SDK
381 return; 440 return;
382 }
383
384 boost::mutex::scoped_lock lock(pimpl_->callbackMutex_);
385
386 for (PImpl::OnChangeCallbacks::const_iterator
387 callback = pimpl_->onChangeCallbacks_.begin();
388 callback != pimpl_->onChangeCallbacks_.end(); ++callback)
389 {
390 (*callback) (c, r, change.GetPublicId().c_str());
391 } 441 }
392 } 442 }
393 443
394 444
395 445
681 } 731 }
682 } 732 }
683 733
684 734
685 void OrthancPlugins::LookupResource(_OrthancPluginService service, 735 void OrthancPlugins::LookupResource(_OrthancPluginService service,
686 const void* parameters) 736 const void* parameters)
687 { 737 {
688 const _OrthancPluginRetrieveDynamicString& p = 738 const _OrthancPluginRetrieveDynamicString& p =
689 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters); 739 *reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters);
690 740
691 /** 741 /**