Search code examples
dicomdcm4che

DICOM listener - take control of association actions


Trying to implement a DICOM Router desktop (Java) application using dcm4che (v.2) toolkit.

The DICOM Router should accept any incoming DICOM send requests, store the files locally (in a certain folder structure) and after each DICOM study send request completion it should process the files in a certain way (internal actions).

I am using the dcmrcv util/tool for implementing a DICOM receiver in the following way (getDcmRcv() is actually a dmcRcv object):

...
private final CustomStorageService storageSCP = new CustomStorageService(CUIDS);
...
public DcmRcv(String name) {
    device = new Device(name);
    executor = new NewThreadExecutor(name);

    device.setNetworkApplicationEntity(ae);
    device.setNetworkConnection(nc);
    ae.setNetworkConnection(nc);
    ae.setAssociationAcceptor(true);
    ae.register(new VerificationService());
    ae.register(storageSCP);
    ae.register(stgcmtSCP);        
    ae.addAssociationListener(storageSCP);
}

I have somehow modified StorageService to manage an AssociationListener in the following way:

private final class CustomStorageService extends StorageService implements AssociationListener {
    public CustomStorageService(final String[] sopClasses) {
        super(sopClasses);
    }

    @Override
    protected void onCStoreRQ(final Association association, final int pcid, final DicomObject dcmReqObj,
                               final PDVInputStream dataStream, final String transferSyntaxUID,
                               final DicomObject dcmRspObj)
            throws DicomServiceException, IOException {

        final String classUID = dcmReqObj.getString(Tag.AffectedSOPClassUID);
        final String instanceUID = dcmReqObj.getString(Tag.AffectedSOPInstanceUID);

        GlobalConfig config = new GlobalConfig();
        final File associationDir = config.getAssocDirFile();

        final String prefixedFileName = instanceUID;
    final String dicomFileBaseName = prefixedFileName + DICOM_FILE_EXTENSION;

    File dicomFile = new File(associationDir, dicomFileBaseName + PARTIAL_FILE_EXTENSION);
    assert !dicomFile.exists();

    final BasicDicomObject fileMetaDcmObj = new BasicDicomObject();
    fileMetaDcmObj.initFileMetaInformation(classUID, instanceUID, transferSyntaxUID);

    final DicomOutputStream outStream = new DicomOutputStream(
        new BufferedOutputStream(new FileOutputStream(dicomFile), 600000));
    try {
        outStream.writeFileMetaInformation(fileMetaDcmObj);
        dataStream.copyTo(outStream);

    } finally {
        outStream.close();
    }
        dicomFile.renameTo(new File(associationDir, dicomFileBaseName));
        System.out.println("DICOM file name: " + dicomFile.getName());
    }
}

In such way i can accept DICOM send requests from a client (e.g. Mayam) BUT the files are stored in a flat structure in directory "rootDirectory" (C:\XXXXXX\YYYY\Development\AssocDir).

I am trying to get information such as StudyID and SeriedID from the association object to create a folder structure like: root/StudyID/SeriesID/DicmFile from dcmReqObj or dicomFile ... However:

dcmReqObj is actually empty (only AffectedSOPClassUID & AffectedSOPInstanceUID tags are populated)

Even if i try to fetch it after: outStream.writeFileMetaInformation(fileMetaDcmObj) the StudyID tag is not yet populated (inside this method) ...

Also in this method if i try to fetch "dicomFile" inside onCStoreRQ i can only take it in a transitional phase where it is not yet a populated DICOM object ...

What i have been missing here?


Solution

  • You'll need to do more than just use the DcmRcv class as is.

    Use it as a starting point, but you'll also want to implement the

    org.dcm4che2.net.AssociationListener
    

    interface to intercept association requests, along with the

    org.dcm4che2.net.service.StorageService
    

    class for the actual data transfer.