Mercurial > hg > orthanc
annotate OrthancServer/OrthancFindRequestHandler.cpp @ 608:0bedf8ff9288 find-move-scp
basic find scp
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 17 Oct 2013 18:07:55 +0200 |
parents | c931ac02db82 |
children | 5ba825b87b21 |
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 { |
608 | 42 static bool ApplyRangeConstraint(const std::string& value, |
43 const std::string& constraint) | |
44 { | |
45 // TODO | |
46 return false; | |
47 } | |
48 | |
49 | |
50 static bool ApplyListConstraint(const std::string& value, | |
51 const std::string& constraint) | |
52 { | |
53 std::cout << value << std::endl; | |
54 | |
55 std::string v1 = value; | |
56 Toolbox::ToLowerCase(v1); | |
57 | |
58 std::vector<std::string> items; | |
59 Toolbox::TokenizeString(items, constraint, '\\'); | |
60 | |
61 for (size_t i = 0; i < items.size(); i++) | |
62 { | |
63 Toolbox::ToLowerCase(items[i]); | |
64 if (items[i] == v1) | |
65 { | |
66 return true; | |
67 } | |
68 } | |
69 | |
70 return false; | |
71 } | |
72 | |
73 | |
74 static bool Matches(const std::string& value, | |
75 const std::string& constraint) | |
76 { | |
77 // http://www.itk.org/Wiki/DICOM_QueryRetrieve_Explained | |
78 // http://dicomiseasy.blogspot.be/2012/01/dicom-queryretrieve-part-i.html | |
79 | |
80 if (constraint.find('-') != std::string::npos) | |
81 { | |
82 return ApplyRangeConstraint(value, constraint); | |
83 } | |
84 | |
85 if (constraint.find('\\') != std::string::npos) | |
86 { | |
87 return ApplyListConstraint(value, constraint); | |
88 } | |
89 | |
90 if (constraint.find('*') != std::string::npos || | |
91 constraint.find('?') != std::string::npos) | |
92 { | |
93 // TODO - Cache the constructed regular expression | |
94 boost::regex pattern(Toolbox::WildcardToRegularExpression(constraint), | |
95 boost::regex::icase /* case insensitive search */); | |
96 return boost::regex_match(value, pattern); | |
97 } | |
98 else | |
99 { | |
100 std::string v1 = value; | |
101 std::string v2 = constraint; | |
102 | |
103 Toolbox::ToLowerCase(v1); | |
104 Toolbox::ToLowerCase(v2); | |
105 | |
106 return v1 == v2; | |
107 } | |
108 } | |
109 | |
110 | |
111 static bool LookupOneInstance(std::string& result, | |
112 ServerIndex& index, | |
113 const std::string& id, | |
114 ResourceType type) | |
115 { | |
116 if (type == ResourceType_Instance) | |
117 { | |
118 result = id; | |
119 return true; | |
120 } | |
121 | |
122 std::string childId; | |
123 | |
124 { | |
125 std::list<std::string> children; | |
126 index.GetChildInstances(children, id); | |
127 | |
128 if (children.size() == 0) | |
129 { | |
130 return false; | |
131 } | |
132 | |
133 childId = children.front(); | |
134 } | |
135 | |
136 return LookupOneInstance(result, index, childId, GetChildResourceType(type)); | |
137 } | |
138 | |
139 | |
140 static bool Matches(const Json::Value& resource, | |
141 const DicomArray& query) | |
142 { | |
143 for (size_t i = 0; i < query.GetSize(); i++) | |
144 { | |
145 if (query.GetElement(i).GetValue().IsNull() || | |
146 query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL || | |
147 query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET) | |
148 { | |
149 continue; | |
150 } | |
151 | |
152 std::string tag = query.GetElement(i).GetTag().Format(); | |
153 std::cout << tag << std::endl; | |
154 | |
155 std::string value; | |
156 if (resource.isMember(tag)) | |
157 { | |
158 value = resource.get(tag, Json::arrayValue).get("Value", "").asString(); | |
159 } | |
160 | |
161 if (!Matches(value, query.GetElement(i).GetValue().AsString())) | |
162 { | |
163 return false; | |
164 } | |
165 } | |
166 | |
167 return true; | |
168 } | |
169 | |
170 | |
171 static void AddAnswer(DicomFindAnswers& answers, | |
172 const Json::Value& resource, | |
173 const DicomArray& query) | |
174 { | |
175 DicomMap result; | |
176 | |
177 for (size_t i = 0; i < query.GetSize(); i++) | |
178 { | |
179 if (query.GetElement(i).GetTag() != DICOM_TAG_QUERY_RETRIEVE_LEVEL && | |
180 query.GetElement(i).GetTag() != DICOM_TAG_SPECIFIC_CHARACTER_SET) | |
181 { | |
182 std::string tag = query.GetElement(i).GetTag().Format(); | |
183 std::string value; | |
184 if (resource.isMember(tag)) | |
185 { | |
186 value = resource.get(tag, Json::arrayValue).get("Value", "").asString(); | |
187 result.SetValue(query.GetElement(i).GetTag(), value); | |
188 } | |
189 } | |
190 } | |
191 | |
192 answers.Add(result); | |
193 } | |
194 | |
195 | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
196 void OrthancFindRequestHandler::Handle(const DicomMap& input, |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
197 DicomFindAnswers& answers) |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
198 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
199 LOG(WARNING) << "Find-SCU request received"; |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
200 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
201 /** |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
202 * Retrieve the query level. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
203 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
204 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
205 const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
206 if (levelTmp == NULL) |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
207 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
208 throw OrthancException(ErrorCode_BadRequest); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
209 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
210 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
211 ResourceType level = StringToResourceType(levelTmp->AsString().c_str()); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
212 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
213 if (level != ResourceType_Patient && |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
214 level != ResourceType_Study && |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
215 level != ResourceType_Series) |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
216 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
217 throw OrthancException(ErrorCode_NotImplemented); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
218 } |
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 /** |
608 | 222 * Retrieve all the resources for this query level. |
223 **/ | |
224 | |
225 Json::Value resources; | |
226 context_.GetIndex().GetAllUuids(resources, level); | |
227 assert(resources.type() == Json::arrayValue); | |
228 | |
229 | |
230 // TODO : Speed up using MainDicomTags (to avoid looping over ALL | |
231 // the resources and reading the JSON file for each of them) | |
232 | |
233 | |
234 /** | |
235 * Loop over all the resources for this query level. | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
236 **/ |
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 DicomArray query(input); |
608 | 239 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
|
240 { |
608 | 241 try |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
242 { |
608 | 243 std::string instance; |
244 if (LookupOneInstance(instance, context_.GetIndex(), resources[i].asString(), level)) | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
245 { |
608 | 246 Json::Value resource; |
247 context_.ReadJson(resource, instance); | |
248 | |
249 if (Matches(resource, query)) | |
250 { | |
251 AddAnswer(answers, resource, query); | |
252 } | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
253 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
254 } |
608 | 255 catch (OrthancException&) |
256 { | |
257 // This resource has been deleted during the find request | |
258 } | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
259 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
260 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
261 } |