Connecting to dcm4chee using dcm4che from a JAVA program

僤鯓⒐⒋嵵緔 提交于 2019-12-12 11:08:11

问题


Update

I dug deeper in dcm4che's source code and found that an IncompatibleConnectionException is thrown if either

  • a connection is "not installed"
  • or the types of protocols are not set or don't match.

I don't know what it means that a connection is "installed" but this flag can be set manually, so I set it for both the local and remote connections to true (even checked them with getInstalled() whether they are "installed" - and yes they are now - previously this property was null).

And as to the protocols, they weren't specified, so for both connections I set them to DICOM.

Results: I still get the same Exception.


I'd like to establish a DICOM association between dcm4chee (2.18.3) and my JAVA application using the dcm4che (5.12.0) toolkit.

The problem is that it doesn't seem to be any documentation available on how to use dcm4che in a JAVA application, so all I can do is read dcm4che's source code and try to figure out what its classes and methods are for, but I'm stuck. If someone already has a working example it would be very helpful.

So far I have:

import org.dcm4che3.net.ApplicationEntity;
import org.dcm4che3.net.Association;
import org.dcm4che3.net.Connection;
import org.dcm4che3.net.Device;
import org.dcm4che3.net.pdu.AAssociateRQ;
import org.dcm4che3.net.pdu.PresentationContext;

...

ApplicationEntity locAE = new ApplicationEntity();
locAE.setAETitle("THIS_JAVA_APP");

Connection localConn = new Connection();
localConn.setCommonName("loc_conn");
localConn.setHostname("localhost");
localConn.setPort(11112);
localConn.setProtocol(Connection.Protocol.DICOM);
localConn.setInstalled(true);
locAE.addConnection(localConn);

ApplicationEntity remAE = new ApplicationEntity();
remAE.setAETitle("DCM4CHEE");

Connection remoteConn = new Connection();
remoteConn.setCommonName("rem_conn");
remoteConn.setHostname("localhost");
remoteConn.setPort(11112);
remoteConn.setProtocol(Connection.Protocol.DICOM);
remoteConn.setInstalled(true);
remAE.addConnection(remoteConn);

AAssociateRQ assocReq = new AAssociateRQ();
assocReq.setCalledAET(remAE.getAETitle());
assocReq.setCallingAET(locAE.getAETitle());
assocReq.setApplicationContext("1.2.840.10008.3.1.1.1");
assocReq.setImplClassUID("1.2.40.0.13.1.3");
assocReq.setImplVersionName("dcm4che-5.12.0");
assocReq.setMaxPDULength(16384);
assocReq.setMaxOpsInvoked(0);
assocReq.setMaxOpsPerformed(0);
assocReq.addPresentationContext(new PresentationContext(
    1, "1.2.840.10008.1.1", "1.2.840.10008.1.2"));

Device device = new Device("device");
device.addConnection(localConn);
device.addApplicationEntity(locAE);

Association assoc = locAE.connect(remAE, assocReq);

but I don't know whether I'm on the right path doing it.

The error I get:

org.dcm4che3.net.IncompatibleConnectionException: No compatible connection to DCM4CHEE available on THIS_JAVA_APP
at org.dcm4che3.net.ApplicationEntity.findCompatibelConnection(ApplicationEntity.java:646)
at org.dcm4che3.net.ApplicationEntity.connect(ApplicationEntity.java:651)

回答1:


Could it be, that You are missing a Device instance from Your setup? It seems, that You need a Device, to which You attach both ApplicationEntity and Connection.

Looking at FindSCU.java source from dcm4che source.

private final Device device = new Device("findscu");
private final ApplicationEntity ae = new ApplicationEntity("FINDSCU");
private final Connection conn = new Connection();

public FindSCU() throws IOException {
    device.addConnection(conn);
    device.addApplicationEntity(ae);
    ae.addConnection(conn);
}

I also think, that maybe the local Connection object can be instantiated without any parameters as the FindSCU example here demonstrates. Maybe the parameters are confusing it somehow, especially considering, that you have both local and remote connections pointing to localhost:11112.

But yes, one has to agree, that the documentation for dcm4che3 API is totally inadequate.




回答2:


Here is the working code: (I don't know if it's the minimal solution, feel free to experiment with it...)

ApplicationEntity locAE = new ApplicationEntity();
locAE.setAETitle("THIS_JAVA_APP");
locAE.setInstalled(true);

Connection localConn = new Connection();
localConn.setCommonName("loc_conn");
localConn.setHostname("localhost");
localConn.setPort(11112);
localConn.setProtocol(Connection.Protocol.DICOM);
localConn.setInstalled(true);
locAE.addConnection(localConn);

ApplicationEntity remAE = new ApplicationEntity();
remAE.setAETitle("DCM4CHEE");
remAE.setInstalled(true);

Connection remoteConn = new Connection();
remoteConn.setCommonName("rem_conn");
remoteConn.setHostname("localhost");
remoteConn.setPort(11112);
remoteConn.setProtocol(Connection.Protocol.DICOM);
remoteConn.setInstalled(true);
remAE.addConnection(remoteConn);

AAssociateRQ assocReq = new AAssociateRQ();
assocReq.setCalledAET(remAE.getAETitle());
assocReq.setCallingAET(locAE.getAETitle());
assocReq.setApplicationContext("1.2.840.10008.3.1.1.1");
assocReq.setImplClassUID("1.2.40.0.13.1.3");
assocReq.setImplVersionName("dcm4che-5.12.0");
assocReq.setMaxPDULength(16384);
assocReq.setMaxOpsInvoked(0);
assocReq.setMaxOpsPerformed(0);
assocReq.addPresentationContext(new PresentationContext(
    1, "1.2.840.10008.1.1", "1.2.840.10008.1.2"));

Device device = new Device("device");
device.addConnection(localConn);
device.addApplicationEntity(locAE);

Executor exec = (Runnable command) -> {};
device.setExecutor(exec);

Association assoc = locAE.connect(localConn, remoteConn, assocReq);

And the relevant dcm4chee log:

2018-03-02 23:21:42,832 INFO  THIS_JAVA_APP->DCM4CHEE (TCPServer-1) [org.dcm4cheri.net.FsmImpl] received AAssociateRQ
    appCtxName: 1.2.840.10008.3.1.1.1/DICOM Application Context Name
    implClass:  1.2.40.0.13.1.3
    implVersion:    dcm4che-5.12.0
    calledAET:  DCM4CHEE
    callingAET: THIS_JAVA_APP
    maxPDULen:  16378
    asyncOpsWindow: 
    pc-1:   as=1.2.840.10008.1.1/Verification SOP Class
        ts=1.2.840.10008.1.2/Implicit VR Little Endian
2018-03-02 23:21:42,843 INFO  THIS_JAVA_APP->DCM4CHEE (TCPServer-1) [org.dcm4cheri.net.FsmImpl] sending AAssociateAC
    appCtxName: 1.2.840.10008.3.1.1.1/DICOM Application Context Name
    implClass:  1.2.40.0.13.1.1.1
    implVersion:    dcm4che-1.4.34
    calledAET:  DCM4CHEE
    callingAET: THIS_JAVA_APP
    maxPDULen:  16352
    asyncOpsWindow: 
    pc-1:   0 - acceptance
        ts=1.2.840.10008.1.2/Implicit VR Little Endian

After you have the association, see this other post for how to perform a C-FIND.




回答3:


Edit

Apparently, I solved the problem. Changing the executor from

Executor exec = (Runnable command) -> {};
device.setExecutor(exec);

to

ExecutorService executorService = Executors.newSingleThreadExecutor();
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
device.setExecutor(executorService);
device.setScheduledExecutor(scheduledExecutorService);

made it so my application correctly received the association response from the server. This might serve as reference for someone else.

Thank you for sharing your code. It was really helpful to me.

Original Post

I am unable to perform the connection with a code similar to the solution you proposed. I am trying to request an association with a dcm4chee-arc-light with dcm4che (both 5.14.1), and I have as it follows:

Device device = new Device(deviceName);
ApplicationEntity locAE = new ApplicationEntity(localAE);
Connection conn = new Connection();
Connection remote = new Connection();
AAssociateRQ rq = new AAssociateRQ();

device.addConnection(conn);
device.addApplicationEntity(locAE);
locAE.addConnection(conn);

ApplicationEntity remAE = new ApplicationEntity();
remAE.setAETitle(remoteAE);

remote.setCommonName("rem_conn");
remote.setHostname(remoteIP);
remote.setPort(remotePort);
remote.setProtocol(Connection.Protocol.DICOM);
remAE.addConnection(remote);

rq.setCalledAET(remAE.getAETitle());
rq.setCallingAET(locAE.getAETitle());
rq.setApplicationContext("1.2.840.10008.3.1.1.1");
rq.setImplClassUID("1.2.40.0.13.1.3");
rq.setImplVersionName("dcm4che-5.14.1");
rq.setMaxPDULength(16384);
rq.setMaxOpsInvoked(0);
rq.setMaxOpsPerformed(0);
rq.addPresentationContext(new PresentationContext(
        1, "1.2.840.10008.5.1.4.1.2.2.1", "1.2.840.10008.1.2"));

Executor exec = (Runnable command) -> {};
device.setExecutor(exec);

//Opens association and connects to remote server
Association as = locAE.connect(conn, remote, rq);

But when trying to connect to a remote AET, it doesn't seem to receive the AAssociation response from the remote AET. My Java application hangs in Sta5 (waiting for association response) while the server hangs in Sta6 (ready for data transfer).

Java log:

[main] INFO org.dcm4che3.net.Connection  - Initiate connection from 0.0.0.0/0.0.0.0:0 to localhost:11112
[main] INFO org.dcm4che3.net.Connection  - Established connection Socket[addr=localhost/127.0.0.1,port=11112,localport=50101]
[main] DEBUG org.dcm4che3.net.Association  - /127.0.0.1:50101>localhost/127.0.0.1:11112(1): enter state: Sta4 - Awaiting transport connection opening to complete
[main] INFO org.dcm4che3.net.Association  - DEVICEAE->DCMQRSCP(1) << A-ASSOCIATE-RQ
[main] DEBUG org.dcm4che3.net.Association  - A-ASSOCIATE-RQ[
  calledAET: DCMQRSCP
  callingAET: DEVICEAE
  applicationContext: 1.2.840.10008.3.1.1.1 - DICOM Application Context Name
  implClassUID: 1.2.40.0.13.1.3
  implVersionName: dcm4che-5.14.1
  maxPDULength: 16378
  maxOpsInvoked/maxOpsPerformed: 1/1
  PresentationContext[id: 1
  as: 1.2.840.10008.5.1.4.1.2.2.1 - Study Root Query/Retrieve Information Model - FIND
  ts: 1.2.840.10008.1.2 - Implicit VR Little Endian
 ]
]
[main] DEBUG org.dcm4che3.net.Association  - DEVICEAE->DCMQRSCP(1): enter state: Sta5 - Awaiting A-ASSOCIATE-AC or A-ASSOCIATE-RJ PDU

Server log:

19:11:29,397 INFO  - Accept connection Socket[addr=/127.0.0.1,port=50101,localport=11112]
19:11:29,397 DEBUG - /127.0.0.1:11112<-/127.0.0.1:50101(3): enter state: Sta2 - Transport connection open
19:11:29,416 INFO  - DCMQRSCP<-DEVICEAE(3) >> A-ASSOCIATE-RQ
19:11:29,416 DEBUG - A-ASSOCIATE-RQ[
 calledAET: DCMQRSCP
 callingAET: DEVICEAE
 applicationContext: 1.2.840.10008.3.1.1.1 - DICOM Application Context Name
 implClassUID: 1.2.40.0.13.1.3
 implVersionName: dcm4che-5.14.1
 maxPDULength: 16378
 maxOpsInvoked/maxOpsPerformed: 1/1
 PresentationContext[id: 1
 as: 1.2.840.10008.5.1.4.1.2.2.1 - Study Root Query/Retrieve Information Model - FIND
 ts: 1.2.840.10008.1.2 - Implicit VR Little Endian
  ]
 ]
19:11:29,419 DEBUG - DCMQRSCP<-DEVICEAE(3): enter state: Sta3 - Awaiting local A-ASSOCIATE response primitive
19:11:29,419 INFO  - DCMQRSCP<-DEVICEAE(3) << A-ASSOCIATE-AC
19:11:29,419 DEBUG - A-ASSOCIATE-AC[
 calledAET: DCMQRSCP
 callingAET: DEVICEAE
 applicationContext: 1.2.840.10008.3.1.1.1 - DICOM Application Context Name
 implClassUID: 1.2.40.0.13.1.3
 implVersionName: dcm4che-5.14.1
 maxPDULength: 16378
 maxOpsInvoked/maxOpsPerformed: 1/1
 PresentationContext[id: 1
 result: 0 - acceptance
 ts: 1.2.840.10008.1.2 - Implicit VR Little Endian
  ]
 ]
19:11:29,427 DEBUG - DCMQRSCP<-DEVICEAE(3): enter state: Sta6 - Association established and ready for data transfer

I feel like I am missing something, but I cannot find the source of the problem. Any help is appreciated, as I am still new to dcm4che and DICOM protocol.

Thank you.



来源:https://stackoverflow.com/questions/49048428/connecting-to-dcm4chee-using-dcm4che-from-a-java-program

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!