Ignore:
Timestamp:
2014-08-16T23:50:43+02:00 (10 years ago)
Author:
Don-vip
Message:

fix #3916 - WMS: Improve exception handling. Proper message is now displayed on tiles.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/io/imagery/WMSGrabber.java

    r7132 r7425  
    99import java.io.InputStream;
    1010import java.io.InputStreamReader;
     11import java.io.StringReader;
    1112import java.net.HttpURLConnection;
    1213import java.net.MalformedURLException;
     
    1718import java.text.DecimalFormatSymbols;
    1819import java.text.NumberFormat;
     20import java.util.ArrayList;
    1921import java.util.HashMap;
     22import java.util.List;
    2023import java.util.Locale;
    2124import java.util.Map;
     
    2427import java.util.regex.Pattern;
    2528
     29import javax.xml.parsers.DocumentBuilder;
     30import javax.xml.parsers.DocumentBuilderFactory;
     31import javax.xml.parsers.ParserConfigurationException;
     32
    2633import org.openstreetmap.josm.Main;
     34import org.openstreetmap.josm.data.ProjectionBounds;
    2735import org.openstreetmap.josm.data.coor.EastNorth;
    2836import org.openstreetmap.josm.data.coor.LatLon;
     
    3543import org.openstreetmap.josm.tools.ImageProvider;
    3644import org.openstreetmap.josm.tools.Utils;
    37 
    38 public class WMSGrabber extends Grabber {
     45import org.w3c.dom.Document;
     46import org.w3c.dom.NodeList;
     47import org.xml.sax.InputSource;
     48import org.xml.sax.SAXException;
     49
     50/**
     51 * WMS grabber, fetching tiles from WMS server.
     52 * @since 3715
     53 */
     54public class WMSGrabber implements Runnable {
     55
     56    protected final MapView mv;
     57    protected final WMSLayer layer;
     58    private final boolean localOnly;
     59
     60    protected ProjectionBounds b;
     61    protected volatile boolean canceled;
    3962
    4063    protected String baseURL;
     
    4265    private Map<String, String> props = new HashMap<>();
    4366
     67    /**
     68     * Constructs a new {@code WMSGrabber}.
     69     * @param mv Map view
     70     * @param layer WMS layer
     71     */
    4472    public WMSGrabber(MapView mv, WMSLayer layer, boolean localOnly) {
    45         super(mv, layer, localOnly);
     73        this.mv = mv;
     74        this.layer = layer;
     75        this.localOnly = localOnly;
    4676        this.info = layer.getInfo();
    4777        this.baseURL = info.getUrl();
    48         if(layer.getInfo().getCookies() != null && !layer.getInfo().getCookies().isEmpty()) {
     78        if (layer.getInfo().getCookies() != null && !layer.getInfo().getCookies().isEmpty()) {
    4979            props.put("Cookie", layer.getInfo().getCookies());
    5080        }
     
    6090    }
    6191
     92    int width() {
     93        return layer.getBaseImageWidth();
     94    }
     95
     96    int height() {
     97        return layer.getBaseImageHeight();
     98    }
     99
    62100    @Override
    63     void fetch(WMSRequest request, int attempt) throws Exception{
     101    public void run() {
     102        while (true) {
     103            if (canceled)
     104                return;
     105            WMSRequest request = layer.getRequest(localOnly);
     106            if (request == null)
     107                return;
     108            this.b = layer.getBounds(request);
     109            if (request.isPrecacheOnly()) {
     110                if (!layer.cache.hasExactMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth)) {
     111                    attempt(request);
     112                } else if (Main.isDebugEnabled()) {
     113                    Main.debug("Ignoring "+request+" (precache only + exact match)");
     114                }
     115            } else if (!loadFromCache(request)){
     116                attempt(request);
     117            } else if (Main.isDebugEnabled()) {
     118                Main.debug("Ignoring "+request+" (loaded from cache)");
     119            }
     120            layer.finishRequest(request);
     121        }
     122    }
     123
     124    protected void attempt(WMSRequest request){ // try to fetch the image
     125        int maxTries = 5; // n tries for every image
     126        for (int i = 1; i <= maxTries; i++) {
     127            if (canceled)
     128                return;
     129            try {
     130                if (!request.isPrecacheOnly() && !layer.requestIsVisible(request))
     131                    return;
     132                fetch(request, i);
     133                break; // break out of the retry loop
     134            } catch (IOException e) {
     135                try { // sleep some time and then ask the server again
     136                    Thread.sleep(random(1000, 2000));
     137                } catch (InterruptedException e1) {
     138                    Main.debug("InterruptedException in "+getClass().getSimpleName()+" during WMS request");
     139                }
     140                if (i == maxTries) {
     141                    Main.error(e);
     142                    request.finish(State.FAILED, null, null);
     143                }
     144            } catch (WMSException e) {
     145                // Fail fast in case of WMS Service exception: useless to retry:
     146                // either the URL is wrong or the server suffers huge problems
     147                Main.error("WMS service exception while requesting "+e.getUrl()+":\n"+e.getMessage().trim());
     148                request.finish(State.FAILED, null, e);
     149                break; // break out of the retry loop
     150            }
     151        }
     152    }
     153
     154    public static int random(int min, int max) {
     155        return (int)(Math.random() * ((max+1)-min) ) + min;
     156    }
     157
     158    public final void cancel() {
     159        canceled = true;
     160    }
     161
     162    private void fetch(WMSRequest request, int attempt) throws IOException, WMSException {
    64163        URL url = null;
    65164        try {
     
    68167                    b.maxEast, b.maxNorth,
    69168                    width(), height());
    70             request.finish(State.IMAGE, grab(request, url, attempt));
    71 
    72         } catch(Exception e) {
     169            request.finish(State.IMAGE, grab(request, url, attempt), null);
     170
     171        } catch (IOException | OsmTransferException e) {
    73172            Main.error(e);
    74             throw new Exception(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""), e);
    75         }
    76     }
    77 
    78     public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000",
    79             new DecimalFormatSymbols(Locale.US));
     173            throw new IOException(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""), e);
     174        }
     175    }
     176
     177    public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000", new DecimalFormatSymbols(Locale.US));
    80178
    81179    protected URL getURL(double w, double s,double e,double n,
     
    133231    }
    134232
    135     @Override
    136233    public boolean loadFromCache(WMSRequest request) {
    137234        BufferedImage cached = layer.cache.getExactMatch(
     
    139236
    140237        if (cached != null) {
    141             request.finish(State.IMAGE, cached);
     238            request.finish(State.IMAGE, cached, null);
    142239            return true;
    143240        } else if (request.isAllowPartialCacheMatch()) {
     
    145242                    Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth);
    146243            if (partialMatch != null) {
    147                 request.finish(State.PARTLY_IN_CACHE, partialMatch);
     244                request.finish(State.PARTLY_IN_CACHE, partialMatch, null);
    148245                return true;
    149246            }
    150247        }
    151248
    152         if((!request.isReal() && !layer.hasAutoDownload())){
    153             request.finish(State.NOT_IN_CACHE, null);
     249        if ((!request.isReal() && !layer.hasAutoDownload())){
     250            request.finish(State.NOT_IN_CACHE, null, null);
    154251            return true;
    155252        }
     
    158255    }
    159256
    160     protected BufferedImage grab(WMSRequest request, URL url, int attempt) throws IOException, OsmTransferException {
     257    protected BufferedImage grab(WMSRequest request, URL url, int attempt) throws WMSException, IOException, OsmTransferException {
    161258        Main.info("Grabbing WMS " + (attempt > 1? "(attempt " + attempt + ") ":"") + url);
    162259
    163260        HttpURLConnection conn = Utils.openHttpConnection(url);
    164         for(Entry<String, String> e : props.entrySet()) {
     261        for (Entry<String, String> e : props.entrySet()) {
    165262            conn.setRequestProperty(e.getKey(), e.getValue());
    166263        }
     
    169266
    170267        String contentType = conn.getHeaderField("Content-Type");
    171         if( conn.getResponseCode() != 200
    172                 || contentType != null && !contentType.startsWith("image") )
    173             throw new IOException(readException(conn));
     268        if (conn.getResponseCode() != 200
     269                || contentType != null && !contentType.startsWith("image") ) {
     270            String xml = readException(conn);
     271            try {
     272                DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
     273                InputSource is = new InputSource(new StringReader(xml));
     274                Document doc = db.parse(is);
     275                NodeList nodes = doc.getElementsByTagName("ServiceException");
     276                List<String> exceptions = new ArrayList<>(nodes.getLength());
     277                for (int i = 0; i < nodes.getLength(); i++) {
     278                    exceptions.add(nodes.item(i).getTextContent());
     279                }
     280                throw new WMSException(request, url, exceptions);
     281            } catch (SAXException | ParserConfigurationException ex) {
     282                throw new IOException(xml, ex);
     283            }
     284        }
    174285
    175286        ByteArrayOutputStream baos = new ByteArrayOutputStream();
Note: See TracChangeset for help on using the changeset viewer.