Mercurial > hg > orthanc
annotate OrthancServer/OrthancFindRequestHandler.cpp @ 610:5ba825b87b21 find-move-scp
fix static build
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 18 Oct 2013 10:32:12 +0200 |
parents | 0bedf8ff9288 |
children | 9924aec1d694 |
rev | line source |
---|---|
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
1 /** |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
2 * Orthanc - A Lightweight, RESTful DICOM Store |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
3 * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
4 * Belgium |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
5 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
6 * This program is free software: you can redistribute it and/or |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
7 * modify it under the terms of the GNU General Public License as |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
8 * published by the Free Software Foundation, either version 3 of the |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
9 * License, or (at your option) any later version. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
10 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
11 * In addition, as a special exception, the copyright holders of this |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
12 * program give permission to link the code of its release with the |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
14 * that use the same license as the "OpenSSL" library), and distribute |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
15 * the linked executables. You must obey the GNU General Public License |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
16 * in all respects for all of the code used other than "OpenSSL". If you |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
17 * modify file(s) with this exception, you may extend this exception to |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
18 * your version of the file(s), but you are not obligated to do so. If |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
19 * you do not wish to do so, delete this exception statement from your |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
20 * version. If you delete this exception statement from all source files |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
21 * in the program, then also delete it here. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
22 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
23 * This program is distributed in the hope that it will be useful, but |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
24 * WITHOUT ANY WARRANTY; without even the implied warranty of |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
26 * General Public License for more details. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
27 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
28 * You should have received a copy of the GNU General Public License |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
29 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
30 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
31 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
32 #include "OrthancFindRequestHandler.h" |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
33 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
34 #include <glog/logging.h> |
608 | 35 #include <boost/regex.hpp> |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
36 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
37 #include "../Core/DicomFormat/DicomArray.h" |
608 | 38 #include "ServerToolbox.h" |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
39 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
40 namespace Orthanc |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
41 { |
610 | 42 static std::string ToLowerCase(const std::string& s) |
43 { | |
44 std::string result = s; | |
45 Toolbox::ToLowerCase(result); | |
46 return result; | |
47 } | |
48 | |
608 | 49 static bool ApplyRangeConstraint(const std::string& value, |
50 const std::string& constraint) | |
51 { | |
610 | 52 size_t separator = constraint.find('-'); |
53 std::string lower = ToLowerCase(constraint.substr(0, separator)); | |
54 std::string upper = ToLowerCase(constraint.substr(separator + 1)); | |
55 std::string v = ToLowerCase(value); | |
56 | |
57 if (lower.size() == 0 && upper.size() == 0) | |
58 { | |
59 return false; | |
60 } | |
61 | |
62 if (lower.size() == 0) | |
63 { | |
64 return v <= upper; | |
65 } | |
66 | |
67 if (upper.size() == 0) | |
68 { | |
69 return v >= lower; | |
70 } | |
71 | |
72 return (v >= lower && v <= upper); | |
608 | 73 } |
74 | |
75 | |
76 static bool ApplyListConstraint(const std::string& value, | |
77 const std::string& constraint) | |
78 { | |
79 std::cout << value << std::endl; | |
80 | |
610 | 81 std::string v1 = ToLowerCase(value); |
608 | 82 |
83 std::vector<std::string> items; | |
84 Toolbox::TokenizeString(items, constraint, '\\'); | |
85 | |
86 for (size_t i = 0; i < items.size(); i++) | |
87 { | |
88 Toolbox::ToLowerCase(items[i]); | |
89 if (items[i] == v1) | |
90 { | |
91 return true; | |
92 } | |
93 } | |
94 | |
95 return false; | |
96 } | |
97 | |
98 | |
99 static bool Matches(const std::string& value, | |
100 const std::string& constraint) | |
101 { | |
102 // http://www.itk.org/Wiki/DICOM_QueryRetrieve_Explained | |
103 // http://dicomiseasy.blogspot.be/2012/01/dicom-queryretrieve-part-i.html | |
104 | |
105 if (constraint.find('-') != std::string::npos) | |
106 { | |
107 return ApplyRangeConstraint(value, constraint); | |
108 } | |
109 | |
110 if (constraint.find('\\') != std::string::npos) | |
111 { | |
112 return ApplyListConstraint(value, constraint); | |
113 } | |
114 | |
115 if (constraint.find('*') != std::string::npos || | |
116 constraint.find('?') != std::string::npos) | |
117 { | |
118 // TODO - Cache the constructed regular expression | |
119 boost::regex pattern(Toolbox::WildcardToRegularExpression(constraint), | |
120 boost::regex::icase /* case insensitive search */); | |
121 return boost::regex_match(value, pattern); | |
122 } | |
123 else | |
124 { | |
610 | 125 return ToLowerCase(value) == ToLowerCase(constraint); |
608 | 126 } |
127 } | |
128 | |
129 | |
130 static bool LookupOneInstance(std::string& result, | |
131 ServerIndex& index, | |
132 const std::string& id, | |
133 ResourceType type) | |
134 { | |
135 if (type == ResourceType_Instance) | |
136 { | |
137 result = id; | |
138 return true; | |
139 } | |
140 | |
141 std::string childId; | |
142 | |
143 { | |
144 std::list<std::string> children; | |
145 index.GetChildInstances(children, id); | |
146 | |
147 if (children.size() == 0) | |
148 { | |
149 return false; | |
150 } | |
151 | |
152 childId = children.front(); | |
153 } | |
154 | |
155 return LookupOneInstance(result, index, childId, GetChildResourceType(type)); | |
156 } | |
157 | |
158 | |
159 static bool Matches(const Json::Value& resource, | |
160 const DicomArray& query) | |
161 { | |
162 for (size_t i = 0; i < query.GetSize(); i++) | |
163 { | |
164 if (query.GetElement(i).GetValue().IsNull() || | |
165 query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL || | |
166 query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET) | |
167 { | |
168 continue; | |
169 } | |
170 | |
171 std::string tag = query.GetElement(i).GetTag().Format(); | |
172 std::string value; | |
173 if (resource.isMember(tag)) | |
174 { | |
175 value = resource.get(tag, Json::arrayValue).get("Value", "").asString(); | |
176 } | |
177 | |
610 | 178 std::cout << tag << " " << value << std::endl; |
179 | |
608 | 180 if (!Matches(value, query.GetElement(i).GetValue().AsString())) |
181 { | |
182 return false; | |
183 } | |
184 } | |
185 | |
186 return true; | |
187 } | |
188 | |
189 | |
190 static void AddAnswer(DicomFindAnswers& answers, | |
191 const Json::Value& resource, | |
192 const DicomArray& query) | |
193 { | |
194 DicomMap result; | |
195 | |
196 for (size_t i = 0; i < query.GetSize(); i++) | |
197 { | |
198 if (query.GetElement(i).GetTag() != DICOM_TAG_QUERY_RETRIEVE_LEVEL && | |
199 query.GetElement(i).GetTag() != DICOM_TAG_SPECIFIC_CHARACTER_SET) | |
200 { | |
201 std::string tag = query.GetElement(i).GetTag().Format(); | |
202 std::string value; | |
203 if (resource.isMember(tag)) | |
204 { | |
205 value = resource.get(tag, Json::arrayValue).get("Value", "").asString(); | |
206 result.SetValue(query.GetElement(i).GetTag(), value); | |
207 } | |
208 } | |
209 } | |
210 | |
211 answers.Add(result); | |
212 } | |
213 | |
214 | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
215 void OrthancFindRequestHandler::Handle(const DicomMap& input, |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
216 DicomFindAnswers& answers) |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
217 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
218 LOG(WARNING) << "Find-SCU request received"; |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
219 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
220 /** |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
221 * Retrieve the query level. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
222 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
223 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
224 const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
225 if (levelTmp == NULL) |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
226 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
227 throw OrthancException(ErrorCode_BadRequest); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
228 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
229 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
230 ResourceType level = StringToResourceType(levelTmp->AsString().c_str()); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
231 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
232 if (level != ResourceType_Patient && |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
233 level != ResourceType_Study && |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
234 level != ResourceType_Series) |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
235 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
236 throw OrthancException(ErrorCode_NotImplemented); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
237 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
238 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
239 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
240 /** |
608 | 241 * Retrieve all the resources for this query level. |
242 **/ | |
243 | |
244 Json::Value resources; | |
245 context_.GetIndex().GetAllUuids(resources, level); | |
246 assert(resources.type() == Json::arrayValue); | |
247 | |
248 | |
249 // TODO : Speed up using MainDicomTags (to avoid looping over ALL | |
250 // the resources and reading the JSON file for each of them) | |
251 | |
252 | |
253 /** | |
254 * Loop over all the resources for this query level. | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
255 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
256 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
257 DicomArray query(input); |
608 | 258 for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++) |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
259 { |
608 | 260 try |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
261 { |
608 | 262 std::string instance; |
263 if (LookupOneInstance(instance, context_.GetIndex(), resources[i].asString(), level)) | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
264 { |
608 | 265 Json::Value resource; |
266 context_.ReadJson(resource, instance); | |
267 | |
268 if (Matches(resource, query)) | |
269 { | |
270 AddAnswer(answers, resource, query); | |
271 } | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
272 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
273 } |
608 | 274 catch (OrthancException&) |
275 { | |
276 // This resource has been deleted during the find request | |
277 } | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
278 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
279 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
280 } |