Java tutorial
/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * 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. * * The Original Code is part of dcm4che, an implementation of DICOM(TM) in * Java(TM), hosted at http://sourceforge.net/projects/dcm4che. * * The Initial Developer of the Original Code is * Gunter Zeilinger, Huetteldorferstr. 24/10, 1150 Vienna/Austria/Europe. * Portions created by the Initial Developer are Copyright (C) 2002-2005 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Gunter Zeilinger <gunterze@gmail.com> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ package org.dcm4che2.tool.dcmof; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.OptionGroup; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.dcm4che2.data.BasicDicomObject; import org.dcm4che2.data.DicomObject; import org.dcm4che2.data.UID; import org.dcm4che2.io.ContentHandlerAdapter; import org.dcm4che2.io.DicomInputStream; import org.dcm4che2.io.DicomOutputStream; import org.dcm4che2.io.SAXWriter; import org.dcm4che2.net.Device; import org.dcm4che2.net.NetworkApplicationEntity; import org.dcm4che2.net.NetworkConnection; import org.dcm4che2.net.NewThreadExecutor; import org.dcm4che2.net.TransferCapability; import org.dcm4che2.net.service.VerificationService; import org.dcm4che2.util.CloseUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author gunter zeilinger(gunterze@gmail.com) * @version $Revision: 11855 $ $Date: 2009-06-23 13:11:51 +0200 (Tue, 23 Jun 2009) $ * @since Jan 22, 2006 * */ public class DcmOF { static Logger LOG = LoggerFactory.getLogger(DcmOF.class); private static final int KB = 1024; private static final String USAGE = "dcmof [Options] [<aet>[@<ip>]:]<port>"; private static final String DESCRIPTION = "DICOM Server providing DICOM service of IHE actor Order Filler:\n" + "- Modality Worklist (MWL SCP),\n" + "- Modality Performed Procedure Step (MPPS SCP)\n" + "- Image Availability Notification (IAN SCP)\n" + "- Basic Study Content Notification (SCN SCP) {not specified by IHE}\n" + "listening on specified <port> for incoming association requests. " + "If no local IP address of the network interface is specified " + "connections on any/all local addresses are accepted. " + "If <aet> is specified, only requests with matching called AE " + "title will be accepted.\n" + "Options:"; private static final String EXAMPLE = "\nExample 1: dcmof DCM4CHE_OF:11112 -mwl /var/local/dcmof/mwl\n" + "=> Starts MWL SCP listening on port 11112, accepting association " + "requests with DCM4CHE_OF as called AE title, provides worklist items " + "stored in files in directory /var/local/dcmof/mwl as MWL SCP.\n" + "Example 2: dcmof DCM4CHE_OF:11112 -mpps /tmp -ian /tmp -scn /tmp\n" + "=> Starts MPPS+IAN+SCN SCP listening on port 11112, accepting association " + "requests with DCM4CHE_OF as called AE title, storing received messages " + "to /tmp."; private static String[] TLS1 = { "TLSv1" }; private static String[] SSL3 = { "SSLv3" }; private static String[] NO_TLS1 = { "SSLv3", "SSLv2Hello" }; private static String[] NO_SSL2 = { "TLSv1", "SSLv3" }; private static String[] NO_SSL3 = { "TLSv1", "SSLv2Hello" }; private static char[] SECRET = { 's', 'e', 'c', 'r', 'e', 't' }; private static final String[] ONLY_DEF_TS = { UID.ImplicitVRLittleEndian }; private static final String[] NATIVE_TS = { UID.ExplicitVRLittleEndian, UID.ExplicitVRBigEndian, UID.ImplicitVRLittleEndian }; private static final String[] NATIVE_LE_TS = { UID.ExplicitVRLittleEndian, UID.ImplicitVRLittleEndian }; private final Executor executor; private final Device device; private final NetworkApplicationEntity ae = new NetworkApplicationEntity(); private final NetworkConnection nc = new NetworkConnection(); private String[] tsuids = NATIVE_LE_TS; private boolean indent = false; private boolean comments = false; private String keyStoreURL = "resource:tls/test_sys_2.p12"; private char[] keyStorePassword = SECRET; private char[] keyPassword; private String trustStoreURL = "resource:tls/mesa_certs.jks"; private char[] trustStorePassword = SECRET; public DcmOF(String name) { device = new Device(name); executor = new NewThreadExecutor(name); device.setNetworkApplicationEntity(ae); device.setNetworkConnection(nc); ae.setNetworkConnection(nc); ae.setAssociationAcceptor(true); ae.register(new VerificationService()); } public final void setAEtitle(String aet) { ae.setAETitle(aet); } public final void setHostname(String hostname) { nc.setHostname(hostname); } public final void setPort(int port) { nc.setPort(port); } public final void setTlsProtocol(String[] tlsProtocol) { nc.setTlsProtocol(tlsProtocol); } public final void setTlsWithoutEncyrption() { nc.setTlsWithoutEncyrption(); } public final void setTls3DES_EDE_CBC() { nc.setTls3DES_EDE_CBC(); } public final void setTlsAES_128_CBC() { nc.setTlsAES_128_CBC(); } public final void setTlsNeedClientAuth(boolean needClientAuth) { nc.setTlsNeedClientAuth(needClientAuth); } public final void setKeyStoreURL(String url) { keyStoreURL = url; } public final void setKeyStorePassword(String pw) { keyStorePassword = pw.toCharArray(); } public final void setKeyPassword(String pw) { keyPassword = pw.toCharArray(); } public final void setTrustStorePassword(String pw) { trustStorePassword = pw.toCharArray(); } public final void setTrustStoreURL(String url) { trustStoreURL = url; } public final void setPackPDV(boolean packPDV) { ae.setPackPDV(packPDV); } public final void setAssociationReaperPeriod(int period) { device.setAssociationReaperPeriod(period); } public final void setTcpNoDelay(boolean tcpNoDelay) { nc.setTcpNoDelay(tcpNoDelay); } public final void setRequestTimeout(int timeout) { nc.setRequestTimeout(timeout); } public final void setReleaseTimeout(int timeout) { nc.setReleaseTimeout(timeout); } public final void setSocketCloseDelay(int delay) { nc.setSocketCloseDelay(delay); } public final void setIdleTimeout(int timeout) { ae.setIdleTimeout(timeout); } public final void setDimseRspTimeout(int timeout) { ae.setDimseRspTimeout(timeout); } public final void setMaxPDULengthSend(int maxLength) { ae.setMaxPDULengthSend(maxLength); } public void setMaxPDULengthReceive(int maxLength) { ae.setMaxPDULengthReceive(maxLength); } public final void setReceiveBufferSize(int bufferSize) { nc.setReceiveBufferSize(bufferSize); } public final void setSendBufferSize(int bufferSize) { nc.setSendBufferSize(bufferSize); } private static CommandLine parse(String[] args) { Options opts = new Options(); OptionBuilder.withArgName("name"); OptionBuilder.hasArg(); OptionBuilder.withDescription("set device name, use DCMOF by default"); opts.addOption(OptionBuilder.create("device")); OptionBuilder.withArgName("NULL|3DES|AES"); OptionBuilder.hasArg(); OptionBuilder.withDescription("enable TLS connection without, 3DES or AES encryption"); opts.addOption(OptionBuilder.create("tls")); OptionGroup tlsProtocol = new OptionGroup(); tlsProtocol.addOption(new Option("tls1", "disable the use of SSLv3 and SSLv2 for TLS connections")); tlsProtocol.addOption(new Option("ssl3", "disable the use of TLSv1 and SSLv2 for TLS connections")); tlsProtocol.addOption(new Option("no_tls1", "disable the use of TLSv1 for TLS connections")); tlsProtocol.addOption(new Option("no_ssl3", "disable the use of SSLv3 for TLS connections")); tlsProtocol.addOption(new Option("no_ssl2", "disable the use of SSLv2 for TLS connections")); opts.addOptionGroup(tlsProtocol); opts.addOption("noclientauth", false, "disable client authentification for TLS"); OptionBuilder.withArgName("file|url"); OptionBuilder.hasArg(); OptionBuilder .withDescription("file path or URL of P12 or JKS keystore, resource:tls/test_sys_2.p12 by default"); opts.addOption(OptionBuilder.create("keystore")); OptionBuilder.withArgName("password"); OptionBuilder.hasArg(); OptionBuilder.withDescription("password for keystore file, 'secret' by default"); opts.addOption(OptionBuilder.create("keystorepw")); OptionBuilder.withArgName("password"); OptionBuilder.hasArg(); OptionBuilder .withDescription("password for accessing the key in the keystore, keystore password by default"); opts.addOption(OptionBuilder.create("keypw")); OptionBuilder.withArgName("file|url"); OptionBuilder.hasArg(); OptionBuilder.withDescription("file path or URL of JKS truststore, resource:tls/mesa_certs.jks by default"); opts.addOption(OptionBuilder.create("truststore")); OptionBuilder.withArgName("password"); OptionBuilder.hasArg(); OptionBuilder.withDescription("password for truststore file, 'secret' by default"); opts.addOption(OptionBuilder.create("truststorepw")); OptionBuilder.withArgName("dir"); OptionBuilder.hasArg(); OptionBuilder.withDescription("Activate MWL SCP, providing MWL Items stored in specified directory."); opts.addOption(OptionBuilder.create("mwl")); OptionGroup mpps = new OptionGroup(); OptionBuilder.withArgName("dir"); OptionBuilder.hasArg(); OptionBuilder.withDescription("Activate MPPS SCP, storing received MPPS in specified directory."); mpps.addOption(OptionBuilder.create("mpps")); OptionBuilder.withArgName("dir"); OptionBuilder.hasArg(); OptionBuilder.withDescription( "Activate MPPS SCP, storing XML received MPPS in specified directory in XML format."); mpps.addOption(OptionBuilder.create("mppsxml")); opts.addOptionGroup(mpps); OptionGroup ian = new OptionGroup(); OptionBuilder.withArgName("dir"); OptionBuilder.hasArg(); OptionBuilder.withDescription("Activate IAN SCP, storing received IAN in specified directory."); ian.addOption(OptionBuilder.create("ian")); OptionBuilder.withArgName("dir"); OptionBuilder.hasArg(); OptionBuilder .withDescription("Activate IAN SCP, storing received IAN in specified directory in XML format."); ian.addOption(OptionBuilder.create("ianxml")); opts.addOptionGroup(ian); OptionGroup scn = new OptionGroup(); OptionBuilder.withArgName("dir"); OptionBuilder.hasArg(); OptionBuilder.withDescription("Activate SCN SCP, storing received SCN in specified directory."); scn.addOption(OptionBuilder.create("scn")); OptionBuilder.withArgName("dir"); OptionBuilder.hasArg(); OptionBuilder .withDescription("Activate SCN SCP, storing received SCN in specified directory in XML format."); scn.addOption(OptionBuilder.create("scnxml")); opts.addOptionGroup(scn); opts.addOption("c", "compact", false, "suppress additional whitespaces in XML output"); opts.addOption("C", "comments", false, "include attribute names as comments in XML output"); OptionGroup ts = new OptionGroup(); OptionBuilder.withDescription("accept only default Transfer Syntax."); ts.addOption(OptionBuilder.create("defts")); OptionBuilder.withDescription("accept Explict VR Big Endian Transfer Syntax."); ts.addOption(OptionBuilder.create("bigendian")); opts.addOptionGroup(ts); OptionBuilder.withArgName("maxops"); OptionBuilder.hasArg(); OptionBuilder.withDescription( "maximum number of outstanding operations performed " + "asynchronously, unlimited by default."); opts.addOption(OptionBuilder.create("async")); opts.addOption("pdv1", false, "send only one PDV in one P-Data-TF PDU, " + "pack command and data PDV in one P-DATA-TF PDU by default."); opts.addOption("tcpdelay", false, "set TCP_NODELAY socket option to false, true by default"); OptionBuilder.withArgName("ms"); OptionBuilder.hasArg(); OptionBuilder.withDescription("delay in ms for Socket close after sending A-ABORT, 50ms by default"); opts.addOption(OptionBuilder.create("soclosedelay")); OptionBuilder.withArgName("ms"); OptionBuilder.hasArg(); OptionBuilder.withDescription("timeout in ms for receiving -ASSOCIATE-RQ, 5s by default"); opts.addOption(OptionBuilder.create("requestTO")); OptionBuilder.withArgName("ms"); OptionBuilder.hasArg(); OptionBuilder.withDescription("timeout in ms for receiving A-RELEASE-RP, 5s by default"); opts.addOption(OptionBuilder.create("releaseTO")); OptionBuilder.withArgName("ms"); OptionBuilder.hasArg(); OptionBuilder.withDescription("period in ms to check for outstanding DIMSE-RSP, 10s by default"); opts.addOption(OptionBuilder.create("reaper")); OptionBuilder.withArgName("ms"); OptionBuilder.hasArg(); OptionBuilder.withDescription("timeout in ms for receiving DIMSE-RQ, 60s by default"); opts.addOption(OptionBuilder.create("idleTO")); OptionBuilder.withArgName("KB"); OptionBuilder.hasArg(); OptionBuilder.withDescription("maximal length in KB of received P-DATA-TF PDUs, 16KB by default"); opts.addOption(OptionBuilder.create("rcvpdulen")); OptionBuilder.withArgName("KB"); OptionBuilder.hasArg(); OptionBuilder.withDescription("maximal length in KB of sent P-DATA-TF PDUs, 16KB by default"); opts.addOption(OptionBuilder.create("sndpdulen")); OptionBuilder.withArgName("KB"); OptionBuilder.hasArg(); OptionBuilder.withDescription("set SO_RCVBUF socket option to specified value in KB"); opts.addOption(OptionBuilder.create("sorcvbuf")); OptionBuilder.withArgName("KB"); OptionBuilder.hasArg(); OptionBuilder.withDescription("set SO_SNDBUF socket option to specified value in KB"); opts.addOption(OptionBuilder.create("sosndbuf")); opts.addOption("h", "help", false, "print this message"); opts.addOption("V", "version", false, "print the version information and exit"); CommandLine cl = null; try { cl = new GnuParser().parse(opts, args); } catch (ParseException e) { exit("dcmof: " + e.getMessage()); throw new RuntimeException("unreachable"); } if (cl.hasOption("V")) { Package p = DcmOF.class.getPackage(); System.out.println("dcmof v" + p.getImplementationVersion()); System.exit(0); } if (cl.hasOption("h") || cl.getArgList().size() == 0) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp(USAGE, DESCRIPTION, opts, EXAMPLE); System.exit(0); } return cl; } @SuppressWarnings("unchecked") public static DcmOF main(String[] args) { CommandLine cl = parse(args); DcmOF dcmof = new DcmOF(cl.hasOption("device") ? cl.getOptionValue("device") : "DCMOF"); final List<String> argList = cl.getArgList(); String port = argList.get(0); String[] aetPort = split(port, ':', 1); dcmof.setPort(parseInt(aetPort[1], "illegal port number", 1, 0xffff)); if (aetPort[0] != null) { String[] aetHost = split(aetPort[0], '@', 0); dcmof.setAEtitle(aetHost[0]); if (aetHost[1] != null) { dcmof.setHostname(aetHost[1]); } } if (cl.hasOption("defts")) dcmof.setTransferSyntax(ONLY_DEF_TS); else if (cl.hasOption("bigendian")) dcmof.setTransferSyntax(NATIVE_TS); if (cl.hasOption("reaper")) dcmof.setAssociationReaperPeriod(parseInt(cl.getOptionValue("reaper"), "illegal argument of option -reaper", 1, Integer.MAX_VALUE)); if (cl.hasOption("idleTO")) dcmof.setIdleTimeout(parseInt(cl.getOptionValue("idleTO"), "illegal argument of option -idleTO", 1, Integer.MAX_VALUE)); if (cl.hasOption("requestTO")) dcmof.setRequestTimeout(parseInt(cl.getOptionValue("requestTO"), "illegal argument of option -requestTO", 1, Integer.MAX_VALUE)); if (cl.hasOption("releaseTO")) dcmof.setReleaseTimeout(parseInt(cl.getOptionValue("releaseTO"), "illegal argument of option -releaseTO", 1, Integer.MAX_VALUE)); if (cl.hasOption("soclosedelay")) dcmof.setSocketCloseDelay(parseInt(cl.getOptionValue("soclosedelay"), "illegal argument of option -soclosedelay", 1, 10000)); if (cl.hasOption("rcvpdulen")) dcmof.setMaxPDULengthReceive( parseInt(cl.getOptionValue("rcvpdulen"), "illegal argument of option -rcvpdulen", 1, 10000) * KB); if (cl.hasOption("sndpdulen")) dcmof.setMaxPDULengthSend( parseInt(cl.getOptionValue("sndpdulen"), "illegal argument of option -sndpdulen", 1, 10000) * KB); if (cl.hasOption("sosndbuf")) dcmof.setSendBufferSize( parseInt(cl.getOptionValue("sosndbuf"), "illegal argument of option -sosndbuf", 1, 10000) * KB); if (cl.hasOption("sorcvbuf")) dcmof.setReceiveBufferSize( parseInt(cl.getOptionValue("sorcvbuf"), "illegal argument of option -sorcvbuf", 1, 10000) * KB); dcmof.setPackPDV(!cl.hasOption("pdv1")); dcmof.setTcpNoDelay(!cl.hasOption("tcpdelay")); if (cl.hasOption("async")) dcmof.setMaxOpsPerformed( parseInt(cl.getOptionValue("async"), "illegal argument of option -async", 0, 0xffff)); ArrayList<TransferCapability> tc = new ArrayList<TransferCapability>(); tc.add(new TransferCapability(UID.VerificationSOPClass, ONLY_DEF_TS, TransferCapability.SCP)); if (cl.hasOption("mwl")) dcmof.registerMWLSCP(new File(cl.getOptionValue("mwl")), tc); if (cl.hasOption("mpps")) dcmof.registerMPPSSCP(new File(cl.getOptionValue("mpps")), tc); if (cl.hasOption("mppsxml")) dcmof.registerMPPSXMLSCP(new File(cl.getOptionValue("mppsxml")), tc); if (cl.hasOption("ian")) dcmof.registerIANSCP(new File(cl.getOptionValue("ian")), tc); if (cl.hasOption("ianxml")) dcmof.registerIANXMLSCP(new File(cl.getOptionValue("ianxml")), tc); if (cl.hasOption("scn")) dcmof.registerSCNSCP(new File(cl.getOptionValue("scn")), tc); if (cl.hasOption("scnxml")) dcmof.registerSCNXMLSCP(new File(cl.getOptionValue("scnxml")), tc); dcmof.setComments(cl.hasOption("C")); dcmof.setIndent(!cl.hasOption("c")); dcmof.setTransferCapability(tc.toArray(new TransferCapability[tc.size()])); if (cl.hasOption("tls")) { String cipher = cl.getOptionValue("tls"); if ("NULL".equalsIgnoreCase(cipher)) { dcmof.setTlsWithoutEncyrption(); } else if ("3DES".equalsIgnoreCase(cipher)) { dcmof.setTls3DES_EDE_CBC(); } else if ("AES".equalsIgnoreCase(cipher)) { dcmof.setTlsAES_128_CBC(); } else { exit("Invalid parameter for option -tls: " + cipher); } if (cl.hasOption("tls1")) { dcmof.setTlsProtocol(TLS1); } else if (cl.hasOption("ssl3")) { dcmof.setTlsProtocol(SSL3); } else if (cl.hasOption("no_tls1")) { dcmof.setTlsProtocol(NO_TLS1); } else if (cl.hasOption("no_ssl3")) { dcmof.setTlsProtocol(NO_SSL3); } else if (cl.hasOption("no_ssl2")) { dcmof.setTlsProtocol(NO_SSL2); } dcmof.setTlsNeedClientAuth(!cl.hasOption("noclientauth")); if (cl.hasOption("keystore")) { dcmof.setKeyStoreURL(cl.getOptionValue("keystore")); } if (cl.hasOption("keystorepw")) { dcmof.setKeyStorePassword(cl.getOptionValue("keystorepw")); } if (cl.hasOption("keypw")) { dcmof.setKeyPassword(cl.getOptionValue("keypw")); } if (cl.hasOption("truststore")) { dcmof.setTrustStoreURL(cl.getOptionValue("truststore")); } if (cl.hasOption("truststorepw")) { dcmof.setTrustStorePassword(cl.getOptionValue("truststorepw")); } try { dcmof.initTLS(); } catch (Exception e) { System.err.println("ERROR: Failed to initialize TLS context:" + e.getMessage()); System.exit(2); } } try { dcmof.start(); return dcmof; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } private void setIndent(boolean b) { this.indent = b; } private void setComments(boolean b) { this.comments = b; } private void setTransferSyntax(String[] tsuids) { this.tsuids = tsuids; } private void registerMWLSCP(File dir, ArrayList<TransferCapability> tc) { MWLSCP mwlscp = new MWLSCP(executor, this); mwlscp.setSource(dir); ae.register(mwlscp); tc.add(new TransferCapability(mwlscp.getSopClass(), tsuids, TransferCapability.SCP)); } private void registerMPPSSCP(File dir, ArrayList<TransferCapability> tc) { register(new MPPSSCP(this), dir, tc); } private void registerMPPSXMLSCP(File dir, ArrayList<TransferCapability> tc) { register(new MPPSSCP.XML(this), dir, tc); } private void register(MPPSSCP mppsscp, File dir, ArrayList<TransferCapability> tc) { mppsscp.setDestination(dir); ae.register(mppsscp.getNCreateSCP()); ae.register(mppsscp.getNSetSCP()); tc.add(new TransferCapability(mppsscp.getNCreateSCP().getSopClass(), tsuids, TransferCapability.SCP)); } private void registerIANXMLSCP(File dir, ArrayList<TransferCapability> tc) { register(new IANSCP.XML(this), dir, tc); } private void registerIANSCP(File dir, ArrayList<TransferCapability> tc) { register(new IANSCP(this), dir, tc); } private void register(IANSCP ianscp, File dir, ArrayList<TransferCapability> tc) { ianscp.setDestination(dir); ae.register(ianscp); tc.add(new TransferCapability(ianscp.getSopClass(), tsuids, TransferCapability.SCP)); } private void registerSCNSCP(File dir, ArrayList<TransferCapability> tc) { register(new SCNSCP(this), dir, tc); } private void registerSCNXMLSCP(File dir, ArrayList<TransferCapability> tc) { register(new SCNSCP.XML(this), dir, tc); } private void register(SCNSCP scnscp, File dir, ArrayList<TransferCapability> tc) { scnscp.setDestination(dir); ae.register(scnscp); tc.add(new TransferCapability(scnscp.getSopClass(), tsuids, TransferCapability.SCP)); } private void setTransferCapability(TransferCapability[] tc) { ae.setTransferCapability(tc); } private void setMaxOpsPerformed(int maxOps) { ae.setMaxOpsPerformed(maxOps); } public void start() throws IOException { device.startListening(executor); LOG.info("Order filler server listening on port " + nc.getPort()); } public void stop() { if (device != null) device.stopListening(); LOG.info("Order filler server stopped on " + nc.getPort()); } private static String[] split(String s, char delim, int defPos) { String[] s2 = new String[2]; s2[defPos] = s; int pos = s.indexOf(delim); if (pos != -1) { s2[0] = s.substring(0, pos); s2[1] = s.substring(pos + 1); } return s2; } private static void exit(String msg) { System.err.println(msg); System.err.println("Try 'dcmof -h' for more information."); System.exit(1); } private static int parseInt(String s, String errPrompt, int min, int max) { try { int i = Integer.parseInt(s); if (i >= min && i <= max) return i; } catch (NumberFormatException e) { // parameter is not a valid integer; fall through to exit } exit(errPrompt); throw new RuntimeException(); } void storeAsXML(File f, DicomObject data) throws Exception { LOG.info("M-WRITE " + f); SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance(); TransformerHandler th = tf.newTransformerHandler(); if (indent) th.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes"); FileOutputStream fos = null; try { fos = new FileOutputStream(f); th.setResult(new StreamResult(fos)); new SAXWriter(th, comments ? th : null).write(data); } finally { if (fos != null) { try { fos.close(); } catch (Exception ioe) { // ignore } } } } void storeAsDICOM(File f, DicomObject data) throws Exception { LOG.info("M-WRITE " + f); DicomOutputStream out = new DicomOutputStream(new FileOutputStream(f)); try { out.writeDicomFile(data); } finally { CloseUtils.safeClose(out); } } DicomObject load(File f) throws Exception { LOG.info("M-READ " + f); return f.getName().endsWith(".xml") ? loadXML(f) : loadDICOM(f); } private DicomObject loadDICOM(File f) throws Exception { DicomInputStream in = new DicomInputStream(f); try { return in.readDicomObject(); } finally { in.close(); } } private DicomObject loadXML(File f) throws Exception { DicomObject dcmobj = new BasicDicomObject(); SAXParser p = SAXParserFactory.newInstance().newSAXParser(); ContentHandlerAdapter ch = new ContentHandlerAdapter(dcmobj); p.parse(f, ch); return dcmobj; } public void initTLS() throws GeneralSecurityException, IOException { KeyStore keyStore = loadKeyStore(keyStoreURL, keyStorePassword); KeyStore trustStore = loadKeyStore(trustStoreURL, trustStorePassword); device.initTLS(keyStore, keyPassword != null ? keyPassword : keyStorePassword, trustStore); } private static KeyStore loadKeyStore(String url, char[] password) throws GeneralSecurityException, IOException { KeyStore key = KeyStore.getInstance(toKeyStoreType(url)); InputStream in = openFileOrURL(url); try { key.load(in, password); } finally { in.close(); } return key; } private static InputStream openFileOrURL(String url) throws IOException { if (url.startsWith("resource:")) { return DcmOF.class.getClassLoader().getResourceAsStream(url.substring(9)); } try { return new URL(url).openStream(); } catch (MalformedURLException e) { return new FileInputStream(url); } } private static String toKeyStoreType(String fname) { return fname.endsWith(".p12") || fname.endsWith(".P12") ? "PKCS12" : "JKS"; } }