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 ***** */
038package org.dcm4che3.tool.qc;
039
040import org.apache.commons.cli.*;
041import org.dcm4che3.data.Attributes;
042import org.dcm4che3.data.Code;
043import org.dcm4che3.data.IDWithIssuer;
044import org.dcm4che3.data.Issuer;
045import org.dcm4che3.json.JSONWriter;
046import org.dcm4che3.tool.common.CLIUtils;
047import org.dcm4che3.tool.qc.test.QCResult;
048import org.slf4j.Logger;
049import org.slf4j.LoggerFactory;
050
051import javax.json.*;
052import javax.json.stream.JsonGenerator;
053import java.io.*;
054import java.net.HttpURLConnection;
055import java.net.URL;
056import java.util.ArrayList;
057import java.util.ResourceBundle;
058
059/**
060 * @author Hesham Elbadawi <bsdreko@gmail.com>
061 *
062 */
063
064public class QC {
065    static final Logger LOG = LoggerFactory.getLogger(QC.class);
066    private static ResourceBundle rb = ResourceBundle
067            .getBundle("org.dcm4che3.tool.qc.messages");
068    private static Options opts;
069    private Code qcRejectionCode;
070    private QCOperation operation;
071    private String targetStudyUID;
072    private String deleteParams;
073    private String studyToDelete;
074    private String seriesToDelete;
075    private String instanceToDelete;
076    private String url;
077    private QCUpdateScope updateScope = QCUpdateScope.NONE;
078    private Attributes targetStudyAttrs = new Attributes();
079    private Attributes targetSeriesAttrs = new Attributes();
080    private Attributes targetPatientAttributes = new Attributes();
081    private Attributes sourcePatientAttributes = new Attributes();
082    private Attributes updateAttrs = new Attributes();
083    private IDWithIssuer pid;
084    private ArrayList<String> moveUIDs;
085    private ArrayList<String> cloneUIDs;
086    private ArrayList<String> mergeUIDs;
087    private ArrayList<String> rrUIDs;
088
089    public QC() {
090
091    }
092
093    public QC(String url, Code qcRejectionCode, QCOperation operation) {
094        this.operation = operation;
095        this.qcRejectionCode = qcRejectionCode;
096        this.url = url;
097    }
098
099    public static void main(String[] args) {
100        CommandLine cl = null;
101        try {
102            cl = parseComandLine(args);
103            QC qc = initArgs(cl);
104            initializeOptions(cl, qc);
105
106            QCResult result = performOperation("Standard CLI tool Call", qc);
107            printResult(result);
108        } catch (Exception e) {
109            System.err.println("qc: " + e.getMessage());
110            System.err.println(rb.getString("try"));
111            System.exit(2);
112        }
113    }
114
115    private static void printResult(QCResult result) {
116        System.out.println("Server Responsed ["+result.getResponseCode()+"]"+": \n"
117                + " with the following message: \n"+ result.getResponseMessage());
118    }
119
120
121    public static QCResult performOperation(String opDescription, QC qc) throws IllegalArgumentException{
122
123        switch (qc.getOperation()){
124
125            case SPLIT:
126            case MERGE:
127            case SEGMENT:
128            case UPDATE:
129            case REJECT:
130            case RESTORE:
131                JsonObject qcMessage = initQCObject(qc);
132                System.out.println(qcMessage.toString());
133                return sendRequest(opDescription, qc, qcMessage);
134            case DELETE:
135                if (checkDelete(qc)) {
136                    return sendDeleteRequest(opDescription, qc);
137                }
138            case PATIENT_LINK:
139            case PATIENT_MERGE:
140            case PATIENT_UNLINK:
141            case PATIENT_UPDATEIDS:
142                JsonArray qcPatientMessage = initPatientObject(qc);
143                qc.setUrl(adjustPatientURL(qc).replace(" ", "%20"));
144                return sendRequest(opDescription, qc, qcPatientMessage);
145            case LINK2MWL:
146            case UPDATE_STUDY_SERIES:
147                JsonObject qfMessage = initQCObject(qc);
148                return sendRequest(opDescription, qc, qfMessage);
149            default:
150                throw new IllegalArgumentException("Incorrect Operation specified");
151        }
152    }
153
154    private static boolean checkDelete(QC qc) {
155
156        if (qc.getPid() != null) {
157            return true;
158        }
159
160        String[] components = qc.getDeleteParams().split(":");
161        int idx = 0;
162        for (String str : components) {
163            switch (idx) {
164                case 0:
165                    qc.setStudyToDelete(str);
166                    break;
167                case 1:
168                    qc.setSeriesToDelete(str);
169                    break;
170                case 2:
171                    qc.setInstanceToDelete(str);
172                    break;
173                default:
174                    return false;
175            }
176            idx++;
177        }
178        return true;
179    }
180    
181    private static String encodeRejectionCode(Code rejCode) {
182        return rejCode.getCodeValue() + ":" + rejCode.getCodeMeaning() + ":" + rejCode.getCodingSchemeDesignator();
183    }
184
185    private static QCResult sendDeleteRequest(String desc, QC qc) {
186        HttpURLConnection connection = null;
187        String bfr = "";
188        QCResult result = null;
189        try {
190            String qcDeleteUrlString = adjustDeleteURL(qc);
191            qcDeleteUrlString += "?rejCode=" + encodeRejectionCode(qc.getQcRejectionCode());
192            qcDeleteUrlString = qcDeleteUrlString.replace(" ", "%20");
193            
194            URL url = new URL(qcDeleteUrlString);
195            
196            connection = (HttpURLConnection) url.openConnection();
197
198            connection.setDoOutput(true);
199            connection.setDoInput(true);
200            connection.setInstanceFollowRedirects(false);
201            connection.setRequestMethod("DELETE");
202
203            int responseCode = connection.getResponseCode();
204            if (responseCode == 200) {
205                InputStream in = connection.getInputStream();
206
207                BufferedReader rdr = new BufferedReader(new InputStreamReader(
208                        in));
209
210                while (rdr.ready())
211                    bfr += rdr.readLine();
212            }
213            result = new QCResult(desc, bfr, responseCode);
214            return result;
215        } catch (Exception e) {
216            System.out.println("Error preparing request or "
217                    + "parsing Server response - " + e);
218        }
219        return result;
220
221    }
222
223    private static String adjustPatientURL(QC qc) {
224        String url = qc.getUrl();
225        return url += "/patients/"+qc.getOperation().toString().split("_")[1].toLowerCase();
226    }
227
228    private static String adjustDeleteURL(QC qc) {
229        String url = qc.getUrl();
230        if (qc.getPid() != null) {
231            url += "/delete/patient/" + qc.getPid().getID();
232            return   url += qc.getPid().getIssuer() != null? "/issuer/"+ qc.getPid().getIssuer().toString(':'):"";
233        }
234        url += "/delete/studies/" + qc.getStudyToDelete();
235        if (qc.getSeriesToDelete() != null)
236            url += "/series/" + qc.getSeriesToDelete();
237        if (qc.getInstanceToDelete() != null)
238            url += "/instances/" + qc.getInstanceToDelete();
239        return url;
240    }
241
242    private static QCResult sendRequest(String desc, QC qc, Object qcMessage) {
243
244        HttpURLConnection connection = null;
245        String bfr = "";
246        QCResult result = null;
247        try {
248            URL url = new URL(qc.getUrl());
249            connection = (HttpURLConnection) url.openConnection();
250
251            connection.setDoOutput(true);
252
253            connection.setDoInput(true);
254
255            connection.setInstanceFollowRedirects(false);
256
257            connection.setRequestMethod("POST");
258            connection.setRequestProperty("Content-Type", "application/json");
259            connection.setRequestProperty("charset", "utf-8");
260
261            connection.setRequestProperty("Accept", "application/json");
262
263            connection.setUseCaches(false);
264
265            writeMessage(connection, (JsonStructure) qcMessage);
266            int rspCode = connection.getResponseCode();
267            InputStream in = rspCode == 200 ? connection.getInputStream() : connection.getErrorStream();
268
269            BufferedReader rdr = new BufferedReader(new InputStreamReader(in));
270            while (rdr.ready())
271                bfr += rdr.readLine();
272            result = new QCResult(desc, bfr, rspCode);
273            return result;
274        } catch (Exception e) {
275            System.out.println("Error preparing request or "
276                    + "parsing Server response - " + e);
277        }
278        connection.disconnect();
279        return result;
280    }
281
282    private static void writeMessage(HttpURLConnection connection,
283                                     JsonStructure qcMessage) throws Exception {
284        DataOutputStream wr;
285        wr = new DataOutputStream(connection.getOutputStream());
286        // wr.writeBytes("Content-Type: application/json" + " \r\n");
287        // wr.writeBytes("\r\n");
288        JsonWriter writer = Json.createWriter(wr);
289        if(qcMessage instanceof JsonObject)
290            writer.writeObject((JsonObject) qcMessage);
291        else
292            writer.writeArray((JsonArray)qcMessage);
293
294        writer.close();
295        wr.close();
296    }
297
298    private static JsonObject initQCObject(QC qc) {
299        mergeUIDs(qc);
300        JsonObjectBuilder builder = Json
301                .createObjectBuilder()
302                .add("operation", qc.getOperation().toString())
303                .add("updateScope", qc.getUpdateScope() == null?
304                        QCUpdateScope.NONE.toString() : qc.getUpdateScope().toString())
305                .add("moveSOPUIDs", toArrayBuilder(qc.getMoveUIDs()))
306                .add("cloneSOPUIDs", toArrayBuilder(qc.getCloneUIDs()))
307                .add("restoreOrRejectUIDs",
308                        toArrayBuilder(qc.getRrUIDs()))
309                .add("targetStudyUID", qc.getTargetStudyUID())
310                .add("qcRejectionCode", toCodeObject(qc.getQcRejectionCode()))
311                .add("targetSeriesData",
312                        toAttributesObject(qc.getTargetSeriesAttrs()))
313                .add("targetStudyData",
314                        toAttributesObject(qc.getTargetStudyAttrs()))
315                .add("updateData", toAttributesObject(qc.getUpdateAttrs()));
316        if(qc.getPid() != null)
317            builder.add("pid", toIDWithIssuerObject(qc.getPid()));
318        return builder.build();
319    }
320
321    private static JsonArray initPatientObject(QC qc) {
322        JsonArrayBuilder builder = Json
323                .createArrayBuilder()
324                .add(toAttributesObject(qc.getSourcePatientAttributes()))
325                .add(toAttributesObject(qc.getTargetPatientAttributes()));
326        return builder.build();
327    }
328
329    protected static void mergeUIDs(QC qc) {
330        if (qc.getOperation() == QCOperation.MERGE) {
331            ArrayList<String> tmpMove = qc.getMoveUIDs() == null ?
332                    new ArrayList<String>() : qc.getMoveUIDs();
333            tmpMove.addAll(qc.getMergeUIDs());
334            qc.setMoveUIDs(tmpMove);
335        }
336    }
337
338    private static JsonObject toIDWithIssuerObject(IDWithIssuer pid) {
339        JsonObjectBuilder builder = Json.createObjectBuilder().add("id", emptyIfNull(pid.getID()));
340        if (pid.getIssuer() != null) {
341            builder.add("issuer", toIssuerObject(pid.getIssuer()));
342        }
343        return builder.build();
344    }
345
346    private static JsonObject toIssuerObject(Issuer issuer) {
347        JsonObjectBuilder builder =  Json
348                .createObjectBuilder()
349                .add("localNamespaceEntityID",
350                        emptyIfNull(issuer.getLocalNamespaceEntityID()));
351        if(issuer.getUniversalEntityID()!=null)
352            builder.add("universalEntityID",
353                    emptyIfNull(issuer.getUniversalEntityID()))
354                    .add("universalEntityIDType",
355                            emptyIfNull(issuer.getUniversalEntityIDType()));
356        return builder.build();
357    }
358
359    private static JsonObject toAttributesObject(Attributes targetSeriesAttrs) {
360        StringWriter strWriter = new StringWriter();
361        JsonGenerator gen = Json.createGenerator(strWriter);
362        JSONWriter writer = new JSONWriter(gen);
363        writer.write(targetSeriesAttrs);
364        gen.flush();
365        gen.close();
366        return Json.createReader(new StringReader(strWriter.toString()))
367                .readObject();
368    }
369
370    private static JsonObject toCodeObject(Code qcRejectionCode) {
371        JsonObjectBuilder codeBuilder = Json
372                .createObjectBuilder()
373                .add("codeValue", emptyIfNull(qcRejectionCode.getCodeValue()))
374                .add("codeMeaning",
375                        emptyIfNull(qcRejectionCode.getCodeMeaning()))
376                .add("codingSchemeDesignator",
377                        emptyIfNull(qcRejectionCode.getCodingSchemeDesignator()));
378        if (qcRejectionCode.getCodingSchemeVersion() != null)
379            codeBuilder.add("codingSchemeVersion",
380                    qcRejectionCode.getCodingSchemeVersion());
381        return codeBuilder.build();
382    }
383
384    private static String emptyIfNull(String obj) {
385        return obj == null ? "" : obj;
386    }
387
388    private static JsonArrayBuilder toArrayBuilder(ArrayList<String> moveUIDs) {
389        JsonArrayBuilder arr = Json.createArrayBuilder();
390        for (String str : moveUIDs)
391            arr.add(str);
392        return arr;
393    }
394
395    private static ArrayList<String> toUIDS(String optionValue) {
396        ArrayList<String> uids = new ArrayList<String>();
397        for (String str : optionValue.split(",")) {
398            uids.add(str);
399        }
400        return uids;
401    }
402
403    public static IDWithIssuer toIDWithIssuer(String optionValue)
404            throws MissingArgumentException {
405        String[] components = optionValue.split(":");
406        if (components.length < 2)
407            throw new MissingArgumentException("Missing issuer information");
408        if (components.length == 2) // pid and local entity uid
409            return new IDWithIssuer(components[0], components[1]);
410        else if (components.length == 3) // pid with universal entity and type
411            return new IDWithIssuer(components[0], new Issuer(null,
412                    components[1], components[2]));
413        else
414            return new IDWithIssuer(components[0], new Issuer(components[1],
415                    components[2], components[3]));
416    }
417
418    private static Code toCode(String codeComponents)
419            throws MissingArgumentException {
420        String[] components = codeComponents.split(":");
421        if (components.length < 3)
422            throw new MissingArgumentException("Invalid code specified "
423                    + " code can be specified as codevalue"
424                    + ":codeschemedesignator"
425                    + ":codemeaning:codeversion where only "
426                    + "version is optional");
427
428        return new Code(components[0], components[2], components.length == 4 ? components[3]
429                : null,components[1]);
430    }
431
432    @SuppressWarnings("static-access")
433    private static CommandLine parseComandLine(String[] args)
434            throws ParseException {
435        opts = new Options();
436        opts.addOption(OptionBuilder.hasArgs().withArgName("[seq/]attr=value")
437                .withValueSeparator('=')
438                .withDescription(rb.getString("updateattributes"))
439                .create("updateattributes"));
440        opts.addOption(OptionBuilder.hasArgs().withArgName("[seq/]attr=value")
441                .withValueSeparator('=')
442                .withDescription(rb.getString("targetpatientattributes"))
443                .create("targetpatientattributes"));
444        opts.addOption(OptionBuilder.hasArgs().withArgName("[seq/]attr=value")
445                .withValueSeparator('=')
446                .withDescription(rb.getString("sourcepatientattributes"))
447                .create("sourcepatientattributes"));
448        CLIUtils.addCommonOptions(opts);
449        opts.addOption(OptionBuilder.hasArgs().withArgName("[seq/]attr=value")
450                .withValueSeparator('=')
451                .withDescription(rb.getString("overrideseriesattributes"))
452                .create("overrideseriesattributes"));
453        opts.addOption(OptionBuilder.hasArgs().withArgName("[seq/]attr=value")
454                .withValueSeparator('=')
455                .withDescription(rb.getString("overridestudyattributes"))
456                .create("overridestudyattributes"));
457        opts.addOption(OptionBuilder.hasArg()
458                .withDescription(rb.getString("cloneuids"))
459                .create("cloneuids"));
460        opts.addOption(OptionBuilder.hasArg()
461                .withDescription(rb.getString("moveuids")).create("moveuids"));
462        opts.addOption(OptionBuilder.hasArg()
463                .withDescription(rb.getString("mergestudyuids"))
464                .create("mergestudyuids"));
465        opts.addOption(OptionBuilder.hasArg()
466                .withDescription(rb.getString("restorerejectuids"))
467                .create("restorerejectuids"));
468        opts.addOption(OptionBuilder.hasArg()
469                .withDescription(rb.getString("pid")).create("pid"));
470        opts.addOption(OptionBuilder.hasArg()
471                .withDescription(rb.getString("updatescope"))
472                .withArgName("<STUDY|SERIES|PATIENT|INSTANCE>")
473                .create("updatescope"));
474        opts.addOption(OptionBuilder.hasArg()
475                .withDescription(rb.getString("deleteobject"))
476                .create("deleteobject"));
477
478        return CLIUtils.parseComandLine(args, opts, rb, QC.class);
479    }
480
481    private static QC initArgs(CommandLine cl) throws MissingArgumentException, IndexOutOfBoundsException {
482
483        String codeComponents = null;
484        String parsedURL = (String) cl.getArgList().get(0);
485        String operation = (String) cl.getArgList().get(1);
486
487        if(cl.getArgList().size() > 2)
488            codeComponents = (String) cl.getArgList().get(2);
489
490        QC qc = new QC(parsedURL, codeComponents!=null?toCode(codeComponents):null,
491                QCOperation.valueOf(operation.toUpperCase()));
492
493        if (cl.getArgList().size() > 3) {
494            qc.setTargetStudyUID((String) cl.getArgList().get(3));
495        }
496
497        return qc;
498    }
499
500    private static void initializeOptions(CommandLine cl, QC qc) throws MissingArgumentException {
501        if (qc.operation == QCOperation.UPDATE)
502            if (!cl.hasOption("update-scope"))
503                throw new MissingArgumentException(
504                        "Missing required argument"
505                                + " update scope for update operation");
506            else
507                qc.setUpdateScope(QCUpdateScope.valueOf(cl
508                        .getOptionValue("update-scope")));
509
510        if (cl.hasOption("overridestudyattributes"))
511            qc.targetStudyAttrs = getAttributes(cl, "overridestudyattributes");
512        if (cl.hasOption("overrideseriesattributes"))
513            qc.setTargetSeriesAttrs(getAttributes(cl,
514                    "overrideseriesattributes"));
515        if (cl.hasOption("updateattributes"))
516            qc.setUpdateAttrs(getAttributes(cl, "updateattributes"));
517        if(cl.hasOption("targetpatientattributes"))
518            qc.setTargetPatientAttributes(getAttributes(cl, "targetpatientattributes"));
519        if(cl.hasOption("sourcepatientattributes"))
520            qc.setSourcePatientAttributes(getAttributes(cl, "sourcepatientattributes"));
521        if (cl.hasOption("pid"))
522            qc.setPid(toIDWithIssuer(cl.getOptionValue("pid")));
523        if (cl.hasOption("moveuids"))
524            qc.setMoveUIDs(toUIDS(cl.getOptionValue("moveuids")));
525        if (cl.hasOption("cloneuids"))
526            qc.setCloneUIDs(toUIDS(cl.getOptionValue("cloneuids")));
527        if (cl.hasOption("restorerejectuids"))
528            qc.setRrUIDs(toUIDS(cl.getOptionValue("restorerejectuids")));
529        if (cl.hasOption("mergestudyuids"))
530            qc.setMergeUIDs(toUIDS(cl.getOptionValue("mergeuids")));
531        if (cl.hasOption("deleteobject")
532                && qc.getOperation() == QCOperation.DELETE)
533            qc.setDeleteParams(cl.getOptionValue("deleteobject"));
534    }
535
536    private static Attributes getAttributes(CommandLine cl, String optionName) {
537        Attributes temp = new Attributes();
538        CLIUtils.addAttributes(temp, cl.getOptionValues(optionName));
539        return temp;
540    }
541
542    public Code getQcRejectionCode() {
543        return qcRejectionCode;
544    }
545
546    public QCOperation getOperation() {
547        return operation;
548    }
549
550    public String getTargetStudyUID() {
551        return targetStudyUID;
552    }
553
554    public String getUrl() {
555        return url;
556    }
557
558    public Attributes getTargetStudyAttrs() {
559        return targetStudyAttrs;
560    }
561
562    public Attributes getTargetSeriesAttrs() {
563        return targetSeriesAttrs;
564    }
565
566    public Attributes getUpdateAttrs() {
567        return updateAttrs;
568    }
569
570    public IDWithIssuer getPid() {
571        return pid;
572    }
573
574    public ArrayList<String> getMoveUIDs() {
575        return moveUIDs == null ? new ArrayList<String>() : moveUIDs;
576    }
577
578    public ArrayList<String> getCloneUIDs() {
579        return cloneUIDs == null ? new ArrayList<String>() : cloneUIDs;
580    }
581
582    public ArrayList<String> getMergeUIDs() {
583        return mergeUIDs == null ? new ArrayList<String>() : mergeUIDs;
584    }
585
586    public ArrayList<String> getRrUIDs() {
587        return rrUIDs == null ? new ArrayList<String>() : rrUIDs;
588    }
589
590    public void setQcRejectionCode(Code qcRejectionCode) {
591        this.qcRejectionCode = qcRejectionCode;
592    }
593
594    public void setOperation(QCOperation operation) {
595        this.operation = operation;
596    }
597
598    public void setTargetStudyUID(String targetStudyUID) {
599        this.targetStudyUID = targetStudyUID;
600    }
601
602    public void setUrl(String url) {
603        this.url = url;
604    }
605
606    public void setTargetStudyAttrs(Attributes targetStudyAttrs) {
607        this.targetStudyAttrs = targetStudyAttrs;
608    }
609
610    public void setTargetSeriesAttrs(Attributes targetSeriesAttrs) {
611        this.targetSeriesAttrs = targetSeriesAttrs;
612    }
613
614    public void setUpdateAttrs(Attributes updateAttrs) {
615        this.updateAttrs = updateAttrs;
616    }
617
618    public void setPid(IDWithIssuer pid) {
619        this.pid = pid;
620    }
621
622    public void setMoveUIDs(ArrayList<String> moveUIDs) {
623        this.moveUIDs = moveUIDs;
624    }
625
626    public void setCloneUIDs(ArrayList<String> cloneUIDs) {
627        this.cloneUIDs = cloneUIDs;
628    }
629
630    public void setMergeUIDs(ArrayList<String> mergeUIDs) {
631        this.mergeUIDs = mergeUIDs;
632    }
633
634    public void setRrUIDs(ArrayList<String> rrUIDs) {
635        this.rrUIDs = rrUIDs;
636    }
637
638    public QCUpdateScope getUpdateScope() {
639        return updateScope;
640    }
641
642    public void setUpdateScope(QCUpdateScope updateScope) {
643        this.updateScope = updateScope;
644    }
645
646    public String getDeleteParams() {
647        return deleteParams;
648    }
649
650    public void setDeleteParams(String deleteParams) {
651        this.deleteParams = deleteParams;
652    }
653
654    public String getStudyToDelete() {
655        return studyToDelete;
656    }
657
658    public void setStudyToDelete(String studyToDelete) {
659        this.studyToDelete = studyToDelete;
660    }
661
662    public String getSeriesToDelete() {
663        return seriesToDelete;
664    }
665
666    public void setSeriesToDelete(String seriesToDelete) {
667        this.seriesToDelete = seriesToDelete;
668    }
669
670    public String getInstanceToDelete() {
671        return instanceToDelete;
672    }
673
674    public void setInstanceToDelete(String instanceToDelete) {
675        this.instanceToDelete = instanceToDelete;
676    }
677
678    public Attributes getTargetPatientAttributes() {
679        return targetPatientAttributes;
680    }
681
682    public void setTargetPatientAttributes(Attributes targetPatientAttributes) {
683        this.targetPatientAttributes = targetPatientAttributes;
684    }
685
686    public Attributes getSourcePatientAttributes() {
687        return sourcePatientAttributes;
688    }
689
690    public void setSourcePatientAttributes(Attributes sourcePatientAttributes) {
691        this.sourcePatientAttributes = sourcePatientAttributes;
692    }
693}