package org.weasis.dicom.qr; import java.io.ByteArrayInputStream; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import javax.swing.JOptionPane; import org.dcm4che3.data.Tag; import org.dcm4che3.net.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.weasis.core.api.explorer.ObservableEvent; import org.weasis.core.api.gui.task.CircularProgressBar; import org.weasis.core.api.gui.util.AppProperties; import org.weasis.core.api.gui.util.GuiExecutor; import org.weasis.core.api.util.FileUtil; import org.weasis.core.api.util.ResourceUtil; import org.weasis.core.api.util.StringUtil; import org.weasis.dicom.codec.wado.WadoParameters; import org.weasis.dicom.explorer.DicomModel; import org.weasis.dicom.explorer.ExplorerTask; import org.weasis.dicom.explorer.LoadLocalDicom; import org.weasis.dicom.explorer.pref.node.AbstractDicomNode; import org.weasis.dicom.explorer.pref.node.AbstractDicomNode.RetrieveType; import org.weasis.dicom.explorer.pref.node.DefaultDicomNode; import org.weasis.dicom.explorer.pref.node.DicomWebNode; import org.weasis.dicom.explorer.wado.LoadRemoteDicomManifest; import org.weasis.dicom.op.CGet; import org.weasis.dicom.op.CMove; import org.weasis.dicom.param.AdvancedParams; import org.weasis.dicom.param.ConnectOptions; import org.weasis.dicom.param.DicomParam; import org.weasis.dicom.param.DicomProgress; import org.weasis.dicom.param.DicomState; import org.weasis.dicom.qr.manisfest.ManifestBuilder; import org.weasis.dicom.tool.DicomListener; public class RetrieveTask extends ExplorerTask<ExplorerTask<Boolean, String>, String> { private static final Logger LOGGER = LoggerFactory.getLogger(RetrieveTask.class); private final List<String> studies; private final DicomModel explorerDcmModel; private final DicomQrView dicomQrView; public RetrieveTask(List<String> studies, DicomModel explorerDcmModel, DicomQrView dicomQrView) { super(AbstractDicomNode.UsageType.RETRIEVE.toString(), false); this.studies = studies; this.explorerDcmModel = explorerDcmModel; this.dicomQrView = dicomQrView; } @Override protected ExplorerTask<Boolean, String> doInBackground() throws Exception { explorerDcmModel.firePropertyChange( new ObservableEvent(ObservableEvent.BasicAction.LOADING_START, explorerDcmModel, null, this)); ExplorerTask<Boolean, String> loadingTask = null; String errorMessage = null; final CircularProgressBar progressBar = getBar(); DicomProgress progress = new DicomProgress(); progress.addProgressListener(p -> GuiExecutor.instance().execute(() -> { int c = p.getNumberOfCompletedSuboperations() + p.getNumberOfFailedSuboperations(); int r = p.getNumberOfRemainingSuboperations(); int t = c + r; if (t > 0) { progressBar.setValue((c * 100) / t); } })); addCancelListener(progress); DicomParam[] dcmParams = { new DicomParam(Tag.StudyInstanceUID, studies.toArray(new String[studies.size()])) }; Object selectedItem = dicomQrView.getComboDestinationNode().getSelectedItem(); if (selectedItem instanceof DefaultDicomNode) { final DefaultDicomNode node = (DefaultDicomNode) selectedItem; DefaultDicomNode callingNode = (DefaultDicomNode) dicomQrView.getComboCallingNode().getSelectedItem(); if (callingNode == null) { errorMessage = Messages.getString("RetrieveTask.no_calling_node"); //$NON-NLS-1$ } else { final DicomState state; RetrieveType type = (RetrieveType) dicomQrView.getComboDicomRetrieveType().getSelectedItem(); AdvancedParams params = new AdvancedParams(); ConnectOptions connectOptions = new ConnectOptions(); connectOptions.setConnectTimeout(3000); connectOptions.setAcceptTimeout(5000); params.setConnectOptions(connectOptions); if (RetrieveType.CGET == type) { File sopClass = ResourceUtil.getResource("store-tcs.properties"); //$NON-NLS-1$ URL url = null; if (sopClass.canRead()) { try { url = sopClass.toURI().toURL(); } catch (MalformedURLException e) { LOGGER.error("SOP Class url conversion", e); //$NON-NLS-1$ } } state = CGet.process(params, callingNode.getDicomNodeWithOnlyAET(), node.getDicomNode(), progress, DicomQrView.tempDir, url, dcmParams); } else if (RetrieveType.CMOVE == type) { DicomListener dicomListener = dicomQrView.getDicomListener(); try { if (dicomListener == null) { errorMessage = Messages.getString("RetrieveTask.msg_start_listener"); //$NON-NLS-1$ } else { dicomListener.setParams(params); if (dicomListener.isRunning()) { errorMessage = Messages.getString("RetrieveTask.msg_running_listener"); //$NON-NLS-1$ } else { dicomListener.start(callingNode.getDicomNode()); } } } catch (Exception e) { dicomListener.stop(); String msg = Messages.getString("RetrieveTask.msg_start_listener"); //$NON-NLS-1$ errorMessage = String.format("%s: %s.", msg, e.getMessage()); //$NON-NLS-1$ LOGGER.error("Start DICOM listener", e); //$NON-NLS-1$ } if (errorMessage != null) { state = new DicomState(Status.UnableToProcess, errorMessage, null); } else { state = CMove.process(params, callingNode.getDicomNode(), node.getDicomNode(), callingNode.getAeTitle(), progress, dcmParams); dicomListener.stop(); } } else if (RetrieveType.WADO == type) { List<AbstractDicomNode> webNodes = AbstractDicomNode.loadDicomNodes(AbstractDicomNode.Type.WEB, AbstractDicomNode.UsageType.RETRIEVE); String host = getHostname(node.getDicomNode().getHostname()); List<URL> wadoURLs = new ArrayList<>(); for (AbstractDicomNode n : webNodes) { if (n instanceof DicomWebNode) { DicomWebNode wn = (DicomWebNode) n; URL url = wn.getUrl(); if (DicomWebNode.WebType.WADO == wn.getWebType() && url != null && getHostname(url.getHost()).contains(host)) { wadoURLs.add(url); } } } if (wadoURLs.isEmpty()) { GuiExecutor.instance() .execute(() -> JOptionPane.showMessageDialog(dicomQrView.getBasePanel(), Messages.getString("RetrieveTask.no_wado_url_match"), //$NON-NLS-1$ RetrieveType.WADO.toString(), JOptionPane.ERROR_MESSAGE)); return null; } if (wadoURLs.size() > 1) { GuiExecutor.instance().invokeAndWait(() -> { Object[] options = wadoURLs.toArray(); Object response = JOptionPane.showInputDialog(dicomQrView.getBasePanel(), Messages.getString("RetrieveTask.several_wado_urls"), RetrieveType.WADO.toString(), //$NON-NLS-1$ JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if (response != null) { wadoURLs.clear(); wadoURLs.add((URL) response); } }); } WadoParameters wadoParameters = new WadoParameters(wadoURLs.get(0).toString(), false, null, null, null); ManifestBuilder manifest = new ManifestBuilder(); manifest.fillSeries(params, callingNode.getDicomNodeWithOnlyAET(), node.getDicomNode(), dicomQrView.getDicomModel(), studies); String wadoXmlGenerated = manifest.xmlManifest(wadoParameters, null); if (wadoXmlGenerated == null) { state = new DicomState(Status.UnableToProcess, Messages.getString("RetrieveTask.msg_build_manifest"), null); //$NON-NLS-1$ } else { List<String> xmlFiles = new ArrayList<>(1); try { File tempFile = File.createTempFile("wado_", ".xml", AppProperties.APP_TEMP_DIR); //$NON-NLS-1$ //$NON-NLS-2$ FileUtil.writeStreamWithIOException( new ByteArrayInputStream(wadoXmlGenerated.getBytes(StandardCharsets.UTF_8)), tempFile); xmlFiles.add(tempFile.getPath()); } catch (Exception e) { LOGGER.info("ungzip manifest", e); //$NON-NLS-1$ } return new LoadRemoteDicomManifest(xmlFiles, explorerDcmModel); } } else { state = new DicomState(Status.UnableToProcess, Messages.getString("RetrieveTask.msg_retrieve_type"), //$NON-NLS-1$ null); } if (state.getStatus() != Status.Success && state.getStatus() != Status.Cancel) { errorMessage = state.getMessage(); if (!StringUtil.hasText(errorMessage)) { DicomState.buildMessage(state, null, null); } if (!StringUtil.hasText(errorMessage)) { errorMessage = Messages.getString("RetrieveTask.msg_unexpected_error"); //$NON-NLS-1$ } LOGGER.error("Dicom retrieve error: {}", errorMessage); //$NON-NLS-1$ } loadingTask = new LoadLocalDicom(new File[] { new File(DicomQrView.tempDir.getPath()) }, false, explorerDcmModel); } } else if (selectedItem instanceof DicomWebNode) { throw new IllegalAccessError("Not implemented yet"); //$NON-NLS-1$ } else { errorMessage = Messages.getString("RetrieveTask.no_calling_node"); //$NON-NLS-1$ } if (errorMessage != null) { final String mes = errorMessage; final String errorTitle = StringUtil.getEmpty2NullObject(dicomQrView.getComboDicomRetrieveType().getSelectedItem()); GuiExecutor.instance().execute(() -> JOptionPane.showMessageDialog(dicomQrView.getBasePanel(), mes, errorTitle, JOptionPane.ERROR_MESSAGE)); } return loadingTask; } @Override protected void done() { this.removeAllCancelListeners(); explorerDcmModel.firePropertyChange( new ObservableEvent(ObservableEvent.BasicAction.LOADING_STOP, explorerDcmModel, null, this)); try { ExplorerTask<Boolean, String> task = get(); if (task != null) { DicomModel.LOADING_EXECUTOR.execute(task); } } catch (InterruptedException e) { LOGGER.warn("Retrieving task Interruption"); //$NON-NLS-1$ } catch (ExecutionException e) { LOGGER.error("Retrieving task", e); //$NON-NLS-1$ } } private static String getHostname(String host) { if ("127.0.0.1".equals(host) || "127.0.1.1".equals(host) || "::1".equals(host)) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return "localhost"; //$NON-NLS-1$ } return host; } }