001    /**
002     * The contents of this file are subject to the Mozilla Public License Version 1.1
003     * (the "License"); you may not use this file except in compliance with the License.
004     * You may obtain a copy of the License at http://www.mozilla.org/MPL/
005     * Software distributed under the License is distributed on an "AS IS" basis,
006     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
007     * specific language governing rights and limitations under the License.
008     *
009     * The Original Code is "Receiver.java".  Description:
010     * "Listens for incoming messages on a certain input stream, and
011     * sends them to the appropriate location."
012     *
013     * The Initial Developer of the Original Code is University Health Network. Copyright (C)
014     * 2002.  All Rights Reserved.
015     *
016     * Contributor(s): _____________.
017     *
018     * Alternatively, the contents of this file may be used under the terms of the
019     * GNU General Public License (the "GPL"), in which case the provisions of the GPL are
020     * applicable instead of those above.  If you wish to allow use of your version of this
021     * file only under the terms of the GPL and not to allow others to use your version
022     * of this file under the MPL, indicate your decision by deleting  the provisions above
023     * and replace  them with the notice and other provisions required by the GPL License.
024     * If you do not delete the provisions above, a recipient may use your version of
025     * this file under either the MPL or the GPL.
026     */
027    
028    package ca.uhn.hl7v2.app;
029    
030    import java.io.IOException;
031    import java.net.SocketException;
032    
033    import org.slf4j.Logger;
034    import org.slf4j.LoggerFactory;
035    
036    import ca.uhn.hl7v2.concurrent.Service;
037    import ca.uhn.hl7v2.llp.HL7Reader;
038    
039    /**
040     * Listens for incoming messages on a certain input stream, and sends them to
041     * the appropriate location.
042     * 
043     * @author Bryan Tripp
044     */
045    public class Receiver extends Service {
046    
047            private static final Logger log = LoggerFactory.getLogger(Receiver.class);
048    
049            private Connection conn;
050            private HL7Reader in;
051    
052            /** Creates a new instance of Receiver, associated with the given Connection */
053            public Receiver(Connection c, HL7Reader in) {
054                    super("Receiver", c.getExecutorService());
055                    this.conn = c;
056                    this.in = in;
057            }
058    
059    
060            @Override
061            protected void handle() {
062                    try {
063                            String message = in.getMessage();
064                            if (message == null) {
065                                    log.debug("Failed to read a message");
066                            } else {
067                                    processMessage(message);
068                            }
069                    } catch (SocketException e)  {
070                            // This probably means that the client closed the server connection normally
071                            conn.close();
072                            log.info("SocketException: closing Connection, will no longer read messages with this Receiver: " + e.getMessage());
073                    } catch (IOException e) {
074                            conn.close();
075                            log.warn("IOException: closing Connection, will no longer read messages with this Receiver. ", e);
076                    } catch (Exception e) {
077                            log.error("Error while closing connection: ", e);
078                    }
079    
080            }
081    
082    
083            /**
084             * Processes a single incoming message by sending it to the appropriate
085             * internal location. If an incoming message contains an MSA-2 field, it is
086             * assumed that this message is meant as a reply to a message that has been
087             * sent earlier. In this case an attempt is give the message to the object
088             * that sent the corresponding outbound message. If the message contains an
089             * MSA-2 but there are no objects that appear to be waiting for it, it is
090             * discarded and an exception is logged. If the message does not contain an
091             * MSA-2 field, it is concluded that the message has arrived unsolicited. In
092             * this case it is sent to the Responder (in a new Thread).
093             */
094            protected void processMessage(String message) {
095                    String ackID = conn.getParser().getAckID(message);
096                    if (ackID == null) {
097                            log.debug("Unsolicited Message Received: {}", message);
098                            getExecutorService().submit(new Grunt(conn, message));
099                    } else {
100                            if (!conn.isRecipientWaiting(ackID, message)) {
101                                    log.info("Unexpected Message Received: {}", message);
102                            } else {
103                                    log.debug("Response Message Received: {}", message);
104                            }
105                    }
106            }
107    
108            /** Independent thread for processing a single message */
109            private class Grunt implements Runnable {
110    
111                    private Connection conn;
112                    private String m;
113    
114                    public Grunt(Connection conn, String message) {
115                            this.conn = conn;
116                            this.m = message;
117                    }
118    
119                    public void run() {
120                            try {
121                                    String response = conn.getResponder().processMessage(m);
122                                    conn.getAckWriter().writeMessage(response);
123                            } catch (Exception e) {
124                                    log.error("Error while processing message: ", e);
125                            }
126                    }
127            }
128    
129    }