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 package ca.uhn.hl7v2.testpanel.model.msg;
27
28 import java.beans.PropertyVetoException;
29 import java.io.IOException;
30 import java.util.List;
31
32 import org.apache.commons.lang.ObjectUtils;
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.commons.lang.Validate;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import ca.uhn.hl7v2.HL7Exception;
39 import ca.uhn.hl7v2.conf.ProfileException;
40 import ca.uhn.hl7v2.model.Message;
41 import ca.uhn.hl7v2.model.Segment;
42 import ca.uhn.hl7v2.parser.EncodingCharacters;
43 import ca.uhn.hl7v2.parser.EncodingNotSupportedException;
44 import ca.uhn.hl7v2.parser.GenericParser;
45 import ca.uhn.hl7v2.preparser.PreParser;
46 import ca.uhn.hl7v2.testpanel.model.conf.ConformanceMessage;
47 import ca.uhn.hl7v2.testpanel.model.conf.ProfileGroup;
48 import ca.uhn.hl7v2.testpanel.model.conf.ProfileGroup.Entry;
49 import ca.uhn.hl7v2.testpanel.util.Range;
50 import ca.uhn.hl7v2.testpanel.util.SegmentAndComponentPath;
51 import ca.uhn.hl7v2.testpanel.xsd.Hl7V2EncodingTypeEnum;
52 import ca.uhn.hl7v2.testpanel.xsd.Hl7V2MessageDefinition;
53 import ca.uhn.hl7v2.util.Terser;
54 import ca.uhn.hl7v2.validation.impl.ValidationContextImpl;
55
56 public abstract class Hl7V2MessageBase extends AbstractMessage<Message> {
57
58 private static final Logger ourLog = LoggerFactory.getLogger(Hl7V2MessageBase.class);
59 private Hl7V2EncodingTypeEnum myEncoding = Hl7V2EncodingTypeEnum.ER_7;
60 private int myIndexWithinCollection;
61 private Message myParsedMessage;
62 private GenericParser myParser;
63 private ProfileGroup myRuntimeProfile;
64 private String mySourceMessage;
65
66
67
68
69 public Hl7V2MessageBase() {
70 super();
71 initParser();
72 }
73
74 public Hl7V2MessageBase(String theId) {
75 super(theId);
76 initParser();
77 }
78
79 public abstract Hl7V2MessageBase asEncoding(Hl7V2EncodingTypeEnum theEncoding);
80
81
82
83
84
85 protected Hl7V2MessageDefinition exportConfig(Hl7V2MessageDefinition theConfig) {
86 super.exportConfig(theConfig);
87 theConfig.setText(mySourceMessage);
88
89 return theConfig;
90 }
91
92
93
94
95 @Override
96 public Hl7V2MessageDefinition exportConfigToXml() {
97 return exportConfig(new Hl7V2MessageDefinition());
98 }
99
100
101
102
103 public Hl7V2EncodingTypeEnum getEncoding() {
104 return myEncoding;
105 }
106
107 public abstract String getHighlitedPath();
108
109 public abstract Range getHighlitedRange();
110
111
112
113
114 public int getIndexWithinCollection() {
115 return myIndexWithinCollection;
116 }
117
118 @Override
119 public Class<Message> getMessageClass() {
120 return Message.class;
121 }
122
123 public String getMessageDescription() {
124 StringBuilder retVal = new StringBuilder();
125
126 Terser t = new Terser(getParsedMessage());
127
128 try {
129 retVal.append(t.get("/.MSH-9-1"));
130 retVal.append("^");
131 retVal.append(t.get("/.MSH-9-2"));
132
133 retVal.append(" ");
134
135 retVal.append(t.get("/.MSH-10"));
136 } catch (HL7Exception e) {
137 ourLog.error("Failed to retrieve message props: ", e);
138 }
139
140 return retVal.toString();
141 }
142
143 @Override
144 public Message getParsedMessage() {
145 return myParsedMessage;
146 }
147
148
149
150
151 public ProfileGroup getRuntimeProfile() {
152 return myRuntimeProfile;
153 }
154
155 @Override
156 public String getSourceMessage() {
157 return mySourceMessage;
158 }
159
160 private void initParser() {
161 myParser = new GenericParser();
162 myParser.setValidationContext(new ValidationContextImpl());
163 }
164
165
166
167
168
169 public void initWithParsedMessage(Message theParsedMessage) {
170 myParsedMessage = theParsedMessage;
171 }
172
173
174
175
176 protected abstract void recalculateIndexes();
177
178
179
180
181
182 public void setEncoding(Hl7V2EncodingTypeEnum theEncoding) {
183 Validate.notNull(theEncoding);
184 if (ObjectUtils.equals(myEncoding, theEncoding)) {
185 return;
186 }
187
188 myEncoding = theEncoding;
189 updateParser();
190
191 if (myParsedMessage == null) {
192 return;
193 }
194
195 String prev = mySourceMessage;
196 try {
197 mySourceMessage = myParser.encode(getParsedMessage());
198 } catch (HL7Exception e) {
199 ourLog.error("Could not re-encode message: " + e.getMessage(), e);
200 }
201
202 firePropertyChange(SOURCE_MESSAGE_PROPERTY, prev, mySourceMessage);
203 }
204
205 public abstract void setHighlitedField(SegmentAndComponentPath thePath);
206
207 public abstract void setHighlitedPathBasedOnRange(Range theAdd);
208
209 public abstract void setHighlitedRangeBasedOnSegment(Segment... theSegment);
210
211
212
213
214
215 public void setIndexWithinCollection(int theIndexWithinCollection) {
216 myIndexWithinCollection = theIndexWithinCollection;
217 }
218
219 public void setRuntimeProfile(ProfileGroup theRuntimeProfile) {
220 if (myRuntimeProfile == theRuntimeProfile) {
221 return;
222 }
223 myRuntimeProfile = theRuntimeProfile;
224
225 if (mySourceMessage == null) {
226 return;
227 }
228
229
230 String sourceMessage = mySourceMessage;
231 mySourceMessage = null;
232 try {
233 setSourceMessage(sourceMessage);
234 } catch (PropertyVetoException e) {
235 ourLog.error("Failed to parse message", e);
236 }
237 }
238
239 @Override
240 public void setSourceMessage(String theMessage) throws PropertyVetoException {
241 theMessage = StringUtils.defaultString(theMessage);
242
243 String original = mySourceMessage;
244 if (mySourceMessage != null && mySourceMessage.equals(theMessage)) {
245 return;
246 }
247
248 String sourceMessage = theMessage.trim();
249 String text = sourceMessage.replaceAll("(\\r|\\n)+", "\r");
250
251 updateParser();
252
253 Message parsedMessage;
254 try {
255
256 ourLog.info("About to parse message");
257
258 if (myRuntimeProfile != null) {
259 Entry profile = determineRuntimeProfile(text);
260
261 if (profile != null) {
262 parsedMessage = ConformanceMessage.newInstanceFromStaticDef(profile.getProfileProxy().getProfile().getMessage(), profile.getTablesId());
263 parsedMessage.setParser(myParser);
264 parsedMessage.parse(text);
265 } else {
266 parsedMessage = myParser.parse(text);
267 }
268 } else {
269 parsedMessage = myParser.parse(text);
270 }
271
272 ourLog.info("Done parsing message");
273
274 } catch (EncodingNotSupportedException e) {
275 ourLog.error("Failed to parse message", e);
276 throw new PropertyVetoException(e.getMessage(), null);
277 } catch (HL7Exception e) {
278 ourLog.error("Failed to parse message", e);
279 throw new PropertyVetoException(e.getMessage(), null);
280 } catch (IOException e) {
281 ourLog.error("Failed to parse message", e);
282 throw new PropertyVetoException(e.getMessage(), null);
283 } catch (ProfileException e) {
284 ourLog.error("Failed to parse message", e);
285 throw new PropertyVetoException(e.getMessage(), null);
286 }
287
288 myParsedMessage = parsedMessage;
289 mySourceMessage = sourceMessage;
290
291 recalculateIndexes();
292
293 firePropertyChange(PARSED_MESSAGE_PROPERTY, original, text);
294 }
295
296 private Entry determineRuntimeProfile(String text) throws HL7Exception {
297 String[] fields = PreParser.getFields(text, "MSH-9-1", "MSH-9-2");
298 Entry profile = null;
299 try {
300 profile = myRuntimeProfile.getProfileForMessage(fields[0], fields[1]);
301 if (profile != null) {
302 profile.getProfileProxy().getProfile();
303 }
304 } catch (IOException e) {
305 ourLog.error("Failed to load profile", e);
306 profile = null;
307 } catch (ProfileException e) {
308 ourLog.error("Failed to load profile", e);
309 profile = null;
310 }
311
312 return profile;
313 }
314
315 private void updateParser() {
316
317
318
319 if (myRuntimeProfile != null) {
320 initParser();
321 }
322
323 switch (myEncoding) {
324 case XML:
325 myParser.setXMLParserAsPrimary();
326 break;
327 case ER_7:
328 default:
329 myParser.setPipeParserAsPrimary();
330 break;
331 }
332 }
333
334 public void updateSourceMessage(String theNewSource, int theChangeStart, int theChangeEnd) throws PropertyVetoException {
335
336 theNewSource = theNewSource.replace('\n', '\r');
337 theNewSource = theNewSource.replace("\n", "");
338
339 if (mySourceMessage.equals(theNewSource.trim())) {
340 return;
341 }
342
343 if (true) {
344 setSourceMessage(theNewSource);
345 }
346
347 mySourceMessage = theNewSource;
348
349
350
351 try {
352 Entry profile = determineRuntimeProfile(theNewSource);
353 if (profile != null) {
354 myParsedMessage = ConformanceMessage.newInstanceFromStaticDef(profile.getProfileProxy().getProfile().getMessage(), profile.getTablesId());
355 myParsedMessage.setParser(myParser);
356 myParsedMessage.parse(theNewSource);
357 } else {
358 myParsedMessage.parse(theNewSource);
359 }
360 } catch (HL7Exception e) {
361 ourLog.error("Failed to parse message", e);
362 } catch (IOException e) {
363 ourLog.error("Failed to parse message", e);
364 } catch (ProfileException e) {
365 ourLog.error("Failed to parse message", e);
366 }
367
368 firePropertyChange(PARSED_MESSAGE_PROPERTY, null, null);
369 }
370
371 public void updateSourceMessageBasedOnParsedMessage() {
372 String newMessage;
373 try {
374 newMessage = myParsedMessage.encode();
375
376 String oldValue = mySourceMessage;
377 mySourceMessage = newMessage;
378 firePropertyChange(SOURCE_MESSAGE_PROPERTY, oldValue, myParsedMessage);
379
380 recalculateIndexes();
381
382 } catch (HL7Exception e) {
383 ourLog.error("Failed to update parsed message", e);
384 }
385 }
386
387 static Range findFieRangege(List<Integer> theField, int theRepNum, Range theSegmentRange, String theSourceMessage, Message theParsedMessage) {
388 EncodingCharacters enc;
389 try {
390 enc = EncodingCharacters.getInstance(theParsedMessage);
391 } catch (HL7Exception e) {
392 ourLog.error("Failed to find field", e);
393 return null;
394 }
395
396 int componentPathIndex = 0;
397 Range currentRange = theSegmentRange;
398 for (Integer next : theField) {
399
400 char sep;
401 int offset = next;
402 switch (componentPathIndex) {
403 case 0:
404 sep = enc.getFieldSeparator();
405 if (!theSegmentRange.applyTo(theSourceMessage).startsWith("MSH")) {
406 offset++;
407 }
408 break;
409 case 1:
410 sep = enc.getComponentSeparator();
411 break;
412 case 2:
413 default:
414 sep = enc.getSubcomponentSeparator();
415 break;
416 }
417
418 while (offset > 0) {
419
420 int nextSeparatorIndex = theSourceMessage.indexOf(sep, currentRange.getStart());
421 if (nextSeparatorIndex == -1 || nextSeparatorIndex > currentRange.getEnd()) {
422 if (offset > 1) {
423 nextSeparatorIndex = currentRange.getEnd() - 1;
424 } else {
425 nextSeparatorIndex = currentRange.getEnd();
426 }
427 }
428
429 if (offset > 1) {
430 currentRange = new Range(nextSeparatorIndex + 1, currentRange.getEnd());
431 } else {
432
433 if (componentPathIndex == 0) {
434 char repSep = enc.getRepetitionSeparator();
435 for (int i = 1; i <= theRepNum; i++) {
436 int repIndex = theSourceMessage.indexOf(repSep, currentRange.getStart());
437 if (repIndex == -1) {
438 if (i == theRepNum) {
439 currentRange = new Range(currentRange.getStart(), nextSeparatorIndex);
440 } else {
441
442
443 return new Range(currentRange.getEnd(), currentRange.getEnd());
444 }
445 } else if (i == theRepNum) {
446 currentRange = new Range(currentRange.getStart(), repIndex);
447 } else {
448 currentRange = new Range(repIndex + 1, currentRange.getEnd());
449 }
450 }
451 } else {
452
453 currentRange = new Range(currentRange.getStart(), nextSeparatorIndex);
454
455 }
456 }
457
458 offset--;
459
460 if (ourLog.isDebugEnabled()) {
461 String applyTo = currentRange.applyTo(theSourceMessage);
462 ourLog.debug("New range is " + applyTo + " (" + applyTo.length() + " chars)");
463 }
464
465 }
466 componentPathIndex++;
467
468 if (ourLog.isDebugEnabled()) {
469 String applyTo = currentRange.applyTo(theSourceMessage);
470 ourLog.debug("New range is " + applyTo + " (" + applyTo.length() + " chars)");
471 }
472
473 }
474 return currentRange;
475 }
476
477 }