001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io.imagery;
003
004import org.openstreetmap.josm.Main;
005import org.openstreetmap.josm.data.ProjectionBounds;
006import org.openstreetmap.josm.data.imagery.GeorefImage.State;
007import org.openstreetmap.josm.gui.MapView;
008import org.openstreetmap.josm.gui.layer.WMSLayer;
009
010public abstract class Grabber implements Runnable {
011    protected final MapView mv;
012    protected final WMSLayer layer;
013    private final boolean localOnly;
014
015    protected ProjectionBounds b;
016    protected volatile boolean canceled;
017
018    Grabber(MapView mv, WMSLayer layer, boolean localOnly) {
019        this.mv = mv;
020        this.layer = layer;
021        this.localOnly = localOnly;
022    }
023
024    abstract void fetch(WMSRequest request, int attempt) throws Exception; // the image fetch code
025
026    int width(){
027        return layer.getBaseImageWidth();
028    }
029
030    int height(){
031        return layer.getBaseImageHeight();
032    }
033
034    @Override
035    public void run() {
036        while (true) {
037            if (canceled)
038                return;
039            WMSRequest request = layer.getRequest(localOnly);
040            if (request == null)
041                return;
042            this.b = layer.getBounds(request);
043            if (request.isPrecacheOnly()) {
044                if (!layer.cache.hasExactMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth)) {
045                    attempt(request);
046                } else if (Main.isDebugEnabled()) {
047                    Main.debug("Ignoring "+request+" (precache only + exact match)");
048                }
049            } else if (!loadFromCache(request)){
050                attempt(request);
051            } else if (Main.isDebugEnabled()) {
052                Main.debug("Ignoring "+request+" (loaded from cache)");
053            }
054            layer.finishRequest(request);
055        }
056    }
057
058    protected void attempt(WMSRequest request){ // try to fetch the image
059        int maxTries = 5; // n tries for every image
060        for (int i = 1; i <= maxTries; i++) {
061            if (canceled)
062                return;
063            try {
064                if (!request.isPrecacheOnly() && !layer.requestIsVisible(request))
065                    return;
066                fetch(request, i);
067                break; // break out of the retry loop
068            } catch (Exception e) {
069                try { // sleep some time and then ask the server again
070                    Thread.sleep(random(1000, 2000));
071                } catch (InterruptedException e1) {
072                    Main.debug("InterruptedException in "+getClass().getSimpleName()+" during WMS request");
073                }
074                if (i == maxTries) {
075                    Main.error(e);
076                    request.finish(State.FAILED, null);
077                }
078            }
079        }
080    }
081
082    public static int random(int min, int max) {
083        return (int)(Math.random() * ((max+1)-min) ) + min;
084    }
085
086    public abstract boolean loadFromCache(WMSRequest request);
087
088    public void cancel() {
089        canceled = true;
090    }
091}