Java tutorial
/** * The contents of this file are subject to the Regenstrief Public License * Version 1.0 (the "License"); you may not use this file except in compliance with the License. * Please contact Regenstrief Institute if you would like to obtain a copy of the license. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) Regenstrief Institute. All Rights Reserved. */ package org.regenstrief.hl7.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.regenstrief.util.Util; import java.io.*; import java.net.Socket; import java.net.UnknownHostException; import java.util.Date; public class HL7IO { private static final Log log = LogFactory.getLog(HL7IO.class); public final static String PROP_TIMEOUT_IN_MILLIS = HL7IO.class.getName() + ".timeoutInMillis"; static final int BOM = 11; static final int EOM = 28; static final int CR = 13; public static int hl7_read_dbv = 0; /** * Defines an interface to be implemented by any type of HL7 message handlers */ public static interface HL7Handler { /** * process an HL7 message received by the HL7 listener * * @param hl7Message received message * @throws Exception unhandled exception */ public void process(final String hl7Message) throws Exception; } // Used to throw IOException, but that looks like a low-level Exception thrown by a deeper Java API; // This class would clearly be thrown by us public final static class HL7IOException extends IOException { private static final long serialVersionUID = 1L; private HL7IOException(final String msg) { super(msg); } private HL7IOException(final String msg, final Throwable cause) { super(msg, cause); } } /* ------------------------------------------------------------- Utilities from mqt.Utl and mqt.AWK ------------------------------------------------------------- */ public static String fileToHeap(final String fname) throws FileNotFoundException, IOException { final File fn = new File(fname); //Utl. dp(">fileToHeap{" + fname + "} len:" + fn.length()); final FileInputStream fis = new FileInputStream(fn); final byte[] a = new byte[(int) fn.length()]; fis.read(a); fis.close(); return new String(a); } public static String convert_lf_to_cr(final String s) { return Util.replaceAllExact(s, "\r\n", "\r").replace('\n', '\r'); } public static void sleep(final long delay) { if (delay <= 0) { return; } try { Thread.sleep(delay * 1000); } catch (final Exception e) { log.error("Exception:", e); } } public static boolean isMscPrint(final int b) { switch (b) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '`': case '~': case '!': case '@': case '#': case '$': case '%': case '^': case '&': case '*': case '(': case ')': case '-': case '_': case '=': case '+': case '{': case '[': case '}': case ']': case '|': case '\\': case ';': case ':': case '"': case '\'': case '<': case ',': case '>': case '.': case '?': case '/': return true; default: return false; } } public static String hex2(final int ch) { final String rv = Integer.toHexString(ch); if (rv.length() < 2) { return "0" + rv; } return rv; } public static String mscPrintableString(final String s) { final StringBuilder sb = new StringBuilder(); final int slen = s.length(); for (int i = 0; i < slen; i++) { final char ch = s.charAt(i); if (isMscPrint(ch)) { sb.append(ch); } else if (ch == 32) { sb.append("[32]"); } else { sb.append("[" + hex2(ch) + "]"); } } return sb.toString(); } // You might get a compiler error here if you have an old compiler /* public static void dp( Object... args) { //dtabprint(); log.info(args[0]); final StringBuilder sb = new StringBuilder(); for ( int i = 1 ; i < args.length ; i++) { sb.append("{"+args[i]+"}"); }; log.info(sb); } */ public static void dp(final String pmt, final int a1) { //dtabprint(); log.info(pmt + "{" + a1 + "}"); } public static void dp(final String pmt, final Object... a) { //dtabprint(); final StringBuilder sb = new StringBuilder(); sb.append(pmt); for (final Object an : a) { sb.append("{" + an + "}"); } log.info(sb); } public static String asc_time_now() { final Date d = new Date(); //return d.toGMTString(); return d.toString(); } public static String s(final int i) { return i + ""; } static public String nthField(final String s, final char ch, final int n) { return nthField(s, ch + "", n); } static public String nthField(final String s, final String ch, final int n) {//0 based int idx; int prev; int cnt = (n > 0 ? n : 0); final int chlen = ch.length(); for (prev = 0, idx = 0; (idx = s.indexOf(ch, prev)) > 0; prev = idx + chlen) { //Utl.di("idx:",idx); //Utl.dis("sofar",idx,s.substring(prev,idx)); if (--cnt < 0) { break; } } if (idx < 0) { return s.substring(prev); } return s.substring(prev, idx); } public static int indexOf(final StringBuffer sb, final char ch, final int startat) { for (int i = startat; i < sb.length(); i++) { if (sb.charAt(i) == ch) { return i; } } return -1; } static public StringBuffer replaceNthField(final StringBuffer sb, final char ch, final int n, final String newval) {// zero based int idx = -1, cnt = (n > 0 ? n : 0); // Find the n'th delim //Utl.dp("replaceNthString:",n); if (n < 0) { return sb; } for (int prev = 0; cnt > 0; prev = idx + 1) { idx = indexOf(sb, ch, prev); //Utl.dp("cnt:",cnt,"idx:",idx); if (idx < 0) { break; } cnt--; //Utl.dis("sofar",idx,s.substring(prev,idx)); } //Utl.dp("End search for nth idx:",idx," cnt = ",cnt); if (cnt > 0) { /* then we need to pad input */ //Utl.dp("pad by cnt:",cnt); //Utl.dp("prev:",prev); while (cnt-- > 0) { sb.append(ch); } // The new field is just appended sb.append(newval); // We are done return sb; } //Utl.dp("cnt:",cnt,"idx:",idx); // Is there a next delimiter final int closer = indexOf(sb, ch, idx + 1); // Utl.dp("closer = ",closer); if (closer > 0) { // Yup, replace the range sb.replace(idx + 1, closer, newval); } else { // No closer sb.replace(idx + 1, sb.length(), newval); } return sb; } static public String replaceNthField(final String s, final char ch, final int n, final String newval) {// zero based final StringBuffer sb = new StringBuffer(s); return replaceNthField(sb, ch, n, newval).toString(); }; /* *********************************************************** HL7 Routines *********************************************************** */ // -------------------------------------- // read_hl7_msg // -------------------------------------- public static String read_hl7_msg(final Reader br) throws IOException { final int ldbv = hl7_read_dbv; //int ccnt = 0; int ach = br.read(); if (ldbv > 0) { dp("ach.1 = ", ach); } if (ach == -1) { dp("Bad socket in first read [read_hl7_msg]"); throw new HL7IOException("EndOfSocket"); } else if (ach == CR) { // skip the CR after EOM ach = br.read(); if (ldbv > 0) { dp("skip cr, leaving ach = ", ach); } } while (ach != BOM) { if (ach == -1) { dp("Bad socket in looking for BOM read [read_hl7_msg]"); throw new HL7IOException("EndOfSocket"); } else if (ldbv > 0) { // sloughing ach dp("slough.ach = ", ach); } ach = br.read(); } final StringBuffer sb = new StringBuffer(); if (ldbv > 0) { dp("After bom=", ach); } ach = br.read(); if (ldbv > 0) { dp("Start collecting:", ach); } while (ach != EOM) { if (ach == -1) { dp("Bad socket in looking for EOM read [read_hl7_msg]"); throw new HL7IOException("EndOfSocket"); } sb.append((char) ach); if (ldbv > 3) { dp("Found:" + sb.length() + " ch:=" + ach); } ach = br.read(); } if (ldbv > 0) { dp("Done collecting ach=" + ach + " sb.length=" + sb.length()); } return sb.toString(); } static String make_ack(final String msg) throws Exception { final int ldbv = hl7_read_dbv; if (!msg.startsWith("MSH")) { dp("Does not start with MSH:", msg); throw new Exception("Bad Message"); } final char fld = msg.charAt(3); final String msh = nthField(msg, "\r", 0); if (ldbv > 0) { dp("msh:", msh); } final String snd_app = nthField(msg, fld, 2), snd_fac = nthField(msg, fld, 3); if (ldbv > 0) { dp("snd_app:" + snd_app + "snd_fac:" + snd_fac); } final StringBuffer sb = new StringBuffer(msh); replaceNthField(sb, fld, 2, nthField(msg, fld, 4)); replaceNthField(sb, fld, 3, nthField(msg, fld, 5)); replaceNthField(sb, fld, 4, nthField(msg, fld, 2)); replaceNthField(sb, fld, 5, nthField(msg, fld, 3)); final String ack = sb.toString() + "\rMSA" + fld + "AA" + fld + nthField(msg, fld, 9) + "\r"; return ack; } public static void send_hl7_msg(final Writer os, final String msg) throws IOException { send_hl7_msg(os, msg, null); } public static void send_hl7_msg(final Writer os, final String msg, final String header) throws IOException { /* \x0b17:MSH|^~\&|XXXX|YYYY\x0d\x1c\x0b HL7 MESSAGE \x1c \x0b = [0][11] = 11 \x0d = [0][13] = 13 \x1c = [1][12] = 1 * 16 + 12 = 28 */ if (header != null) { os.write(11); os.write("17:"); os.write(header); os.write(13); os.write(28); } os.write(11); os.write(msg); os.write(28); os.write(13); os.flush(); } public static String send_rcv_hl7_msg(final String host, final int port, final Writer dsd_w, final Reader dsd_r, final String msg) throws IOException { return send_rcv_hl7_msg(host, port, dsd_w, dsd_r, msg, null); } public static String send_rcv_hl7_msg(final String host, final int port, final Writer dsd_w, final Reader dsd_r, final String msg, final String header) throws IOException { try { send_hl7_msg(dsd_w, msg, header); } catch (final Exception e) { throw new HL7IOException("Could not send HL7 to " + host + ":" + port, e); } try { return read_hl7_msg(dsd_r); } catch (final Exception e) { throw new HL7IOException("Could not receive HL7 from " + host + ":" + port, e); } } public static String send_rcv_hl7_msg(final String host, final int port, final int retries, final String msg) throws IOException { return send_rcv_hl7_msg(host, port, retries, msg, null); } public static String send_rcv_hl7_msg(final String host, final int port, final int retries, final String msg, final String header) throws IOException { final Socket sd = connect(host, port, retries); Writer w; BufferedReader r; try { w = new PrintWriter(new BufferedOutputStream(getOutputStream(host, port, sd))); r = new BufferedReader(new InputStreamReader(getInputStream(host, port, sd))); return send_rcv_hl7_msg(host, port, w, r, msg, header); } finally { sd.close(); } } private static OutputStream getOutputStream(final String host, final int port, final Socket sd) throws IOException { try { return sd.getOutputStream(); } catch (final Exception e) { throw new HL7IOException("Could not open HL7 OutputStream for " + host + ":" + port, e); } } private static InputStream getInputStream(final String host, final int port, final Socket sd) throws IOException { try { return sd.getInputStream(); } catch (final Exception e) { throw new HL7IOException("Could not open HL7 InputStream for " + host + ":" + port, e); } } public static String invoke(final String propHost, final String propPort, final String displayName, final String msg) throws IOException { return invoke(propHost, propPort, displayName, msg, null); } private static String getProp(final String displayName, final String key) { return assertProp(displayName, key, Util.getProperty(key)); } private static String assertProp(final String displayName, final String key, final String value) { if (Util.isEmpty(value)) { throw new RuntimeException("Can't invoke " + displayName + " unless property " + key + " is valued"); } return value; } public static String invoke(final String propHost, final String propPort, final String displayName, final String msg, final String header) throws IOException { return invokeLiteral(getProp(displayName, propHost), getProp(displayName, propPort), displayName, msg, header); } private static String invokeLiteral(final String host, final String port, final String displayName, String msg, final String header) throws IOException { msg = convert_lf_to_cr(msg); log.info("Sending " + displayName + " request to " + host + ":" + port); return send_rcv_hl7_msg(host, Integer.parseInt(port), 20, msg, header); } public static void setTimeoutInMillis(final int millis) { Util.setProperty(PROP_TIMEOUT_IN_MILLIS, Integer.toString(millis)); } public static Socket connect(final String host, final int port, int nrRetries) throws UnknownHostException, IOException { final String prop = Util.getProperty(PROP_TIMEOUT_IN_MILLIS); final int timeout = prop == null ? -1 : Integer.parseInt(prop); while (nrRetries-- >= 0) { try { final Socket rv = new Socket(host, port); if (timeout >= 0) { rv.setSoTimeout(timeout); } return rv; } catch (final UnknownHostException e) { e.fillInStackTrace(); //Utl.dp("connect failed: unknownHost:", host, port); throw e; } catch (final IOException e) { if (nrRetries < 0) { e.fillInStackTrace(); //Utl.dp("connect failed: connection refused:", host, port); throw e; } sleep(10); } } throw new HL7IOException("connect nr retries exceeded:" + host + "|" + port + "|" + nrRetries); } } /* Local Variables: */ /* *special-compile*: "javac -Xemacs HL7IO.java" */ /* *xspecial-compile*: "vaxput HL7IO.java ds:HL7IO.java" */ /* *vms-disable-local-xfer*: nil */ /* *vms-directory-x*: "op nlmput HL7IO.java /a/tmp/." */ /* End: */