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
010abstract public 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    int height(){
030        return layer.getBaseImageHeight();
031    }
032
033    @Override
034    public void run() {
035        while (true) {
036            if (canceled)
037                return;
038            WMSRequest request = layer.getRequest(localOnly);
039            if (request == null)
040                return;
041            this.b = layer.getBounds(request);
042            if (request.isPrecacheOnly()) {
043                if (!layer.cache.hasExactMatch(Main.getProjection(), request.getPixelPerDegree(), b.minEast, b.minNorth)) {
044                    attempt(request);
045                }
046            } else {
047                if(!loadFromCache(request)){
048                    attempt(request);
049                }
050            }
051            layer.finishRequest(request);
052        }
053    }
054
055    protected void attempt(WMSRequest request){ // try to fetch the image
056        int maxTries = 5; // n tries for every image
057        for (int i = 1; i <= maxTries; i++) {
058            if (canceled)
059                return;
060            try {
061                if (!request.isPrecacheOnly() && !layer.requestIsVisible(request))
062                    return;
063                fetch(request, i);
064                break; // break out of the retry loop
065            } catch (Exception e) {
066                try { // sleep some time and then ask the server again
067                    Thread.sleep(random(1000, 2000));
068                } catch (InterruptedException e1) {
069                    Main.debug("InterruptedException in "+getClass().getSimpleName()+" during WMS request");
070                }
071                if(i == maxTries) {
072                    e.printStackTrace();
073                    request.finish(State.FAILED, null);
074                }
075            }
076        }
077    }
078
079    public static int random(int min, int max) {
080        return (int)(Math.random() * ((max+1)-min) ) + min;
081    }
082
083    abstract public boolean loadFromCache(WMSRequest request);
084
085    public void cancel() {
086        canceled = true;
087    }
088
089}