title: DCM4CHE, Network operations,Handling a C-Move call
body: <p>Hi I'm trying to make a PACS server using Java. dcm4che appears to be quite popular. But I'm unable to find any good examples about it.</p>
  <p>As a starting point I inspected dcmqrscp and it successfully stores a DICOM image. But I cannot manage to handle a C-MOVE call. Here's my CMove handler. It finds requested the DICOM file adds a URL and other stuff, it doesn't throw any exception yet client doesn't receive any files.</p>
  <pre><code>private final class CMoveSCPImpl extends BasicCMoveSCP {
  
      private final String[] qrLevels;
      private final QueryRetrieveLevel rootLevel;
  
      public CMoveSCPImpl(String sopClass, String... qrLevels) {
          super(sopClass);
          this.qrLevels = qrLevels;
          this.rootLevel = QueryRetrieveLevel.valueOf(qrLevels[0]);
      }
  
      @Override
      protected RetrieveTask calculateMatches(Association as, PresentationContext pc, final Attributes rq, Attributes keys) throws DicomServiceException {
          QueryRetrieveLevel level = QueryRetrieveLevel.valueOf(keys, qrLevels);
          try {
              level.validateRetrieveKeys(keys, rootLevel, relational(as, rq));
          } catch (Exception e) {
              e.printStackTrace();
          }
          String moveDest = rq.getString(Tag.MoveDestination);
          final Connection remote = new Connection(&quot;reciverAE&quot;,as.getSocket().getInetAddress().getHostAddress(), 11113);
          if (remote == null)
              throw new DicomServiceException(Status.MoveDestinationUnknown, &quot;Move Destination: &quot; + moveDest + &quot; unknown&quot;);
          List&lt;T&gt; matches = DcmQRSCP.this.calculateMatches(keys);
          if (matches.isEmpty())
              return null;
          AAssociateRQ aarq;
          Association storeas = null;
          try {
              aarq = makeAAssociateRQ(as.getLocalAET(), moveDest, matches);
              storeas = openStoreAssociation(as, remote, aarq);
          } catch (Exception e) {
              e.printStackTrace();
          }
          BasicRetrieveTask&lt;T&gt; retrieveTask = null;
          retrieveTask = new BasicRetrieveTask&lt;T&gt;(Dimse.C_MOVE_RQ, as, pc, rq, matches, storeas, new BasicCStoreSCU&lt;T&gt;());
          retrieveTask.setSendPendingRSPInterval(getSendPendingCMoveInterval());
  
          return retrieveTask;
      }
  
      private Association openStoreAssociation(Association as, Connection remote, AAssociateRQ aarq)
              throws DicomServiceException {
          try {
              return as.getApplicationEntity().connect(as.getConnection(),
                      remote, aarq);
          } catch (Exception e) {
              throw new DicomServiceException(
                      Status.UnableToPerformSubOperations, e);
          }
      }
  
      private AAssociateRQ makeAAssociateRQ(String callingAET,
                                            String calledAET, List&lt;T&gt; matches) {
          AAssociateRQ aarq = new AAssociateRQ();
          aarq.setCalledAET(calledAET);
          aarq.setCallingAET(callingAET);
          for (InstanceLocator match : matches) {
              if (aarq.addPresentationContextFor(match.cuid, match.tsuid)) {
                  if (!UID.ExplicitVRLittleEndian.equals(match.tsuid))
                      aarq.addPresentationContextFor(match.cuid,
                              UID.ExplicitVRLittleEndian);
                  if (!UID.ImplicitVRLittleEndian.equals(match.tsuid))
                      aarq.addPresentationContextFor(match.cuid,
                              UID.ImplicitVRLittleEndian);
              }
          }
          return aarq;
      }
  
      private boolean relational(Association as, Attributes rq) {
          String cuid = rq.getString(Tag.AffectedSOPClassUID);
          ExtendedNegotiation extNeg = as.getAAssociateAC().getExtNegotiationFor(cuid);
          return QueryOption.toOptions(extNeg).contains(
                  QueryOption.RELATIONAL);
      }
  }
  </code></pre>
  <hr />
  <p>I added the code below to send a DICOM file as a response:</p>
  <pre><code>String cuid = rq.getString(Tag.AffectedSOPClassUID);
  String iuid = rq.getString(Tag.AffectedSOPInstanceUID);
  String tsuid = pc.getTransferSyntax();
  
  try {
      DcmQRSCP.this.as=as;
      File f = new File(&quot;D:\\dcmqrscpTestDCMDir\\1.2.840.113619.2.30.1.1762295590.1623.978668949.886\\1.2.840.113619.2.30.1.1762295590.1623.978668949.887\\1.2.840.113619.2.30.1.1762295590.1623.978668949.888&quot;);
      FileInputStream in = new FileInputStream(f);
      InputStreamDataWriter data = new InputStreamDataWriter(in);
      // !1! as.cmove(cuid,1,keys,tsuid,&quot;STORESCU&quot;);
      as.cstore(cuid,iuid,1,data,tsuid,rspHandlerFactory.createDimseRSPHandler(f));
  } catch (Exception e) {
      e.printStackTrace();
  }
  </code></pre>
  <p>Throws this exception</p>
  <blockquote>
  <p>org.dcm4che3.net.NoRoleSelectionException: No Role Selection for SOP Class 1.2.840.10008.5.1.4.1.2.2.2 - Study Root Query/Retrieve Information Model - MOVE as SCU negotiated</p>
  </blockquote>