/******************************************************************************* * Copyright (c) 2009-2019 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v20.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.dicom.op; import java.text.MessageFormat; import org.dcm4che3.data.Attributes; import org.dcm4che3.data.ElementDictionary; import org.dcm4che3.data.Tag; import org.dcm4che3.data.VR; import org.dcm4che3.net.Connection; import org.dcm4che3.net.Status; import org.dcm4che3.net.service.QueryRetrieveLevel; import org.dcm4che3.tool.findscu.FindSCU; import org.dcm4che3.tool.findscu.FindSCU.InformationModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.weasis.core.util.FileUtil; import org.weasis.core.util.StringUtil; import org.weasis.dicom.param.AdvancedParams; import org.weasis.dicom.param.DeviceOpService; import org.weasis.dicom.param.DicomNode; import org.weasis.dicom.param.DicomParam; import org.weasis.dicom.param.DicomState; import org.weasis.dicom.util.ServiceUtil; public class CFind { private static final Logger LOGGER = LoggerFactory.getLogger(CFind.class); public static final DicomParam PatientID = new DicomParam(Tag.PatientID); public static final DicomParam IssuerOfPatientID = new DicomParam(Tag.IssuerOfPatientID); public static final DicomParam PatientName = new DicomParam(Tag.PatientName); public static final DicomParam PatientBirthDate = new DicomParam(Tag.PatientBirthDate); public static final DicomParam PatientSex = new DicomParam(Tag.PatientSex); public static final DicomParam StudyInstanceUID = new DicomParam(Tag.StudyInstanceUID); public static final DicomParam AccessionNumber = new DicomParam(Tag.AccessionNumber); public static final DicomParam IssuerOfAccessionNumberSequence = new DicomParam(Tag.IssuerOfAccessionNumberSequence); public static final DicomParam StudyID = new DicomParam(Tag.StudyID); public static final DicomParam ReferringPhysicianName = new DicomParam(Tag.ReferringPhysicianName); public static final DicomParam StudyDescription = new DicomParam(Tag.StudyDescription); public static final DicomParam StudyDate = new DicomParam(Tag.StudyDate); public static final DicomParam StudyTime = new DicomParam(Tag.StudyTime); public static final DicomParam SeriesInstanceUID = new DicomParam(Tag.SeriesInstanceUID); public static final DicomParam Modality = new DicomParam(Tag.Modality); public static final DicomParam SeriesNumber = new DicomParam(Tag.SeriesNumber); public static final DicomParam SeriesDescription = new DicomParam(Tag.SeriesDescription); public static final DicomParam SOPInstanceUID = new DicomParam(Tag.SOPInstanceUID); public static final DicomParam InstanceNumber = new DicomParam(Tag.InstanceNumber); private CFind() { } /** * @param callingNode * the calling DICOM node configuration * @param calledNode * the called DICOM node configuration * @param keys * the matching and returning keys. DicomParam with no value is a returning key. * @return The DicomSate instance which contains the DICOM response, the DICOM status, the error message and the * progression. */ public static DicomState process(DicomNode callingNode, DicomNode calledNode, DicomParam... keys) { return process(null, callingNode, calledNode, 0, QueryRetrieveLevel.STUDY, keys); } /** * @param params * optional advanced parameters (proxy, authentication, connection and TLS) * @param callingNode * the calling DICOM node configuration * @param calledNode * the called DICOM node configuration * @param keys * the matching and returning keys. DicomParam with no value is a returning key. * @return The DicomSate instance which contains the DICOM response, the DICOM status, the error message and the * progression. */ public static DicomState process(AdvancedParams params, DicomNode callingNode, DicomNode calledNode, DicomParam... keys) { return process(params, callingNode, calledNode, 0, QueryRetrieveLevel.STUDY, keys); } /** * @param params * optional advanced parameters (proxy, authentication, connection and TLS) * @param callingNode * the calling DICOM node configuration * @param calledNode * the called DICOM node configuration * @param cancelAfter * cancel the query request after the receive of the specified number of matches. * @param level * specifies retrieve level. Use by default STUDY for PatientRoot, StudyRoot, PatientStudyOnly model. * @param keys * the matching and returning keys. DicomParam with no value is a returning key. * @return The DicomSate instance which contains the DICOM response, the DICOM status, the error message and the * progression. */ public static DicomState process(AdvancedParams params, DicomNode callingNode, DicomNode calledNode, int cancelAfter, QueryRetrieveLevel level, DicomParam... keys) { if (callingNode == null || calledNode == null) { throw new IllegalArgumentException("callingNode or calledNode cannot be null!"); } AdvancedParams options = params == null ? new AdvancedParams() : params; try (FindSCU findSCU = new FindSCU()) { Connection remote = findSCU.getRemoteConnection(); Connection conn = findSCU.getConnection(); options.configureConnect(findSCU.getAAssociateRQ(), remote, calledNode); options.configureBind(findSCU.getApplicationEntity(), conn, callingNode); DeviceOpService service = new DeviceOpService(findSCU.getDevice()); // configure options.configure(conn); options.configureTLS(conn, remote); findSCU.setInformationModel(getInformationModel(options), options.getTsuidOrder(), options.getQueryOptions()); if (level != null) { findSCU.addLevel(level.name()); } for (DicomParam p : keys) { addAttributes(findSCU.getKeys(), p); } findSCU.setCancelAfter(cancelAfter); findSCU.setPriority(options.getPriority()); service.start(); try { DicomState dcmState = findSCU.getState(); long t1 = System.currentTimeMillis(); findSCU.open(); long t2 = System.currentTimeMillis(); findSCU.query(); ServiceUtil.forceGettingAttributes(dcmState, findSCU); long t3 = System.currentTimeMillis(); String timeMsg = MessageFormat.format("DICOM C-Find connected in {2}ms from {0} to {1}. Query in {3}ms.", findSCU.getAAssociateRQ().getCallingAET(), findSCU.getAAssociateRQ().getCalledAET(), t2 - t1, t3 - t2); return DicomState.buildMessage(dcmState, timeMsg, null); } catch (Exception e) { LOGGER.error("findscu", e); ServiceUtil.forceGettingAttributes(findSCU.getState(), findSCU); return DicomState.buildMessage(findSCU.getState(), null, e); } finally { FileUtil.safeClose(findSCU); service.stop(); } } catch (Exception e) { LOGGER.error("findscu", e); return new DicomState(Status.UnableToProcess, "DICOM Find failed" + StringUtil.COLON_AND_SPACE + e.getMessage(), null); } } private static InformationModel getInformationModel(AdvancedParams options) { Object model = options.getInformationModel(); if (model instanceof InformationModel) { return (InformationModel) model; } return InformationModel.StudyRoot; } public static void addAttributes(Attributes attrs, DicomParam param) { int tag = param.getTag(); String[] ss = param.getValues(); VR vr = ElementDictionary.vrOf(tag, attrs.getPrivateCreator(tag)); if (ss == null || ss.length == 0) { // Returning key if (vr == VR.SQ) { attrs.newSequence(tag, 1).add(new Attributes(0)); } else { attrs.setNull(tag, vr); } } else { // Matching key attrs.setString(tag, vr, ss); } } }