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 package ca.uhn.hl7v2.llp;
28
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.OutputStream;
32 import java.net.SocketException;
33 import java.net.SocketTimeoutException;
34
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import static ca.uhn.hl7v2.llp.MllpConstants.END_BYTE1;
39 import static ca.uhn.hl7v2.llp.MllpConstants.END_BYTE2;
40 import static ca.uhn.hl7v2.llp.MllpConstants.START_BYTE;
41
42
43
44
45
46
47
48
49 enum MllpDecoderState {
50
51 START(START_BYTE, true) {
52 @Override
53 protected MllpDecoderState proceed() {
54 return BODY;
55 }
56
57 @Override
58 protected void handleEndOfStream() throws IOException {
59 LOG.info("End of input stream reached.");
60 throw new SocketException("End of input stream reached before message starts");
61 }
62
63 },
64 BODY(END_BYTE1, false) {
65 @Override
66 protected MllpDecoderState proceed() {
67 return PREPARE_END;
68 }
69
70 @Override
71 protected void handleEndOfStream() throws LLPException {
72 throw new LLPException("MLLP protocol violation - Stream ends in the message body");
73 }
74
75 },
76 PREPARE_END(END_BYTE2, true) {
77 @Override
78 protected MllpDecoderState proceed() {
79 return END;
80 }
81
82 @Override
83 protected void handleEndOfStream() throws LLPException {
84 throw new LLPException("MLLP protocol violation - Stream ends before LLP end byte");
85 }
86 },
87 END(0, false) {
88 @Override
89 protected MllpDecoderState proceed() {
90 return END;
91 }
92
93 @Override
94 protected void handleEndOfStream() {
95 }
96
97 @Override
98 MllpDecoderState read(InputStream in, OutputStream out) throws LLPException {
99 throw new LLPException("Internal error - reading after end of message");
100 }
101 };
102
103 private final int nextStateByte;
104 private final boolean mustChangeState;
105
106 private static final Logger LOG = LoggerFactory.getLogger(MllpDecoderState.class);
107
108
109 MllpDecoderState(int nextStateByte, boolean mustChangeState) {
110 this.nextStateByte = nextStateByte;
111 this.mustChangeState = mustChangeState;
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125 MllpDecoderState read(InputStream in, OutputStream out) throws SocketTimeoutException, IOException, LLPException {
126 int c;
127 try {
128 if ((c = in.read()) == -1) {
129 handleEndOfStream();
130 } else {
131 LowerLayerProtocol.logCharacterReceived(c);
132 }
133 if (c == nextStateByte) {
134 return proceed();
135 }
136 if (mustChangeState) {
137 throw new LLPException("MLLP protocol violation - Expected byte '" + nextStateByte +
138 "' in state " + this + " but was '" + c + "'");
139 }
140 out.write(c);
141 } catch (SocketException e) {
142 LOG.info("SocketException on read() attempt. Socket appears to have been closed: " + e.getMessage());
143 throw e;
144 }
145 return this;
146 }
147
148
149
150
151
152
153 protected abstract MllpDecoderState proceed();
154
155
156
157
158
159
160
161 protected abstract void handleEndOfStream() throws IOException, LLPException;
162
163 }