Ticket #22733: 22733.patch
| File 22733.patch, 12.3 KB (added by , 3 years ago) |
|---|
-
src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java
Subject: [PATCH] Fix #22733: UI blocks while trying different WMS endpoint urls and cannot handle `nan` in responses --- IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java b/src/org/openstreetmap/josm/gui/preferences/imagery/AddWMSLayerPanel.java
a b 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.GraphicsEnvironment; 7 import java.awt.event.ActionEvent; 6 8 import java.awt.event.ActionListener; 7 9 import java.io.IOException; 8 10 import java.net.MalformedURLException; … … 15 17 import javax.swing.JButton; 16 18 import javax.swing.JCheckBox; 17 19 import javax.swing.JComboBox; 20 import javax.swing.JComponent; 18 21 import javax.swing.JLabel; 19 22 import javax.swing.JOptionPane; 20 23 import javax.swing.JScrollPane; … … 23 26 import org.openstreetmap.josm.data.imagery.ImageryInfo; 24 27 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; 25 28 import org.openstreetmap.josm.data.imagery.LayerDetails; 29 import org.openstreetmap.josm.gui.MainApplication; 30 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 26 31 import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser; 32 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 33 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 34 import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; 27 35 import org.openstreetmap.josm.gui.util.GuiHelper; 28 36 import org.openstreetmap.josm.gui.widgets.JosmTextArea; 37 import org.openstreetmap.josm.io.OsmTransferException; 29 38 import org.openstreetmap.josm.io.imagery.WMSImagery; 30 39 import org.openstreetmap.josm.tools.GBC; 31 40 import org.openstreetmap.josm.tools.Logging; 32 41 import org.openstreetmap.josm.tools.Utils; 42 import org.xml.sax.SAXException; 33 43 34 44 /** 35 45 * An imagery panel used to add WMS imagery sources. … … 81 91 add(new JLabel(tr("{0} Enter name for this layer", "7.")), GBC.eol()); 82 92 add(name, GBC.eop().fill(GBC.HORIZONTAL)); 83 93 84 getLayers.addActionListener(e -> { 85 try { 86 wms = new WMSImagery(Utils.strip(rawUrl.getText()), getCommonHeaders()); 87 tree.updateTree(wms); 88 Collection<String> wmsFormats = wms.getFormats(); 89 formats.setModel(new DefaultComboBoxModel<>(wmsFormats.toArray(new String[0]))); 90 formats.setSelectedItem(wms.getPreferredFormat()); 91 } catch (MalformedURLException | InvalidPathException ex1) { 92 Logging.log(Logging.LEVEL_ERROR, ex1); 93 JOptionPane.showMessageDialog(getParent(), tr("Invalid service URL."), 94 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 95 } catch (IOException ex2) { 96 Logging.log(Logging.LEVEL_ERROR, ex2); 97 JOptionPane.showMessageDialog(getParent(), tr("Could not retrieve WMS layer list."), 98 tr("WMS Error"), JOptionPane.ERROR_MESSAGE); 99 } catch (WMSImagery.WMSGetCapabilitiesException ex3) { 100 String incomingData = ex3.getIncomingData() != null ? ex3.getIncomingData().trim() : ""; 101 String title = tr("WMS Error"); 102 StringBuilder message = new StringBuilder(tr("Could not parse WMS layer list.")); 103 Logging.log(Logging.LEVEL_ERROR, "Could not parse WMS layer list. Incoming data:\n"+incomingData, ex3); 104 if ((incomingData.startsWith("<html>") || incomingData.startsWith("<HTML>")) 105 && (incomingData.endsWith("</html>") || incomingData.endsWith("</HTML>"))) { 106 GuiHelper.notifyUserHtmlError(this, title, message.toString(), incomingData); 107 } else { 108 if (ex3.getMessage() != null) { 109 message.append('\n').append(ex3.getMessage()); 110 } 111 JOptionPane.showMessageDialog(getParent(), message.toString(), title, JOptionPane.ERROR_MESSAGE); 112 } 113 } 114 }); 94 getLayers.addActionListener(e -> MainApplication.worker.execute(new GetCapabilitiesRunnable(e))); 115 95 116 96 ActionListener availabilityManagerAction = a -> { 117 97 setDefaultLayers.setEnabled(endpoint.isSelected()); … … 151 131 registerValidableComponent(setDefaultLayers); 152 132 } 153 133 134 /** 135 * Perform the get WMS layers network calls in a separate thread, mostly to allow for cancellation 136 */ 137 private class GetCapabilitiesRunnable extends PleaseWaitRunnable { 138 private final ActionEvent actionEvent; 139 140 protected GetCapabilitiesRunnable(ActionEvent actionEvent) { 141 super(tr("Trying WMS urls"), GraphicsEnvironment.isHeadless() ? NullProgressMonitor.INSTANCE : new PleaseWaitProgressMonitor(), 142 false); 143 this.actionEvent = actionEvent; 144 } 145 146 @Override 147 protected void cancel() { 148 // We don't really have something we can do -- we use the monitor to pass the cancel state on 149 } 150 151 @Override 152 protected void realRun() throws SAXException, IOException, OsmTransferException { 153 if (actionEvent.getSource() instanceof JComponent) { 154 GuiHelper.runInEDT(() -> ((JComponent) actionEvent.getSource()).setEnabled(false)); 155 } 156 ProgressMonitor monitor = getProgressMonitor(); 157 try { 158 wms = new WMSImagery(Utils.strip(rawUrl.getText()), getCommonHeaders(), monitor); 159 } catch (MalformedURLException | InvalidPathException ex1) { 160 Logging.log(Logging.LEVEL_ERROR, ex1); 161 GuiHelper.runInEDT(() -> JOptionPane.showMessageDialog(getParent(), tr("Invalid service URL."), 162 tr("WMS Error"), JOptionPane.ERROR_MESSAGE)); 163 } catch (IOException ex2) { 164 Logging.log(Logging.LEVEL_ERROR, ex2); 165 GuiHelper.runInEDT(() -> JOptionPane.showMessageDialog(getParent(), tr("Could not retrieve WMS layer list."), 166 tr("WMS Error"), JOptionPane.ERROR_MESSAGE)); 167 } catch (WMSImagery.WMSGetCapabilitiesException ex3) { 168 String incomingData = ex3.getIncomingData() != null ? ex3.getIncomingData().trim() : ""; 169 String title = tr("WMS Error"); 170 StringBuilder message = new StringBuilder(tr("Could not parse WMS layer list.")); 171 Logging.log(Logging.LEVEL_ERROR, "Could not parse WMS layer list. Incoming data:\n"+incomingData, ex3); 172 if ((incomingData.startsWith("<html>") || incomingData.startsWith("<HTML>")) 173 && (incomingData.endsWith("</html>") || incomingData.endsWith("</HTML>"))) { 174 GuiHelper.runInEDT(() -> GuiHelper.notifyUserHtmlError(AddWMSLayerPanel.this, title, message.toString(), incomingData)); 175 } else { 176 if (ex3.getMessage() != null) { 177 message.append('\n').append(ex3.getMessage()); 178 } 179 GuiHelper.runInEDT(() -> JOptionPane.showMessageDialog(getParent(), message.toString(), title, JOptionPane.ERROR_MESSAGE)); 180 } 181 } 182 } 183 184 @Override 185 protected void finish() { 186 if (wms != null) { 187 GuiHelper.runInEDT(() -> { 188 tree.updateTree(wms); 189 Collection<String> wmsFormats = wms.getFormats(); 190 formats.setModel(new DefaultComboBoxModel<>(wmsFormats.toArray(new String[0]))); 191 formats.setSelectedItem(wms.getPreferredFormat()); 192 }); 193 } 194 if (actionEvent.getSource() instanceof JComponent) { 195 GuiHelper.runInEDT(() -> ((JComponent) actionEvent.getSource()).setEnabled(true)); 196 } 197 } 198 } 199 154 200 protected final void onLayerSelectionChanged() { 155 201 if (wms != null && wms.buildRootUrl() != null) { 156 202 wmsUrl.setText(wms.buildGetMapUrl( -
src/org/openstreetmap/josm/io/imagery/WMSImagery.java
IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/io/imagery/WMSImagery.java b/src/org/openstreetmap/josm/io/imagery/WMSImagery.java
a b 11 11 import java.net.URL; 12 12 import java.nio.file.InvalidPathException; 13 13 import java.util.ArrayList; 14 import java.util.Arrays; 14 15 import java.util.Collection; 15 16 import java.util.Collections; 16 17 import java.util.HashSet; … … 35 36 import org.openstreetmap.josm.data.imagery.LayerDetails; 36 37 import org.openstreetmap.josm.data.projection.Projection; 37 38 import org.openstreetmap.josm.data.projection.Projections; 39 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; 40 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 38 41 import org.openstreetmap.josm.io.CachedFile; 39 42 import org.openstreetmap.josm.tools.Logging; 40 43 import org.openstreetmap.josm.tools.Utils; … … 150 153 * @throws InvalidPathException if a Path object cannot be constructed for the capabilities cached file 151 154 */ 152 155 public WMSImagery(String url, Map<String, String> headers) throws IOException, WMSGetCapabilitiesException { 156 this(url, headers, NullProgressMonitor.INSTANCE); 157 } 158 159 /** 160 * Make getCapabilities request towards given URL using headers 161 * @param url service url 162 * @param headers HTTP headers to be sent with request 163 * @param monitor Feedback for which URL we are currently trying, the integer is the <i>total number of urls</i> we are going to try 164 * @throws IOException when connection error when fetching get capabilities document 165 * @throws WMSGetCapabilitiesException when there are errors when parsing get capabilities document 166 * @throws InvalidPathException if a Path object cannot be constructed for the capabilities cached file 167 */ 168 public WMSImagery(String url, Map<String, String> headers, ProgressMonitor monitor) 169 throws IOException, WMSGetCapabilitiesException { 153 170 if (headers != null) { 154 171 this.headers.putAll(headers); 155 172 } 156 173 157 174 IOException savedExc = null; 158 175 String workingAddress = null; 159 url_search: 160 for (String z: new String[]{ 161 normalizeUrl(url), 162 url, 163 url + CAPABILITIES_QUERY_STRING, 164 }) { 165 for (String ver: new String[]{"", "&VERSION=1.3.0", "&VERSION=1.1.1"}) { 176 final String[] baseAdditions = { 177 normalizeUrl(url), 178 url, 179 url + CAPABILITIES_QUERY_STRING, 180 }; 181 final String[] versionAdditions = {"", "&VERSION=1.3.0", "&VERSION=1.1.1"}; 182 final int totalNumberOfUrlsToTry = baseAdditions.length * versionAdditions.length; 183 monitor.setTicksCount(totalNumberOfUrlsToTry); 184 url_search: 185 for (String z : baseAdditions) { 186 for (String ver : versionAdditions) { 187 if (monitor.isCanceled()) { 188 break url_search; 189 } 166 190 try { 191 monitor.setCustomText(z + ver); 192 monitor.worked(1); 167 193 attemptGetCapabilities(z + ver); 168 194 workingAddress = z; 169 195 calculateChildren(); … … 192 218 } 193 219 } 194 220 } 195 196 221 if (savedExc != null) { 197 222 throw savedExc; 198 223 } … … 615 640 } 616 641 617 642 private static Bounds parseBBox(Projection conv, String miny, String minx, String maxy, String maxx) { 618 if (miny == null || minx == null || maxy == null || maxx == null ) {643 if (miny == null || minx == null || maxy == null || maxx == null || Arrays.asList(miny, minx, maxy, maxx).contains("nan")) { 619 644 return null; 620 645 } 621 646 if (conv != null) {
