1 | |
package ca.uhn.hl7v2.hoh.encoder; |
2 | |
|
3 | |
import static ca.uhn.hl7v2.hoh.util.StringUtils.*; |
4 | |
|
5 | |
import java.io.ByteArrayOutputStream; |
6 | |
import java.io.IOException; |
7 | |
import java.io.OutputStream; |
8 | |
import java.io.OutputStreamWriter; |
9 | |
import java.text.DateFormat; |
10 | |
import java.text.SimpleDateFormat; |
11 | |
import java.util.Date; |
12 | |
import java.util.LinkedHashMap; |
13 | |
import java.util.Map; |
14 | |
import java.util.zip.GZIPOutputStream; |
15 | |
|
16 | |
import ca.uhn.hl7v2.hoh.api.EncodeException; |
17 | |
import ca.uhn.hl7v2.hoh.api.ISendable; |
18 | |
import ca.uhn.hl7v2.hoh.sign.SignatureFailureException; |
19 | |
import ca.uhn.hl7v2.hoh.util.GZipUtils; |
20 | |
import ca.uhn.hl7v2.hoh.util.HTTPUtils; |
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | 8800 | public abstract class AbstractHl7OverHttpEncoder extends AbstractHl7OverHttp { |
27 | |
|
28 | 5 | private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AbstractHl7OverHttpEncoder.class); |
29 | |
private static DateFormat ourRfc1123DateFormat; |
30 | |
|
31 | |
static { |
32 | 5 | ourRfc1123DateFormat = new SimpleDateFormat("EEE, dd MMM yy HH:mm:ss z"); |
33 | 5 | } |
34 | |
|
35 | |
private String myActionLine; |
36 | |
private boolean myGzipData; |
37 | |
private ISendable<?> mySendable; |
38 | |
|
39 | |
|
40 | |
|
41 | |
|
42 | |
public AbstractHl7OverHttpEncoder() { |
43 | 390 | super(); |
44 | 390 | } |
45 | |
|
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
public void encode() throws EncodeException { |
51 | 390 | ourLog.trace("Entering encode()"); |
52 | 390 | verifyNotUsed(); |
53 | |
|
54 | 390 | if (isBlank(getMessage()) && mySendable == null) { |
55 | 0 | throw new IllegalStateException("Either Message or Sendable must be set"); |
56 | |
} |
57 | 390 | if (getMessage() != null) { |
58 | 275 | byte[] bytes = getMessage().getBytes(getCharset()); |
59 | 275 | if (myGzipData) { |
60 | |
try { |
61 | 5 | bytes = GZipUtils.compress(bytes); |
62 | 0 | } catch (IOException e) { |
63 | 0 | throw new EncodeException("Failed to apply GZip coding", e); |
64 | 5 | } |
65 | |
} |
66 | 275 | setData(bytes); |
67 | 275 | } else { |
68 | 115 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
69 | |
OutputStream os; |
70 | 115 | if (myGzipData) { |
71 | |
try { |
72 | 0 | os = new GZIPOutputStream(bos); |
73 | 0 | } catch (IOException e) { |
74 | 0 | throw new EncodeException("Failed to create GZip encoder", e); |
75 | 0 | } |
76 | |
} else { |
77 | 115 | os = bos; |
78 | |
} |
79 | |
|
80 | 115 | OutputStreamWriter w = new OutputStreamWriter(os, getCharset()); |
81 | |
try { |
82 | 115 | mySendable.writeMessage(w); |
83 | 0 | } catch (IOException e) { |
84 | 0 | throw new EncodeException("Failed to convert message to sendable bytes"); |
85 | 115 | } |
86 | 115 | setData(bos.toByteArray()); |
87 | |
} |
88 | |
|
89 | 390 | setActionLineAppropriately(); |
90 | |
|
91 | 390 | setHeaders(new LinkedHashMap<String, String>()); |
92 | |
|
93 | 390 | StringBuilder ctBuilder = new StringBuilder(); |
94 | 390 | if (mySendable != null) { |
95 | 115 | ctBuilder.append(mySendable.getEncodingStyle().getContentType()); |
96 | |
} else { |
97 | 275 | ctBuilder.append(EncodingStyle.detect(getMessage()).getContentType()); |
98 | |
} |
99 | 390 | ctBuilder.append("; charset="); |
100 | 390 | ctBuilder.append(getCharset().name()); |
101 | 390 | getHeaders().put("Content-Type", ctBuilder.toString()); |
102 | |
|
103 | 390 | getHeaders().put("Content-Length", Integer.toString(getData().length)); |
104 | |
|
105 | 390 | addSpecificHeaders(); |
106 | |
|
107 | 390 | synchronized (ourRfc1123DateFormat) { |
108 | 390 | getHeaders().put("Date", ourRfc1123DateFormat.format(new Date())); |
109 | 390 | } |
110 | |
|
111 | 390 | if (getSigner() != null) { |
112 | |
try { |
113 | 15 | getHeaders().put(HTTP_HEADER_HL7_SIGNATURE, getSigner().sign(getData())); |
114 | 0 | } catch (SignatureFailureException e) { |
115 | 0 | throw new EncodeException(e); |
116 | 15 | } |
117 | |
} |
118 | |
|
119 | 390 | ourLog.trace("Exiting encode()"); |
120 | 390 | } |
121 | |
|
122 | |
public void encodeToOutputStream(OutputStream theOutputStream) throws IOException, EncodeException { |
123 | 300 | encode(); |
124 | |
|
125 | 300 | ourLog.debug("Writing HTTP action: {}", getActionLine()); |
126 | |
|
127 | 300 | OutputStreamWriter w = new OutputStreamWriter(theOutputStream, HTTPUtils.DEFAULT_CHARSET); |
128 | 300 | w.write(getActionLine()); |
129 | 300 | w.write("\r\n"); |
130 | |
|
131 | 300 | for (Map.Entry<String, String> next : getHeaders().entrySet()) { |
132 | 1515 | ourLog.debug("Writing HTTP header- {}: {}", next.getKey(), next.getValue()); |
133 | |
|
134 | 1515 | w.write(next.getKey()); |
135 | 1515 | w.write(": "); |
136 | 1515 | w.write(next.getValue()); |
137 | 1515 | w.write("\r\n"); |
138 | 1515 | } |
139 | |
|
140 | 300 | w.write("\r\n"); |
141 | 300 | w.flush(); |
142 | |
|
143 | 300 | ourLog.debug("Writing {} bytes of actual data", getData().length); |
144 | 300 | theOutputStream.write(getData()); |
145 | |
|
146 | 300 | } |
147 | |
|
148 | |
|
149 | |
|
150 | |
|
151 | |
public String getActionLine() { |
152 | 600 | return myActionLine; |
153 | |
} |
154 | |
|
155 | |
|
156 | |
|
157 | |
|
158 | |
|
159 | |
public void setActionLine(String theActionLine) { |
160 | 390 | myActionLine = theActionLine; |
161 | 390 | } |
162 | |
|
163 | |
|
164 | |
|
165 | |
|
166 | |
|
167 | |
public void setDataProvider(ISendable<?> theSendable) { |
168 | 115 | if (getMessage() != null) { |
169 | 0 | throw new IllegalStateException("Message already provided"); |
170 | |
} |
171 | 115 | mySendable = theSendable; |
172 | 115 | } |
173 | |
|
174 | |
|
175 | |
|
176 | |
|
177 | |
|
178 | |
@Override |
179 | |
public void setMessage(String theData) { |
180 | 275 | if (mySendable != null) { |
181 | 0 | throw new IllegalStateException("Data provider already provided"); |
182 | |
} |
183 | 275 | super.setMessage(theData); |
184 | 275 | } |
185 | |
|
186 | |
protected abstract void addSpecificHeaders(); |
187 | |
|
188 | |
protected abstract void setActionLineAppropriately(); |
189 | |
|
190 | |
boolean isGzipData() { |
191 | 160 | return myGzipData; |
192 | |
} |
193 | |
|
194 | |
|
195 | |
|
196 | |
|
197 | |
|
198 | |
|
199 | |
void setGzipData(boolean theGzipData) { |
200 | 125 | myGzipData = theGzipData; |
201 | 125 | } |
202 | |
|
203 | |
} |