/*******************************************************************************
* 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.beans.PropertyChangeListener;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import javax.swing.JOptionPane;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.weasis.core.api.explorer.ObservableEvent;
import org.weasis.core.api.explorer.ObservableEvent.BasicAction;
import org.weasis.core.api.explorer.model.DataExplorerModel;
import org.weasis.core.api.gui.util.GuiExecutor;
import org.weasis.core.api.service.BundleTools;
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.ui.docking.UIManager;
import org.weasis.dicom.explorer.DicomModel;
import org.weasis.dicom.explorer.ExplorerTask;
import org.weasis.dicom.explorer.Messages;
import org.weasis.dicom.explorer.pref.download.SeriesDownloadPrefView;
import org.weasis.dicom.explorer.wado.DownloadManager.PriorityTaskComparator;
public class LoadRemoteDicomManifest extends ExplorerTask<Boolean, String> {
private static final Logger LOGGER = LoggerFactory.getLogger(LoadRemoteDicomManifest.class);
private final DicomModel dicomModel;
private final List<String> xmlFiles;
private final AtomicInteger retryNb = new AtomicInteger(0);
private final List<LoadSeries> loadSeriesList = new ArrayList<>();
private final PropertyChangeListener propertyChangeListener = evt -> {
if (evt instanceof ObservableEvent) {
ObservableEvent event = (ObservableEvent) evt;
if (event.getNewValue() instanceof LoadSeries) {
LoadSeries s = (LoadSeries) event.getNewValue();
BasicAction cmd = event.getActionCommand();
if (ObservableEvent.BasicAction.LOADING_STOP.equals(cmd)
|| ObservableEvent.BasicAction.LOADING_CANCEL.equals(cmd)) {
checkDownloadIssues(s);
} else if (ObservableEvent.BasicAction.LOADING_START.equals(cmd)) {
if (!loadSeriesList.contains(s)) {
loadSeriesList.add(s);
}
}
}
}
};
public LoadRemoteDicomManifest(List<String> xmlFiles, DataExplorerModel explorerModel) {
super(Messages.getString("DicomExplorer.loading"), true); //$NON-NLS-1$
if (xmlFiles == null || !(explorerModel instanceof DicomModel)) {
throw new IllegalArgumentException("invalid parameters"); //$NON-NLS-1$
}
this.xmlFiles = xmlFiles.stream().filter(Objects::nonNull).collect(Collectors.toList());
this.dicomModel = (DicomModel) explorerModel;
}
private void checkDownloadIssues(LoadSeries loadSeries) {
if (!loadSeries.hasDownloadFailed()) {
loadSeriesList.remove(loadSeries);
}
if (DownloadManager.TASKS.isEmpty() || DownloadManager.TASKS.stream().allMatch(l -> l.isStopped())) {
if (!loadSeriesList.isEmpty() && tryDownloadingAgain(null)) {
LOGGER.info("Try downloading ({}) the missing elements", retryNb.get()); //$NON-NLS-1$
List<LoadSeries> oldList = new ArrayList<>(loadSeriesList);
loadSeriesList.clear();
dicomModel.removePropertyChangeListener(propertyChangeListener);
for (LoadSeries s : oldList) {
LoadSeries task = s.cancelAndReplace(s);
loadSeriesList.add(task);
}
startDownloadingSeries(loadSeriesList, true);
dicomModel.addPropertyChangeListener(propertyChangeListener);
} else {
dicomModel.removePropertyChangeListener(propertyChangeListener);
}
}
}
private boolean tryDownloadingAgain(DownloadException e) {
if (retryNb.getAndIncrement() == 0) {
return true;
}
boolean[] ret = { false };
GuiExecutor.instance().invokeAndWait(() -> {
int confirm = JOptionPane.showConfirmDialog(UIManager.getApplicationWindow(), getErrorMessage(e),
Messages.getString("LoadRemoteDicomManifest.net_err_msg"), JOptionPane.YES_NO_OPTION); //$NON-NLS-1$
ret[0] = JOptionPane.YES_OPTION == confirm;
});
return ret[0];
}
private static String getErrorMessage(DownloadException e) {
StringBuilder buf = new StringBuilder();
if (e == null) { // images
buf.append(Messages.getString("LoadRemoteDicomManifest.cannot_download")); //$NON-NLS-1$
} else { // xml manifest
buf.append(StringUtil.getTruncatedString(e.getMessage(), 130, Suffix.THREE_PTS));
if (e.getCause() instanceof StreamIOException) {
String serverMessage = e.getCause().getMessage();
if (StringUtil.hasText(serverMessage)) {
buf.append("\n"); //$NON-NLS-1$
buf.append(Messages.getString("LoadRemoteDicomManifest.server_resp")); //$NON-NLS-1$
buf.append(StringUtil.COLON_AND_SPACE);
buf.append(StringUtil.getTruncatedString(serverMessage, 100, Suffix.THREE_PTS));
}
}
}
buf.append("\n\n"); //$NON-NLS-1$
buf.append(Messages.getString("LoadRemoteDicomManifest.download_again")); //$NON-NLS-1$
return buf.toString();
}
@Override
protected void done() {
DownloadManager.CONCURRENT_EXECUTOR.prestartAllCoreThreads();
}
@Override
protected Boolean doInBackground() throws Exception {
try {
Iterator<String> iter = xmlFiles.iterator();
while (iter.hasNext()) {
downloadManifest(iter);
}
} catch (DownloadException e) {
LOGGER.error("Download failed", e); //$NON-NLS-1$
if (tryDownloadingAgain(e)) {
LOGGER.info("Try donloaging again: {}", xmlFiles); //$NON-NLS-1$
LoadRemoteDicomManifest mf = new LoadRemoteDicomManifest(xmlFiles, dicomModel);
mf.retryNb.set(retryNb.get());
mf.execute();
}
}
// Add listener to know when download of series ends
dicomModel.addPropertyChangeListener(propertyChangeListener);
return true;
}
private void downloadManifest(Iterator<String> iter) throws DownloadException {
URI uri = null;
try {
String path = iter.next();
if (!path.startsWith("http")) { //$NON-NLS-1$
try {
File file = new File(path);
if (file.canRead()) {
uri = file.toURI();
}
} catch (Exception e) {
// Do nothing
}
}
if (uri == null) {
uri = new URL(path).toURI();
}
List<LoadSeries> wadoTasks = DownloadManager.buildDicomSeriesFromXml(uri, dicomModel);
iter.remove();
if (wadoTasks != null) {
loadSeriesList.addAll(wadoTasks);
boolean downloadImmediately = BundleTools.SYSTEM_PREFERENCES
.getBooleanProperty(SeriesDownloadPrefView.DOWNLOAD_IMMEDIATELY, true);
startDownloadingSeries(wadoTasks, downloadImmediately);
}
} catch (URISyntaxException | MalformedURLException e) {
LOGGER.error("Loading manifest", e); //$NON-NLS-1$
}
}
private void startDownloadingSeries(List<LoadSeries> series, boolean downloadImmediately) {
for (final LoadSeries loadSeries : series) {
DownloadManager.addLoadSeries(loadSeries, dicomModel, downloadImmediately);
}
// Sort tasks from the download priority order (low number has a higher priority), TASKS
// is sorted from low to high priority).
Collections.sort(DownloadManager.TASKS, Collections.reverseOrder(new PriorityTaskComparator()));
}
}