Hi Guys,
I'm not sure whether this will be what you are looking for, Kate, but it's sort of similar and I thought it might be worth sharing what I do for importing data, just in case it *is* exactly what someone else is looking for.
This is the configuration for the DICOM receiver for our "clinical" version of XNAT. I allow two modes:
1. All studies sent from one of the clinical scanners go to the AETITLE XXXX_RPACS01 (not the real value!) which is assigned to us by the hospital and conforms to their DICOM node nomenclature. These data are processed such that XNAT will place them into a fixed "CLINICAL" project, but with subject name taken from the incoming DICOM and session name automatically generated from two fields in the incoming DICOM file.
but I thought it might be worth posting a working piece of code that allows dual functionality, together with working versions of extensions to ClassicDicomObjectIdentifier for the session naming.
I don't promise that this is the tidiest XML or Java, but it seems to do what I expected.
Hope it's useful.
Simon
dicom-import-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<bean name="dicomObjectIdentifier" class="org.nrg.dcm.id.ClassicDicomObjectIdentifier">
<property name="userProvider" ref="receivedFileUserProvider" />
</bean>
<bean name="dicomSCPExecutor" class="java.util.concurrent.Executors"
factory-method="newCachedThreadPool" />
<bean name="rpacsProjectIdent" class="org.nrg.dcm.id.FixedDicomProjectIdentifier">
<constructor-arg value="XXXX_RPACS01"/>
</bean>
<bean name="baseSubjectIdent" class="org.nrg.dcm.id.ICRDicomObjectIdentifier" factory-method="getSubjectExtractors"/>
<bean name="baseSessionIdent" class="org.nrg.dcm.id.ICRDicomObjectIdentifier" factory-method="getSessionExtractors"/>
<bean name="baseAAIdent" class="org.nrg.dcm.id.ICRDicomObjectIdentifier" factory-method="getAAExtractors"/>
<bean name="rpacsObjectIdent" class="org.nrg.dcm.id.CompositeDicomObjectIdentifier">
<constructor-arg ref="rpacsProjectIdent"/>
<constructor-arg ref="baseSubjectIdent"/>
<constructor-arg ref="baseSessionIdent"/>
<constructor-arg ref="baseAAIdent"/>
<property name="userProvider" ref="receivedFileUserProvider"/>
</bean>
<util:map id="cstores">
<entry key="XXXX_RPACS01" value-ref="rpacsObjectIdent"/>
<entry key="XNAT_XXXX" value-ref="dicomObjectIdentifier"/>
</util:map>
<bean name="dicomSCP" class="org.nrg.dcm.DicomSCP" factory-method="create">
<constructor-arg ref="dicomSCPExecutor" />
<constructor-arg value="8104" />
<constructor-arg ref="receivedFileUserProvider" />
<constructor-arg ref="cstores" />
</bean>
<bean name="dicomSCPManager" class="org.nrg.dcm.DicomSCPManager">
<constructor-arg ref="dicomSCP" />
</bean>
</beans>
New class, located in /home/xnat/Tomcat/Home/webapps/XNAT_XXXX/resources/java/org/nrg/dcm/id in the final build:
import java.util.List;
import java.util.regex.Pattern;
import org.dcm4che2.data.Tag;
import org.nrg.dcm.ContainedAssignmentExtractor;
import org.nrg.dcm.Extractor;
import org.nrg.dcm.TextExtractor;
import org.nrg.dcm.TwoFieldExtractor;
import org.nrg.dcm.TwoFieldExtractorTruncate;
import com.google.common.collect.ImmutableList;
/**
* DicomObjectIdentifier that implements the a custom object identification for the ICR Research PACS
* Modified by Simon Doran
*
*/
public class ICRDicomObjectIdentifier extends CompositeDicomObjectIdentifier {
private static final ImmutableList<Extractor> aaExtractors, sessionExtractors, subjectExtractors;
static {
final ImmutableList.Builder<Extractor> aab = new ImmutableList.Builder<Extractor>();
aab.add(new ContainedAssignmentExtractor(Tag.PatientComments, "AA", Pattern.CASE_INSENSITIVE),
new ContainedAssignmentExtractor(Tag.StudyComments, "AA", Pattern.CASE_INSENSITIVE));
aaExtractors = aab.build();
final ImmutableList.Builder<Extractor> sessb = new ImmutableList.Builder<Extractor>();
sessb.add(new TwoFieldExtractorTruncate(Tag.StudyDate, Tag.StudyTime),
new ContainedAssignmentExtractor(Tag.PatientComments, "Session", Pattern.CASE_INSENSITIVE),
new ContainedAssignmentExtractor(Tag.StudyComments, "Session", Pattern.CASE_INSENSITIVE));
sessionExtractors = sessb.build();
final ImmutableList.Builder<Extractor> subjb = new ImmutableList.Builder<Extractor>();
subjb.add(new TwoFieldExtractor(Tag.PatientName, Tag.PatientBirthDate),
new TextExtractor(Tag.PatientID),
new ContainedAssignmentExtractor(Tag.PatientComments, "Subject", Pattern.CASE_INSENSITIVE),
new ContainedAssignmentExtractor(Tag.StudyComments, "Subject", Pattern.CASE_INSENSITIVE));
subjectExtractors = subjb.build();
}
public static final List<Extractor> getAAExtractors() { return aaExtractors; }
public static final List<Extractor> getSessionExtractors() { return sessionExtractors; }
public static final List<Extractor> getSubjectExtractors() { return subjectExtractors; }
public ICRDicomObjectIdentifier() {
super(new Xnat15DicomProjectIdentifier(), subjectExtractors, sessionExtractors, aaExtractors);
}
}
New class TwoFieldExtractor.java sitting in /home/xnat/Tomcat/Home/webapps/XNAT_XXXX/resources/java/org/nrg/dcm
package org.nrg.dcm;
import java.util.SortedSet;
import java.util.TreeSet;
import org.dcm4che2.data.DicomObject;
import org.nrg.util.SortedSets;
public class TwoFieldExtractor implements Extractor
{
private final int tag1;
private final int tag2;
public TwoFieldExtractor(final int tag1, final int tag2)
{
this.tag1 = tag1;
this.tag2 = tag2;
}
/*
* (non-Javadoc)
* @see org.nrg.dcm.Extractor#extract(org.dcm4che2.data.DicomObject)
*/
public String extract(final DicomObject o)
{
StringBuilder sb = new StringBuilder(o.getString(tag1));
sb.append("_");
sb.append(o.getString(tag2));
return sb.toString();
}
/*
* (non-Javadoc)
* @see org.nrg.dcm.Extractor#getTags()
*/
public SortedSet<Integer> getTags()
{
SortedSet<Integer> ss = new TreeSet<Integer>();
ss.add(tag1);
ss.add(tag2);
return ss;
}
}