Storage Commitment Service (push model): how i get the result back to my SCU? - standards

I planned to implement a Storage Commitment Service to verify if files previously sent to the storage were safely stored.
My architecture is very simple and straightforward my SCU sends some secondary capture images to the storage and I want to be sure they are safely stored before delete them.
I am going to adopt push model and I wonder what steps/features I need to implement to accomplish the service
What I understood is
I need to issue a N-ACTION request with SOP Class UID
1.2.840.10008.1.20.1 and add to the request a transaction identifier together with a list of Referenced SOP Class UID – Referenced SOP
Instance UID where Referenced SOP Instance UID are the UIDs of the
secondary capture images I previously sent to the storage and
Referenced SOP Class UID in my case is the soap class identifier
representing the Secondary Capture Image
Wait for my N-ACTION response to see if the N-ACTION request succeed
or not
Get the response from the storage in form of N-EVENT-REPORT
But when? How the storage give me back the
N-EVENT-REPORT along with the results? Does my SCP AE implements some
SCP features? Or I need to issue a N-EVENT request to get a
N-EVENT-REPORT?

Have a look at the image below copied from here:
Now, about your question, following is the explanation assuming same association will be used for entire communication. For communication over multiple associations, refer above article from Roni.
But when?
Immediately. On same connection/association. On receiving NAction response, you should wait for timeout configured in your application. Before timeout expires, you should get the NEventReport.
How the storage give me back the N-EVENT-REPORT along with the results?
When you receive NAction response from SCP, that means SCP saying "Ok; I understood what you want. Now wait while I fetch your data...". So, you wait. When SCP is ready with all the data (check list) necessary, it just sends it back on same association through NEventReport. You parse the Report and do your stuff and send response to SCP saying "Fine; I am done with you." and close the association.
Does my SCP AE implements some SCP features?
No (in most of the cases); you do not need to implement any SCP features in both (single association/multiple associations) cases. You should get NEventReport on same association as mentioned above. DICOM works on TCPIP. Client/Server concept in TCP is only limited to who establishes the connection and who listens for connections. Once the connection is established, any one can read/write data on socket.
In rare cases, SCP sends NEventReport by initiating new association on its own. In that case, SCU need to implement SCP features. This model is not in use as far as I am aware. It is difficult to implement this model for both SCP and SCU. It also needs multiple configurations which everyone tends to avoid. So, this could be neglected. I am calling this rare because I never (at least so far) come across such implementation. But yes; this is valid case for valid reason.
Or I need to issue a N-EVENT request to get a N-EVENT-REPORT?
No; as said above. Refer this.
J.3.3 Notifications
The DICOM AEs that claim conformance to this SOP Class as an SCP shall invoke the N-EVENT-REPORT request. The DICOM AEs that claim conformance to this SOP Class as an SCU shall be capable of receiving the N-EVENT-REPORT request.
That said, SCU should be able to process NEventReport. It will NOT issue it.

There are three different sequences of events possible. I could describe them here, but this article is really excellent: Roni's DICOM blog
I have nothing to add to what is written there.

Related

How to use DCMTK binaries to send Modality Worklist to modalities without receiving Query from them?

I am using DCMTK storescp.exe to receive images from a CR modality and then process/save them in my DB.
Is it possible to use other DCMTK binary to manually send the PatientName and PatientId to CR modality before the patient goes there?
I have read somewhere that the modality makes a query to get the Modality Worklist. I would like to reverse that flow. I want to directly send the Modality Worklist to the modality, whenever I like, without receiving the query from Modality.
Is that possible? If yes; how can I do that with DCMTK?
Please note that this is not an off-site tool request. I just want to know the DCMTK binary that implements required DICOM service/command.
You are looking for Modality Worklist or MWL service which implements C-FIND command.
SOP Class: 1.2.840.10008.5.1.4.31 [Modality Worklist Information Model – FIND].
But it does not work the way you are expecting; and it should not - for good.
MWL SCU (in your case - CR) initiates the query with the (optional) filters it suits. As usual, association happens and MWL SCP receives the MWL Request. It then fetch the data from its database matching the filters if any. It then sends one MWL Response for each row fetched from database, status for each response is PENDING. When all the rows are transferred, final SUCCESS response is sent. If no rows were found matching the filter, only final response is sent. If something goes wrong, proper failure response is sent. SCU then, sends the Release Request and on receiving Release Response, it closes the association.
Now, why your expected workflow is not possible?
Generally MWL SCP is implemented by RIS systems. These systems have tools/features to register the patient demographic data while/before admission of the patient in hospitals. They also have features to schedule the orders to be executed by Modalities. There might be multiple modalities in given DICOM Network (hospital). Though, RIS have a way to decide which order should go to which modality (based on AE Title if configured and used properly), they cannot push it because they are acting as SCP i.e. Server. As any other server in any network protocol, they have to wait for request from client i.e. SCU.
Further, though SCP may know which order should be sent to which modality, modality may not expecting that order for many reasons. So, the general flow in MWL is the way I explained above. You cannot implement your reverse workflow with any DICOM service/command.
Just for the sake of clarity:
All this has nothing to do with the data you received and stored in DB using storescp.exe. I mean, you do not generally send that data to modality as Modality Worklist.
MWL happens first. When modality get the MWL Worklist item, it conducts the study and acquires images with the demographic data received in MWL Worklist item. This way, errors are avoided, redundant inputs are avoided and flow is bit automated. When done, modality push (C-STORE) the instances (CR images in your case) to C-STORE SCP which is storescp.exe in your case.

Intended usage of /network-map/ack-parameters: parameters Hash and(?) NodeKey?

The Corda Node can accept the new network parameters update with the /network-map/ack-parameters post request. The Parameters Hash is sent to the network operator with this request.
Therefore, there are 2 questions:
Is it intended that the network operator can know from which Node this acceptance request came? By other word, how the network operator can know which node accepted the new network parameters update?
If I check the Cordite Network Map Service implementation(https://gitlab.com/cordite/network-map-service/blob/master/src/main/kotlin/io/cordite/networkmap/service/NetworkMapService.kt#L294), the submitted parameter is interpreted as a key for NodeInfo in the NodeInfo storage, instead of being interpreted as Parameters Hash. It looks inconsistent with how the Corda defines the /ack-parameters request parameters. Does Cordite implementation of Network Map Service is adequate on this aspect?
I'll do my best to use my own intuition to answer these as they're quite specific.
Yes it's intended for the network operator to know where the acceptance request comes from as it's part of properly managing the parties on the network. You can actually check this out in the corda source code here to see how the "doorman" handles new node participants: https://github.com/corda/corda
I don't think cordite needs to be semantically exactly similar to the way that Corda does it. That being said it's certainly adequate.

GDCM C-Move issue with studies containing documents/reports

I don't think I"m going to get the answer I want but I figured I would ask before giving up with GDCM.
I've built a tool using the GDCM library to do some Query/Retrieve on our local PACS. During testing, everything worked fine, but now that I've deployed it, we have one major issue.
When C-Move is transferring a study (with multiple series) and comes upon a series with a document or a report (IE patient protocol, dose report), it stops transferring any more images, even for the other series in the study. Using Wireshark, I can see that the C-Move requests are being sent, but no C-Store transfers are being sent back in return.
This will continue until the next Study, which will transfer normally until it gets to another series that has a document/report. We didn't catch this during early testing because we were testing on select studies that did not contain reports.
Is there a reason why GDCM doesn't play ball with non-images using C-Move? If I can't overcome this limitation of the library easily, is there a way to ignore series with reports, or series with only 1 image (which is how scout images and reports are stored and neither are necessary for me). Do I need to change the DCMTK library instead for my Q/R tool?
Cheers,
Shensmobile
Well to begin with:
Your question needs some more information. I will still try to answer with obvious reasons.
I never used GDCM. I will answer in context of DICOM.
GDCM is: QR SCU and CStore SCP.
PACS is: QR SCP and CStore SCU.
If above is reverse, it does not change the answer much, just reverse the roles.
I do not think problem is with your PACS or GDCM. I think the problem is while Association part of MOVE request.
Your CStore SCP does not support those SOP class because:
Simply, it does not support those at all.
May be you need to configure it to add the support. I do not know what to do here. I neither know GDCM nor your PACS. You need to figure this out yourself.
Those are not proposed by SCU at all.
Configure your SCU to propose those classes.
Those are proposed by SCU but not accepted by SCP.
Check why SCP is rejecting those classes in Associate Response. I strongly suspect this is the problem. Most probably, your CStore SCP is not configured to accept instances with those SOP classes.
Those are accepted by SCP but on CStore Request, instances are being rejected for some reason.
Why, I do not know. You may need to check your logs and configurations.
Please understand that most of the problems in DICOM network communication lies in Association part. Focus your debugging there.
What I can say for sure is that, this problem is not related to C-Find or C-Move Requests/Responses. This problem is related to C-Store operation and its Association part.
Please read following excellent articles from Roni:
http://dicomiseasy.blogspot.com/2012/01/dicom-queryretrieve-part-i.html
http://dicomiseasy.blogspot.com/2012/02/c-move.html
Using Wireshark, I can see that the C-Move requests are being sent, but no C-Store transfers are being sent back in return.
Assuming your are moving a Study, MOVE request is sent once to initiate MOVE operation. Then, MOVE SCP will become CStore SCU and will initiate another Association with CStore SCP. CStore SCP can be different from original MOVE SCU; but I do not think this is the case in your scenario. Then for each (optionally; do not rely on this. Read Roni's articles mentioned below) CStore operation, MOVE response is communicated. You did not mention about MOVE responses in your question.
Is there a reason why GDCM doesn't play ball with non-images using C-Move?
I do not think this is about "non-image" as mentioned above; but cannot bypass this possibility all together. May be that CStore SCP is accepting those SOP classes (incorrectly, even though it does not support those) but reject the instances for some reason (may be non-image instance) while C-Store. You need to check logs and configurations of your CStore SCP here.
If I can't overcome this limitation of the library easily, is there a way to ignore series with reports, or series with only 1 image
You may choose to bypass the Study level retrieve/MOVE and try Series level retrieve. To do this, you first need to fetch list (C-Find) of SeriesInstanceUIDs for that Study. Then MOVE each series independently. In C-Find response, you also get other attributes like image count where you can put your filters for further MOVE operation.
Do I need to change the DCMTK library instead for my Q/R tool?
As I said above, I do not think this problem is with library.

DICOM: C-Move without C-Find (Query Retrieve SCU)

In DICOM, following are the classes defined for C-Find and C-Move at Study Root.
Study Root Query/Retrieve Information Model - FIND: 1.2.840.10008.5.1.4.1.2.2.1
Study Root Query/Retrieve Information Model - MOVE: 1.2.840.10008.5.1.4.1.2.2.2
I have implemented Query Retrieve SCP and SCU in multiple applications. In all those cases, I always implemented both the classes. I do C-Find first to get the list of matching data. Then based on result, I do (automatically or manually) C-Move to get the instances. All those implementations are working fine.
Recently, I am working on one application that combines DICOM with other private protocol to fulfill some specific requirements. It just stuck to my mind if it is possible to directly do C-Move without doing C-Find as SCU?
I already know the identifier (StudyInstanceUID) to retrieve and I also know that it does present on SCP.
I looked into specifications but could not found anything conclusive. I am aware that C-Find and C-Move could be issued by SCU to SCP on different connections/associations. So in first glance, what I am thinking looks possible and legal.
I worked with many third party DICOM applications; none of them implements SCU the way I am thinking. All SCUs implement C-Find AND C-Move both.
Question:
Is it DICOM legal and practical to implement Query Retrieve SCU C-Move command without C-Find command? Please point me to the reference in specifications if possible.
Short answer: Yes this is perfectly legal per DICOM specification.
Long answer: Let's consider the DCMTK reference DICOM Q/R implementation. It provides a set of basic SCU command line tools, namely findscu and movescu. The idea is to pipe the output of findscu to movescu to construct a valid C-MOVE (SCU) request.
In your requirement you are simply replacing the findscu step with a private implementation that does not rely on the publicly defined C-FIND (SCU) protocol but by another mechanism (extension to DICOM).
So yes your C-MOVE (SCU) implementation is perfectly valid, since there is no requirement to provide C-FIND (SCU) during this query.
I understand you are not trying to backup an entire database using C-MOVE (SCU), that was just a possible scenario where someone would be trying to use C-MOVE (SCU) without first querying with a valid C-FIND (SCU) result.

Use-cases for reactive streams using java 9 Flows in Servlets?

I'm looking for use-cases for using reactive streams within a servlet container (or just a HTTP server).
The Jetty project has started being asked: "is Jetty reactive?" and we've noticed the proposal to add reactive streams to java 9.
So we've started some experiments with using the reactive streams API for async servlet IO, which are interesting enough..... but lack any focus because we lack real use-cases to focus which concerns are most important.
So does anybody have any good use-cases that they could share/explain so that we can direct our jetty experiments to meet their needs. The sort of thing I've imagined is having a RS based database publisher sending objects all the way out on a HTTP response or websocket connection using Flow.Processors for the conversions along the way.
A viable use case is when consuming the POSTing of multi-part form data, particularly when uploading files.
The Typesafe ConductR project (disclaimer: I'm the Tech Lead for it), receives multi-part form data when a user loads a bundle. We use akka-streams/http.
We read off the first two parts of the stream as our protocol specifies that they must declare some meta data in order for us to know which node to write the bundles to. After some validation, we then determine the node to write them to, and connect the partially consumed stream. Thus the node that receives the request to upload the bundle negotiates which node it is going to write it to, while not having to consume the entire stream (which could be 200MB) and then write it out again.
Writing out multi-part form data is also a great use-case given that you can stream the file from disk as a source and pass it on to some http endpoint i.e. the client-side of what I describe above.
The benefits with both use-cases are that you minimise the amount of memory needed to move bytes over a network, and you only perform file IO where it is necessary.

Resources