Coverage Report - ca.uhn.hl7v2.app.Receiver
 
Classes in this File Line Coverage Branch Coverage Complexity
Receiver
86%
26/30
83%
5/6
2.333
Receiver$Grunt
83%
10/12
100%
2/2
2.333
 
 1  
 /**
 2  
  * The contents of this file are subject to the Mozilla Public License Version 1.1
 3  
  * (the "License"); you may not use this file except in compliance with the License.
 4  
  * You may obtain a copy of the License at http://www.mozilla.org/MPL/
 5  
  * Software distributed under the License is distributed on an "AS IS" basis,
 6  
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
 7  
  * specific language governing rights and limitations under the License.
 8  
  *
 9  
  * The Original Code is "Receiver.java".  Description:
 10  
  * "Listens for incoming messages on a certain input stream, and
 11  
  * sends them to the appropriate location."
 12  
  *
 13  
  * The Initial Developer of the Original Code is University Health Network. Copyright (C)
 14  
  * 2002.  All Rights Reserved.
 15  
  *
 16  
  * Contributor(s): _____________.
 17  
  *
 18  
  * Alternatively, the contents of this file may be used under the terms of the
 19  
  * GNU General Public License (the "GPL"), in which case the provisions of the GPL are
 20  
  * applicable instead of those above.  If you wish to allow use of your version of this
 21  
  * file only under the terms of the GPL and not to allow others to use your version
 22  
  * of this file under the MPL, indicate your decision by deleting  the provisions above
 23  
  * and replace  them with the notice and other provisions required by the GPL License.
 24  
  * If you do not delete the provisions above, a recipient may use your version of
 25  
  * this file under either the MPL or the GPL.
 26  
  */
 27  
 
 28  
 package ca.uhn.hl7v2.app;
 29  
 
 30  
 import java.io.IOException;
 31  
 import java.net.SocketException;
 32  
 
 33  
 import org.slf4j.Logger;
 34  
 import org.slf4j.LoggerFactory;
 35  
 
 36  
 import ca.uhn.hl7v2.concurrent.Service;
 37  
 import ca.uhn.hl7v2.llp.HL7Reader;
 38  
 
 39  
 /**
 40  
  * Listens for incoming messages on a certain input stream, and sends them to
 41  
  * the appropriate location.
 42  
  * 
 43  
  * @author Bryan Tripp
 44  
  */
 45  10
 public class Receiver extends Service {
 46  
 
 47  5
         private static final Logger log = LoggerFactory.getLogger(Receiver.class);
 48  
 
 49  
         private ActiveConnection conn;
 50  
         private HL7Reader in;
 51  
 
 52  
         /** Creates a new instance of Receiver, associated with the given Connection */
 53  
         public Receiver(ActiveConnection c, HL7Reader in) {
 54  543
                 super("Receiver", c.getExecutorService());
 55  543
                 this.conn = c;
 56  543
                 this.in = in;
 57  543
         }
 58  
 
 59  
 
 60  
         @Override
 61  
         protected void handle() {
 62  
                 try {
 63  1859
                         String message = in.getMessage();
 64  1345
                         if (message == null) {
 65  134
                                 log.debug("Failed to read a message");
 66  
                         } else {
 67  1211
                                 processMessage(message);
 68  
                         }
 69  499
                 } catch (SocketException e)  {
 70  
                         // This probably means that the client closed the server connection normally
 71  499
                         conn.close();
 72  499
                         log.info("SocketException: closing Connection from " + describeRemoteConnection() + ", will no longer read messages with this Receiver: " + e.getMessage());
 73  0
                 } catch (IOException e) {
 74  0
                         conn.close();
 75  0
                         log.warn("IOException: closing Connection from " + describeRemoteConnection() + ", will no longer read messages with this Receiver. ", e);
 76  10
                 } catch (Exception e) {
 77  10
                         conn.close();
 78  10
                         log.error("Unexpected error, closing connection from " + describeRemoteConnection() + " - ", e);
 79  1844
                 }
 80  
 
 81  1854
         }
 82  
 
 83  
 
 84  
         private String describeRemoteConnection() {
 85  509
                 return conn.getRemoteAddress().getHostAddress() + ":" + conn.getRemotePort();
 86  
         }
 87  
 
 88  
 
 89  
         /**
 90  
          * Processes a single incoming message by sending it to the appropriate
 91  
          * internal location. If an incoming message contains an MSA-2 field, it is
 92  
          * assumed that this message is meant as a reply to a message that has been
 93  
          * sent earlier. In this case an attempt is give the message to the object
 94  
          * that sent the corresponding outbound message. If the message contains an
 95  
          * MSA-2 but there are no objects that appear to be waiting for it, it is
 96  
          * discarded and an exception is logged. If the message does not contain an
 97  
          * MSA-2 field, it is concluded that the message has arrived unsolicited. In
 98  
          * this case it is sent to the Responder (in a new Thread).
 99  
          */
 100  
         protected void processMessage(String message) {
 101  1211
                 String ackID = conn.getParser().getAckID(message);
 102  1211
                 if (ackID == null) {
 103  633
                         log.debug("Unsolicited Message Received: {}", message);
 104  633
                         getExecutorService().submit(new Grunt(conn, message));
 105  
                 } else {
 106  578
                         if (!conn.isRecipientWaiting(ackID, message)) {
 107  0
                                 log.info("Unexpected Message Received. This message appears to be an acknowledgement (MSA-2 has a value) so it will be ignored: {}", message);
 108  
                         } else {
 109  578
                                 log.debug("Response Message Received: {}", message);
 110  
                         }
 111  
                 }
 112  1211
         }
 113  
 
 114  
         /** Independent thread for processing a single message */
 115  
         private static class Grunt implements Runnable {
 116  
 
 117  
                 private ActiveConnection conn;
 118  
                 private String m;
 119  
 
 120  633
                 public Grunt(ActiveConnection conn, String message) {
 121  633
                         this.conn = conn;
 122  633
                         this.m = message;
 123  633
                 }
 124  
 
 125  
                 public void run() {
 126  
                         try {
 127  633
                                 String response = conn.getResponder().processMessage(m);
 128  633
                                 if (response != null) {
 129  623
                                         conn.getAckWriter().writeMessage(response);
 130  
                                 } else {
 131  10
                                         log.debug("Not responding to incoming message");
 132  
                                 }
 133  0
                         } catch (Exception e) {
 134  0
                                 log.error("Error while processing message: ", e);
 135  633
                         }
 136  633
                 }
 137  
         }
 138  
 
 139  
 }