1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.openehealth.ipf.commons.ihe.xds.core.validate.requests;
17
18 import org.openehealth.ipf.commons.core.modules.api.Validator;
19 import org.openehealth.ipf.commons.ihe.core.InteractionId;
20 import org.openehealth.ipf.commons.ihe.xds.core.ebxml.EbXMLAdhocQueryRequest;
21 import org.openehealth.ipf.commons.ihe.xds.core.requests.query.QueryReturnType;
22 import org.openehealth.ipf.commons.ihe.xds.core.requests.query.QueryType;
23 import org.openehealth.ipf.commons.ihe.xds.core.transform.requests.QueryParameter;
24 import org.openehealth.ipf.commons.ihe.xds.core.validate.*;
25 import org.openehealth.ipf.commons.ihe.xds.core.validate.query.*;
26
27 import java.util.*;
28 import java.util.stream.Collectors;
29
30 import static org.apache.commons.lang3.Validate.notNull;
31 import static org.openehealth.ipf.commons.ihe.xds.XCA.Interactions.ITI_38;
32 import static org.openehealth.ipf.commons.ihe.xds.XCF.Interactions.ITI_63;
33 import static org.openehealth.ipf.commons.ihe.xds.XDS.Interactions.ITI_18;
34 import static org.openehealth.ipf.commons.ihe.xds.XDS.Interactions.ITI_51;
35 import static org.openehealth.ipf.commons.ihe.xds.core.requests.query.QueryType.*;
36 import static org.openehealth.ipf.commons.ihe.xds.core.transform.requests.QueryParameter.*;
37 import static org.openehealth.ipf.commons.ihe.xds.core.validate.ValidationMessage.*;
38 import static org.openehealth.ipf.commons.ihe.xds.core.validate.ValidatorAssertions.metaDataAssert;
39
40
41
42
43
44
45 public class AdhocQueryRequestValidator implements Validator<EbXMLAdhocQueryRequest, ValidationProfile> {
46 private static final CXValidator cxValidator = new CXValidator(true);
47 private static final TimeValidator timeValidator = new TimeValidator();
48 private static final NopValidator nopValidator = new NopValidator();
49
50
51 private static void addAllowedMultipleSlots(QueryType queryType, QueryParameter... parameters) {
52 Set<String> slotNames = Arrays.stream(parameters)
53 .map(QueryParameter::getSlotName)
54 .collect(Collectors.toSet());
55 ALLOWED_MULTIPLE_SLOTS.put(queryType, slotNames);
56 }
57
58
59 private static final Map<QueryType, Set<String>> ALLOWED_MULTIPLE_SLOTS;
60
61 static {
62 ALLOWED_MULTIPLE_SLOTS = new EnumMap<>(QueryType.class);
63
64 addAllowedMultipleSlots(FIND_DOCUMENTS,
65 DOC_ENTRY_EVENT_CODE,
66 DOC_ENTRY_CONFIDENTIALITY_CODE);
67
68 addAllowedMultipleSlots(FIND_DOCUMENTS_BY_REFERENCE_ID,
69 DOC_ENTRY_REFERENCE_IDS,
70 DOC_ENTRY_EVENT_CODE,
71 DOC_ENTRY_CONFIDENTIALITY_CODE);
72
73 addAllowedMultipleSlots(FIND_DOCUMENTS_MPQ,
74 DOC_ENTRY_EVENT_CODE,
75 DOC_ENTRY_CONFIDENTIALITY_CODE);
76
77 addAllowedMultipleSlots(FIND_FOLDERS,
78 FOLDER_CODES);
79
80 addAllowedMultipleSlots(FIND_FOLDERS_MPQ,
81 FOLDER_CODES);
82
83 addAllowedMultipleSlots(GET_ALL,
84 DOC_ENTRY_CONFIDENTIALITY_CODE);
85
86 addAllowedMultipleSlots(GET_SUBMISSION_SET_AND_CONTENTS,
87 DOC_ENTRY_CONFIDENTIALITY_CODE);
88
89 addAllowedMultipleSlots(GET_FOLDER_AND_CONTENTS,
90 DOC_ENTRY_CONFIDENTIALITY_CODE);
91
92 addAllowedMultipleSlots(FETCH,
93 DOC_ENTRY_EVENT_CODE,
94 DOC_ENTRY_CONFIDENTIALITY_CODE);
95 }
96
97
98 private static final Map<InteractionId, Set<QueryType>> ALLOWED_QUERY_TYPES;
99
100 static {
101 Set<QueryType> storedQueryTypes = EnumSet.of(
102 FIND_DOCUMENTS,
103 FIND_DOCUMENTS_BY_REFERENCE_ID,
104 FIND_SUBMISSION_SETS,
105 FIND_FOLDERS,
106 GET_ALL,
107 GET_DOCUMENTS,
108 GET_FOLDERS,
109 GET_ASSOCIATIONS,
110 GET_DOCUMENTS_AND_ASSOCIATIONS,
111 GET_SUBMISSION_SETS,
112 GET_SUBMISSION_SET_AND_CONTENTS,
113 GET_FOLDER_AND_CONTENTS,
114 GET_FOLDERS_FOR_DOCUMENT,
115 GET_RELATED_DOCUMENTS);
116
117 ALLOWED_QUERY_TYPES = new HashMap<>(5);
118 ALLOWED_QUERY_TYPES.put(ITI_18, storedQueryTypes);
119 ALLOWED_QUERY_TYPES.put(ITI_38, storedQueryTypes);
120 ALLOWED_QUERY_TYPES.put(ITI_51, EnumSet.of(FIND_DOCUMENTS_MPQ, FIND_FOLDERS_MPQ));
121 ALLOWED_QUERY_TYPES.put(ITI_63, EnumSet.of(FETCH));
122 }
123
124
125 private QueryParameterValidation[] getValidators(QueryType queryType, ValidationProfile profile) {
126 boolean requireHomeCommunityId = profile.getInteractionProfile().requiresHomeCommunityId();
127
128 switch (queryType) {
129 case FETCH:
130 return new QueryParameterValidation[]{
131 new StringValidation(DOC_ENTRY_PATIENT_ID, cxValidator, false),
132 new CodeValidation(DOC_ENTRY_CLASS_CODE, false),
133 new CodeValidation(DOC_ENTRY_TYPE_CODE),
134 new CodeValidation(DOC_ENTRY_PRACTICE_SETTING_CODE),
135 new CodeValidation(DOC_ENTRY_HEALTHCARE_FACILITY_TYPE_CODE),
136 new CodeValidation(DOC_ENTRY_FORMAT_CODE),
137 new NumberValidation(DOC_ENTRY_CREATION_TIME_FROM, timeValidator),
138 new NumberValidation(DOC_ENTRY_CREATION_TIME_TO, timeValidator),
139 new NumberValidation(DOC_ENTRY_SERVICE_START_TIME_FROM, timeValidator),
140 new NumberValidation(DOC_ENTRY_SERVICE_START_TIME_TO, timeValidator),
141 new NumberValidation(DOC_ENTRY_SERVICE_STOP_TIME_FROM, timeValidator),
142 new NumberValidation(DOC_ENTRY_SERVICE_STOP_TIME_TO, timeValidator),
143 new QueryListCodeValidation(DOC_ENTRY_EVENT_CODE, DOC_ENTRY_EVENT_CODE_SCHEME),
144 new QueryListCodeValidation(DOC_ENTRY_CONFIDENTIALITY_CODE, DOC_ENTRY_CONFIDENTIALITY_CODE_SCHEME),
145 new StringListValidation(DOC_ENTRY_AUTHOR_PERSON, nopValidator),
146 new HomeCommunityIdValidation(true),
147 };
148
149 case FIND_DOCUMENTS:
150 case FIND_DOCUMENTS_MPQ:
151 return new QueryParameterValidation[]{
152
153
154
155 queryType.equals(FIND_DOCUMENTS)
156 ? new StringValidation(DOC_ENTRY_PATIENT_ID, cxValidator, false)
157 : new StringListValidation(DOC_ENTRY_PATIENT_ID, cxValidator),
158 new CodeValidation(DOC_ENTRY_CLASS_CODE),
159 new CodeValidation(DOC_ENTRY_TYPE_CODE),
160 new CodeValidation(DOC_ENTRY_PRACTICE_SETTING_CODE),
161 new CodeValidation(DOC_ENTRY_HEALTHCARE_FACILITY_TYPE_CODE),
162 new CodeValidation(DOC_ENTRY_FORMAT_CODE),
163 new NumberValidation(DOC_ENTRY_CREATION_TIME_FROM, timeValidator),
164 new NumberValidation(DOC_ENTRY_CREATION_TIME_TO, timeValidator),
165 new NumberValidation(DOC_ENTRY_SERVICE_START_TIME_FROM, timeValidator),
166 new NumberValidation(DOC_ENTRY_SERVICE_START_TIME_TO, timeValidator),
167 new NumberValidation(DOC_ENTRY_SERVICE_STOP_TIME_FROM, timeValidator),
168 new NumberValidation(DOC_ENTRY_SERVICE_STOP_TIME_TO, timeValidator),
169 new QueryListCodeValidation(DOC_ENTRY_EVENT_CODE, DOC_ENTRY_EVENT_CODE_SCHEME),
170 new QueryListCodeValidation(DOC_ENTRY_CONFIDENTIALITY_CODE, DOC_ENTRY_CONFIDENTIALITY_CODE_SCHEME),
171 new StringListValidation(DOC_ENTRY_AUTHOR_PERSON, nopValidator),
172 new StatusValidation(DOC_ENTRY_STATUS),
173 new DocumentEntryTypeValidation(),
174 };
175
176 case FIND_DOCUMENTS_BY_REFERENCE_ID:
177 return new QueryParameterValidation[]{
178 new StringValidation(DOC_ENTRY_PATIENT_ID, cxValidator, false),
179 new CodeValidation(DOC_ENTRY_CLASS_CODE),
180 new CodeValidation(DOC_ENTRY_TYPE_CODE),
181 new CodeValidation(DOC_ENTRY_PRACTICE_SETTING_CODE),
182 new CodeValidation(DOC_ENTRY_HEALTHCARE_FACILITY_TYPE_CODE),
183 new CodeValidation(DOC_ENTRY_FORMAT_CODE),
184 new NumberValidation(DOC_ENTRY_CREATION_TIME_FROM, timeValidator),
185 new NumberValidation(DOC_ENTRY_CREATION_TIME_TO, timeValidator),
186 new NumberValidation(DOC_ENTRY_SERVICE_START_TIME_FROM, timeValidator),
187 new NumberValidation(DOC_ENTRY_SERVICE_START_TIME_TO, timeValidator),
188 new NumberValidation(DOC_ENTRY_SERVICE_STOP_TIME_FROM, timeValidator),
189 new NumberValidation(DOC_ENTRY_SERVICE_STOP_TIME_TO, timeValidator),
190 new QueryListCodeValidation(DOC_ENTRY_EVENT_CODE, DOC_ENTRY_EVENT_CODE_SCHEME),
191 new QueryListCodeValidation(DOC_ENTRY_CONFIDENTIALITY_CODE, DOC_ENTRY_CONFIDENTIALITY_CODE_SCHEME),
192 new StringListValidation(DOC_ENTRY_AUTHOR_PERSON, nopValidator),
193 new StatusValidation(DOC_ENTRY_STATUS),
194 new DocumentEntryTypeValidation(),
195 new StringListValidation(DOC_ENTRY_REFERENCE_IDS, nopValidator),
196 };
197
198 case FIND_SUBMISSION_SETS:
199 return new QueryParameterValidation[]{
200 new StringValidation(SUBMISSION_SET_PATIENT_ID, cxValidator, false),
201
202
203 new NumberValidation(SUBMISSION_SET_SUBMISSION_TIME_FROM, timeValidator),
204 new NumberValidation(SUBMISSION_SET_SUBMISSION_TIME_TO, timeValidator),
205 new StringValidation(SUBMISSION_SET_AUTHOR_PERSON, nopValidator, true),
206 new CodeValidation(SUBMISSION_SET_CONTENT_TYPE_CODE),
207 new StatusValidation(SUBMISSION_SET_STATUS),
208 };
209
210 case FIND_FOLDERS:
211 case FIND_FOLDERS_MPQ:
212 return new QueryParameterValidation[]{
213
214
215
216 queryType.equals(FIND_FOLDERS) ? new StringValidation(FOLDER_PATIENT_ID, cxValidator, false) : new StringListValidation(FOLDER_PATIENT_ID, cxValidator),
217 new NumberValidation(FOLDER_LAST_UPDATE_TIME_FROM, timeValidator),
218 new NumberValidation(FOLDER_LAST_UPDATE_TIME_TO, timeValidator),
219 new QueryListCodeValidation(FOLDER_CODES, FOLDER_CODES_SCHEME),
220 new StatusValidation(FOLDER_STATUS),
221 };
222
223 case GET_ALL:
224 return new QueryParameterValidation[]{
225 new StringValidation(PATIENT_ID, cxValidator, false),
226 new StatusValidation(DOC_ENTRY_STATUS),
227 new StatusValidation(SUBMISSION_SET_STATUS),
228 new StatusValidation(FOLDER_STATUS),
229 new QueryListCodeValidation(DOC_ENTRY_FORMAT_CODE, DOC_ENTRY_FORMAT_CODE_SCHEME),
230 new DocumentEntryTypeValidation(),
231 };
232
233 case GET_DOCUMENTS:
234 return new QueryParameterValidation[]{
235 new HomeCommunityIdValidation(requireHomeCommunityId),
236 new ChoiceValidation(DOC_ENTRY_UUID, DOC_ENTRY_UNIQUE_ID, DOC_ENTRY_LOGICAL_ID),
237 new StringListValidation(DOC_ENTRY_UUID, nopValidator),
238 new StringListValidation(DOC_ENTRY_UNIQUE_ID, nopValidator),
239 };
240
241 case GET_DOCUMENTS_AND_ASSOCIATIONS:
242 return new QueryParameterValidation[]{
243 new HomeCommunityIdValidation(requireHomeCommunityId),
244 new ChoiceValidation(DOC_ENTRY_UUID, DOC_ENTRY_UNIQUE_ID),
245 new StringListValidation(DOC_ENTRY_UUID, nopValidator),
246 new StringListValidation(DOC_ENTRY_UNIQUE_ID, nopValidator),
247 };
248
249 case GET_FOLDERS_FOR_DOCUMENT:
250 return new QueryParameterValidation[]{
251 new HomeCommunityIdValidation(requireHomeCommunityId),
252 new ChoiceValidation(DOC_ENTRY_UUID, DOC_ENTRY_UNIQUE_ID),
253 new StringValidation(DOC_ENTRY_UUID, nopValidator, true),
254 new StringValidation(DOC_ENTRY_UNIQUE_ID, nopValidator, true),
255 };
256
257 case GET_FOLDERS:
258 return new QueryParameterValidation[]{
259 new HomeCommunityIdValidation(requireHomeCommunityId),
260 new ChoiceValidation(FOLDER_UUID, FOLDER_UNIQUE_ID, FOLDER_LOGICAL_ID),
261 new StringListValidation(FOLDER_UUID, nopValidator),
262 new StringListValidation(FOLDER_UNIQUE_ID, nopValidator),
263 };
264
265 case GET_ASSOCIATIONS:
266 case GET_SUBMISSION_SETS:
267 return new QueryParameterValidation[]{
268 new HomeCommunityIdValidation(requireHomeCommunityId),
269 new StringListValidation(UUID, nopValidator),
270 };
271
272 case GET_SUBMISSION_SET_AND_CONTENTS:
273 return new QueryParameterValidation[]{
274 new HomeCommunityIdValidation(requireHomeCommunityId),
275 new ChoiceValidation(SUBMISSION_SET_UUID, SUBMISSION_SET_UNIQUE_ID),
276 new StringValidation(SUBMISSION_SET_UUID, nopValidator, true),
277 new StringValidation(SUBMISSION_SET_UNIQUE_ID, nopValidator, true),
278 new QueryListCodeValidation(DOC_ENTRY_CONFIDENTIALITY_CODE, DOC_ENTRY_CONFIDENTIALITY_CODE_SCHEME),
279 new QueryListCodeValidation(DOC_ENTRY_FORMAT_CODE, DOC_ENTRY_FORMAT_CODE_SCHEME),
280 new DocumentEntryTypeValidation(),
281 };
282
283 case GET_FOLDER_AND_CONTENTS:
284 return new QueryParameterValidation[]{
285 new HomeCommunityIdValidation(requireHomeCommunityId),
286 new ChoiceValidation(FOLDER_UUID, FOLDER_UNIQUE_ID),
287 new StringValidation(FOLDER_UUID, nopValidator, true),
288 new StringValidation(FOLDER_UNIQUE_ID, nopValidator, true),
289 new QueryListCodeValidation(DOC_ENTRY_CONFIDENTIALITY_CODE, DOC_ENTRY_CONFIDENTIALITY_CODE_SCHEME),
290 new QueryListCodeValidation(DOC_ENTRY_FORMAT_CODE, DOC_ENTRY_FORMAT_CODE_SCHEME),
291 new DocumentEntryTypeValidation(),
292 };
293
294 case GET_RELATED_DOCUMENTS:
295 return new QueryParameterValidation[]{
296 new HomeCommunityIdValidation(requireHomeCommunityId),
297 new ChoiceValidation(DOC_ENTRY_UUID, DOC_ENTRY_UNIQUE_ID),
298 new StringValidation(DOC_ENTRY_UUID, nopValidator, true),
299 new StringValidation(DOC_ENTRY_UNIQUE_ID, nopValidator, true),
300 new AssociationValidation(ASSOCIATION_TYPE),
301 new DocumentEntryTypeValidation(),
302 };
303 }
304
305 return null;
306 }
307
308 @Override
309 public void validate(EbXMLAdhocQueryRequest request, ValidationProfile profile) {
310 notNull(request, "request cannot be null");
311
312 if (profile == ITI_63) {
313 metaDataAssert(QueryReturnType.LEAF_CLASS_WITH_REPOSITORY_ITEM.getCode().equals(request.getReturnType()),
314 UNKNOWN_RETURN_TYPE, request.getReturnType());
315 } else {
316 metaDataAssert(QueryReturnType.LEAF_CLASS.getCode().equals(request.getReturnType())
317 || QueryReturnType.OBJECT_REF.getCode().equals(request.getReturnType()),
318 UNKNOWN_RETURN_TYPE, request.getReturnType());
319 }
320
321 QueryType queryType = QueryType.valueOfId(request.getId());
322 metaDataAssert(queryType != null, UNKNOWN_QUERY_TYPE, request.getId());
323
324 Set<QueryType> allowedQueryTypes = ALLOWED_QUERY_TYPES.getOrDefault(profile.getInteractionId(), Collections.emptySet());
325 metaDataAssert(allowedQueryTypes.contains(queryType), UNSUPPORTED_QUERY_TYPE, queryType);
326
327 new SlotLengthAndNameUniquenessValidator().validateQuerySlots(
328 request.getSlots(),
329 ALLOWED_MULTIPLE_SLOTS.getOrDefault(queryType, Collections.emptySet()));
330 QueryParameterValidation[] validations = getValidators(queryType, profile);
331 if (validations != null) {
332 for (QueryParameterValidation validation : validations) {
333 validation.validate(request);
334 }
335 }
336
337 if (queryType == FIND_DOCUMENTS_MPQ) {
338 metaDataAssert(
339 (!request.getSlotValues(DOC_ENTRY_CLASS_CODE.getSlotName()).isEmpty()) ||
340 (!request.getSlotValues(DOC_ENTRY_EVENT_CODE.getSlotName()).isEmpty()) ||
341 (!request.getSlotValues(DOC_ENTRY_HEALTHCARE_FACILITY_TYPE_CODE.getSlotName()).isEmpty()),
342 ValidationMessage.MISSING_REQUIRED_QUERY_PARAMETER,
343 "at least one of $XDSDocumentEntryClassCode, $XDSDocumentEntryEventCodeList, $XDSDocumentEntryHealthcareFacilityTypeCode");
344 }
345
346 }
347 }