001/* ***** BEGIN LICENSE BLOCK ***** 002 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 003 * 004 * The contents of this file are subject to the Mozilla Public License Version 005 * 1.1 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * http://www.mozilla.org/MPL/ 008 * 009 * Software distributed under the License is distributed on an "AS IS" basis, 010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 011 * for the specific language governing rights and limitations under the 012 * License. 013 * 014 * The Original Code is part of dcm4che, an implementation of DICOM(TM) in 015 * Java(TM), hosted at https://github.com/gunterze/dcm4che. 016 * 017 * The Initial Developer of the Original Code is 018 * Agfa Healthcare. 019 * Portions created by the Initial Developer are Copyright (C) 2012 020 * the Initial Developer. All Rights Reserved. 021 * 022 * Contributor(s): 023 * See @authors listed below 024 * 025 * Alternatively, the contents of this file may be used under the terms of 026 * either the GNU General Public License Version 2 or later (the "GPL"), or 027 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 028 * in which case the provisions of the GPL or the LGPL are applicable instead 029 * of those above. If you wish to allow use of your version of this file only 030 * under the terms of either the GPL or the LGPL, and not to allow others to 031 * use your version of this file under the terms of the MPL, indicate your 032 * decision by deleting the provisions above and replace them with the notice 033 * and other provisions required by the GPL or the LGPL. If you do not delete 034 * the provisions above, a recipient may use your version of this file under 035 * the terms of any one of the MPL, the GPL or the LGPL. 036 * 037 * ***** END LICENSE BLOCK ***** */ 038 039package org.dcm4che3.tool.hl7pix; 040 041import java.io.IOException; 042import java.net.Socket; 043import java.security.GeneralSecurityException; 044import java.util.List; 045import java.util.ResourceBundle; 046 047import org.apache.commons.cli.CommandLine; 048import org.apache.commons.cli.MissingOptionException; 049import org.apache.commons.cli.OptionBuilder; 050import org.apache.commons.cli.Options; 051import org.apache.commons.cli.ParseException; 052import org.dcm4che3.hl7.HL7Message; 053import org.dcm4che3.hl7.HL7Segment; 054import org.dcm4che3.hl7.MLLPConnection; 055import org.dcm4che3.net.Connection; 056import org.dcm4che3.net.Device; 057import org.dcm4che3.net.IncompatibleConnectionException; 058import org.dcm4che3.tool.common.CLIUtils; 059 060/** 061 * @author Gunter Zeilinger <gunterze@gmail.com> 062 * 063 */ 064public class HL7Pix extends Device { 065 066 private static ResourceBundle rb = 067 ResourceBundle.getBundle("org.dcm4che3.tool.hl7pix.messages"); 068 069 private final Connection conn = new Connection(); 070 private final Connection remote = new Connection(); 071 private String sendingApplication = "hl7pix^dcm4che"; 072 private String receivingApplication = ""; 073 private String charset; 074 075 private Socket sock; 076 private MLLPConnection mllp; 077 078 public HL7Pix() throws IOException { 079 super("hl7pix"); 080 addConnection(conn); 081 } 082 083 public String getSendingApplication() { 084 return sendingApplication; 085 } 086 087 public void setSendingApplication(String sendingApplication) { 088 this.sendingApplication = sendingApplication; 089 } 090 091 public String getReceivingApplication() { 092 return receivingApplication; 093 } 094 095 public void setReceivingApplication(String receivingApplication) { 096 this.receivingApplication = receivingApplication; 097 } 098 099 public void setCharacterSet(String charset) { 100 this.charset = charset; 101 } 102 103 private static CommandLine parseComandLine(String[] args) 104 throws ParseException{ 105 Options opts = new Options(); 106 addConnectOption(opts); 107 addBindOption(opts); 108 addCharsetOption(opts); 109 CLIUtils.addResponseTimeoutOption(opts); 110 CLIUtils.addSocketOptions(opts); 111 CLIUtils.addTLSOptions(opts); 112 CLIUtils.addCommonOptions(opts); 113 return CLIUtils.parseComandLine(args, opts, rb, HL7Pix.class); 114 } 115 116 @SuppressWarnings("static-access") 117 private static void addCharsetOption(Options opts) { 118 opts.addOption(OptionBuilder 119 .withLongOpt("charset") 120 .hasArg() 121 .withArgName("name") 122 .withDescription(rb.getString("charset")) 123 .create(null)); 124 } 125 126 @SuppressWarnings("static-access") 127 private static void addConnectOption(Options opts) { 128 opts.addOption(OptionBuilder 129 .hasArg() 130 .withArgName("app^fac@host:port") 131 .withDescription(rb.getString("connect")) 132 .withLongOpt("connect") 133 .create("c")); 134 opts.addOption(OptionBuilder 135 .hasArg() 136 .withArgName("[user:password@]host:port") 137 .withDescription(rb.getString("proxy")) 138 .withLongOpt("proxy") 139 .create(null)); 140 CLIUtils.addConnectTimeoutOption(opts); 141 } 142 143 @SuppressWarnings("static-access") 144 private static void addBindOption(Options opts) { 145 opts.addOption(OptionBuilder 146 .hasArg() 147 .withArgName("app^fac[@ip]") 148 .withDescription(rb.getString("bind")) 149 .withLongOpt("bind") 150 .create("b")); 151 } 152 153 private static void configureConnect(HL7Pix hl7pix, CommandLine cl) 154 throws MissingOptionException, ParseException { 155 String appAtHostPort = cl.getOptionValue("c"); 156 if (appAtHostPort == null) 157 throw new MissingOptionException( 158 CLIUtils.rb.getString("missing-connect-opt")); 159 160 String[] appHostPort = HL7Segment.split(appAtHostPort , '@'); 161 if (appHostPort.length != 2) 162 throw new ParseException(CLIUtils.rb.getString("invalid-connect-opt")); 163 164 String[] hostPort = HL7Segment.split(appHostPort[1], ':'); 165 if (hostPort.length != 2) 166 throw new ParseException(CLIUtils.rb.getString("invalid-connect-opt")); 167 168 hl7pix.setReceivingApplication(appHostPort[0]); 169 hl7pix.remote.setHostname(hostPort[0]); 170 hl7pix.remote.setPort(Integer.parseInt(hostPort[1])); 171 hl7pix.remote.setHttpProxy(cl.getOptionValue("proxy")); 172 } 173 174 private static void configureBind(HL7Pix hl7pix, CommandLine cl) { 175 String appAtHost = cl.getOptionValue("b"); 176 if (appAtHost != null) { 177 String[] appHost = HL7Segment.split(appAtHost, '@'); 178 hl7pix.setSendingApplication(appHost[0]); 179 if (appHost.length > 1) 180 hl7pix.conn.setHostname(appHost[1]); 181 } 182 } 183 184 @SuppressWarnings("unchecked") 185 public static void main(String[] args) { 186 try { 187 CommandLine cl = parseComandLine(args); 188 HL7Pix main = new HL7Pix(); 189 configureConnect(main, cl); 190 configureBind(main, cl); 191 CLIUtils.configure(main.conn, cl); 192 main.setCharacterSet(cl.getOptionValue("charset")); 193 main.remote.setTlsProtocols(main.conn.tlsProtocols()); 194 main.remote.setTlsCipherSuites(main.conn.getTlsCipherSuites()); 195 List<String> argList = cl.getArgList(); 196 if (argList.isEmpty()) 197 throw new ParseException(rb.getString("missing")); 198 try { 199 main.open(); 200 main.query(argList.get(0), 201 argList.subList(1, argList.size()).toArray(new String[0])); 202 } finally { 203 main.close(); 204 } 205 } catch (ParseException e) { 206 System.err.println("hl7pix: " + e.getMessage()); 207 System.err.println(rb.getString("try")); 208 System.exit(2); 209 } catch (Exception e) { 210 System.err.println("hl7pix: " + e.getMessage()); 211 e.printStackTrace(); 212 System.exit(2); 213 } 214 } 215 216 public void open() throws IOException, IncompatibleConnectionException, GeneralSecurityException { 217 sock = conn.connect(remote); 218 sock.setSoTimeout(conn.getResponseTimeout()); 219 mllp = new MLLPConnection(sock); 220 } 221 222 public void close() { 223 conn.close(sock); 224 } 225 226 public void query(String pid, String[] domains) throws IOException { 227 HL7Message qbp = HL7Message.makePixQuery(pid, domains); 228 HL7Segment msh = qbp.get(0); 229 msh.setSendingApplicationWithFacility(sendingApplication); 230 msh.setReceivingApplicationWithFacility(receivingApplication); 231 msh.setField(17, charset); 232 mllp.writeMessage(qbp.getBytes(charset)); 233 if (mllp.readMessage() == null) 234 throw new IOException("Connection closed by receiver"); 235 } 236}