Coverage Report - ca.uhn.hl7v2.hoh.encoder.AbstractHl7OverHttpEncoder
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractHl7OverHttpEncoder
84%
71/84
80%
16/20
2.909
 
 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  
  * Base class that creates HL7 over HTTP requests. This class is intended to be
 24  
  * single use, so please create a new instance for each message.
 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  
          * Constructor
 41  
          */
 42  
         public AbstractHl7OverHttpEncoder() {
 43  390
                 super();
 44  390
         }
 45  
 
 46  
         /**
 47  
          * @throws EncodeException
 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  
          * @return the actionLine
 150  
          */
 151  
         public String getActionLine() {
 152  600
                 return myActionLine;
 153  
         }
 154  
 
 155  
         /**
 156  
          * @param theActionLine
 157  
          *            the actionLine to set
 158  
          */
 159  
         public void setActionLine(String theActionLine) {
 160  390
                 myActionLine = theActionLine;
 161  390
         }
 162  
 
 163  
         /**
 164  
          * Provide the message to send with a {@link ISendable} instance. Either
 165  
          * this method OR {@link #setMessage(String)} must be called, but not both.
 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  
          * Provide the message to send with a String. Either this method OR
 176  
          * {@link #setDataProvider(ISendable)} must be called, but not both.
 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  
          * Should the encoded data be GZipped? Note that this doesn't set any
 196  
          * headers indicating this fact, so it's up to callers of this method to
 197  
          * take care of that.
 198  
          */
 199  
         void setGzipData(boolean theGzipData) {
 200  125
                 myGzipData = theGzipData;
 201  125
         }
 202  
 
 203  
 }