Coverage Report - ca.uhn.hl7v2.app.SimpleServer
 
Classes in this File Line Coverage Branch Coverage Complexity
SimpleServer
59%
41/69
33%
4/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  5
         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  10
                 this(port, new MinLowerLayerProtocol(), new PipeParser(), false);
 95  10
         }
 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  10
                 this(port, llp, parser, false);
 110  10
         }
 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  20
                 this(port, llp, parser, tls, DefaultExecutorService.getDefaultService());
 117  20
         }
 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  20
                 super(parser, llp, executorService);
 127  20
                 this.port = port;
 128  20
                 this.tls = tls;
 129  20
                 this.hapiContext = new DefaultHapiContext();
 130  20
                 this.queue = new LinkedBlockingQueue<AcceptedSocket>(100);
 131  20
         }
 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  105
                 super(hapiContext);
 143  105
                 this.hapiContext = hapiContext;
 144  105
                 this.port = port;
 145  105
                 this.tls = tls;
 146  105
                 this.queue = new LinkedBlockingQueue<AcceptedSocket>(100);
 147  105
         }
 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  120
                         super.afterStartup();
 158  120
                         log.info("Starting SimpleServer running on port {}", port);
 159  120
                         SocketFactory ss = this.hapiContext.getSocketFactory();
 160  120
                         acceptor = new AcceptorThread(port, tls, getExecutorService(), queue, ss);
 161  120
                         acceptor.start();
 162  0
                 } catch (Exception e) {
 163  0
                         log.error("Failed starting SimpleServer on port", port);
 164  0
                         throw new RuntimeException(e);
 165  120
                 }
 166  120
         }
 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  3337
                 if (acceptor.getServiceExitedWithException() != null) {
 175  5
                         setServiceExitedWithException(acceptor.getServiceExitedWithException());
 176  
                 }
 177  
                 
 178  
                 try {
 179  
                         // Wait some period of time for connections
 180  3337
                         AcceptedSocket newSocket = queue.poll(500, TimeUnit.MILLISECONDS);
 181  3262
                         if (newSocket != null) {
 182  370
                                 log.info("Accepted connection from {}:{} on local port {}", 
 183  185
                                                 new Object[] { newSocket.socket.getInetAddress().getHostAddress(), newSocket.socket.getPort(), port });
 184  185
                                 ActiveConnection c = new ActiveConnection(getParser(), getLlp(), newSocket.socket,
 185  185
                                                 getExecutorService());
 186  185
                                 newConnection(c);
 187  
                         }
 188  45
                 } catch (InterruptedException ie) { 
 189  
                         // just timed out
 190  0
                 } catch (Exception e) {
 191  0
                         log.error("Error while accepting connections: ", e);
 192  3307
                 }
 193  3307
         }
 194  
 
 195  
         /**
 196  
          * Close down socket
 197  
          */
 198  
         @Override
 199  
         protected void afterTermination() {
 200  90
                 super.afterTermination();
 201  90
                 acceptor.stop();
 202  90
         }
 203  
 
 204  
         /**
 205  
          * Run server from command line. Port number should be passed as an
 206  
          * argument, and a file containing a list of Applications to use can also be
 207  
          * specified as an optional argument (as per
 208  
          * <code>loadApplicationsFromFile(...)</code>). Uses the default
 209  
          * LowerLayerProtocol.
 210  
          */
 211  
         public static void main(String args[]) {
 212  0
                 if (args.length < 1 || args.length > 2) {
 213  0
                         System.out
 214  0
                                         .println("Usage: ca.uhn.hl7v2.app.SimpleServer port_num [application_spec_file_name]");
 215  0
                         System.exit(1);
 216  
                 }
 217  
 
 218  0
                 int port = 0;
 219  
                 try {
 220  0
                         port = Integer.parseInt(args[0]);
 221  0
                 } catch (NumberFormatException e) {
 222  0
                         System.err.println("The given port (" + args[0]
 223  
                                         + ") is not an integer.");
 224  0
                         System.exit(1);
 225  0
                 }
 226  
 
 227  0
                 File appFile = null;
 228  0
                 if (args.length == 2) {
 229  0
                         appFile = new File(args[1]);
 230  
                 }
 231  
 
 232  
                 try {
 233  0
                         SimpleServer server = new SimpleServer(port);
 234  0
                         if (appFile != null)
 235  0
                                 server.loadApplicationsFromFile(appFile);
 236  0
                         server.start();
 237  0
                 } catch (Exception e) {
 238  0
                         e.printStackTrace();
 239  0
                 }
 240  
 
 241  0
         }
 242  
 
 243  
 }