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) 2011
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.mppsscu.test;
040
041import static org.junit.Assert.assertTrue;
042
043import java.io.File;
044import java.io.IOException;
045import java.security.GeneralSecurityException;
046import java.text.MessageFormat;
047import java.util.ArrayList;
048import java.util.Arrays;
049import java.util.concurrent.ExecutorService;
050import java.util.concurrent.Executors;
051import java.util.concurrent.ScheduledExecutorService;
052
053import org.dcm4che3.data.Attributes;
054import org.dcm4che3.data.Tag;
055import org.dcm4che3.data.UID;
056import org.dcm4che3.net.ApplicationEntity;
057import org.dcm4che3.net.Association;
058import org.dcm4che3.net.Connection;
059import org.dcm4che3.net.Device;
060import org.dcm4che3.net.DimseRSPHandler;
061import org.dcm4che3.net.IncompatibleConnectionException;
062import org.dcm4che3.net.Status;
063import org.dcm4che3.tool.common.test.TestResult;
064import org.dcm4che3.tool.common.test.TestTool;
065import org.dcm4che3.tool.mppsscu.MppsSCU;
066import org.dcm4che3.util.TagUtils;
067
068/**
069 * @author Umberto Cappellini <umberto.cappellini@agfa.com>
070 * @author Hesham Elbadawi <bsdreko@gmail.com>
071 */
072public class MppsTool implements TestTool{
073
074    private String host;
075    private int port;
076    private String aeTitle;
077    private Device device;
078    private Connection conn;
079    private String sourceAETitle;
080    private File baseDirectory;
081
082    private int nCreateSent;  
083    private int nCreateWarnings;    
084    private int nCreateFailures;
085    private int nSetSent;  
086    private int nSetFailures;
087    private ArrayList<Attributes> nSetcmdRSP = new ArrayList<Attributes>();
088    private ArrayList<Attributes> nCreatecmdRSP = new ArrayList<Attributes>();
089    private TestResult result;
090    
091    /**
092     * @param host
093     * @param port
094     * @param aeTitle
095     * @param baseDirectory
096     * @param conn 
097     */
098    public MppsTool(String host, int port, String aeTitle, File baseDirectory, Device device, String sourceAETitle, Connection conn) {
099        super();
100        this.host = host;
101        this.port = port;
102        this.aeTitle = aeTitle;
103        this.baseDirectory = baseDirectory;
104        this.sourceAETitle = sourceAETitle;
105        this.device = device;
106        this.conn = conn;
107    }
108
109    public void mppsscu(String testDescription, String fileName) throws IOException, InterruptedException,
110            IncompatibleConnectionException, GeneralSecurityException {
111        
112        long t1, t2, t3;
113        
114        File file = new File(baseDirectory, fileName);
115        
116        assertTrue(
117                "file or directory does not exists: " + file.getAbsolutePath(),
118                file.exists());
119        
120        device.setInstalled(true);
121        ApplicationEntity ae = new ApplicationEntity(sourceAETitle);
122        device.addApplicationEntity(ae);
123        ae.addConnection(conn);
124        
125        final MppsSCU main = new MppsSCU(ae);
126        
127        main.setRspHandlerFactory(new MppsSCU.RSPHandlerFactory() {
128            
129            @Override
130            public DimseRSPHandler createDimseRSPHandlerForNCreate(final MppsSCU.MppsWithIUID mppsWithUID) {
131                return new DimseRSPHandler(0) {
132                    @Override
133                    public void onDimseRSP(Association as, Attributes cmd,
134                            Attributes data) {
135                        
136                        switch(cmd.getInt(Tag.Status, -1)) {
137                        case Status.Success:
138                        case Status.AttributeListError:
139                        case Status.AttributeValueOutOfRange:
140                            mppsWithUID.iuid = cmd.getString(
141                                    Tag.AffectedSOPInstanceUID, mppsWithUID.iuid);
142                            main.addCreatedMpps(mppsWithUID);
143                        }
144                        
145                        super.onDimseRSP(as, cmd, data);
146                        MppsTool.this.onNCreateRSP(cmd);
147                    }
148                };
149            }
150            
151            @Override
152            public DimseRSPHandler createDimseRSPHandlerForNSet() {
153                
154                return new DimseRSPHandler(0) {
155                    
156                    @Override
157                    public void onDimseRSP(Association as, Attributes cmd, Attributes data) {
158                        
159                        super.onDimseRSP(as, cmd, data);
160                        MppsTool.this.onNSetRSP(cmd);
161                    }
162                };
163            }
164
165        });
166
167        // configure
168        main.getAAssociateRQ().setCalledAET(aeTitle);
169        main.getRemoteConnection().setHostname(host);
170        main.getRemoteConnection().setPort(port);
171        main.setTransferSyntaxes(new String[]{UID.ImplicitVRLittleEndian, UID.ExplicitVRLittleEndian, UID.ExplicitVRBigEndianRetired});
172      //ensure secure connection
173        main.getRemoteConnection().setTlsCipherSuites(conn.getTlsCipherSuites());
174        main.getRemoteConnection().setTlsProtocols(conn.tlsProtocols());
175        main.setAttributes(new Attributes());
176
177        // scan
178        t1 = System.currentTimeMillis();
179        main.scanFiles(Arrays.asList(file.getAbsolutePath()), false); //do not printout
180        t2 = System.currentTimeMillis();
181
182        // create executor
183        ExecutorService executorService = Executors.newSingleThreadExecutor();
184        ScheduledExecutorService scheduledExecutorService = Executors
185                .newSingleThreadScheduledExecutor();
186        device.setExecutor(executorService);
187        device.setScheduledExecutor(scheduledExecutorService);
188
189        // open and send
190        try {
191            main.open();
192
193            t1 = System.currentTimeMillis();
194            main.createMpps();
195            t2 = System.currentTimeMillis();
196            main.updateMpps();
197            t3 = System.currentTimeMillis();
198        } finally {
199            main.close();
200            executorService.shutdown();
201            scheduledExecutorService.shutdown();
202        }
203
204        init(new MppsResult(testDescription, fileName, 
205                nCreateSent, nCreateWarnings, nCreateFailures, 
206                nSetSent, nSetFailures, (t2-t1), (t3-t2), nCreatecmdRSP, nSetcmdRSP));
207    }
208
209    private void onNCreateRSP(Attributes cmd) {
210        nCreatecmdRSP.add(cmd);
211        int status = cmd.getInt(Tag.Status, -1);
212        switch (status) {
213        case Status.Success:
214            ++nCreateSent;
215            break;
216        case Status.CoercionOfDataElements:
217        case Status.AttributeListError:
218        case Status.AttributeValueOutOfRange:
219            ++nCreateSent;
220            ++nCreateWarnings;
221            break;
222        default:
223            ++nCreateFailures;
224            System.err.println(MessageFormat.format("error",
225                    TagUtils.shortToHexString(status)));
226            System.err.println(cmd);
227        }
228    }
229
230    private void onNSetRSP(Attributes cmd) {
231        nSetcmdRSP.add(cmd);
232        int status = cmd.getInt(Tag.Status, -1);
233        switch (status) {
234        case Status.Success:
235            ++nSetSent;
236            break;
237        default:
238            ++nSetFailures;
239            System.err.println(MessageFormat.format("error",
240                    TagUtils.shortToHexString(status)));
241            System.err.println(cmd);
242        }
243    }
244
245    @Override
246    public void init(TestResult result) {
247        this.result = result;
248    }
249
250    @Override
251    public TestResult getResult() {
252        return this.result;
253    }
254
255}