1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | |
|
27 | |
|
28 | |
package ca.uhn.hl7v2.conf.check; |
29 | |
|
30 | |
import java.io.BufferedReader; |
31 | |
import java.io.File; |
32 | |
import java.io.FileReader; |
33 | |
import java.io.IOException; |
34 | |
import java.util.ArrayList; |
35 | |
import java.util.List; |
36 | |
|
37 | |
import ca.uhn.hl7v2.model.*; |
38 | |
import org.slf4j.Logger; |
39 | |
import org.slf4j.LoggerFactory; |
40 | |
|
41 | |
import ca.uhn.hl7v2.DefaultHapiContext; |
42 | |
import ca.uhn.hl7v2.HL7Exception; |
43 | |
import ca.uhn.hl7v2.HapiContext; |
44 | |
import ca.uhn.hl7v2.HapiContextSupport; |
45 | |
import ca.uhn.hl7v2.conf.ProfileException; |
46 | |
import ca.uhn.hl7v2.conf.parser.ProfileParser; |
47 | |
import ca.uhn.hl7v2.conf.spec.RuntimeProfile; |
48 | |
import ca.uhn.hl7v2.conf.spec.message.AbstractComponent; |
49 | |
import ca.uhn.hl7v2.conf.spec.message.AbstractSegmentContainer; |
50 | |
import ca.uhn.hl7v2.conf.spec.message.Component; |
51 | |
import ca.uhn.hl7v2.conf.spec.message.Field; |
52 | |
import ca.uhn.hl7v2.conf.spec.message.ProfileStructure; |
53 | |
import ca.uhn.hl7v2.conf.spec.message.Seg; |
54 | |
import ca.uhn.hl7v2.conf.spec.message.SegGroup; |
55 | |
import ca.uhn.hl7v2.conf.spec.message.StaticDef; |
56 | |
import ca.uhn.hl7v2.conf.spec.message.SubComponent; |
57 | |
import ca.uhn.hl7v2.conf.store.CodeStore; |
58 | |
import ca.uhn.hl7v2.conf.store.ProfileStoreFactory; |
59 | |
import ca.uhn.hl7v2.parser.EncodingCharacters; |
60 | |
import ca.uhn.hl7v2.parser.GenericParser; |
61 | |
import ca.uhn.hl7v2.parser.Parser; |
62 | |
import ca.uhn.hl7v2.parser.PipeParser; |
63 | |
import ca.uhn.hl7v2.util.Terser; |
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | |
|
72 | |
public class DefaultValidator extends HapiContextSupport implements Validator { |
73 | |
|
74 | |
private EncodingCharacters enc; |
75 | 5 | private static final Logger log = LoggerFactory.getLogger(DefaultValidator.class); |
76 | 60 | private boolean validateChildren = true; |
77 | |
private CodeStore codeStore; |
78 | |
|
79 | |
|
80 | |
public DefaultValidator() { |
81 | 30 | this(new DefaultHapiContext()); |
82 | 30 | } |
83 | |
|
84 | |
public DefaultValidator(HapiContext context) { |
85 | 60 | super(context); |
86 | 60 | enc = new EncodingCharacters('|', null); |
87 | 60 | } |
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
public void setValidateChildren(boolean validateChildren) { |
94 | 0 | this.validateChildren = validateChildren; |
95 | 0 | } |
96 | |
|
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
|
102 | |
|
103 | |
|
104 | |
|
105 | |
public void setCodeStore(CodeStore theCodeStore) { |
106 | 0 | codeStore = theCodeStore; |
107 | 0 | } |
108 | |
|
109 | |
|
110 | |
|
111 | |
|
112 | |
public HL7Exception[] validate(Message message, StaticDef profile) throws ProfileException, |
113 | |
HL7Exception { |
114 | 105 | List<HL7Exception> exList = new ArrayList<HL7Exception>(); |
115 | 105 | Terser t = new Terser(message); |
116 | |
|
117 | 105 | checkMessageType(t.get("/MSH-9-1"), profile, exList); |
118 | 105 | checkEventType(t.get("/MSH-9-2"), profile, exList); |
119 | 105 | checkMessageStructure(t.get("/MSH-9-3"), profile, exList); |
120 | |
|
121 | 105 | exList.addAll(doTestGroup(message, profile, profile.getIdentifier(), |
122 | |
validateChildren)); |
123 | 105 | return exList.toArray(new HL7Exception[exList.size()]); |
124 | |
} |
125 | |
|
126 | |
|
127 | |
protected void checkEventType(String evType, StaticDef profile, List<HL7Exception> exList) throws HL7Exception { |
128 | 105 | if (!evType.equals(profile.getEventType()) |
129 | 30 | && !profile.getEventType().equalsIgnoreCase("ALL")) { |
130 | 0 | HL7Exception e = new ProfileNotFollowedException("Event type " + evType |
131 | 0 | + " doesn't match profile type of " + profile.getEventType()); |
132 | 0 | exList.add(e); |
133 | |
} |
134 | 105 | } |
135 | |
|
136 | |
protected void checkMessageType(String msgType, StaticDef profile, List<HL7Exception> exList) throws HL7Exception { |
137 | 105 | if (!msgType.equals(profile.getMsgType())) { |
138 | 0 | HL7Exception e = new ProfileNotFollowedException("Message type " + msgType |
139 | 0 | + " doesn't match profile type of " + profile.getMsgType()); |
140 | 0 | exList.add(e); |
141 | |
} |
142 | 105 | } |
143 | |
|
144 | |
protected void checkMessageStructure(String msgStruct, StaticDef profile, List<HL7Exception> exList) { |
145 | 105 | if (msgStruct == null || !msgStruct.equals(profile.getMsgStructID())) { |
146 | 0 | HL7Exception e = new ProfileNotFollowedException("Message structure " + msgStruct |
147 | 0 | + " doesn't match profile type of " + profile.getMsgStructID()); |
148 | 0 | exList.add(e); |
149 | |
} |
150 | 105 | } |
151 | |
|
152 | |
|
153 | |
|
154 | |
|
155 | |
public List<HL7Exception> testGroup(Group group, SegGroup profile, String profileID) |
156 | |
throws ProfileException { |
157 | 0 | return doTestGroup(group, profile, profileID, true); |
158 | |
} |
159 | |
|
160 | |
protected List<HL7Exception> doTestGroup(Group group, AbstractSegmentContainer profile, |
161 | |
String profileID, boolean theValidateChildren) throws ProfileException { |
162 | 105 | List<HL7Exception> exList = new ArrayList<HL7Exception>(); |
163 | 105 | List<String> allowedStructures = new ArrayList<String>(); |
164 | |
|
165 | 105 | for (ProfileStructure struct : profile) { |
166 | |
|
167 | |
|
168 | 340 | if (!struct.getUsage().equalsIgnoreCase("X")) { |
169 | 330 | allowedStructures.add(struct.getName()); |
170 | |
|
171 | |
|
172 | |
try { |
173 | 330 | List<Structure> instancesWithContent = new ArrayList<Structure>(); |
174 | 510 | for (Structure instance : group.getAll(struct.getName())) { |
175 | 180 | if (!instance.isEmpty()) |
176 | 180 | instancesWithContent.add(instance); |
177 | |
} |
178 | |
|
179 | 640 | testCardinality(instancesWithContent.size(), struct.getMin(), |
180 | 320 | struct.getMax(), struct.getUsage(), struct.getName(), exList); |
181 | |
|
182 | |
|
183 | 320 | if (theValidateChildren) { |
184 | 320 | for (Structure s : instancesWithContent) { |
185 | 180 | exList.addAll(testStructure(s, struct, profileID)); |
186 | 180 | } |
187 | |
} |
188 | |
|
189 | 10 | } catch (HL7Exception he) { |
190 | 10 | exList.add(new ProfileNotHL7CompliantException(struct.getName() |
191 | |
+ " not found in message")); |
192 | 320 | } |
193 | |
} |
194 | 340 | } |
195 | |
|
196 | |
|
197 | 105 | checkForExtraStructures(group, allowedStructures, exList); |
198 | |
|
199 | 105 | return exList; |
200 | |
} |
201 | |
|
202 | |
|
203 | |
|
204 | |
|
205 | |
|
206 | |
|
207 | |
protected void checkForExtraStructures(Group group, List<String> allowedStructures, List<HL7Exception> exList) |
208 | |
throws ProfileException { |
209 | 1845 | for (String childName : group.getNames()) { |
210 | 1740 | if (!allowedStructures.contains(childName)) { |
211 | |
try { |
212 | 1430 | for (Structure rep : group.getAll(childName)) { |
213 | 5 | if (!rep.isEmpty()) { |
214 | 5 | HL7Exception e = new XElementPresentException("The structure " |
215 | |
+ childName + " appears in the message but not in the profile"); |
216 | 5 | exList.add(e); |
217 | |
} |
218 | |
} |
219 | 0 | } catch (HL7Exception he) { |
220 | 0 | throw new ProfileException("Problem checking profile", he); |
221 | 1425 | } |
222 | |
} |
223 | |
} |
224 | 105 | } |
225 | |
|
226 | |
|
227 | |
|
228 | |
|
229 | |
|
230 | |
|
231 | |
|
232 | |
|
233 | |
|
234 | |
|
235 | |
|
236 | |
|
237 | |
|
238 | |
protected HL7Exception testCardinality(int reps, int min, int max, String usage, String name, List<HL7Exception> exList) { |
239 | 2965 | HL7Exception e = null; |
240 | 2965 | if (reps < min && usage.equalsIgnoreCase("R")) { |
241 | 50 | e = new ProfileNotFollowedException(name + " must have at least " + min |
242 | |
+ " repetitions (has " + reps + ")"); |
243 | 2915 | } else if (max > 0 && reps > max) { |
244 | 0 | e = new ProfileNotFollowedException(name + " must have no more than " + max |
245 | |
+ " repetitions (has " + reps + ")"); |
246 | |
} |
247 | 2965 | if (e != null) exList.add(e); |
248 | 2965 | return e; |
249 | |
} |
250 | |
|
251 | |
|
252 | |
|
253 | |
|
254 | |
public List<HL7Exception> testStructure(Structure s, ProfileStructure profile, String profileID) |
255 | |
throws ProfileException { |
256 | 180 | List<HL7Exception> exList = new ArrayList<HL7Exception>(); |
257 | 180 | if (profile instanceof Seg) { |
258 | 180 | if (Segment.class.isAssignableFrom(s.getClass())) { |
259 | 180 | exList.addAll(doTestSegment((Segment) s, (Seg) profile, profileID, validateChildren)); |
260 | |
} else { |
261 | 0 | exList.add(new ProfileNotHL7CompliantException( |
262 | |
"Mismatch between a segment in the profile and the structure " |
263 | 0 | + s.getClass().getName() + " in the message")); |
264 | |
} |
265 | 0 | } else if (profile instanceof SegGroup) { |
266 | 0 | if (Group.class.isAssignableFrom(s.getClass())) { |
267 | 0 | exList.addAll(testGroup((Group) s, (SegGroup) profile, profileID)); |
268 | |
} else { |
269 | 0 | exList.add(new ProfileNotHL7CompliantException( |
270 | |
"Mismatch between a group in the profile and the structure " |
271 | 0 | + s.getClass().getName() + " in the message")); |
272 | |
} |
273 | |
} |
274 | 180 | return exList; |
275 | |
} |
276 | |
|
277 | |
|
278 | |
|
279 | |
|
280 | |
public List<HL7Exception> testSegment(ca.uhn.hl7v2.model.Segment segment, Seg profile, |
281 | |
String profileID) throws ProfileException { |
282 | 0 | return doTestSegment(segment, profile, profileID, true); |
283 | |
} |
284 | |
|
285 | |
protected List<HL7Exception> doTestSegment(ca.uhn.hl7v2.model.Segment segment, Seg profile, |
286 | |
String profileID, boolean theValidateChildren) throws ProfileException { |
287 | 180 | List<HL7Exception> exList = new ArrayList<HL7Exception>(); |
288 | 180 | List<Integer> allowedFields = new ArrayList<Integer>(); |
289 | |
|
290 | 2835 | for (int i = 1; i <= profile.getFields(); i++) { |
291 | 2655 | Field field = profile.getField(i); |
292 | |
|
293 | |
|
294 | 2655 | if (!field.getUsage().equalsIgnoreCase("X")) { |
295 | 2645 | allowedFields.add(i); |
296 | |
|
297 | |
|
298 | |
try { |
299 | 2645 | Type[] instances = segment.getField(i); |
300 | 2645 | List<Type> instancesWithContent = new ArrayList<Type>(); |
301 | 3700 | for (Type instance : instances) { |
302 | 1055 | if (!instance.isEmpty()) |
303 | 1040 | instancesWithContent.add(instance); |
304 | |
} |
305 | |
|
306 | 5290 | HL7Exception ce = testCardinality(instancesWithContent.size(), field.getMin(), |
307 | 2645 | field.getMax(), field.getUsage(), field.getName(), exList); |
308 | 2645 | if (ce != null) { |
309 | 30 | ce.setFieldPosition(i); |
310 | |
} |
311 | |
|
312 | |
|
313 | 2645 | if (theValidateChildren) { |
314 | 2645 | for (Type s : instancesWithContent) { |
315 | |
|
316 | 1040 | boolean escape = !(profile.getName().equalsIgnoreCase("MSH") && i < 3); |
317 | 1040 | List<HL7Exception> childExceptions = doTestField(s, field, escape, |
318 | |
profileID, validateChildren); |
319 | 1040 | for (HL7Exception ex : childExceptions) { |
320 | 215 | ex.setFieldPosition(i); |
321 | 215 | } |
322 | 1040 | exList.addAll(childExceptions); |
323 | 1040 | } |
324 | |
} |
325 | |
|
326 | 0 | } catch (HL7Exception he) { |
327 | 0 | exList.add(new ProfileNotHL7CompliantException("Field " + i |
328 | |
+ " not found in message")); |
329 | 2645 | } |
330 | |
} |
331 | |
|
332 | |
} |
333 | |
|
334 | |
|
335 | 180 | checkForExtraFields(segment, allowedFields, exList); |
336 | |
|
337 | 180 | for (HL7Exception ex : exList) { |
338 | 250 | ex.setSegmentName(profile.getName()); |
339 | 250 | } |
340 | 180 | return exList; |
341 | |
} |
342 | |
|
343 | |
|
344 | |
|
345 | |
|
346 | |
|
347 | |
|
348 | |
|
349 | |
|
350 | |
protected void checkForExtraFields(Segment segment, List<Integer> allowedFields, List<HL7Exception> exList) |
351 | |
throws ProfileException { |
352 | 2835 | for (int i = 1; i <= segment.numFields(); i++) { |
353 | 2655 | if (!allowedFields.contains(i)) { |
354 | |
try { |
355 | 10 | Type[] reps = segment.getField(i); |
356 | 15 | for (Type rep : reps) { |
357 | 5 | if (!rep.isEmpty()) { |
358 | 5 | HL7Exception e = new XElementPresentException("Field " + i + " in " |
359 | 5 | + segment.getName() |
360 | |
+ " appears in the message but not in the profile"); |
361 | 5 | exList.add(e); |
362 | |
} |
363 | |
} |
364 | 0 | } catch (HL7Exception he) { |
365 | 0 | throw new ProfileException("Problem testing against profile", he); |
366 | 10 | } |
367 | |
} |
368 | |
} |
369 | 180 | } |
370 | |
|
371 | |
|
372 | |
|
373 | |
|
374 | |
|
375 | |
|
376 | |
|
377 | |
public List<HL7Exception> testType(Type type, AbstractComponent<?> profile, String encoded, |
378 | |
String profileID) { |
379 | 3065 | List<HL7Exception> exList = new ArrayList<HL7Exception>(); |
380 | 3065 | if (encoded == null) |
381 | 2845 | encoded = PipeParser.encode(type, this.enc); |
382 | |
|
383 | 3065 | testUsage(encoded, profile.getUsage(), profile.getName(), exList); |
384 | |
|
385 | 3065 | if (!profile.getUsage().equals("X")) { |
386 | 2970 | checkDataType(profile.getDatatype(), type, exList); |
387 | 2970 | checkLength(profile.getLength(), profile.getName(), encoded, exList); |
388 | 2970 | checkConstantValue(profile.getConstantValue(), encoded, exList); |
389 | |
|
390 | 2970 | testTypeAgainstTable(type, profile, profileID, exList); |
391 | |
} |
392 | |
|
393 | 3065 | return exList; |
394 | |
} |
395 | |
|
396 | |
protected void checkConstantValue(String value, String encoded, List<HL7Exception> exList) { |
397 | |
|
398 | 2970 | if (value != null && value.length() > 0) { |
399 | 0 | if (!encoded.equals(value)) |
400 | 0 | exList.add(new ProfileNotFollowedException("'" + encoded |
401 | |
+ "' doesn't equal constant value of '" + value + "'")); |
402 | |
} |
403 | 2970 | } |
404 | |
|
405 | |
protected void checkLength(long length, String name, String encoded, List<HL7Exception> exList) { |
406 | |
|
407 | 2970 | if (encoded.length() > length) |
408 | 200 | exList.add(new ProfileNotFollowedException("The type " + name |
409 | 100 | + " has length " + encoded.length() + " which exceeds max of " |
410 | |
+ length)); |
411 | 2970 | } |
412 | |
|
413 | |
protected void checkDataType(String dataType, Type type, List<HL7Exception> exList) { |
414 | |
|
415 | 2970 | String typeName = type.getName(); |
416 | 2970 | if (!(type instanceof Varies || typeName.equals(dataType))) { |
417 | 45 | exList.add(new ProfileNotHL7CompliantException("HL7 datatype " + typeName |
418 | |
+ " doesn't match profile datatype " + dataType)); |
419 | |
} |
420 | 2970 | } |
421 | |
|
422 | |
|
423 | |
|
424 | |
|
425 | |
|
426 | |
|
427 | |
public HL7Exception testLength(Type type, int maxLength) { |
428 | 0 | HL7Exception e = null; |
429 | 0 | String encoded = PipeParser.encode(type, this.enc); |
430 | 0 | if (encoded.length() > maxLength) { |
431 | 0 | e = new ProfileNotFollowedException("Length of " + encoded.length() |
432 | |
+ " exceeds maximum of " + maxLength); |
433 | |
} |
434 | 0 | return e; |
435 | |
} |
436 | |
|
437 | |
|
438 | |
|
439 | |
|
440 | |
|
441 | |
|
442 | |
|
443 | |
|
444 | |
|
445 | |
|
446 | |
protected void testUsage(String encoded, String usage, String name, List<HL7Exception> exList) { |
447 | 3065 | if (usage.equalsIgnoreCase("R")) { |
448 | 1135 | if (encoded.length() == 0) |
449 | 60 | exList.add(new ProfileNotFollowedException("Required element " + name + " is missing")); |
450 | 1930 | } else if (usage.equalsIgnoreCase("RE")) { |
451 | |
|
452 | 1930 | } else if (usage.equalsIgnoreCase("O")) { |
453 | |
|
454 | 295 | } else if (usage.equalsIgnoreCase("C")) { |
455 | |
|
456 | 140 | } else if (usage.equalsIgnoreCase("CE")) { |
457 | |
|
458 | 140 | } else if (usage.equalsIgnoreCase("X")) { |
459 | 95 | if (encoded.length() > 0) |
460 | 10 | exList.add(new XElementPresentException("Element \"" + name |
461 | |
+ "\" is present but specified as not used (X)")); |
462 | 45 | } else if (usage.equalsIgnoreCase("B")) { |
463 | |
|
464 | |
} |
465 | 3065 | } |
466 | |
|
467 | |
|
468 | |
|
469 | |
|
470 | |
|
471 | |
protected void testTypeAgainstTable(Type type, AbstractComponent<?> profile, |
472 | |
String profileID, List<HL7Exception> exList) { |
473 | 2970 | if (profile.getTable() != null |
474 | 1570 | && (type.getName().equals("IS") || type.getName().equals("ID"))) { |
475 | 1225 | String codeSystem = String.format("HL7%1$4s", profile.getTable()).replace(" ", "0"); |
476 | 1225 | String value = ((Primitive) type).getValue(); |
477 | 1225 | addTableTestResult(profileID, codeSystem, value, exList); |
478 | 1225 | } else if (type.getName().equals("CE")) { |
479 | 215 | String value = Terser.getPrimitive(type, 1, 1).getValue(); |
480 | 215 | String codeSystem = Terser.getPrimitive(type, 3, 1).getValue(); |
481 | 215 | addTableTestResult(profileID, codeSystem, value, exList); |
482 | |
|
483 | 215 | value = Terser.getPrimitive(type, 4, 1).getValue(); |
484 | 215 | codeSystem = Terser.getPrimitive(type, 6, 1).getValue(); |
485 | 215 | addTableTestResult(profileID, codeSystem, value, exList); |
486 | |
} |
487 | 2970 | } |
488 | |
|
489 | |
protected void addTableTestResult(String profileID, String codeSystem, String value, List<HL7Exception> exList) { |
490 | 1655 | if (codeSystem != null && value != null && validateChildren) { |
491 | 735 | testValueAgainstTable(profileID, codeSystem, value, exList); |
492 | |
} |
493 | 1655 | } |
494 | |
|
495 | |
protected void testValueAgainstTable(String profileID, String codeSystem, String value, List<HL7Exception> exList) { |
496 | 735 | CodeStore store = codeStore; |
497 | 735 | if (codeStore == null) { |
498 | 735 | store = getHapiContext().getCodeStoreRegistry().getCodeStore(profileID, codeSystem); |
499 | |
} |
500 | |
|
501 | 735 | if (store == null) { |
502 | 710 | log.info( |
503 | |
"Not checking value {}: no code store was found for profile {} code system {}", |
504 | |
new Object[] { value, profileID, codeSystem }); |
505 | |
} else { |
506 | 25 | if (!store.knowsCodes(codeSystem)) { |
507 | 0 | log.warn("Not checking value {}: Don't have a table for code system {}", value, |
508 | |
codeSystem); |
509 | 25 | } else if (!store.isValidCode(codeSystem, value)) { |
510 | 5 | exList.add(new ProfileNotFollowedException("Code '" + value + "' not found in table " |
511 | |
+ codeSystem + ", profile " + profileID)); |
512 | |
} |
513 | |
} |
514 | |
|
515 | 735 | } |
516 | |
|
517 | |
public List<HL7Exception> testField(Type type, Field profile, boolean escape, String profileID) |
518 | |
throws ProfileException, HL7Exception { |
519 | 15 | return doTestField(type, profile, escape, profileID, true); |
520 | |
} |
521 | |
|
522 | |
protected List<HL7Exception> doTestField(Type type, Field profile, boolean escape, String profileID, |
523 | |
boolean theValidateChildren) throws ProfileException, HL7Exception { |
524 | 1055 | List<HL7Exception> exList = new ArrayList<HL7Exception>(); |
525 | |
|
526 | |
|
527 | 1055 | String encoded = null; |
528 | 1055 | if (!escape && Primitive.class.isAssignableFrom(type.getClass())) |
529 | 220 | encoded = ((Primitive) type).getValue(); |
530 | |
|
531 | 1055 | exList.addAll(testType(type, profile, encoded, profileID)); |
532 | |
|
533 | |
|
534 | 1055 | if (theValidateChildren) { |
535 | 1055 | if (profile.getComponents() > 0 && !profile.getUsage().equals("X")) { |
536 | 620 | if (Composite.class.isAssignableFrom(type.getClass())) { |
537 | 620 | Composite comp = (Composite) type; |
538 | 2615 | for (int i = 1; i <= profile.getComponents(); i++) { |
539 | 1995 | Component childProfile = profile.getComponent(i); |
540 | |
try { |
541 | 1995 | Type child = comp.getComponent(i - 1); |
542 | 1995 | exList.addAll(doTestComponent(child, childProfile, profileID, validateChildren)); |
543 | 0 | } catch (DataTypeException de) { |
544 | 0 | exList.add(new ProfileNotHL7CompliantException( |
545 | |
"More components in profile than allowed in message: " |
546 | 0 | + de.getMessage())); |
547 | 1995 | } |
548 | |
} |
549 | 620 | checkExtraComponents(comp, profile.getComponents(), exList); |
550 | 620 | } else { |
551 | 0 | exList.add(new ProfileNotHL7CompliantException("A field has type primitive " |
552 | 0 | + type.getClass().getName() + " but the profile defines components")); |
553 | |
} |
554 | |
} |
555 | |
} |
556 | |
|
557 | 1055 | return exList; |
558 | |
} |
559 | |
|
560 | |
public List<HL7Exception> testComponent(Type type, Component profile, String profileID) |
561 | |
throws ProfileException, HL7Exception { |
562 | 0 | return doTestComponent(type, profile, profileID, true); |
563 | |
} |
564 | |
|
565 | |
protected List<HL7Exception> doTestComponent(Type type, Component profile, String profileID, |
566 | |
boolean theValidateChildren) throws ProfileException, HL7Exception { |
567 | 1995 | List<HL7Exception> exList = new ArrayList<HL7Exception>(); |
568 | 1995 | exList.addAll(testType(type, profile, null, profileID)); |
569 | |
|
570 | |
|
571 | 1995 | if (profile.getSubComponents() > 0 && !profile.getUsage().equals("X") && (!type.isEmpty())) { |
572 | 5 | if (Composite.class.isAssignableFrom(type.getClass())) { |
573 | 5 | Composite comp = (Composite) type; |
574 | |
|
575 | 5 | if (theValidateChildren) { |
576 | 20 | for (int i = 1; i <= profile.getSubComponents(); i++) { |
577 | 15 | SubComponent childProfile = profile.getSubComponent(i); |
578 | |
try { |
579 | 15 | Type child = comp.getComponent(i - 1); |
580 | 15 | exList.addAll(testType(child, childProfile, null, profileID)); |
581 | 0 | } catch (DataTypeException de) { |
582 | 0 | exList.add(new ProfileNotHL7CompliantException( |
583 | |
"More subcomponents in profile than allowed in message: " |
584 | 0 | + de.getMessage())); |
585 | 15 | } |
586 | |
} |
587 | |
} |
588 | |
|
589 | 5 | checkExtraComponents(comp, profile.getSubComponents(), exList); |
590 | 5 | } else { |
591 | 0 | exList.add(new ProfileNotFollowedException("A component has primitive type " |
592 | 0 | + type.getClass().getName() + " but the profile defines subcomponents")); |
593 | |
} |
594 | |
} |
595 | |
|
596 | 1995 | return exList; |
597 | |
} |
598 | |
|
599 | |
|
600 | |
protected void checkExtraComponents(Composite comp, int numInProfile, List<HL7Exception> exList) |
601 | |
throws ProfileException { |
602 | 625 | StringBuilder extra = new StringBuilder(); |
603 | 625 | for (int i = numInProfile; i < comp.getComponents().length; i++) { |
604 | |
try { |
605 | 0 | String s = PipeParser.encode(comp.getComponent(i), enc); |
606 | 0 | if (s.length() > 0) { |
607 | 0 | extra.append(s).append(enc.getComponentSeparator()); |
608 | |
} |
609 | 0 | } catch (DataTypeException de) { |
610 | 0 | throw new ProfileException("Problem testing against profile", de); |
611 | 0 | } |
612 | |
} |
613 | |
|
614 | 625 | if (extra.length() > 0) { |
615 | 0 | exList.add(new XElementPresentException( |
616 | 0 | "The following components are not defined in the profile: " + extra.toString())); |
617 | |
} |
618 | |
|
619 | 625 | } |
620 | |
|
621 | |
public static void main(String args[]) { |
622 | |
|
623 | 0 | if (args.length != 2) { |
624 | 0 | System.out.println("Usage: DefaultValidator message_file profile_file"); |
625 | 0 | System.exit(1); |
626 | |
} |
627 | |
|
628 | 0 | DefaultValidator val = new DefaultValidator(); |
629 | |
try { |
630 | 0 | String msgString = loadFile(args[0]); |
631 | 0 | Parser parser = new GenericParser(); |
632 | 0 | Message message = parser.parse(msgString); |
633 | |
|
634 | 0 | String profileString = loadFile(args[1]); |
635 | 0 | ProfileParser profParser = new ProfileParser(true); |
636 | 0 | RuntimeProfile profile = profParser.parse(profileString); |
637 | |
|
638 | 0 | HL7Exception[] exceptions = val.validate(message, profile.getMessage()); |
639 | |
|
640 | 0 | System.out.println("Exceptions: "); |
641 | 0 | for (int i = 0; i < exceptions.length; i++) { |
642 | 0 | System.out.println((i + 1) + ". " + exceptions[i].getMessage()); |
643 | |
} |
644 | 0 | } catch (Exception e) { |
645 | 0 | e.printStackTrace(); |
646 | 0 | } |
647 | 0 | } |
648 | |
|
649 | |
|
650 | |
private static String loadFile(String path) throws IOException { |
651 | 0 | File file = new File(path); |
652 | |
|
653 | 0 | BufferedReader in = new BufferedReader(new FileReader(file)); |
654 | 0 | StringBuffer buf = new StringBuffer(5000); |
655 | |
int c; |
656 | 0 | while ((c = in.read()) != -1) { |
657 | 0 | buf.append((char) c); |
658 | |
} |
659 | |
|
660 | 0 | in.close(); |
661 | |
|
662 | 0 | return buf.toString(); |
663 | |
} |
664 | |
|
665 | |
} |