/*******************************************************************************
 *  Copyright 2017-2018 Centre for Development of Advanced Computing(C-DAC), Pune
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *   http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package cdac.medinfo.sdk.dcm30_04.services.mediacreation.testcases.customizedscp;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConstants;

import java.io.IOException;
import java.util.Date;


import cdac.medinfo.sdk.dcm30_04.baselibs.DataSet;
import cdac.medinfo.sdk.dcm30_04.baselibs.ExplicitDE;
import cdac.medinfo.sdk.dcm30_04.baselibs.ImplicitDE;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataElement;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDataSet;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IDictionaryReader;
import cdac.medinfo.sdk.dcm30_04.commoninterface.IItem;
import cdac.medinfo.sdk.dcm30_04.commoninterface.ITransferSyntax;
import cdac.medinfo.sdk.dcm30_04.enums.EnumCommandField;
import cdac.medinfo.sdk.dcm30_04.enums.EnumExecutionStatus;
import cdac.medinfo.sdk.dcm30_04.enums.EnumExecutionStatusInfo;
import cdac.medinfo.sdk.dcm30_04.enums.EnumLoggingLevel;
import cdac.medinfo.sdk.dcm30_04.enums.EnumPDUType;
import cdac.medinfo.sdk.dcm30_04.services.association.AReleaseRQorRP;
import cdac.medinfo.sdk.dcm30_04.services.association.AssociateRQ;
import cdac.medinfo.sdk.dcm30_04.services.association.AssociationNegotiator;
import cdac.medinfo.sdk.dcm30_04.services.association.DefaultAssociation;
import cdac.medinfo.sdk.dcm30_04.services.association.IDIMSEAssociation;
import cdac.medinfo.sdk.dcm30_04.services.association.RQPresContext;
import cdac.medinfo.sdk.dcm30_04.services.cget.commons.CGetRQ;
import cdac.medinfo.sdk.dcm30_04.services.cget.scu.CGetSCU;
import cdac.medinfo.sdk.dcm30_04.services.dicomdir.DICOMDIRSinkImpl;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumDataSink;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumDataSource;
import cdac.medinfo.sdk.dcm30_04.services.dicomnetcommons.EnumServiceType;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DIMSEResponse;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.DicomMessage;
import cdac.medinfo.sdk.dcm30_04.services.dimsecommons.IDataSink;
import cdac.medinfo.sdk.dcm30_04.services.mediacreation.dbhelper.MediaCreation_DBAgent;
import cdac.medinfo.sdk.dcm30_04.services.mediacreation.mediacreationsinkimpl.MediaCreation_SinkImpl;
import cdac.medinfo.sdk.dcm30_04.services.mediacreation.mediacreationsourceimpl.IMediaHandler;
import cdac.medinfo.sdk.dcm30_04.services.mediacreation.mediacreationsourceimpl.MediaCreation_SourceImpl;
import cdac.medinfo.sdk.dcm30_04.services.naction.scp.NActionSCP;
import cdac.medinfo.sdk.dcm30_04.services.ncreate.scp.NCreateSCP;
import cdac.medinfo.sdk.dcm30_04.services.nget.scp.NGetSCP;
import cdac.medinfo.sdk.dcm30_04.services.scp.commons.ClientSession;
import cdac.medinfo.sdk.dcm30_04.services.scp.commons.ProcessHandler;
import cdac.medinfo.sdk.dcm30_04.services.scp.commons.SCPSession;
import cdac.medinfo.sdk.dcm30_04.services.scu.commons.SCUSession;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConfig;
import cdac.medinfo.sdk.dcm30_04.utils.DicomConstants;
import cdac.medinfo.sdk.dcm30_04.utils.IPairedCollection;
import cdac.medinfo.sdk.dcm30_04.utils.ISingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.PairedCollection;
import cdac.medinfo.sdk.dcm30_04.utils.SingleCollection;
import cdac.medinfo.sdk.dcm30_04.utils.StandardMethods;

/**
 * This sample code defines the customized implementation of SCP for Media Creation Management Service Class.
 * This code process the request for all services belonging to Media Creation Management service group.
 * Supported services for Media Creation Management are :
 * 1. N-Create
 * 2. N-Action
 * 3. N-Get
 * This sample code implements all required methods of IProcessHandler for in order to process the request.
 * Connection establishment process : onConnect()
 * Association establishment process : onAssociateReceive()
 * Service Request process : onServiceRequest()
 * 
 * Implementation of IMediaHandler is laos provided in this sample code.
 * IMediaHandler will be used by default DataSource Impl provided by sdk.
 * This implementation of IMediaHandler dumps the requested images on disk in DICOM DIR format.
 * It retrieves images from a NGet Service Class Provider and dumps on disk.
 * For proper working of this implementation an NGet SCP should be started and listening on specific IP/Port.
 */
public class Media_Creation_SCP_Cust_ProcHandler
{

	public static void main(String[] args) throws IOException
	{
		try
		{		
			DicomConfig objDicomConfig = DicomConfig.createInstance();

			//enable logging,specify the path of the directory where log files are created.
			//User can specify any directory in place of 'c:\DCM_Logs'.
			//If no directory is defined by user to create logs then it is created in User Temp DIR.
			objDicomConfig.enableLogging(EnumLoggingLevel.INFO, "C:\\DCM_Logs");
			//Creates MediaCreation_SCP.
			MediaCreation_SCP objMediaCreation_SCP = new MediaCreation_SCP();

			//Create SCP session.
			SCPSession session = new SCPSession();

			/*
			 * Create Sink with ConnectionString and driver String.
			 * MediaCreation_SinkImpl and MediaCreation_SourceImpl are default implementation of library which uses JavaDB. 
			 * Sink and source Impl process all Media Creation supported services. 
			 * The user has to start javaDB server before connection creation if Client Server model in java DB is used.
			 * The SQL Script needed to create database is provided at %InstallDir%/SQLScripts/MediaCreationServiceDB.sql
			 * User has to first create the Database then it should be set in the MediaCreation SCP.
			 * This DataSink should be set on process handler class working as MediaCreation SCP.
			 * User can also provide its own implementation of IDataSink interface for MediaCreation.
			 */
			String dataBasePath = "D:/DataBase/MediaCreationSDKdb";
			String ConnectionString = "jdbc:derby://localhost:5050/" + dataBasePath;
			String driverString = "org.apache.derby.jdbc.ClientDriver";

			IDataSink objMediaCreationSink = new MediaCreation_SinkImpl(ConnectionString,driverString);
			MediaCreation_SourceImpl objMediaCreationSource = new MediaCreation_SourceImpl(ConnectionString,driverString);
			objMediaCreationSource.setMediaHandler(objMediaCreation_SCP);

			/*
			 * Add Datasink on Process Handler.
			 * Here MediaCreation_SCP is acting as the Process handler,hence adding Data Sink to Process Handler.
			 */
			objMediaCreation_SCP.addDataSink(EnumDataSink.MEDIA_CREATION,objMediaCreationSink);
			objMediaCreation_SCP.addDataSource(EnumDataSource.MEDIA_CREATION,objMediaCreationSource);

			/*
			 * Initializes the supporting service types and sets it on SCP Session
			 * EnumService Type configures SCP Session to load corresponding association context and start
			 * corresponding DIMSE Services.
			 */
			EnumServiceType[] arrenumServiceType = new EnumServiceType[3];
			arrenumServiceType[0] = EnumServiceType.NCREATE_MEDIA_CREATION;
			arrenumServiceType[1] = EnumServiceType.NACTION_MEDIA_CREATION;
			arrenumServiceType[2] = EnumServiceType.NGET_MEDIA_CREATION;
			session.selectServices(arrenumServiceType);

			//Set MediaCreationServices_SCP as ProcessHandler.
			session.setIProcessHandler(objMediaCreation_SCP);
			
			/*
			 * Setting time out as 5000 milli second. It will wait 5000 mili seconds for read and write operation.
			 * If in the time specified (5000 ms) read or write operation is not performed then 
			 * session is time out.
			 */ 
			//session.setTimeOut(5000);

			//Start the Session
			session.start("SDK","192.168.8.94",9000);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}

/**
 * Note ProcessHandler is the class which implements interface IProcessHandler or extends ProcessHandler.
 * This class is implemented to process the MediaCreation service requests.
 * In order to run the following class , please refer to this link($Link) to create the environment.
 * To implement an SCP of a particular we need to do the following things :
 * To create SCP user should either has to implement class IProcessHandler (which is an interface ) or extends Process handler.
 * If test code implements process handler then user has to provide implementation of the methods declared in the interface.
 * Otherwise he can extend the process handler which containts the default implementation for processing of association and service request.
 * Create the SCPSession object which maintains the session of the SCP. 
 * Set the services for which SCP is started and Process handler(reference of test code) in SCPSession.
 * Its "start" method starts the SCP server.
 * When an SCU send connection request to SCP,SCP creates a client session for that SCU.
 * On SCP side a call back will be generated to 'onConnect' method of ProcessHandler whenever a connection request arrives.
 * Now user can retrieve the connection parameters from client session and can decide whether to accept the connection or not.
 * To accpect the connection user has to pass true to acceptConnection function in ClientSession class.
 * After the connection is established the next request expected to arrive at SCP is Association request.
 * When Assocaition request arrives, callback is made to 'onAssociateReceive' method of IProcessHandler.
 * User now can negotioate Association request with the default association and create AssociateAC or AssociationRJ
 * according to the acceptance or rejection.
 * The library provides AssociationNegotiator Class to negotiate and create appropriate response.
 * When a service request arrives the call back is made to 'onServiceRequest' method of ProcessHandler.
 * The user can retrieve the arrived Request from current ClientSession object passed in onServiceRequest method, processes it
 * and create respective Response.
 * SDK provides processRequest method in respective SCP to process the request and to generate response.
 * The SCP can handle multiple request simultaneously.
 * After this, when Association Release-RQ arrives , Create Release response and send it to the SCU.
 * Whenever the SCU goes down its client session is also closed or SCP can close the client session 
 * by calling close method of client session.
 * 
 * This class also implements all required methods of IMediaHandler.
 * In this implementation it dumps the requested images on disk in DICOM DIR format.
 */
class MediaCreation_SCP extends ProcessHandler implements IMediaHandler,Runnable
{
	/*
	 * This class initiates a separate thread to process media creation.
	 */
	Thread MediaWriterThread;
	IPairedCollection<String,IDataSet> objDataSetQueue = new PairedCollection<String,IDataSet>();
	boolean stopProcess = false;
	MediaCreation_DBAgent objMediaCreation_DBAgent = null;

	public MediaCreation_SCP()
	{
		MediaWriterThread = new Thread(this);
		MediaWriterThread.start();
	}

	@SuppressWarnings("unchecked")
	public void run()
	{
		try
		{
			/*
			 * This thread continuously waiting for media creation process.
			 * It will be notified when a media creation initiation signal is triggered
			 */
			ISingleCollection<String> objSOPInstanceList = null;
			String strMediaCreationInstanceUID = null;
			while(true)
			{
				synchronized(this)
				{
					try
					{
						wait();
					}
					catch(InterruptedException ioe)
					{
						ioe.printStackTrace();
					}
				}

				short i = 0;
				while(!stopProcess)
				{
					if(objDataSetQueue != null && objDataSetQueue.size() != 0)
					{
						/*
						 * Retrieving MediaCreation Dataset using SOP Instance UID.
						 * It retrieves sop instance uid of all images which are requested for media creation 
						 * and populated the list of SOPInstances which will be used for retrieval.
						 */
						Object []arrObject = objDataSetQueue.getKeys();
						strMediaCreationInstanceUID = arrObject[0].toString();
						IDataSet objIDataset = objDataSetQueue.get(strMediaCreationInstanceUID);
						System.out.println("Dataset Procesed");
						objDataSetQueue.remove(strMediaCreationInstanceUID);
						if(objIDataset.isPresent(0x0008,0x1199))
						{
							if(objSOPInstanceList == null)
								objSOPInstanceList = new SingleCollection<String>();
							ISingleCollection<IItem> objItemList = (ISingleCollection<IItem>)objIDataset.getValue(0x0008,0x1199);
							for(IItem objItem : objItemList)
							{
								String strSOPInstance = objItem.getValue(0x0008,0x1155).toString();
								objSOPInstanceList.add(strSOPInstance);
							}
						}
					}
					if(objSOPInstanceList != null && objSOPInstanceList.size() != 0)
					{
						/*
						 * Retrieving images from NGet SCP and dumping on disk in DICOM DIR format
						 */
						String strStoragePath = "D://testing/" + ((new Date()).getTime());
						WriteToCD(objSOPInstanceList.elementAt(0),strStoragePath);
						objSOPInstanceList.remove(0);
						i++;
						updateScheduledInstanceInfo(strMediaCreationInstanceUID,i,EnumExecutionStatus.CREATING.getValue(),EnumExecutionStatusInfo.EXECUTION_STATUS_DONE_OR_PRINTING.getValue());
						System.out.println("Media Written :: " + i);
					}
					else
					{
						break;
					}

				}
				if(objSOPInstanceList.size() == 0)
				{
					/*
					 * If all requested images has been processed then completion information will be updated in database
					 */
					updateScheduledInstanceInfo(strMediaCreationInstanceUID,i,EnumExecutionStatus.DONE.getValue(),EnumExecutionStatusInfo.EXECUTION_STATUS_DONE_OR_PRINTING.getValue());
					objSOPInstanceList = null;
					stopProcess = false;
				}
				else if(stopProcess && objSOPInstanceList.size() != 0)
				{
					/*
					 * If cancel operation has been triggered than failure information will be updated in database
					 */
					updateScheduledInstanceInfo(strMediaCreationInstanceUID,i,EnumExecutionStatus.FAILURE.getValue(),EnumExecutionStatusInfo.EXECUTION_STATUS_DONE_OR_PRINTING.getValue());
					objSOPInstanceList = null;
					stopProcess = false;
				}
			}

		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/*
	 * Updates the scheduling information according to the current status provided to it.
	 * Here it is using the same database which is being used by MediaCreationSourceImpl. 
	 */
	public void updateScheduledInstanceInfo(String strSOPInstanceUID,short noOfCompletedMedia,String strExecutionStatus,String strExecutionInfo)
	{
		try
		{
			/*
			 * Creating dataset using provided information and sending it for updation using DBAgent.
			 */
			IDataSet objSchedulingDataset = new DataSet();
			ITransferSyntax objITransferSyntax = objSchedulingDataset.getTransferSyntax();
			IDictionaryReader objIDictionaryReader = objSchedulingDataset.getDictionaryReader();

			objSchedulingDataset.addDataElement(getDataElement(0x2100,0x0020, strExecutionStatus, objITransferSyntax, objIDictionaryReader));
			objSchedulingDataset.addDataElement(getDataElement(0x2100,0x0030, strExecutionInfo, objITransferSyntax, objIDictionaryReader));
			objSchedulingDataset.addDataElement(getDataElement(0x2200,0x000B, noOfCompletedMedia, objITransferSyntax, objIDictionaryReader));

			if(objMediaCreation_DBAgent == null)
			{
				String dataBasePath = "D:/DataBase/MediaCreationSDKdb";
				String ConnectionString = "jdbc:derby://localhost:5050/" + dataBasePath;
				String driverString = "org.apache.derby.jdbc.ClientDriver";
				objMediaCreation_DBAgent = MediaCreation_DBAgent.createInstance(ConnectionString,driverString);
			}

			objMediaCreation_DBAgent.updateScheduledInstanceInfo(objSchedulingDataset,strSOPInstanceUID);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	//Creating DataElement using provided information
	private IDataElement getDataElement(int GroupNo,int ElementNo,Object objVal,ITransferSyntax objITransferSyntax,IDictionaryReader objDictionaryReader)
	{
		IDataElement objIDataElement = null;
		int iVRType = 0;
		if(objITransferSyntax.getVRTransferSyntax() == DicomConstants.DCM_VR_IMPLICIT)
			objIDataElement = new ImplicitDE(GroupNo,ElementNo,objVal,objITransferSyntax,objDictionaryReader);
		else
		{
			iVRType = StandardMethods.getiVRtype(objDictionaryReader.getVR(GroupNo, ElementNo));
			objIDataElement = new ExplicitDE(GroupNo,ElementNo,iVRType,objVal,objITransferSyntax,objDictionaryReader);
		}

		return objIDataElement;
	}

	/*
	 * Writing files on Disk in DICOM DIR format.
	 * This method internally works as service class user for NGet service and retrieves the files from a NGet SCP.
	 * On NGet SCU DICOM DIR impl is set which dumps the files on disk in DICOM DIR format.
	 */
	public void WriteToCD(String strSOPInstanceUID,String strStoragePath)
	{

		try
		{
			//Creating connection to NGet SCP
			SCUSession objSession = new SCUSession();

			objSession.start("192.168.8.94", 7000);

			//Populating Association RQ and establishing association
			EnumServiceType[] arrenumServiceType = new EnumServiceType[1];
			arrenumServiceType[0] = EnumServiceType.CGET;

			DefaultAssociation objDefaultAssociation = new DefaultAssociation("SDK");
			objDefaultAssociation.loadAssociation(arrenumServiceType);

			/*
			 * Populating association request for file 0003.DCM because 
			 * SCU has been implemented to send request for this file only.
			 * User can modify it for other files also.
			 */
			ISingleCollection<String> objTSList = new SingleCollection<String>();
			objTSList.add("1.2.840.10008.1.2.4.50");
			RQPresContext objRQPresContext = new RQPresContext();
			objRQPresContext.setAbstractSyntaxName("1.2.840.10008.5.1.4.1.1.12.1");
			objRQPresContext.setTSCollection(objTSList);

			objDefaultAssociation.addPresContext(objRQPresContext);


			//Create Association RQ
			AssociateRQ objAssociateRQ = objDefaultAssociation.getAssociationRQ("SDK");

			if(objSession.sendAssociationMessage(objAssociateRQ))
			{
				IDataSink objIDataSink = new DICOMDIRSinkImpl();
				CGetSCU objCGetSCU = new CGetSCU(objSession); 
				objCGetSCU.setDataSink(objIDataSink);
				objCGetSCU.setDestinationPath(strStoragePath);
				IDataSet objQryDataSet = new DataSet();
				IDictionaryReader objIDictionaryReader = objQryDataSet.getDictionaryReader();
				IDataElement objIDataElement = new ImplicitDE(0x0008,0x0018,strSOPInstanceUID,objIDictionaryReader);
				objQryDataSet.addDataElement(objIDataElement);	

				CGetRQ objCGetRQ = CGetRQ.getDefaultRQ(DicomConstants.DCM_PATIENT_ROOT_QUERY_OR_RETRIVE_INFORMATION_MODEL_GET,objQryDataSet);

				//Sending retrieval request to SCP
				if(objCGetSCU.sendMessage(objCGetRQ))
				{
					System.out.println("Media written on drive");
				}

				AReleaseRQorRP objAReleaseRQorRP = new AReleaseRQorRP(EnumPDUType.RELEASE_RQ);
				if(objSession.sendAssociationMessage(objAReleaseRQorRP))
				{
					objSession.close();
				}
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * This method notifies when a new client connection is requested. A decision is to be made whether to
	 * accept or reject the conenction.  
	 * @param objClientSession  object of client session.
	 */
	public void onConnect(ClientSession objClientSession)
	{
		objClientSession.acceptConnection(true);
	}

	/**
	 * This method notifies when Association Request, Associate Release Request or Abort is received from one of the 
	 * SCUs. 
	 * If Association Request is received,
	 * 		Create Association Negotiator which negotiates the request with the existing default association and
	 * 		creates an AgreedAssociation which contains the negotiated association values. AssociationNegotiator
	 * 		returns the Association Response as AssociateAC when request is accepted or returns AssociateRJ is 
	 * 		none of the values in Association Request are acceptable.
	 * 	If Associate Release Request is received,
	 * 		Create a Associate Release Response and send the response to the SCU using the respective ClientSession.
	 *  If Abort is received,
	 *  	An Abort response must be generated and sent using ClientSession
	 *    
	 * @param objClientSession instance of Client Session.
	 */
	public void onAssociateReceive(ClientSession objClientSession) 
	{
		//Get Association RQ
		IDIMSEAssociation objIDIMSEAssociation = objClientSession.getDIMSEAssociation();
		EnumPDUType enumPDUType = objIDIMSEAssociation.getPDUType();
		IDIMSEAssociation objAssociationRSP = null;

		//For Association Request negotiate with Default Association and generate Response
		switch(enumPDUType)
		{
		case ASSOCIATE_RQ :
		{
			System.out.println("Association Request Received");
			AssociateRQ objAssociateRQ = (AssociateRQ)objIDIMSEAssociation;

			//get the default association from Client Session.
			DefaultAssociation objDefaultAssociation = objClientSession.getDefaultAssociation();

			//Negotiatie and get Response
			AssociationNegotiator objAssNegotiator = new AssociationNegotiator();
			objAssociationRSP = objAssNegotiator.negotiate(objDefaultAssociation, objAssociateRQ);

			//set agreed association in client Session.
			objClientSession.setAgreedAssociation(objAssNegotiator.getAgreedAssociation());

			//Send Response
			objClientSession.sendAssociationMessage(objAssociationRSP);
			break;
		}
		case RELEASE_RQ :
		{
			System.out.println("Release Request Received");

			//Create Release Response.
			objAssociationRSP = new AReleaseRQorRP(EnumPDUType.RELEASE_RP);

			//Send Release Response.
			objClientSession.sendAssociationMessage(objAssociationRSP);
			System.out.println("Release Response sent");

			//Close Client Session
			objClientSession.close();
			break;
		}
		case ABORT :
		{
			System.out.println("Abort has arrived Stop Porcessing -- Association is no longer available");
			break;
		}
		}
	}

	/**
	 * This method notifies when a service related request is received.
	 * For Example,
	 * If N-Create-RQ is received,
	 * 		Create NCreateSCP using the ClientSession.
	 * 		Process the reqeust using the NCreateSCP which process the request and returns a NCreateRSP.
	 * 		Send this response using the ClientSession.
	 * @see objClientSession Object of Client Session.
	 */
	public void onServiceRequest(ClientSession objClientSession)
	{
		DIMSEResponse objDResponse = null;

		//Retrieving DicomMessage from ClientSession which contains service request.
		DicomMessage objDicomMessage = objClientSession.getDicomMessage();

		try
		{
			if(objDicomMessage.getCommandType() == EnumCommandField.N_CREATE_RQ)
			{
				System.out.println("N-Create Request Received");
				NCreateSCP objNCreateSCP = NCreateSCP.createInstance(objClientSession);

				objNCreateSCP.setDataSinkList(getDataSinkList());

				objDResponse = objNCreateSCP.processRequest(objDicomMessage);

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);
				System.out.println("N-Create Response Sent");
			}
			else if(objDicomMessage.getCommandType() == EnumCommandField.N_GET_RQ)
			{
				System.out.println("N-Get Request Received");
				NGetSCP objNGetSCP  = NGetSCP.createInstance(objClientSession);

				objNGetSCP.setDataSourceList(getDataSourceList());

				objDResponse = objNGetSCP.processRequest(objDicomMessage);

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);
				System.out.println("N-Get Response Sent");
			}
			else if(objDicomMessage.getCommandType() == EnumCommandField.N_ACTION_RQ)
			{
				System.out.println("N-Action Request Received");
				NActionSCP objNActionSCP  = NActionSCP.createInstance(objClientSession);

				objNActionSCP.setDataSourceList(getDataSourceList());

				objDResponse = objNActionSCP.processRequest(objDicomMessage);

				if(objDResponse != null)
					objClientSession.sendServiceMessage(objDResponse);
				System.out.println("N-Action Response Sent");
			}
		}
		catch(Exception ioe)
		{
			ioe.printStackTrace();
			objClientSession.close();
		}
	}

	/**
	 * This method will be notified by MediaHandlerSourceImpl when a initiation request is received.
	 * On notification it starts the media creation process which internally dumps the images on disk.
	 * @param strSOPInstanceUID value of instance uid for which process need to be initiated
	 * @param objIDataSet instance of dataset which contains information of media creation sop instance
	 */
	public void process(String strSOPInstanceUID,IDataSet objIDataSet)
	{
		System.out.println("Processing of media creation started");
		objDataSetQueue.put(strSOPInstanceUID,objIDataSet);
		synchronized (this)
		{
			notify();	
		}
	}

	/**
	 * This method will be notified by MediaHandlerSourceImpl when a cancellation request is received.
	 * On notification it stops the media creation process.
	 * @param strSOPInstanceUID value of instance uid for which process need to be stopped
	 */
	public void stopProcess(String strSOPInstance)
	{
		stopProcess = true;
	}
}
