001/**
002 * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
003 *
004 * This file is part of Dicoogle/dicoogle.
005 *
006 * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * Dicoogle/dicoogle is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package pt.ua.dicoogle.server.queryretrieve;
020
021import aclmanager.core.LuceneQueryACLManager;
022import aclmanager.models.Principal;
023import java.net.InetAddress;
024import java.net.URI;
025import java.net.URISyntaxException;
026import java.util.ArrayList;
027import java.util.concurrent.Executor;
028
029import org.dcm4che2.data.Tag;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034import javax.xml.transform.TransformerConfigurationException;
035import org.dcm4che2.data.DicomElement;
036import org.dcm4che2.data.DicomObject;
037import org.dcm4che2.net.Association;
038import org.dcm4che2.net.DicomServiceException;
039import org.dcm4che2.net.DimseRSP;
040import org.dcm4che2.net.Status;
041import pt.ua.dicoogle.core.exceptions.CFindNotSupportedException;
042
043import pt.ua.dicoogle.DicomLog.LogDICOM;
044import pt.ua.dicoogle.DicomLog.LogLine;
045import pt.ua.dicoogle.DicomLog.LogXML;
046import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
047import pt.ua.dicoogle.server.DicomNetwork;
048import pt.ua.dicoogle.server.SearchDicomResult;
049import pt.ua.dicoogle.core.ServerSettings;
050import pt.ua.dicoogle.rGUI.server.controllers.Logs;
051
052/**
053 *
054 * @author Luís A. Bastião Silva <bastiao@ua.pt>
055 */
056public class CMoveServiceSCP extends CMoveService {
057
058    private DicomNetwork service = null;
059    private LuceneQueryACLManager luke;
060
061    public CMoveServiceSCP(String[] sopClasses, Executor executor, LuceneQueryACLManager luke) {
062        super(sopClasses, executor);
063         this.luke = luke;
064    }
065
066    public CMoveServiceSCP(String sopClass, Executor executor) {
067        super(sopClass, executor);
068        this.luke = null;
069    }
070    
071    
072    @Override
073    protected DimseRSP doCMove(Association as, int pcid, DicomObject cmd,
074            DicomObject data, DicomObject rsp) throws DicomServiceException {
075        //DebugManager.getInstance().debug("doCMove");
076        //DebugManager.getInstance().debug("DoCmove");
077
078        DimseRSP replay = null;
079
080        /**
081         * Verify Permited AETs
082         */
083        //DebugManager.getInstance().debug(":: Verify Permited AETs @??C-MOVE Action ");
084
085        boolean permited = false;
086
087        if (ServerSettings.getInstance().getPermitAllAETitles()) {
088            permited = true;
089        } else 
090        {
091            String permitedAETs[] = ServerSettings.getInstance().getCAET();
092
093            for (int i = 0; i < permitedAETs.length; i++) {
094                if (permitedAETs[i].equals(as.getCallingAET())) {
095                    permited = true;
096                    break;
097                }
098            }
099        }
100
101        if (!permited) {
102            //DebugManager.getInstance().debug("Client association NOT permited: " + as.getCallingAET() + "!");
103            as.abort();
104
105            return new MoveRSP(data, rsp);
106        } else {
107            //DebugManager.getInstance().debug("Client association permited: " + as.getCallingAET() + "!");
108        }
109
110        /** FIXME: Write wait by rspreplay */
111        try {
112            Thread.sleep(ServerSettings.getInstance().getRspDelay());
113        } catch (Exception e) {
114            e.printStackTrace();
115        }
116
117
118
119        /**
120         *
121         * Now it is the code to move
122         * In this sense it have a fork, besides we can open the store request
123         * in the source direction, or it can make a store to a third party
124         *
125         */
126        /** Get the real IP to move */
127        InetAddress ip = as.getSocket().getInetAddress();
128        /** Get the port to move */
129        int portAddr = as.getSocket().getPort();
130
131        String destination = cmd.getString(org.dcm4che2.data.Tag.MoveDestination);
132        //DebugManager.getInstance().debug("A Move was required to <ip:port> : <"
133        //        + ip.getHostAddress() + ":" + portAddr + ">" + " to --> " + destination);
134
135
136
137        /** Verify if it have the field destination */
138        if (destination == null) {
139            throw new DicomServiceException(cmd, Status.UnrecognizedOperation,
140                    "Missing Move Destination");
141        }
142
143        /*DebugManager.getInstance().debug("-- Objects containing the data requested by C-MOVE");
144        DebugManager.getInstance().debug(data.toString());
145        DebugManager.getInstance().debug(cmd.toString());
146        DebugManager.getInstance().debug(rsp.toString());*/
147        String SOPUID = new String(data.get(Integer.parseInt("0020000D", 16)).getBytes());
148        String CMoveID = cmd.getString(org.dcm4che2.data.Tag.MessageID);
149        System.out.println("C-MOVE ID REQUEST: " + CMoveID);
150        
151        /**
152         * Get object to search
153         */
154        ArrayList<String> extrafields = null;
155        extrafields = new ArrayList<String>();
156
157        extrafields.add("PatientName");
158        extrafields.add("PatientID");
159        extrafields.add("Modality");
160        extrafields.add("StudyDate");
161        extrafields.add("Thumbnail");
162        extrafields.add("StudyInstanceUID");
163        
164        SearchDicomResult.QUERYLEVEL level = null;
165        if (CFindBuilder.isPatientRoot(rsp)) {
166            level = SearchDicomResult.QUERYLEVEL.PATIENT;
167        } else if (CFindBuilder.isStudyRoot(rsp)) {
168            level = SearchDicomResult.QUERYLEVEL.STUDY;
169        }
170
171        CFindBuilder cfind = null;
172        try {
173            cfind = new CFindBuilder(data, rsp);
174        } catch (CFindNotSupportedException ex) {
175            ex.printStackTrace();
176        }
177        String query = cfind.getQueryString();
178               
179        if(luke != null){
180            String filterQuery = luke.produceQueryFilter(new Principal("AETitle", as.getCallingAET()));
181            if(query.length() > 0 )
182                 query += filterQuery;
183        }
184        //TODO: FIlter Query;
185        SearchDicomResult search = new SearchDicomResult(query,
186                true, extrafields, SearchDicomResult.QUERYLEVEL.IMAGE);
187        ArrayList<URI> files = new ArrayList<URI>();
188
189
190
191
192        if (search == null) {
193            //DebugManager.getInstance().debug(">> Search is null, so"
194            //        + " somethig is wrong ");
195        } else {
196
197            while (search.hasNext()) {
198                DicomObject obj = search.next();
199                DicomElement e = obj.get(Integer.parseInt("0020000D", 16));
200                String tmp = null;
201                if (e != null) {
202                    tmp = new String(e.getBytes());
203                }
204                if (SOPUID != null && tmp != null) {
205                    //files.add(new File(search.getCurrentFile()));
206                    String uriString = search.getCurrentFile();
207                     
208                    try {
209                        URI nURI = new URI(uriString);
210                        
211                           files.add(nURI);
212                    } catch (URISyntaxException ex) {
213                        LoggerFactory.getLogger(CMoveServiceSCP.class).error(ex.getMessage(), ex);
214                    }
215                }
216
217            }
218        }
219
220
221
222
223
224        if (files.size() != 0) {
225
226            /**
227             * What is the destination?
228             *
229             */
230            String hostDest = ip.getHostAddress();
231            ServerSettings ob = ServerSettings.getInstance();
232            for (MoveDestination m : ob.getMoves()) {
233                if (m.getAETitle().equals(destination)) {
234                    hostDest = m.getIpAddrs();
235                    portAddr = m.getPort();
236                }
237            }
238
239
240
241            LogLine ll = new LogLine("cmove", LogLine.getDateTime(), destination,
242                    "Files: " + files.size() + " -- (" + hostDest + ":" + portAddr + ")","studyUID="+data.getString(Tag.StudyInstanceUID));
243            LogDICOM.getInstance().addLine(ll);
244
245            synchronized (LogDICOM.getInstance()) {
246                try {
247                    LogXML l = new LogXML();
248                    l.printXML();
249                } catch (TransformerConfigurationException ex) {
250                    LoggerFactory.getLogger(CMoveServiceSCP.class).error(ex.getMessage(), ex);
251                }
252            }
253
254            //Logs.getInstance().addLog(ll);
255            if (CMoveID==null||CMoveID.equals(""))
256            {
257                //DebugManager.getInstance().debug("No originator message ID");
258                return null;
259            }
260            try
261            {
262                System.out.println("Destination: " + destination);
263                new CallDCMSend(files, portAddr, hostDest, destination, CMoveID);
264            } catch (Exception ex)
265            {
266                ex.printStackTrace();
267                //DebugManager.getInstance().debug("Error Sending files to Storage Server!");
268            }
269        }
270
271        /** UnNecessary now 
272
273        // put a BufferedReader on the ls output
274
275        InputStream inputstream =
276        proc.getInputStream();
277        InputStreamReader inputstreamreader =
278        new InputStreamReader(inputstream);
279        BufferedReader bufferedreader =
280        new BufferedReader(inputstreamreader);
281
282        // read the ls output
283
284        String line;
285        try
286        {
287        while ((line = bufferedreader.readLine()) != null)
288        {
289        System.out.println(">>>"+line);
290        }
291        //replay = new MoveRSP(keys, rsp, this.core); // Third Party Move
292        } catch (IOException ex)
293        {
294        LoggerFactory.getLogger(CMoveServiceSCP.class).error(ex.getMessage(), ex);
295        }
296        try
297        {
298        Thread.sleep(100);
299        //replay = new MoveRSP(keys, rsp, this.core); // Third Party Move
300        } catch (InterruptedException ex)
301        {
302        LoggerFactory.getLogger(CMoveServiceSCP.class).error(ex.getMessage(), ex);
303        }
304         */
305        replay = new MoveRSP(data, rsp); // Third Party Move
306        return replay;
307
308    }
309
310    /**
311     * @return the service
312     */
313    public DicomNetwork getService() {
314        return service;
315    }
316
317    /**
318     * @param service the service to set
319     */
320    public void setService(DicomNetwork service) {
321        this.service = service;
322    }
323}