All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.uhn.hl7v2.app.HL7ServerTestHelper Maven / Gradle / Ivy

/*
 * HL7ServerTest.java
 */

package ca.uhn.hl7v2.app;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PushbackReader;
import java.io.Reader;
import java.net.Socket;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper class used to send messages from a flat file to 
 * an ip and port. 
 * 
 * Messasges are sent using MLLP and ACK protocal
 * 
 * @author Laura Bright
 * @author Neal Acharya
 * 
 * @version $Revision: 1.2 $ updated on $Date: 2009-03-18 23:27:58 $ by $Author: jamesagnew $
 * @deprecated
 */
public class HL7ServerTestHelper {
    
    private static final Logger ourLog = LoggerFactory.getLogger(HL7ServerTestHelper.class);
    
    private static final String HL7_START_OF_MESSAGE = "\u000b";
    private static final String HL7_END_OF_MESSGAE = "\u001c";

    private String host = null;
    
    private int port = 0;

    private Socket socket = null;

    private OutputStream os = null;
    private InputStream is = null;
    
    public HL7ServerTestHelper(String host, int port) {
        this.host = host;
        this.port = port;
    }

    /*
     * 
     */
    public void openSocket() throws IOException{
        socket = new Socket(host, port);
        socket.setSoLinger(true, 1000);
        
        os = socket.getOutputStream();
        is = socket.getInputStream();
    }
    
    /**
     * 
     *
     */
    public void closeSocket() {
        try {
            Socket sckt = socket;
            socket = null;
            if (sckt != null)
                sckt.close();
        }
        catch (Exception e) {
            ourLog.error(e.getMessage(), e);
        }
    }
 
    
    public int process( InputStream theMsgInputStream ) throws FileNotFoundException, IOException
    {
     
    	BufferedReader in = null;
    	try {
	        in = new BufferedReader( 
	                new CommentFilterReader( new InputStreamReader( theMsgInputStream ) )
	            );
	        	
	        StringBuffer rawMsgBuffer = new StringBuffer();
	        
	        //String line = in.readLine();
	        int c = 0;
			while( (c = in.read()) >= 0) {
				rawMsgBuffer.append( (char) c);
			}
			
			String[] messages = getHL7Messages(rawMsgBuffer.toString());
	        int retVal = 0;
	        
	        //start time
	        long startTime = new GregorianCalendar().getTimeInMillis(); 
	            
	            
			for (int i = 0; i < messages.length; i++) {
				sendMessage(messages[i]);	
				readAck();	
	            retVal++;
			}
	        
	        //end time
	        long endTime =  new GregorianCalendar().getTimeInMillis();
	        
	        //elapsed time
	        long elapsedTime = (endTime - startTime) / 1000;
	        
	        ourLog.info("{} messages sent.", retVal);
	        ourLog.info("Elapsed Time in seconds: {} ", elapsedTime);
	        return retVal;
    	} finally {
    		if (in != null) {
    			try {
					in.close();
				} catch (IOException e) {
				}
    		}
    	}
			
        
    }
    
	private String readAck() throws IOException
	{
		StringBuffer stringbuffer = new StringBuffer();
		int i = 0;
		do {
			i = is.read();
			if (i == -1)
				return null;
            
			stringbuffer.append((char) i);
		}
		while (i != 28);        
		return stringbuffer.toString();
	}
    
    
    
	/** 
	 * Given a string that contains HL7 messages, and possibly other junk, 
	 * returns an array of the HL7 messages.  
	 * An attempt is made to recognize segments even if there is other 
	 * content between segments, for example if a log file logs segments 
	 * individually with timestamps between them.  
	 * 
	 * @param theSource a string containing HL7 messages 
	 * @return the HL7 messages contained in theSource
	 */
	public static String[] getHL7Messages(String theSource) {
		List messages = new ArrayList(20); 
		Pattern startPattern = Pattern.compile("^MSH", Pattern.MULTILINE);
		Matcher startMatcher = startPattern.matcher(theSource);

		while (startMatcher.find()) {
			String messageExtent = 
				getMessageExtent(theSource.substring(startMatcher.start()), startPattern);
			
			char fieldDelim = messageExtent.charAt(3);
			Pattern segmentPattern = Pattern.compile("^[A-Z\\d]{3}\\" + fieldDelim + ".*$", Pattern.MULTILINE);
			Matcher segmentMatcher = segmentPattern.matcher(messageExtent);
			StringBuffer msg = new StringBuffer();
			while (segmentMatcher.find()) {
				msg.append(segmentMatcher.group().trim());
				msg.append('\r');
			}
			messages.add(msg.toString());
		}
		return messages.toArray(new String[0]);
	}
    
	/** 
	 * Given a string that contains at least one HL7 message, returns the 
	 * smallest string that contains the first of these messages.  
	 */
	private static String getMessageExtent(String theSource, Pattern theStartPattern) {
		Matcher startMatcher = theStartPattern.matcher(theSource);
		if (!startMatcher.find()) {
			throw new IllegalArgumentException(theSource + "does not contain message start pattern" 
				+ theStartPattern.toString());
		}
    	
		int start = startMatcher.start();
		int end = theSource.length();
		if (startMatcher.find()) {
			end = startMatcher.start();
		}
 	
		return theSource.substring(start, end).trim();
	}
    
    
    private void sendMessage(String theMessage) throws IOException
    {
        os.write( HL7_START_OF_MESSAGE.getBytes() );
        os.write( theMessage.getBytes() );
        os.write( HL7_END_OF_MESSGAE.getBytes() );
        os.write(13);
        os.flush();
        ourLog.info("Sent: " + theMessage);
    }
     
    
    
    /**
     * Main method for running the application
     * 
     * example command lines args:
     * 
     * -f UHN_PRO_DEV_PATIENTS.dat -h 142.224.178.152 -p 3999
     * 
     */
    public static void main( String[] theArgs ) {

        //parse command line arguments        

        //create the command line parser
        CommandLineParser parser = new PosixParser();

        //create the Options
        Options options = new Options();

        options.addOption("h", "host", true, "IP of host to send to");
        options.addOption("p", "port", true, "port to send to");
        options.addOption("f", "file", true, "file to read HL7 messages from");
        
        CommandLine cmdLine = null;
        try
        {
            // parse the command line arguments
            cmdLine = parser.parse(options, theArgs);
        }
        catch (ParseException e)
        {
            ourLog.error(e.getMessage(), e);
            return;
        }

        String portString = cmdLine.getOptionValue("p");
        int port = 0;
        String host = cmdLine.getOptionValue("h");        
        String file = cmdLine.getOptionValue("f");
        
        if (portString == null || host == null || file == null)
        {
            //automatically generate the help statement
            HelpFormatter formatter = new HelpFormatter();
            //assuming that a shell script named serverTest will be created
            formatter.printHelp( "serverTest", options );
            return;
        }
        else {
            //parse portAsString
            port = Integer.parseInt(portString);
        }
        
        HL7ServerTestHelper serverTest = new HL7ServerTestHelper( host, port );
        
        //InputStream msgInputStream = HL7ServerTestHelper.class.getResourceAsStream( file );
		InputStream msgInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(file);		
        try{            
            serverTest.openSocket();
            serverTest.process( msgInputStream );
        }
        catch(Exception e){
        	e.printStackTrace();
            HelpFormatter formatter = new HelpFormatter();
            //assuming that a shell script named hl7mom will be created
            formatter.printHelp( "serverTest", options );
            System.exit(-1);
        }
        
        serverTest.closeSocket();
    }
    
	/**
	 * TODO: this code is copied from HAPI ... should make it part of HAPI public API instead
	 * Removes C and C++ style comments from a reader stream.  C style comments are
	 * distinguished from URL protocol delimiters by the preceding colon in the
	 * latter.
	 */
	public static class CommentFilterReader extends PushbackReader {
        
		private final char[] startCPPComment = {'/', '*'};
		private final char[] endCPPComment = {'*', '/'};
		private final char[] startCComment = {'/', '/'};
		private final char[] endCComment = {'\n'};
		private final char[] protocolDelim = {':', '/', '/'};
        
		public CommentFilterReader(Reader in) {
			super(in, 5);
		}
        
		/**
		 * Returns the next character, not including comments.
		 */
		public int read() throws IOException {
			if (atSequence(protocolDelim)) {
				//proceed normally
			} else if (atSequence(startCPPComment)) {
				//skip() doesn't seem to work for some reason
				while (!atSequence(endCPPComment)) super.read();
				for (int i = 0; i < endCPPComment.length; i++) super.read();
			} else if (atSequence(startCComment)) {
				while (!atSequence(endCComment)) super.read();
				for (int i = 0; i < endCComment.length; i++) super.read();
			}
			int ret = super.read();
			if (ret == 65535) ret = -1;
			return ret;            
		}
                
		public int read(char[] cbuf, int off, int len) throws IOException {
			int i = -1;
			boolean done = false;
			while (++i < len) {
				int next = read();
				if (next == 65535 || next == -1) { //Pushback causes -1 to convert to 65535
					done = true;
					break;  
				}
				cbuf[off + i] = (char) next;
			}
			if (i == 0 && done) i = -1; 
			return i; 
		}            
        
		/**
		 * Tests incoming data for match with char sequence, resets reader when done.
		 */
		private boolean atSequence(char[] sequence) throws IOException {
			boolean result = true;
			int i = -1;
			int[] data = new int[sequence.length];
			while (++i < sequence.length && result == true) {
				data[i] = super.read();
				if ((char) data[i] != sequence[i]) result = false; //includes case where end of stream reached
			}
			for (int j = i-1; j >= 0; j--) {
				this.unread(data[j]);
			}
			return result;
		}        
	}
    

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy