View Javadoc

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  
15  import ca.uhn.hl7v2.hoh.api.EncodeException;
16  import ca.uhn.hl7v2.hoh.api.ISendable;
17  import ca.uhn.hl7v2.hoh.sign.SignatureFailureException;
18  import ca.uhn.hl7v2.hoh.util.HTTPUtils;
19  
20  
21  /**
22   * Base class that creates HL7 over HTTP requests. This class is intended to be
23   * single use, so please create a new instance for each message.
24   */
25  public abstract class AbstractHl7OverHttpEncoder extends AbstractHl7OverHttp {
26  
27  	private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AbstractHl7OverHttpEncoder.class);
28  
29  	private String myActionLine;
30  
31  	private ISendable mySendable;
32  	private static DateFormat ourRfc1123DateFormat;
33  	
34  	static {
35  		ourRfc1123DateFormat = new SimpleDateFormat("EEE, dd MMM yy HH:mm:ss z");
36  	}
37  	
38  	/**
39  	 * Constructor
40  	 */
41  	public AbstractHl7OverHttpEncoder() {
42  		super();
43  	}
44  
45  
46  	/**
47  	 * @throws EncodeException 
48  	 * 
49  	 */
50  	public void encode() throws EncodeException {
51  		ourLog.trace("Entering encode()");
52  		verifyNotUsed();
53  		
54  		if (isBlank(getMessage()) && mySendable == null) {
55  			throw new IllegalStateException("Either Message or Sendable must be set");
56  		}
57  		if (getMessage() != null) {
58  			setData(getMessage().getBytes(getCharset()));
59  		} else {
60  			ByteArrayOutputStream bos = new ByteArrayOutputStream();
61  			OutputStreamWriter w = new OutputStreamWriter(bos, getCharset());
62  			try {
63  				mySendable.writeMessage(w);
64  			} catch (IOException e) {
65  				throw new EncodeException("Failed to convert message to sendable bytes");
66  			}
67  			setData(bos.toByteArray());
68  		}
69  
70  		setActionLineAppropriately();
71  
72  		setHeaders(new LinkedHashMap<String, String>());
73  		
74  		StringBuilder ctBuilder = new StringBuilder();
75  		if (mySendable != null) {
76  			ctBuilder.append(mySendable.getEncodingStyle().getContentType());
77  		} else {
78  			ctBuilder.append(EncodingStyle.detect(getMessage()).getContentType());
79  		}
80  		ctBuilder.append("; charset=");
81  		ctBuilder.append(getCharset().name());
82  		getHeaders().put("Content-Type", ctBuilder.toString());
83  
84  		getHeaders().put("Content-Length", Integer.toString(getData().length));
85  
86  		addSpecificHeaders();
87  
88  		synchronized (ourRfc1123DateFormat) {
89  			getHeaders().put("Date", ourRfc1123DateFormat.format(new Date()));
90  		}
91  		
92  		if (getSigner() != null) {
93  			try {
94  				getHeaders().put(HTTP_HEADER_HL7_SIGNATURE, getSigner().sign(getData()));
95  			} catch (SignatureFailureException e) {
96  				throw new EncodeException(e);
97  			}
98  		}
99  
100 		ourLog.trace("Exiting encode()");
101 	}
102 
103 
104 	protected abstract void addSpecificHeaders();
105 
106 
107 	protected abstract void setActionLineAppropriately();
108 
109 	/**
110 	 * Provide the message to send with a {@link ISendable} instance. Either this method
111 	 * OR {@link #setMessage(String)} must be called, but not both.
112 	 */
113 	public void setDataProvider(ISendable theSendable) {
114 		if (getMessage() != null) {
115 			throw new IllegalStateException("Message already provided");
116 		}
117 		mySendable = theSendable;
118 	}
119 
120 
121 	/**
122 	 * Provide the message to send with a String. Either this method
123 	 * OR {@link #setDataProvider(ISendable)} must be called, but not both.
124 	 */
125 	@Override
126 	public void setMessage(String theData) {
127 		if (mySendable != null) {
128 			throw new IllegalStateException("Data provider already provided");
129 		}
130 		super.setMessage(theData);
131 	}
132 
133 
134 	public void encodeToOutputStream(OutputStream theOutputStream) throws IOException, EncodeException {
135 		encode();
136 
137 		ourLog.debug("Writing HTTP action: {}", getActionLine());
138 		
139 		OutputStreamWriter w = new OutputStreamWriter(theOutputStream, HTTPUtils.DEFAULT_CHARSET);
140 		w.write(getActionLine());
141 		w.write("\r\n");
142 		
143 		for (Map.Entry<String, String> next : getHeaders().entrySet()) {
144 			ourLog.debug("Writing HTTP header- {}: {}", next.getKey(), next.getValue());
145 
146 			w.write(next.getKey());
147 			w.write(": ");
148 			w.write(next.getValue());
149 			w.write("\r\n");
150 		}
151 		
152 		w.write("\r\n");
153 		w.flush();
154 		
155 		ourLog.debug("Writing {} bytes of actual data", getData().length);
156 		theOutputStream.write(getData());
157 		
158 	}
159 
160 	
161 	/**
162 	 * @return the actionLine
163 	 */
164 	public String getActionLine() {
165 		return myActionLine;
166 	}
167 
168 
169 	/**
170 	 * @param theActionLine the actionLine to set
171 	 */
172 	public void setActionLine(String theActionLine) {
173 		myActionLine = theActionLine;
174 	}
175 
176 }