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.net;
040
041import org.dcm4che3.data.Tag;
042import org.dcm4che3.data.Attributes;
043import org.dcm4che3.data.VR;
044import org.dcm4che3.util.UIDUtils;
045
046/**
047 * @author Gunter Zeilinger <gunterze@gmail.com>
048 *
049 */
050public class Commands {
051
052    public static final int NO_DATASET = 0x0101;
053    private static int withDatasetType = 0x0000;
054
055    public static Attributes mkCStoreRQ(int msgId, String cuid, String iuid,
056            int priority)  {
057       Attributes rq = mkRQ(msgId, 0x0001, withDatasetType);
058       rq.setString(Tag.AffectedSOPClassUID, VR.UI, cuid);
059       rq.setString(Tag.AffectedSOPInstanceUID, VR.UI, iuid);
060       rq.setInt(Tag.Priority, VR.US, priority);
061       return rq;
062    }
063
064    public static Attributes mkCStoreRQ(int msgId, String cuid, String iuid,
065            int priority, String moveOriginatorAET, int moveOriginatorMsgId) {
066       Attributes rq = mkCStoreRQ(msgId, cuid, iuid, priority);
067       rq.setString(Tag.MoveOriginatorApplicationEntityTitle, VR.AE,
068               moveOriginatorAET);
069       rq.setInt(Tag.MoveOriginatorMessageID, VR.US, moveOriginatorMsgId);
070       return rq;
071    }
072
073    public static Attributes mkCStoreRSP(Attributes cmd, int status) {
074        return mkRSP(cmd, status, Dimse.C_STORE_RQ);
075    }
076
077    public static Attributes mkCFindRQ(int msgId, String cuid, int priority) {
078       Attributes rq = mkRQ(msgId, 0x0020, withDatasetType);
079       rq.setString(Tag.AffectedSOPClassUID, VR.UI, cuid);
080       rq.setInt(Tag.Priority, VR.US, priority);
081       return rq;
082    }
083
084    public static Attributes mkCFindRSP(Attributes cmd, int status) {
085        return mkRSP(cmd, status, Dimse.C_FIND_RQ);
086    }
087
088    public static Attributes mkCGetRQ(int msgId, String cuid, int priority) {
089       Attributes rq = mkRQ(msgId, 0x0010, withDatasetType);
090       rq.setString(Tag.AffectedSOPClassUID, VR.UI, cuid);
091       rq.setInt(Tag.Priority, VR.US, priority);
092       return rq;
093    }
094
095    public static Attributes mkCGetRSP(Attributes cmd, int status) {
096        return mkRSP(cmd, status, Dimse.C_GET_RQ);
097    }
098
099    public static Attributes mkCMoveRQ(int msgId, String cuid, int priority,
100            String destination) {
101       Attributes rq = mkRQ(msgId, 0x0021, withDatasetType);
102       rq.setString(Tag.AffectedSOPClassUID, VR.UI, cuid);
103       rq.setInt(Tag.Priority, VR.US, priority);
104       rq.setString(Tag.MoveDestination, VR.AE, destination);
105       return rq;
106    }
107
108    public static Attributes mkCMoveRSP(Attributes cmd, int status) {
109        return mkRSP(cmd, status, Dimse.C_MOVE_RQ);
110    }
111
112    public static Attributes mkCCancelRQ(int msgId) {
113        Attributes rq = new Attributes();
114        rq.setInt(Tag.CommandField, VR.US, Dimse.C_CANCEL_RQ.commandField());
115        rq.setInt(Tag.CommandDataSetType, VR.US, NO_DATASET);
116        rq.setInt(Tag.MessageIDBeingRespondedTo, VR.US, msgId);
117        return rq;
118    }
119
120    public static Attributes mkCEchoRQ(int msgId, String cuid) {
121       Attributes rq = mkRQ(msgId, 0x0030, NO_DATASET);
122       rq.setString(Tag.AffectedSOPClassUID, VR.UI, cuid);
123       return rq;
124    }
125
126    public static Attributes mkEchoRSP(Attributes cmd, int status) {
127        return mkRSP(cmd, status, Dimse.C_ECHO_RQ);
128    }
129
130    public static Attributes mkNEventReportRQ(int msgId, String cuid,
131            String iuid, int eventTypeID, Attributes data) {
132       Attributes rq = mkRQ(msgId, 0x0100,
133               data == null ? NO_DATASET : withDatasetType);
134       rq.setString(Tag.AffectedSOPClassUID, VR.UI, cuid);
135       rq.setString(Tag.AffectedSOPInstanceUID, VR.UI, iuid);
136       rq.setInt(Tag.EventTypeID, VR.US, eventTypeID);
137       return rq;
138    }
139
140    public static Attributes mkNEventReportRSP(Attributes cmd, int status) {
141        return mkRSP(cmd, status, Dimse.N_EVENT_REPORT_RQ);
142    }
143
144    public static Attributes mkNGetRQ(int msgId, String cuid, String iuid,
145            int[] tags) {
146       Attributes rq = mkRQ(msgId, 0x0110, NO_DATASET);
147       rq.setString(Tag.RequestedSOPClassUID, VR.UI, cuid);
148       rq.setString(Tag.RequestedSOPInstanceUID, VR.UI, iuid);
149       if (tags != null)
150           rq.setInt(Tag.AttributeIdentifierList, VR.AT, tags);
151       return rq;
152    }
153
154    public static Attributes mkNGetRSP(Attributes cmd, int status) {
155        return mkRSP(cmd, status, Dimse.N_GET_RQ);
156    }
157
158    public static Attributes mkNSetRQ(int msgId, String cuid, String iuid) {
159        Attributes rq = mkRQ(msgId, 0x0120, withDatasetType);
160        rq.setString(Tag.RequestedSOPClassUID, VR.UI, cuid);
161        rq.setString(Tag.RequestedSOPInstanceUID, VR.UI, iuid);
162        return rq;
163    }
164
165    public static Attributes mkNSetRSP(Attributes cmd, int status) {
166        return mkRSP(cmd, status, Dimse.N_SET_RQ);
167    }
168
169    public static Attributes mkNActionRQ(int msgId, String cuid,
170            String iuid, int actionTypeID, Attributes data) {
171       Attributes rq = mkRQ(msgId, 0x0130, 
172               data == null ? NO_DATASET : withDatasetType);
173       rq.setString(Tag.RequestedSOPClassUID, VR.UI, cuid);
174       rq.setString(Tag.RequestedSOPInstanceUID, VR.UI, iuid);
175       rq.setInt(Tag.ActionTypeID, VR.US, actionTypeID);
176       return rq;
177    }
178
179    public static Attributes mkNActionRSP(Attributes cmd, int status) {
180        return mkRSP(cmd, status, Dimse.N_ACTION_RQ);
181    }
182
183    public static Attributes mkNCreateRQ(int msgId, String cuid, String iuid) {
184        Attributes rq = mkRQ(msgId, 0x0140, withDatasetType);
185        rq.setString(Tag.AffectedSOPClassUID, VR.UI, cuid);
186        if (iuid != null)
187            rq.setString(Tag.AffectedSOPInstanceUID, VR.UI, iuid);
188        return rq;
189    }
190
191    public static Attributes mkNCreateRSP(Attributes cmd, int status) {
192        String iuid = cmd.getString(Tag.AffectedSOPInstanceUID);
193        if (iuid == null)
194            cmd.setString(Tag.AffectedSOPInstanceUID, VR.UI, UIDUtils.createUID());
195        return mkRSP(cmd, status, Dimse.N_CREATE_RQ);
196    }
197
198    public static Attributes mkNDeleteRQ(int msgId, String cuid, String iuid) {
199        Attributes rq = mkRQ(msgId, 0x0150, NO_DATASET);
200        rq.setString(Tag.RequestedSOPClassUID, VR.UI, cuid);
201        rq.setString(Tag.RequestedSOPInstanceUID, VR.UI, iuid);
202        return rq;
203    }    
204
205    public static Attributes mkNDeleteRSP(Attributes cmd, int status) {
206        return mkRSP(cmd, status, Dimse.N_DELETE_RQ);
207    }
208
209    private static Attributes mkRQ(int msgId, int cmdField, int datasetType) {
210        Attributes rsp = new Attributes();
211        rsp.setInt(Tag.MessageID, VR.US, msgId);
212        rsp.setInt(Tag.CommandField, VR.US, cmdField);
213        rsp.setInt(Tag.CommandDataSetType, VR.US, datasetType);
214        return rsp;
215    }
216
217    public static Attributes mkRSP(Attributes rq, int status, Dimse rqCmd) {
218        Attributes rsp = new Attributes();
219        rsp.setInt(Tag.CommandField, VR.US, rqCmd.commandFieldOfRSP());
220        rsp.setInt(Tag.Status, VR.US, status);
221        rsp.setInt(Tag.MessageIDBeingRespondedTo, VR.US,
222                rq.getInt(Tag.MessageID, 0));
223        rsp.setString(Tag.AffectedSOPClassUID, VR.UI,
224                rq.getString(rqCmd.tagOfSOPClassUID()));
225        int tagOfIUID = rqCmd.tagOfSOPInstanceUID();
226        if (tagOfIUID != 0)
227            rsp.setString(Tag.AffectedSOPInstanceUID, VR.UI,
228                    rq.getString(tagOfIUID));
229        return rsp;
230    }
231
232    public static void initNumberOfSuboperations(Attributes rsp,
233            int remaining) {
234        rsp.setInt(Tag.NumberOfRemainingSuboperations, VR.US, remaining);
235        rsp.setInt(Tag.NumberOfCompletedSuboperations, VR.US, 0);
236        rsp.setInt(Tag.NumberOfFailedSuboperations, VR.US, 0);
237        rsp.setInt(Tag.NumberOfWarningSuboperations, VR.US, 0);
238    }
239
240    public static void incNumberOfSuboperations(int tag, Attributes rsp) {
241        synchronized (rsp) {
242            rsp.setInt(tag, VR.US, rsp.getInt(tag, 0) + 1);
243            rsp.setInt(Tag.NumberOfRemainingSuboperations, VR.US, 
244                    rsp.getInt(Tag.NumberOfRemainingSuboperations, 1) - 1);
245        }
246    }
247
248    public static int getWithDatasetType() {
249        return withDatasetType;
250    }
251
252    public static void setWithDatasetType(int withDatasetType) {
253        if (withDatasetType == NO_DATASET
254                || (withDatasetType & 0xffff0000) != 0)
255            throw new IllegalArgumentException("withDatasetType: " 
256                    + Integer.toHexString(withDatasetType) + "H");
257        Commands.withDatasetType = withDatasetType;
258    }
259
260    public static boolean hasDataset(Attributes cmd) {
261        return cmd.getInt(Tag.CommandDataSetType, 0) != NO_DATASET;
262    }
263
264}