nl.cloudfarming.client.geoviewer.jxmap.map.cache.OfflineTileRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of geoviewer-jxmap Show documentation
Show all versions of geoviewer-jxmap Show documentation
AgroSense geoviewer JXMap implementation. Contains a map/geoviewer TopComponent based on the JXMap classes from swingx.
The newest version!
/**
* Copyright (C) 2008-2012 AgroSense Foundation.
*
* AgroSense is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* There are special exceptions to the terms and conditions of the GPLv3 as it is applied to
* this software, see the FLOSS License Exception
* .
*
* AgroSense is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AgroSense. If not, see .
*/
package nl.cloudfarming.client.geoviewer.jxmap.map.cache;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingUtilities;
import nl.cloudfarming.client.geoviewer.jxmap.map.cache.spi.CacheManager;
import nl.cloudfarming.client.geoviewer.jxmap.map.cache.spi.DefaultTileService;
import nl.cloudfarming.client.util.connection.ConnectionChecker;
import org.jdesktop.swingx.graphics.GraphicsUtilities;
import org.jdesktop.swingx.mapviewer.Tile;
import org.jdesktop.swingx.mapviewer.TileCache;
/**
* Runner does the loading.
Mostly copied from AbstractTileFactory
*
* First we check memory cache. If failed, disk cache is searched.
If
* also unsuccessful and online, download tile from openstreetmap server
* Otherwise create offline Tile
*
* @author Frantisek Post
*/
public class OfflineTileRunner implements Runnable {
private static final Logger LOG = Logger.getLogger(OfflineTileRunner.class.getName());
private OfflineTileFactory tileFactory;
private TileCache tileCache;
private ConnectionChecker connectionChecker;
public OfflineTileRunner(OfflineTileFactory tileFactory) {
this.tileFactory = tileFactory;
connectionChecker = ConnectionChecker.getInstance();
tileCache = tileFactory.getTileCache();
}
protected URI getURI(Tile tile) throws URISyntaxException {
if (tile.getURL() == null) {
return null;
}
return new URI(tile.getURL());
}
@Override
public void run() {
/*
* 3 strikes and you're out. Attempt to load the url. If it fails,
* decrement the number of tries left and try again. Log failures.
* If I run out of try s just get out. This way, if there is some
* kind of serious failure, I can get out and let other tiles
* try to load.
*/
final OfflineTile tile = (OfflineTile) tileFactory.getTileQueue().remove();
int trys = 3;
while (!tile.isLoaded() && trys > 0) {
try {
BufferedImage img;
URI uri = getURI(tile);
img = tileCache.get(uri);
if (img == null) {
TileCacheInfo info = CacheUriTranslator.getCacheInfo(uri);
if (CacheManager.getInstance().isCached(info.getZoom(), info.getX(), info.getY())) {
img = TileRepository.getInstance().getTile(info);
byte[] bimg = imageToByteArray(img);
tileCache.put(uri, bimg, img);
img = tileCache.get(uri);
} else if (connectionChecker.isOnline()) {
byte[] bimg = cacheInputStream(uri.toURL());
img = GraphicsUtilities.loadCompatibleImage(new ByteArrayInputStream(bimg));//ImageIO.read(new URL(tile.url));
tileCache.put(uri, bimg, img);
img = tileCache.get(uri);
DefaultTileService.getInstance().writeTile(info, img);
} else {
offlineTile(tile);
}
}
if (img == null) {
trys--;
} else {
final BufferedImage i = img;
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
tile.setImage(new SoftReference<>(i));
tile.setLoaded(true);
}
});
}
} catch (OutOfMemoryError memErr) {
tileCache.needMoreMemory();
} catch (UnknownHostException | NoRouteToHostException | ConnectException ex) {
offlineTile(tile);
} catch (Throwable e) {
LOG.log(Level.SEVERE,
"Failed to load a tile at url: " + tile.getURL() + ", retrying", e);
Object oldError = tile.getError();
tile.setError(e);
tile.firePropertyChangeOnEDT("loadingError", oldError, e);
if (trys == 0) {
tile.firePropertyChangeOnEDT("unrecoverableError", null, e);
} else {
trys--;
}
}
}
tile.setLoading(false);
}
private void offlineTile(OfflineTile tile) {
tile.createOfflineImage();
tile.setLoaded(true);
tile.setLoading(false);
}
private byte[] cacheInputStream(URL url) throws IOException {
URLConnection conn = url.openConnection();
//Setting user agent to get connection through firewalls
conn.setRequestProperty("User-Agent", "Mozilla 5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.11) ");
InputStream ins = conn.getInputStream();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buf = new byte[256];
while (true) {
int n = ins.read(buf);
if (n == -1) {
break;
}
bout.write(buf, 0, n);
}
return bout.toByteArray();
}
private byte[] imageToByteArray(BufferedImage image) {
WritableRaster raster = image.getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return data.getData();
}
}