es.urjc.mctwp.pacs.impl.DcmStorageServerImpl.java Source code

Java tutorial

Introduction

Here is the source code for es.urjc.mctwp.pacs.impl.DcmStorageServerImpl.java

Source

//Copyright 2008, 2009, 2010 Miguel ?ngel Laguna Lobato
//
//This file is part of Multiclinical Trial Web-PACS.
//
//Multiclinical  Trial Web-PACS is free  software: you  can redistribute 
//it and/or modify it under  the terms of the GNU General Public License 
//as published by the Free  Software Foundation, either version 3 of the 
//License, or (at your option) any later version.
//
//Multiclinical  Trial Web-PACS is distributed  in the hope that it will 
//be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
//of  MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
//General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with Multiclinical Trial Web-PACS.  If not, see 
//<http://www.gnu.org/licenses/>.

//This file  has been created using source code of DcmRcv.java created by
//Gunter Zeilinger. Project dcm4che2

package es.urjc.mctwp.pacs.impl;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;

import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.dcm4che2.data.BasicDicomObject;
import org.dcm4che2.data.DicomObject;
import org.dcm4che2.data.Tag;
import org.dcm4che2.data.UID;
import org.dcm4che2.io.DicomOutputStream;
import org.dcm4che2.net.Association;
import org.dcm4che2.net.Device;
import org.dcm4che2.net.DicomServiceException;
import java.util.concurrent.Executor;
import org.dcm4che2.net.NetworkApplicationEntity;
import org.dcm4che2.net.NetworkConnection;
import org.dcm4che2.net.NewThreadExecutor;
import org.dcm4che2.net.PDVInputStream;
import org.dcm4che2.net.Status;
import org.dcm4che2.net.TransferCapability;
import org.dcm4che2.net.service.StorageService;
import org.dcm4che2.net.service.VerificationService;

import es.urjc.mctwp.image.management.ImageCollectionManager;
import es.urjc.mctwp.pacs.DcmException;
import es.urjc.mctwp.pacs.DcmStorageServer;
import es.urjc.mctwp.service.Command;
import es.urjc.mctwp.service.ServiceDelegate;
import es.urjc.mctwp.service.commands.ModalityAllowed;

public class DcmStorageServerImpl extends StorageService implements DcmStorageServer, BeanFactoryAware {
    private ServiceDelegate service = null;
    private BeanFactory bf = null;

    //Objects for C-Store
    private NetworkApplicationEntity localAE = null;
    private NetworkConnection localConn = null;
    private ImageCollectionManager imc = null;
    private Executor executor = null;
    private Device device = null;
    private Logger logger = null;

    //Params
    private File tempDirectory = null;
    private String hostname = null;
    private String aeTitle = null;
    private String thrName = null;
    private int bufferSize = 1024;
    private int rspDelay = 0;
    private int port = 0;

    //Constants
    private String[] tsuids = NON_RETIRED_LE_TS;
    private static final int KB = 1024;
    private static final String[] ONLY_DEF_TS = { UID.ImplicitVRLittleEndian };
    private static final String[] NON_RETIRED_LE_TS = { UID.JPEGLSLossless, UID.JPEGLossless,
            UID.JPEGLosslessNonHierarchical14, UID.JPEG2000LosslessOnly, UID.DeflatedExplicitVRLittleEndian,
            UID.RLELossless, UID.ExplicitVRLittleEndian, UID.ImplicitVRLittleEndian, UID.JPEGBaseline1,
            UID.JPEGExtended24, UID.JPEGLSLossyNearLossless, UID.JPEG2000, UID.MPEG2 };
    private static final String[] CUIDS = { UID.BasicStudyContentNotificationSOPClassRetired,
            UID.StoredPrintStorageSOPClassRetired, UID.HardcopyGrayscaleImageStorageSOPClassRetired,
            UID.HardcopyColorImageStorageSOPClassRetired, UID.ComputedRadiographyImageStorage,
            UID.DigitalXRayImageStorageForPresentation, UID.DigitalXRayImageStorageForProcessing,
            UID.DigitalMammographyXRayImageStorageForPresentation,
            UID.DigitalMammographyXRayImageStorageForProcessing,
            UID.DigitalIntraoralXRayImageStorageForPresentation, UID.DigitalIntraoralXRayImageStorageForProcessing,
            UID.StandaloneModalityLUTStorageRetired, UID.EncapsulatedPDFStorage, UID.StandaloneVOILUTStorageRetired,
            UID.GrayscaleSoftcopyPresentationStateStorageSOPClass,
            UID.ColorSoftcopyPresentationStateStorageSOPClass,
            UID.PseudoColorSoftcopyPresentationStateStorageSOPClass,
            UID.BlendingSoftcopyPresentationStateStorageSOPClass, UID.XRayAngiographicImageStorage,
            UID.EnhancedXAImageStorage, UID.XRayRadiofluoroscopicImageStorage, UID.EnhancedXRFImageStorage,
            UID.XRayAngiographicBiPlaneImageStorageRetired, UID.PositronEmissionTomographyImageStorage,
            UID.StandalonePETCurveStorageRetired, UID.CTImageStorage, UID.EnhancedCTImageStorage,
            UID.NuclearMedicineImageStorage, UID.UltrasoundMultiframeImageStorageRetired,
            UID.UltrasoundMultiframeImageStorage, UID.MRImageStorage, UID.EnhancedMRImageStorage,
            UID.MRSpectroscopyStorage, UID.RTImageStorage, UID.RTDoseStorage, UID.RTStructureSetStorage,
            UID.RTBeamsTreatmentRecordStorage, UID.RTPlanStorage, UID.RTBrachyTreatmentRecordStorage,
            UID.RTTreatmentSummaryRecordStorage, UID.NuclearMedicineImageStorageRetired,
            UID.UltrasoundImageStorageRetired, UID.UltrasoundImageStorage, UID.RawDataStorage,
            UID.SpatialRegistrationStorage, UID.SpatialFiducialsStorage, UID.RealWorldValueMappingStorage,
            UID.SecondaryCaptureImageStorage, UID.MultiframeSingleBitSecondaryCaptureImageStorage,
            UID.MultiframeGrayscaleByteSecondaryCaptureImageStorage,
            UID.MultiframeGrayscaleWordSecondaryCaptureImageStorage,
            UID.MultiframeTrueColorSecondaryCaptureImageStorage, UID.VLImageStorageTrialRetired,
            UID.VLEndoscopicImageStorage, UID.VideoEndoscopicImageStorage, UID.VLMicroscopicImageStorage,
            UID.VideoMicroscopicImageStorage, UID.VLSlideCoordinatesMicroscopicImageStorage,
            UID.VLPhotographicImageStorage, UID.VideoPhotographicImageStorage,
            UID.OphthalmicPhotography8BitImageStorage, UID.OphthalmicPhotography16BitImageStorage,
            UID.StereometricRelationshipStorage, UID.VLMultiframeImageStorageTrialRetired,
            UID.StandaloneOverlayStorageRetired, UID.BasicTextSRStorage, UID.EnhancedSRStorage,
            UID.ComprehensiveSRStorage, UID.ComprehensiveSRStorageTrialRetired, UID.ProcedureLogStorage,
            UID.MammographyCADSRStorage, UID.KeyObjectSelectionDocumentStorage, UID.ChestCADSRStorage,
            UID.StandaloneCurveStorageRetired, UID._12leadECGWaveformStorage, UID.GeneralECGWaveformStorage,
            UID.AmbulatoryECGWaveformStorage, UID.HemodynamicWaveformStorage,
            UID.CardiacElectrophysiologyWaveformStorage, UID.BasicVoiceAudioWaveformStorage,
            UID.HangingProtocolStorage, UID.SiemensCSANonImageStorage };

    public void setService(ServiceDelegate service) {
        this.service = service;
    }

    public ServiceDelegate getService() {
        return service;
    }

    public void setAeTitle(String aeTitle) {
        this.aeTitle = aeTitle;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }

    public void setBufferSize(int bufferSize) {
        if ((bufferSize > 0) && (bufferSize < 1025))
            this.bufferSize = bufferSize * KB;
    }

    public void setRspDelay(int rspDelay) {
        this.rspDelay = rspDelay;
    }

    public void setThrName(String thrName) {
        this.thrName = thrName;
    }

    @Override
    public void setImageCollectionManager(ImageCollectionManager imc) {
        this.imc = imc;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setTempDirectory(String tempDirectory) {
        if (tempDirectory != null)
            this.tempDirectory = new File(tempDirectory);
        if (!this.tempDirectory.exists())
            this.tempDirectory = null;
    }

    public DcmStorageServerImpl() {
        super(CUIDS);
        logger = Logger.getLogger(this.getClass());
    }

    /**
     * Initialize server. 
     * 
     * @throws Exception if no properly configurated
     */
    public void init() throws DcmException {

        //Check parameters configuration
        if ((aeTitle == null) || (thrName == null) || (hostname == null) || (tempDirectory == null)
                || (port == 0)) {

            String error = "Bad configuration, review server parameters";
            logger.error(error);
            throw new DcmException(error);

        } else {

            try {
                //Create objects
                executor = new NewThreadExecutor(thrName);
                device = new Device(thrName);
                localAE = new NetworkApplicationEntity();
                localConn = new NetworkConnection();

                //init objects
                device.setNetworkApplicationEntity(localAE);
                device.setNetworkConnection(localConn);
                localAE.setNetworkConnection(localConn);
                localAE.setAssociationAcceptor(true);
                localAE.register(new VerificationService());
                localAE.register(this);

                localAE.setAETitle(aeTitle);
                localConn.setHostname(hostname);
                localConn.setPort(port);
                localConn.setReceiveBufferSize(bufferSize);
                localConn.setSendBufferSize(bufferSize);

                initTransferCapability();
            } catch (Exception e) {
                throw new DcmException(e);
            }
        }
    }

    public void start() throws DcmException {
        try {
            device.startListening(executor);
        } catch (IOException ioe) {
            throw new DcmException(ioe);
        }
    }

    public void stop() {
        device.stopListening();
    }

    private void initTransferCapability() {
        TransferCapability[] tc = new TransferCapability[CUIDS.length + 1];
        tc[0] = new TransferCapability(UID.VerificationSOPClass, ONLY_DEF_TS, TransferCapability.SCP);

        for (int i = 0; i < CUIDS.length; i++)
            tc[i + 1] = new TransferCapability(CUIDS[i], tsuids, TransferCapability.SCP);

        localAE.setTransferCapability(tc);
    }

    /**
     * Callback that stores DICOM received file into FS
     */
    protected void doCStore(Association as, int pcid, DicomObject rq, PDVInputStream dataStream, String tsuid,
            DicomObject rsp) throws IOException, DicomServiceException {

        //Is modality allowed?
        Command cmd = getCommand(ModalityAllowed.class);
        ((ModalityAllowed) cmd).setModality(as.getCallingAET());
        cmd = runCommand(cmd);

        if (((ModalityAllowed) cmd).getResult())
            try {
                //Get Dicom object
                String cuid = rq.getString(Tag.AffectedSOPClassUID);
                String iuid = rq.getString(Tag.AffectedSOPInstanceUID);
                BasicDicomObject fmi = new BasicDicomObject();
                fmi.initFileMetaInformation(cuid, iuid, tsuid);

                //Store temporary dicom file
                String filename = iuid + ".dcm";
                File file = new File(FilenameUtils.concat(tempDirectory.getAbsolutePath(), filename));
                FileOutputStream fos = new FileOutputStream(file);
                BufferedOutputStream bos = new BufferedOutputStream(fos, bufferSize);
                DicomOutputStream dos = new DicomOutputStream(bos);
                dos.writeFileMetaInformation(fmi);
                dataStream.copyTo(dos);
                dos.close();

                //Store into persistent space
                ArrayList<File> files = new ArrayList<File>();
                files.add(file);
                imc.storeTemporalImages(as.getCallingAET(), files);
                file.delete();
            } catch (Exception e) {
                throw new DicomServiceException(rq, Status.ProcessingFailure, e.getMessage());
            }

        //Wait if there is delay configured
        if (rspDelay > 0)
            try {
                Thread.sleep(rspDelay);
            } catch (InterruptedException e) {
            }
    }

    /**
     * Return new instance of command identified by clazz
     * 
     * @param clase
     * @return
     */
    private Command getCommand(Class<?> clazz) {
        Command command = null;

        //Build a new command using Web Application Context (wac)
        try {
            Constructor<?> c = clazz.getConstructor(BeanFactory.class);
            command = (Command) c.newInstance(bf);
        } catch (Exception e) {
            logger.error("Error creating new command [" + clazz.toString() + "] : " + e.getMessage());
        }

        return command;
    }

    /**
     * It runs a command safely and catching all error info. If commands fail, 
     * it will redirect action to error page.
     * 
     * @param cmd
     * @return
     */
    private Command runCommand(Command cmd) {
        Command result = cmd;

        try {
            result = service.runCommand(cmd);
        } catch (Exception ce) {
            logger.error("Error running command [" + cmd.toString() + "] : " + ce.getMessage());
        }

        return result;
    }

    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        this.bf = arg0;
    }
}