Coverage Report - ca.uhn.hl7v2.app.SimpleServer
 
Classes in this File Line Coverage Branch Coverage Complexity
SimpleServer
57%
38/66
25%
3/12
2.2
 
 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 "SimpleServer.java".  Description:
 10  
  * "A simple TCP/IP-based HL7 server."
 11  
  *
 12  
  * The Initial Developer of the Original Code is University Health Network. Copyright (C)
 13  
  * 2002.  All Rights Reserved.
 14  
  *
 15  
  * Contributor(s): Kyle Buza
 16  
  *
 17  
  * Alternatively, the contents of this file may be used under the terms of the
 18  
  * GNU General Public License (the  �GPL�), in which case the provisions of the GPL are
 19  
  * applicable instead of those above.  If you wish to allow use of your version of this
 20  
  * file only under the terms of the GPL and not to allow others to use your version
 21  
  * of this file under the MPL, indicate your decision by deleting  the provisions above
 22  
  * and replace  them with the notice and other provisions required by the GPL License.
 23  
  * If you do not delete the provisions above, a recipient may use your version of
 24  
  * this file under either the MPL or the GPL.
 25  
  */
 26  
 
 27  
 package ca.uhn.hl7v2.app;
 28  
 
 29  
 import java.io.File;
 30  
 import java.util.concurrent.BlockingQueue;
 31  
 import java.util.concurrent.ExecutorService;
 32  
 import java.util.concurrent.LinkedBlockingQueue;
 33  
 import java.util.concurrent.TimeUnit;
 34  
 
 35  
 import org.slf4j.Logger;
 36  
 import org.slf4j.LoggerFactory;
 37  
 
 38  
 import ca.uhn.hl7v2.DefaultHapiContext;
 39  
 import ca.uhn.hl7v2.HapiContext;
 40  
 import ca.uhn.hl7v2.app.AcceptorThread.AcceptedSocket;
 41  
 import ca.uhn.hl7v2.concurrent.DefaultExecutorService;
 42  
 import ca.uhn.hl7v2.llp.LowerLayerProtocol;
 43  
 import ca.uhn.hl7v2.llp.MinLowerLayerProtocol;
 44  
 import ca.uhn.hl7v2.parser.Parser;
 45  
 import ca.uhn.hl7v2.parser.PipeParser;
 46  
 import ca.uhn.hl7v2.util.SocketFactory;
 47  
 
 48  
 /**
 49  
  * <p>
 50  
  * A simple TCP/IP-based HL7 server. This server listens for connections on a
 51  
  * particular port, and creates a ConnectionManager for each incoming
 52  
  * connection.
 53  
  * </p>
 54  
  * <p>
 55  
  * A single SimpleServer can only service requests that use a single class of
 56  
  * LowerLayerProtocol (specified at construction time).
 57  
  * </p>
 58  
  * <p>
 59  
  * The ConnectionManager uses a {@link PipeParser} of the version specified in
 60  
  * the constructor
 61  
  * </p>
 62  
  * <p>
 63  
  * ConnectionManagers currently only support original mode processing.
 64  
  * </p>
 65  
  * <p>
 66  
  * The ConnectionManager routes messages to various {@link Application}s based
 67  
  * on message type. From the HL7 perspective, an {@link Application} is
 68  
  * something that does something with a message.
 69  
  * </p>
 70  
  * 
 71  
  * @author Bryan Tripp
 72  
  * @author Christian Ohr
 73  
  */
 74  
 public class SimpleServer extends HL7Service {
 75  
 
 76  
         /**
 77  
          * Socket timeout for simple server
 78  
          */
 79  
         public static final int SO_TIMEOUT = AcceptorThread.TIMEOUT;
 80  
 
 81  1
         private static final Logger log = LoggerFactory.getLogger(SimpleServer.class);
 82  
         
 83  
         private int port;
 84  
         private boolean tls;
 85  
         private final BlockingQueue<AcceptedSocket> queue;
 86  
         private AcceptorThread acceptor;
 87  
         private HapiContext hapiContext;
 88  
 
 89  
         /**
 90  
          * Creates a new instance of SimpleServer that listens on the given port,
 91  
          * using the {@link MinLowerLayerProtocol} and a standard {@link PipeParser}.
 92  
          */
 93  
         public SimpleServer(int port) {
 94  2
                 this(port, new MinLowerLayerProtocol(), new PipeParser(), false);
 95  2
         }
 96  
         
 97  
         /**
 98  
          * Creates a new instance of SimpleServer that listens on the given port,
 99  
          * using the {@link MinLowerLayerProtocol} and a standard {@link PipeParser}.
 100  
          */
 101  
         public SimpleServer(int port, boolean tls) {
 102  0
                 this(port, new MinLowerLayerProtocol(), new PipeParser(), tls);
 103  0
         }        
 104  
 
 105  
         /**
 106  
          * Creates a new instance of SimpleServer that listens on the given port.
 107  
          */
 108  
         public SimpleServer(int port, LowerLayerProtocol llp, Parser parser) {
 109  3
                 this(port, llp, parser, false);
 110  3
         }
 111  
         
 112  
         /**
 113  
          * Creates a new instance of SimpleServer that listens on the given port.
 114  
          */
 115  
         public SimpleServer(int port, LowerLayerProtocol llp, Parser parser, boolean tls) {
 116  5
                 this(port, llp, parser, tls, DefaultExecutorService.getDefaultService());
 117  5
         }
 118  
 
 119  
         /**
 120  
          * Creates a new instance of SimpleServer using a custom {link
 121  
          * {@link ExecutorService}. This {@link ExecutorService} instance will
 122  
          * <i>not</i> be shut down after the server stops!
 123  
          */
 124  
         public SimpleServer(int port, LowerLayerProtocol llp, Parser parser, boolean tls,
 125  
                         ExecutorService executorService) {
 126  5
                 super(parser, llp, executorService);
 127  5
                 this.port = port;
 128  5
                 this.tls = tls;
 129  5
                 this.hapiContext = new DefaultHapiContext();
 130  5
                 this.queue = new LinkedBlockingQueue<AcceptedSocket>(100);
 131  5
         }
 132  
 
 133  
         /**
 134  
          * Creates a new instance of SimpleServer that listens on a given server socket.
 135  
          * SimpleServer will bind the socket when it is started, so the server socket 
 136  
          * must not already be bound. 
 137  
          * 
 138  
          * @since 2.1
 139  
          * @throws IllegalStateException If serverSocket is already bound
 140  
          */
 141  
         public SimpleServer(HapiContext hapiContext, int port, boolean tls) {
 142  9
                 super(hapiContext);
 143  9
                 this.hapiContext = hapiContext;
 144  9
                 this.port = port;
 145  9
                 this.tls = tls;
 146  9
                 this.queue = new LinkedBlockingQueue<AcceptedSocket>(100);
 147  9
         }
 148  
 
 149  
         /**
 150  
          * Prepare server by initializing the server socket
 151  
          * 
 152  
          * @see ca.uhn.hl7v2.app.HL7Service#afterStartup()
 153  
          */
 154  
         @Override
 155  
         protected void afterStartup() {
 156  
                 try {
 157  13
                         super.afterStartup();
 158  13
                         log.info("Starting SimpleServer running on port {}", port);
 159  13
                         SocketFactory ss = this.hapiContext.getSocketFactory();
 160  13
                         acceptor = new AcceptorThread(port, tls, getExecutorService(), queue, ss);
 161  13
                         acceptor.start();
 162  0
                 } catch (Exception e) {
 163  0
                         log.error("Failed starting SimpleServer on port", port);
 164  0
                         throw new RuntimeException(e);
 165  13
                 }
 166  13
         }
 167  
 
 168  
         /**
 169  
          * Loop that waits for a connection and starts a ConnectionManager when it
 170  
          * gets one.
 171  
          */
 172  
         @Override
 173  
         protected void handle() {
 174  865
                 if (acceptor.getServiceExitedWithException() != null) {
 175  0
                         setServiceExitedWithException(acceptor.getServiceExitedWithException());
 176  
                 }
 177  
                 
 178  
                 try {
 179  
                         // Wait some period of time for connections
 180  865
                         AcceptedSocket newSocket = queue.poll(AcceptorThread.TIMEOUT, TimeUnit.MILLISECONDS);
 181  860
                         if (newSocket != null) {
 182  25
                                 log.info("Accepted connection from {} on port {}", newSocket.socket.getInetAddress().getHostAddress(), port);
 183  25
                                 Connection c = new Connection(getParser(), getLlp(), newSocket.socket,
 184  
                                                 getExecutorService());
 185  25
                                 newConnection(c);
 186  
                         }
 187  1
                 } catch (InterruptedException ie) { 
 188  
                         // just timed out
 189  0
                 } catch (Exception e) {
 190  0
                         log.error("Error while accepting connections: ", e);
 191  861
                 }
 192  861
         }
 193  
 
 194  
         /**
 195  
          * Close down socket
 196  
          */
 197  
         @Override
 198  
         protected void afterTermination() {
 199  9
                 super.afterTermination();
 200  9
                 acceptor.stop();
 201  9
         }
 202  
 
 203  
         /**
 204  
          * Run server from command line. Port number should be passed as an
 205  
          * argument, and a file containing a list of Applications to use can also be
 206  
          * specified as an optional argument (as per
 207  
          * <code>loadApplicationsFromFile(...)</code>). Uses the default
 208  
          * LowerLayerProtocol.
 209  
          */
 210  
         public static void main(String args[]) {
 211  0
                 if (args.length < 1 || args.length > 2) {
 212  0
                         System.out
 213  
                                         .println("Usage: ca.uhn.hl7v2.app.SimpleServer port_num [application_spec_file_name]");
 214  0
                         System.exit(1);
 215  
                 }
 216  
 
 217  0
                 int port = 0;
 218  
                 try {
 219  0
                         port = Integer.parseInt(args[0]);
 220  0
                 } catch (NumberFormatException e) {
 221  0
                         System.err.println("The given port (" + args[0]
 222  
                                         + ") is not an integer.");
 223  0
                         System.exit(1);
 224  0
                 }
 225  
 
 226  0
                 File appFile = null;
 227  0
                 if (args.length == 2) {
 228  0
                         appFile = new File(args[1]);
 229  
                 }
 230  
 
 231  
                 try {
 232  0
                         SimpleServer server = new SimpleServer(port);
 233  0
                         if (appFile != null)
 234  0
                                 server.loadApplicationsFromFile(appFile);
 235  0
                         server.start();
 236  0
                 } catch (Exception e) {
 237  0
                         e.printStackTrace();
 238  0
                 }
 239  
 
 240  0
         }
 241  
 
 242  
 }