comparison Plugins/Samples/ModalityWorklists/Plugin.cpp @ 2205:395522e46b2b

refactoring of the worklist sample using OrthancPluginCppWrapper
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 08 Dec 2016 16:16:25 +0100
parents 7a05144cb919
children 27106f7e3759
comparison
equal deleted inserted replaced
2204:0158f2de8cad 2205:395522e46b2b
16 * You should have received a copy of the GNU General Public License 16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 **/ 18 **/
19 19
20 20
21 #include <orthanc/OrthancCPlugin.h> 21 #include "../Common/OrthancPluginCppWrapper.h"
22 22
23 #include <boost/filesystem.hpp> 23 #include <boost/filesystem.hpp>
24 #include <json/value.h> 24 #include <json/value.h>
25 #include <json/reader.h> 25 #include <json/reader.h>
26 #include <string.h> 26 #include <string.h>
29 29
30 static OrthancPluginContext* context_ = NULL; 30 static OrthancPluginContext* context_ = NULL;
31 static std::string folder_; 31 static std::string folder_;
32 32
33 33
34 static bool ReadFile(std::string& result,
35 const std::string& path)
36 {
37 OrthancPluginMemoryBuffer tmp;
38 if (OrthancPluginReadFile(context_, &tmp, path.c_str()))
39 {
40 return false;
41 }
42 else
43 {
44 result.assign(reinterpret_cast<const char*>(tmp.data), tmp.size);
45 OrthancPluginFreeMemoryBuffer(context_, &tmp);
46 return true;
47 }
48 }
49
50
51 /** 34 /**
52 * This is the main function for matching a DICOM worklist against a query. 35 * This is the main function for matching a DICOM worklist against a query.
53 **/ 36 **/
54 static OrthancPluginErrorCode MatchWorklist(OrthancPluginWorklistAnswers* answers, 37 static OrthancPluginErrorCode MatchWorklist(OrthancPluginWorklistAnswers* answers,
55 const OrthancPluginWorklistQuery* query, 38 const OrthancPluginWorklistQuery* query,
56 const std::string& path) 39 const std::string& path)
57 { 40 {
58 std::string dicom; 41 OrthancPlugins::MemoryBuffer dicom(context_);
59 if (!ReadFile(dicom, path)) 42 dicom.ReadFile(path);
60 { 43
61 // Cannot read this file, ignore this error 44 if (OrthancPluginWorklistIsMatch(context_, query, dicom.GetData(), dicom.GetSize()))
62 return OrthancPluginErrorCode_Success;
63 }
64
65 if (OrthancPluginWorklistIsMatch(context_, query, dicom.c_str(), dicom.size()))
66 { 45 {
67 // This DICOM file matches the worklist query, add it to the answers 46 // This DICOM file matches the worklist query, add it to the answers
68 return OrthancPluginWorklistAddAnswer 47 return OrthancPluginWorklistAddAnswer
69 (context_, answers, query, dicom.c_str(), dicom.size()); 48 (context_, answers, query, dicom.GetData(), dicom.GetSize());
70 } 49 }
71 else 50 else
72 { 51 {
73 // This DICOM file does not match 52 // This DICOM file does not match
74 return OrthancPluginErrorCode_Success; 53 return OrthancPluginErrorCode_Success;
75 } 54 }
76 } 55 }
77 56
78 57
79 58
80 static bool ConvertToJson(Json::Value& result, 59 static void GetQueryDicom(Json::Value& value,
81 char* content)
82 {
83 if (content == NULL)
84 {
85 return false;
86 }
87 else
88 {
89 Json::Reader reader;
90 bool success = reader.parse(content, content + strlen(content), result);
91 OrthancPluginFreeString(context_, content);
92 return success;
93 }
94 }
95
96
97 static bool GetQueryDicom(Json::Value& value,
98 const OrthancPluginWorklistQuery* query) 60 const OrthancPluginWorklistQuery* query)
99 { 61 {
100 OrthancPluginMemoryBuffer dicom; 62 OrthancPlugins::MemoryBuffer dicom(context_);
101 if (OrthancPluginWorklistGetDicomQuery(context_, &dicom, query)) 63 dicom.GetDicomQuery(query);
102 { 64
103 return false; 65 OrthancPlugins::OrthancString str(context_);
104 } 66 str.DicomToJson(dicom, OrthancPluginDicomToJsonFormat_Short,
105 67 static_cast<OrthancPluginDicomToJsonFlags>(0), 0);
106 char* json = OrthancPluginDicomBufferToJson(context_, reinterpret_cast<const char*>(dicom.data), 68
107 dicom.size, 69 str.ToJson(value);
108 OrthancPluginDicomToJsonFormat_Short, 70 }
109 static_cast<OrthancPluginDicomToJsonFlags>(0), 0); 71
110 OrthancPluginFreeMemoryBuffer(context_, &dicom);
111
112 return ConvertToJson(value, json);
113 }
114
115 72
116 static void ToLowerCase(std::string& s) 73 static void ToLowerCase(std::string& s)
117 { 74 {
118 std::transform(s.begin(), s.end(), s.begin(), tolower); 75 std::transform(s.begin(), s.end(), s.begin(), tolower);
119 } 76 }
122 OrthancPluginErrorCode Callback(OrthancPluginWorklistAnswers* answers, 79 OrthancPluginErrorCode Callback(OrthancPluginWorklistAnswers* answers,
123 const OrthancPluginWorklistQuery* query, 80 const OrthancPluginWorklistQuery* query,
124 const char* remoteAet, 81 const char* remoteAet,
125 const char* calledAet) 82 const char* calledAet)
126 { 83 {
127 namespace fs = boost::filesystem;
128
129 Json::Value json;
130
131 if (!GetQueryDicom(json, query))
132 {
133 return OrthancPluginErrorCode_InternalError;
134 }
135
136 {
137 std::string msg = ("Received worklist query from remote modality " +
138 std::string(remoteAet) + ":\n" + json.toStyledString());
139 OrthancPluginLogInfo(context_, msg.c_str());
140 }
141
142 fs::path source(folder_);
143 fs::directory_iterator end;
144
145 try 84 try
146 { 85 {
147 for (fs::directory_iterator it(source); it != end; ++it) 86 namespace fs = boost::filesystem;
148 { 87
149 fs::file_type type(it->status().type()); 88 {
150 89 Json::Value json;
151 if (type == fs::regular_file || 90 GetQueryDicom(json, query);
152 type == fs::reparse_file) // cf. BitBucket issue #11 91
92 std::string msg = ("Received worklist query from remote modality " +
93 std::string(remoteAet) + ":\n" + json.toStyledString());
94 OrthancPluginLogInfo(context_, msg.c_str());
95 }
96
97 fs::path source(folder_);
98 fs::directory_iterator end;
99
100 try
101 {
102 for (fs::directory_iterator it(source); it != end; ++it)
153 { 103 {
154 std::string extension = fs::extension(it->path()); 104 fs::file_type type(it->status().type());
155 ToLowerCase(extension); 105
156 106 if (type == fs::regular_file ||
157 if (extension == ".wl") 107 type == fs::reparse_file) // cf. BitBucket issue #11
158 { 108 {
159 OrthancPluginErrorCode error = MatchWorklist(answers, query, it->path().string()); 109 std::string extension = fs::extension(it->path());
160 if (error) 110 ToLowerCase(extension);
111
112 if (extension == ".wl")
161 { 113 {
162 OrthancPluginLogError(context_, "Error while adding an answer to a worklist request"); 114 OrthancPluginErrorCode error = MatchWorklist(answers, query, it->path().string());
163 return error; 115 if (error)
116 {
117 OrthancPluginLogError(context_, "Error while adding an answer to a worklist request");
118 return error;
119 }
164 } 120 }
165 } 121 }
166 } 122 }
167 } 123 }
168 } 124 catch (fs::filesystem_error&)
169 catch (fs::filesystem_error&) 125 {
170 { 126 std::string description = std::string("Inexistent folder while scanning for worklists: ") + source.string();
171 std::string description = std::string("Inexistent folder while scanning for worklists: ") + source.string(); 127 OrthancPluginLogError(context_, description.c_str());
172 OrthancPluginLogError(context_, description.c_str()); 128 return OrthancPluginErrorCode_DirectoryExpected;
173 return OrthancPluginErrorCode_DirectoryExpected; 129 }
174 } 130
175 131 // Uncomment the following line if too many answers are to be returned
176 // Uncomment the following line if too many answers are to be returned 132 // OrthancPluginMarkWorklistAnswersIncomplete(context_, answers);
177 // OrthancPluginMarkWorklistAnswersIncomplete(context_, answers); 133
178 134 return OrthancPluginErrorCode_Success;
179 return OrthancPluginErrorCode_Success; 135 }
136 catch (OrthancPlugins::PluginException& e)
137 {
138 return e.GetErrorCode();
139 }
180 } 140 }
181 141
182 142
183 extern "C" 143 extern "C"
184 { 144 {
185 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c) 145 ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c)
186 { 146 {
187 context_ = c; 147 context_ = c;
188 OrthancPluginLogWarning(context_, "Sample worklist plugin is initializing");
189 OrthancPluginSetDescription(context_, "Serve DICOM modality worklists from a folder with Orthanc.");
190 148
191 /* Check the version of the Orthanc core */ 149 /* Check the version of the Orthanc core */
192 if (OrthancPluginCheckVersion(c) == 0) 150 if (OrthancPluginCheckVersion(c) == 0)
193 { 151 {
194 char info[1024]; 152 char info[1024];
199 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); 157 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
200 OrthancPluginLogError(context_, info); 158 OrthancPluginLogError(context_, info);
201 return -1; 159 return -1;
202 } 160 }
203 161
204 Json::Value configuration; 162 OrthancPlugins::LogWarning(context_, "Sample worklist plugin is initializing");
205 if (!ConvertToJson(configuration, OrthancPluginGetConfiguration(context_))) 163 OrthancPluginSetDescription(context_, "Serve DICOM modality worklists from a folder with Orthanc.");
206 { 164
207 OrthancPluginLogError(context_, "Cannot access the configuration of the worklist server"); 165 OrthancPlugins::OrthancConfiguration configuration(context_);
208 return -1; 166
209 } 167 OrthancPlugins::OrthancConfiguration worklists;
210 168 configuration.GetSection(worklists, "Worklists");
211 bool enabled = false; 169
212 170 bool enabled = worklists.GetBooleanValue("Enable", false);
213 if (configuration.isMember("Worklists")) 171 if (enabled)
214 { 172 {
215 const Json::Value& config = configuration["Worklists"]; 173 if (worklists.LookupStringValue(folder_, "Database"))
216 if (!config.isMember("Enable") ||
217 config["Enable"].type() != Json::booleanValue)
218 { 174 {
219 OrthancPluginLogError(context_, "The configuration option \"Worklists.Enable\" must contain a Boolean"); 175 OrthancPlugins::LogWarning(context_, "The database of worklists will be read from folder: " + folder_);
220 return -1; 176 OrthancPluginRegisterWorklistCallback(context_, Callback);
221 } 177 }
222 else 178 else
223 { 179 {
224 enabled = config["Enable"].asBool(); 180 OrthancPlugins::LogError(context_, "The configuration option \"Worklists.Database\" must contain a path");
225 if (enabled) 181 return -1;
226 {
227 if (!config.isMember("Database") ||
228 config["Database"].type() != Json::stringValue)
229 {
230 OrthancPluginLogError(context_, "The configuration option \"Worklists.Database\" must contain a path");
231 return -1;
232 }
233
234 folder_ = config["Database"].asString();
235 }
236 else
237 {
238 OrthancPluginLogWarning(context_, "Worklists server is disabled by the configuration file");
239 }
240 } 182 }
241 } 183 }
242 else 184 else
243 { 185 {
244 OrthancPluginLogWarning(context_, "Worklists server is disabled, no suitable configuration section was provided"); 186 OrthancPlugins::LogWarning(context_, "Worklists server is disabled by the configuration file");
245 }
246
247 if (enabled)
248 {
249 std::string message = "The database of worklists will be read from folder: " + folder_;
250 OrthancPluginLogWarning(context_, message.c_str());
251
252 OrthancPluginRegisterWorklistCallback(context_, Callback);
253 } 187 }
254 188
255 return 0; 189 return 0;
256 } 190 }
257 191