/*******************************************************************************
* Copyright (c) 2016 Weasis Team and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nicolas Roduit - initial API and implementation
*******************************************************************************/
package org.weasis.dicom.explorer.wado;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URI;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPInputStream;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker.StateValue;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.dcm4che3.data.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.weasis.core.api.explorer.ObservableEvent;
import org.weasis.core.api.gui.util.AppProperties;
import org.weasis.core.api.gui.util.GuiExecutor;
import org.weasis.core.api.media.MimeInspector;
import org.weasis.core.api.media.data.MediaSeriesGroup;
import org.weasis.core.api.media.data.MediaSeriesGroupNode;
import org.weasis.core.api.media.data.Series;
import org.weasis.core.api.media.data.TagUtil;
import org.weasis.core.api.media.data.TagW;
import org.weasis.core.api.media.data.Thumbnail;
import org.weasis.core.api.service.BundleTools;
import org.weasis.core.api.util.FileUtil;
import org.weasis.core.api.util.NetworkUtil;
import org.weasis.core.api.util.StreamIOException;
import org.weasis.core.api.util.StringUtil;
import org.weasis.core.api.util.StringUtil.Suffix;
import org.weasis.core.api.util.ThreadUtil;
import org.weasis.core.ui.docking.UIManager;
import org.weasis.core.ui.editor.image.ViewerPlugin;
import org.weasis.core.ui.util.ColorLayerUI;
import org.weasis.dicom.codec.DicomInstance;
import org.weasis.dicom.codec.DicomSeries;
import org.weasis.dicom.codec.TagD;
import org.weasis.dicom.codec.TagD.Level;
import org.weasis.dicom.codec.utils.DicomMediaUtils;
import org.weasis.dicom.codec.wado.WadoParameters;
import org.weasis.dicom.explorer.DicomModel;
import org.weasis.dicom.explorer.DicomSorter;
import org.weasis.dicom.explorer.Messages;
import org.xml.sax.SAXException;
public class DownloadManager {
private static final Logger LOGGER = LoggerFactory.getLogger(DownloadManager.class);
public static final String SCHEMA =
"xmlns=\"http://manifest.service.weasis/v2.5\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""; //$NON-NLS-1$
public static final String TAG_XML_ROOT = "manifest"; //$NON-NLS-1$
public static final String TAG_ARC_QUERY = "arcQuery"; //$NON-NLS-1$
public static final String TAG_ARCHIVE_ID = "arcId"; //$NON-NLS-1$
public static final String TAG_BASE_URL = "baseUrl"; //$NON-NLS-1$
public static final String TAG_PR_ROOT = "presentations"; //$NON-NLS-1$
public static final String TAG_PR = "presentation"; //$NON-NLS-1$
public static final String CONCURRENT_SERIES = "download.concurrent.series"; //$NON-NLS-1$
public static final List<LoadSeries> TASKS = new ArrayList<>();
// Executor without concurrency (only one task is executed at the same time)
private static final BlockingQueue<Runnable> UNIQUE_QUEUE =
new PriorityBlockingQueue<>(10, new PriorityTaskComparator());
public static final ThreadPoolExecutor UNIQUE_EXECUTOR =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, UNIQUE_QUEUE);
// Executor with simultaneous tasks
private static final BlockingQueue<Runnable> PRIORITY_QUEUE =
new PriorityBlockingQueue<>(10, new PriorityTaskComparator());
public static final ThreadPoolExecutor CONCURRENT_EXECUTOR =
new ThreadPoolExecutor(BundleTools.SYSTEM_PREFERENCES.getIntProperty(CONCURRENT_SERIES, 3),
BundleTools.SYSTEM_PREFERENCES.getIntProperty(CONCURRENT_SERIES, 3), 0L, TimeUnit.MILLISECONDS,
PRIORITY_QUEUE, ThreadUtil.getThreadFactory("Series Downloader")); //$NON-NLS-1$
public static class PriorityTaskComparator implements Comparator<Runnable>, Serializable {
private static final long serialVersionUID = 513213203958362767L;
@Override
public int compare(final Runnable r1, final Runnable r2) {
LoadSeries o1 = (LoadSeries) r1;
LoadSeries o2 = (LoadSeries) r2;
DownloadPriority val1 = o1.getPriority();
DownloadPriority val2 = o2.getPriority();
int rep = val1.getPriority().compareTo(val2.getPriority());
if (rep != 0) {
return rep;
}
if (val1.getPatient() != val2.getPatient()) {
rep = DicomSorter.PATIENT_COMPARATOR.compare(val1.getPatient(), val2.getPatient());
}
if (rep != 0) {
return rep;
}
if (val1.getStudy() != val2.getStudy()) {
rep = DicomSorter.STUDY_COMPARATOR.compare(val1.getStudy(), val2.getStudy());
}
if (rep != 0) {
return rep;
}
return DicomSorter.SERIES_COMPARATOR.compare(val1.getSeries(), val2.getSeries());
}
}
private DownloadManager() {
}
public static boolean removeSeriesInQueue(final LoadSeries series) {
return series.getPriority().hasConcurrentDownload() ? DownloadManager.PRIORITY_QUEUE.remove(series)
: DownloadManager.UNIQUE_QUEUE.remove(series);
}
public static void offerSeriesInQueue(final LoadSeries series) {
if (series.getPriority().hasConcurrentDownload()) {
DownloadManager.PRIORITY_QUEUE.offer(series);
} else {
DownloadManager.UNIQUE_QUEUE.offer(series);
}
}
public static synchronized void addLoadSeries(final LoadSeries series, DicomModel dicomModel,
boolean startLoading) {
if (series != null) {
if (startLoading) {
offerSeriesInQueue(series);
} else {
GuiExecutor.instance().execute(() -> {
series.getProgressBar().setValue(0);
series.stop();
});
}
if (dicomModel != null) {
dicomModel.firePropertyChange(
new ObservableEvent(ObservableEvent.BasicAction.LOADING_START, dicomModel, null, series));
}
if (!DownloadManager.TASKS.contains(series)) {
DownloadManager.TASKS.add(series);
}
}
}
public static synchronized void removeLoadSeries(LoadSeries series, DicomModel dicomModel) {
if (series != null) {
DownloadManager.TASKS.remove(series);
if (dicomModel != null) {
if (series.isCancelled()) {
dicomModel.firePropertyChange(
new ObservableEvent(ObservableEvent.BasicAction.LOADING_CANCEL, dicomModel, null, series));
} else {
dicomModel.firePropertyChange(
new ObservableEvent(ObservableEvent.BasicAction.LOADING_STOP, dicomModel, null, series));
}
}
if (DownloadManager.TASKS.isEmpty()) {
// When all loadseries are ended, reset to default the number of simultaneous download (series)
DownloadManager.CONCURRENT_EXECUTOR.setCorePoolSize(
BundleTools.SYSTEM_PREFERENCES.getIntProperty(DownloadManager.CONCURRENT_SERIES, 3));
}
}
}
public static void stopDownloading(DicomSeries series, DicomModel dicomModel) {
if (series != null) {
synchronized (DownloadManager.TASKS) {
for (final LoadSeries loading : DownloadManager.TASKS) {
if (loading.getDicomSeries() == series) {
removeLoadSeries(loading, dicomModel);
removeSeriesInQueue(loading);
if (StateValue.STARTED.equals(loading.getState())) {
loading.cancel();
}
// Ensure to stop downloading
series.setSeriesLoader(null);
break;
}
}
}
}
}
public static void resume() {
handleAllSeries(loadSeries -> loadSeries.resume());
}
public static void stop() {
handleAllSeries(loadSeries -> loadSeries.stop());
}
private static void handleAllSeries(LoadSeriesHandler handler) {
for (LoadSeries loadSeries : new ArrayList<>(DownloadManager.TASKS)) {
handler.handle(loadSeries);
Thumbnail thumbnail = (Thumbnail) loadSeries.getDicomSeries().getTagValue(TagW.Thumbnail);
if (thumbnail != null) {
thumbnail.repaint();
}
}
}
@FunctionalInterface
private static interface LoadSeriesHandler {
void handle(LoadSeries loadSeries);
}
public static List<LoadSeries> buildDicomSeriesFromXml(URI uri, final DicomModel model) throws DownloadException {
ArrayList<LoadSeries> seriesList = new ArrayList<>();
XMLStreamReader xmler = null;
InputStream stream = null;
try {
XMLInputFactory xmlif = XMLInputFactory.newInstance();
String path = uri.getPath();
URLConnection urlConnection = uri.toURL().openConnection();
if (BundleTools.SESSION_TAGS_MANIFEST.size() > 0) {
for (Iterator<Entry<String, String>> iter =
BundleTools.SESSION_TAGS_MANIFEST.entrySet().iterator(); iter.hasNext();) {
Entry<String, String> element = iter.next();
urlConnection.setRequestProperty(element.getKey(), element.getValue());
}
}
urlConnection.setUseCaches(false);
LOGGER.info("Downloading XML manifest: {}", path); //$NON-NLS-1$
InputStream urlInputStream = NetworkUtil.getUrlInputStream(urlConnection);
if (path.endsWith(".gz")) { //$NON-NLS-1$
stream = new BufferedInputStream(new GZIPInputStream(urlInputStream));
} else if (path.endsWith(".xml")) { //$NON-NLS-1$
stream = urlInputStream;
} else {
// In case wado file has no extension
File outFile = File.createTempFile("wado_", "", AppProperties.APP_TEMP_DIR); //$NON-NLS-1$ //$NON-NLS-2$
FileUtil.writeStreamWithIOException(urlInputStream, outFile);
if (MimeInspector.isMatchingMimeTypeFromMagicNumber(outFile, "application/x-gzip")) { //$NON-NLS-1$
stream = new BufferedInputStream(new GZIPInputStream(new FileInputStream(outFile)));
} else {
stream = new FileInputStream(outFile);
}
}
File tempFile = null;
if (uri.toString().startsWith("file:") && path.endsWith(".xml")) { //$NON-NLS-1$ //$NON-NLS-2$
tempFile = new File(path);
} else {
tempFile = File.createTempFile("wado_", ".xml", AppProperties.APP_TEMP_DIR); //$NON-NLS-1$ //$NON-NLS-2$
FileUtil.writeStreamWithIOException(stream, tempFile);
}
xmler = xmlif.createXMLStreamReader(new FileInputStream(tempFile));
Source xmlFile = new StAXSource(xmler);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
Schema schema = schemaFactory.newSchema(new Source[] {
new StreamSource(DownloadManager.class.getResource("/config/wado_query.xsd").toExternalForm()), //$NON-NLS-1$
new StreamSource(DownloadManager.class.getResource("/config/wado_query25.xsd").toExternalForm()) }); //$NON-NLS-1$
Validator validator = schema.newValidator();
validator.validate(xmlFile);
LOGGER.info("[Validate with XSD schema] wado_query is valid"); //$NON-NLS-1$
} catch (SAXException e) {
LOGGER.error("[Validate with XSD schema] wado_query is NOT valid", e); //$NON-NLS-1$
} catch (Exception e) {
LOGGER.error("Error when validate XSD schema. Try to update JRE", e); //$NON-NLS-1$
}
// Try to read the xml even it is not valid.
xmler = xmlif.createXMLStreamReader(new FileInputStream(tempFile));
int eventType;
if (xmler.hasNext()) {
eventType = xmler.next();
switch (eventType) {
case XMLStreamConstants.START_ELEMENT:
String key = xmler.getName().getLocalPart();
// xmlns="http://www.weasis.org/xsd/2.5"
if (TAG_XML_ROOT.equals(key)) {
boolean state = true;
while (xmler.hasNext() && state) {
eventType = xmler.next();
switch (eventType) {
case XMLStreamConstants.START_ELEMENT:
key = xmler.getName().getLocalPart();
if (TAG_ARC_QUERY.equals(key)) {
readArcQuery(model, seriesList, xmler);
} else if (TAG_PR_ROOT.equals(key)) {
// TODO implement reader of presentation
// GraphicList list = XmlSerializer.readMeasurementGraphics(gpxFile);
// if (list != null) {
// loader.setTag(TagW.MeasurementGraphics, list);
// }
}
break;
case XMLStreamConstants.END_ELEMENT:
if (TAG_XML_ROOT.equals(xmler.getName().getLocalPart())) {
state = false;
}
break;
default:
break;
}
}
} else {
// Read old manifest: xmlns="http://www.weasis.org/xsd"
if (WadoParameters.TAG_DOCUMENT_ROOT.equals(key)) {
readWadoQuery(model, seriesList, xmler);
}
}
break;
default:
break;
}
}
} catch (StreamIOException e) {
throw new DownloadException(getErrorMessage(uri), e); // rethrow network issue
} catch (Exception e) {
String message = getErrorMessage(uri);
LOGGER.error("{}", message, e); //$NON-NLS-1$
final int messageType = JOptionPane.ERROR_MESSAGE;
GuiExecutor.instance().execute(() -> {
ColorLayerUI layer = ColorLayerUI.createTransparentLayerUI(UIManager.BASE_AREA);
JOptionPane.showOptionDialog(ColorLayerUI.getContentPane(layer),
StringUtil.getTruncatedString(message, 130, Suffix.THREE_PTS), null, JOptionPane.DEFAULT_OPTION,
messageType, null, null, null);
if (layer != null) {
layer.hideUI();
}
});
} finally {
FileUtil.safeClose(xmler);
FileUtil.safeClose(stream);
}
return seriesList;
}
private static String getErrorMessage(URI uri) {
StringBuilder buf = new StringBuilder(Messages.getString("DownloadManager.error_load_xml")); //$NON-NLS-1$
buf.append(StringUtil.COLON_AND_SPACE);
buf.append(uri.toString());
return buf.toString();
}
private static void readArcQuery(DicomModel model, ArrayList<LoadSeries> seriesList, XMLStreamReader xmler)
throws XMLStreamException {
String wadoURL = TagUtil.getTagAttribute(xmler, TAG_BASE_URL, null);
boolean onlySopUID =
Boolean.parseBoolean(TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_ONLY_SOP_UID, "false")); //$NON-NLS-1$
String additionnalParameters =
TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_ADDITIONNAL_PARAMETERS, ""); //$NON-NLS-1$
String overrideList = TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_OVERRIDE_TAGS, null);
String webLogin = TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_WEB_LOGIN, null);
final WadoParameters wadoParameters =
new WadoParameters(wadoURL, onlySopUID, additionnalParameters, overrideList, webLogin);
readQuery(model, seriesList, xmler, wadoParameters, TAG_ARC_QUERY);
}
private static void readWadoQuery(DicomModel model, ArrayList<LoadSeries> seriesList, XMLStreamReader xmler)
throws XMLStreamException {
String wadoURL = TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_URL, null);
boolean onlySopUID =
Boolean.parseBoolean(TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_ONLY_SOP_UID, "false")); //$NON-NLS-1$
String additionnalParameters =
TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_ADDITIONNAL_PARAMETERS, ""); //$NON-NLS-1$
String overrideList = TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_OVERRIDE_TAGS, null);
String webLogin = TagUtil.getTagAttribute(xmler, WadoParameters.TAG_WADO_WEB_LOGIN, null);
final WadoParameters wadoParameters =
new WadoParameters(wadoURL, onlySopUID, additionnalParameters, overrideList, webLogin);
readQuery(model, seriesList, xmler, wadoParameters, WadoParameters.TAG_DOCUMENT_ROOT);
}
private static void readQuery(DicomModel model, ArrayList<LoadSeries> seriesList, XMLStreamReader xmler,
final WadoParameters wadoParameters, String endElement) throws XMLStreamException {
int pat = 0;
MediaSeriesGroup patient = null;
boolean state = true;
while (xmler.hasNext() && state) {
int eventType = xmler.next();
switch (eventType) {
case XMLStreamConstants.START_ELEMENT:
String key = xmler.getName().getLocalPart();
// <Patient> Tag
if (TagD.Level.PATIENT.getTagName().equals(key)) {
patient = readPatient(model, seriesList, xmler, wadoParameters);
pat++;
} else if (WadoParameters.TAG_HTTP_TAG.equals(key)) {
String httpkey = TagUtil.getTagAttribute(xmler, "key", null); //$NON-NLS-1$
String httpvalue = TagUtil.getTagAttribute(xmler, "value", null); //$NON-NLS-1$
wadoParameters.addHttpTag(httpkey, httpvalue);
// <Message> tag
} else if ("Message".equals(key)) { //$NON-NLS-1$
final String title = TagUtil.getTagAttribute(xmler, "title", null); //$NON-NLS-1$
final String message = TagUtil.getTagAttribute(xmler, "description", null); //$NON-NLS-1$
if (StringUtil.hasText(title) && StringUtil.hasText(message)) {
String severity = TagUtil.getTagAttribute(xmler, "severity", "WARN"); //$NON-NLS-1$ //$NON-NLS-2$
final int messageType = "ERROR".equals(severity) ? JOptionPane.ERROR_MESSAGE //$NON-NLS-1$
: "INFO" //$NON-NLS-1$
.equals(severity) ? JOptionPane.INFORMATION_MESSAGE : JOptionPane.WARNING_MESSAGE;
GuiExecutor.instance().execute(() -> {
ColorLayerUI layer = ColorLayerUI.createTransparentLayerUI(UIManager.BASE_AREA);
JOptionPane.showMessageDialog(ColorLayerUI.getContentPane(layer), message, title,
messageType);
if (layer != null) {
layer.hideUI();
}
});
}
}
break;
case XMLStreamConstants.END_ELEMENT:
if (endElement.equals(xmler.getName().getLocalPart())) {
state = false;
}
break;
default:
break;
}
}
if (pat == 1) {
// In case of the patient already exists, select it
final MediaSeriesGroup uniquePatient = patient;
GuiExecutor.instance().execute(() -> {
synchronized (UIManager.VIEWER_PLUGINS) {
for (final ViewerPlugin p : UIManager.VIEWER_PLUGINS) {
if (uniquePatient.equals(p.getGroupID())) {
p.setSelectedAndGetFocus();
break;
}
}
}
});
}
for (LoadSeries loadSeries : seriesList) {
String modality = TagD.getTagValue(loadSeries.getDicomSeries(), Tag.Modality, String.class);
boolean ps = modality != null && ("PR".equals(modality) || "KO".equals(modality)); //$NON-NLS-1$ //$NON-NLS-2$
if (!ps) {
loadSeries.startDownloadImageReference(wadoParameters);
}
}
}
private static MediaSeriesGroup readPatient(DicomModel model, ArrayList<LoadSeries> seriesList,
XMLStreamReader xmler, WadoParameters wadoParameters) throws XMLStreamException {
// PatientID, PatientBirthDate, StudyInstanceUID, SeriesInstanceUID and SOPInstanceUID override
// the tags located in DICOM object (because original DICOM can contain different values after merging
// patient or study
TagW idTag = TagD.get(Tag.PatientID);
TagW issuerIdTag = TagD.get(Tag.IssuerOfPatientID);
TagW nameTag = TagD.get(Tag.PatientName);
String patientID = TagUtil.getTagAttribute(xmler, idTag.getKeyword(), TagW.NO_VALUE);
String issuerOfPatientID = TagUtil.getTagAttribute(xmler, issuerIdTag.getKeyword(), null);
String name = TagUtil.getTagAttribute(xmler, nameTag.getKeyword(), TagW.NO_VALUE);
String patientPseudoUID = DicomMediaUtils.buildPatientPseudoUID(patientID, issuerOfPatientID, name);
MediaSeriesGroup patient = model.getHierarchyNode(MediaSeriesGroupNode.rootNode, patientPseudoUID);
if (patient == null) {
patient =
new MediaSeriesGroupNode(TagD.getUID(Level.PATIENT), patientPseudoUID, DicomModel.patient.getTagView());
patient.setTag(idTag, patientID);
patient.setTag(nameTag, name);
patient.setTagNoNull(issuerIdTag, issuerOfPatientID);
TagW[] tags = TagD.getTagFromIDs(Tag.PatientSex, Tag.PatientBirthDate, Tag.PatientBirthTime);
for (TagW tag : tags) {
tag.readValue(xmler, patient);
}
model.addHierarchyNode(MediaSeriesGroupNode.rootNode, patient);
LOGGER.info("Adding new patient: " + patient); //$NON-NLS-1$
}
int eventType;
boolean state = true;
while (xmler.hasNext() && state) {
eventType = xmler.next();
switch (eventType) {
case XMLStreamConstants.START_ELEMENT:
// <Study> Tag
if (TagD.Level.STUDY.getTagName().equals(xmler.getName().getLocalPart())) {
readStudy(model, seriesList, xmler, patient, wadoParameters);
}
break;
case XMLStreamConstants.END_ELEMENT:
if (TagD.Level.PATIENT.getTagName().equals(xmler.getName().getLocalPart())) {
state = false;
}
break;
default:
break;
}
}
return patient;
}
private static MediaSeriesGroup readStudy(DicomModel model, ArrayList<LoadSeries> seriesList, XMLStreamReader xmler,
MediaSeriesGroup patient, WadoParameters wadoParameters) throws XMLStreamException {
String studyUID = (String) TagD.getUID(Level.STUDY).getValue(xmler);
MediaSeriesGroup study = model.getHierarchyNode(patient, studyUID);
if (study == null) {
study = new MediaSeriesGroupNode(TagD.getUID(Level.STUDY), studyUID, DicomModel.study.getTagView());
TagW[] tags = TagD.getTagFromIDs(Tag.StudyDate, Tag.StudyTime, Tag.StudyDescription, Tag.AccessionNumber,
Tag.StudyID);
for (TagW tag : tags) {
tag.readValue(xmler, study);
}
model.addHierarchyNode(patient, study);
}
int eventType;
boolean state = true;
while (xmler.hasNext() && state) {
eventType = xmler.next();
switch (eventType) {
case XMLStreamConstants.START_ELEMENT:
// <Series> Tag
if (TagD.Level.SERIES.getTagName().equals(xmler.getName().getLocalPart())) {
readSeries(model, seriesList, xmler, patient, study, wadoParameters);
}
break;
case XMLStreamConstants.END_ELEMENT:
if (TagD.Level.STUDY.getTagName().equals(xmler.getName().getLocalPart())) {
state = false;
}
break;
default:
break;
}
}
return study;
}
private static Series readSeries(DicomModel model, ArrayList<LoadSeries> seriesList, XMLStreamReader xmler,
MediaSeriesGroup patient, MediaSeriesGroup study, WadoParameters wadoParameters) throws XMLStreamException {
TagW seriesTag = TagD.get(Tag.SeriesInstanceUID);
String seriesUID = (String) seriesTag.getValue(xmler);
Series dicomSeries = (Series) model.getHierarchyNode(study, seriesUID);
if (dicomSeries == null) {
dicomSeries = new DicomSeries(seriesUID);
dicomSeries.setTag(seriesTag, seriesUID);
dicomSeries.setTag(TagW.ExplorerModel, model);
dicomSeries.setTag(TagW.WadoParameters, wadoParameters);
dicomSeries.setTag(TagW.WadoInstanceReferenceList, new ArrayList<DicomInstance>());
TagW[] tags =
TagD.getTagFromIDs(Tag.Modality, Tag.SeriesNumber, Tag.SeriesDescription, Tag.ReferringPhysicianName);
for (TagW tag : tags) {
tag.readValue(xmler, dicomSeries);
}
dicomSeries.setTagNoNull(TagW.WadoTransferSyntaxUID,
TagUtil.getTagAttribute(xmler, TagW.WadoTransferSyntaxUID.getKeyword(), null));
dicomSeries.setTagNoNull(TagW.WadoCompressionRate,
TagUtil.getIntegerTagAttribute(xmler, TagW.WadoCompressionRate.getKeyword(), null));
dicomSeries.setTagNoNull(TagW.DirectDownloadThumbnail,
TagUtil.getTagAttribute(xmler, TagW.DirectDownloadThumbnail.getKeyword(), null));
model.addHierarchyNode(study, dicomSeries);
} else {
WadoParameters wado = (WadoParameters) dicomSeries.getTagValue(TagW.WadoParameters);
if (wado == null) {
// Should not happen
dicomSeries.setTag(TagW.WadoParameters, wadoParameters);
} else if (!wado.getWadoURL().equals(wadoParameters.getWadoURL())) {
LOGGER.error("Wado parameters must be unique within a DICOM Series: {}", dicomSeries); //$NON-NLS-1$
return dicomSeries;
}
}
List<DicomInstance> dicomInstances =
(List<DicomInstance>) dicomSeries.getTagValue(TagW.WadoInstanceReferenceList);
if (dicomInstances == null) {
dicomInstances = new ArrayList<>();
dicomSeries.setTag(TagW.WadoInstanceReferenceList, dicomInstances);
}
int eventType;
boolean state = true;
while (xmler.hasNext() && state) {
eventType = xmler.next();
switch (eventType) {
case XMLStreamConstants.START_ELEMENT:
// <Instance> Tag
if (TagD.Level.INSTANCE.getTagName().equals(xmler.getName().getLocalPart())) {
String sopInstanceUID =
TagUtil.getTagAttribute(xmler, TagD.getKeywordFromTag(Tag.SOPInstanceUID, null), null);
if (sopInstanceUID != null) {
DicomInstance dcmInstance = new DicomInstance(sopInstanceUID);
if (dicomInstances.contains(dcmInstance)) {
LOGGER.warn("DICOM instance {} already exists, abort downloading.", sopInstanceUID); //$NON-NLS-1$
} else {
dcmInstance.setInstanceNumber(TagUtil.getIntegerTagAttribute(xmler,
TagD.getKeywordFromTag(Tag.InstanceNumber, null), -1));
dcmInstance.setDirectDownloadFile(
TagUtil.getTagAttribute(xmler, TagW.DirectDownloadFile.getKeyword(), null));
dicomInstances.add(dcmInstance);
}
}
}
break;
case XMLStreamConstants.END_ELEMENT:
if (TagD.Level.SERIES.getTagName().equals(xmler.getName().getLocalPart())) {
state = false;
}
break;
default:
break;
}
}
if (!dicomInstances.isEmpty()) {
final LoadSeries loadSeries = new LoadSeries(dicomSeries, model,
BundleTools.SYSTEM_PREFERENCES.getIntProperty(LoadSeries.CONCURRENT_DOWNLOADS_IN_SERIES, 4), true);
loadSeries.setPriority(new DownloadPriority(patient, study, dicomSeries, true));
seriesList.add(loadSeries);
}
return dicomSeries;
}
}