/*
Copyright (C) 2001, 2007 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.layers.rpf;
import com.sun.opengl.util.texture.TextureData;
import com.sun.opengl.util.texture.TextureIO;
import gov.nasa.worldwind.Configuration;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.avlist.AVList;
import gov.nasa.worldwind.avlist.AVListImpl;
import gov.nasa.worldwind.cache.BasicMemoryCache;
import gov.nasa.worldwind.cache.MemoryCache;
import gov.nasa.worldwind.formats.dds.DDSConverter;
import gov.nasa.worldwind.geom.Angle;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.geom.Vec4;
import gov.nasa.worldwind.layers.TextureTile;
import gov.nasa.worldwind.layers.TiledImageLayer;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.retrieve.RetrievalPostProcessor;
import gov.nasa.worldwind.retrieve.Retriever;
import gov.nasa.worldwind.util.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
/**
* @author dcollins
* @version $Id: RPFTiledImageLayer.java 5055 2008-04-14 05:19:11Z tgaskins $
*/
public class RPFTiledImageLayer extends TiledImageLayer
{
private AVList creationParams;
private final RPFGenerator rpfGenerator;
private final Object fileLock = new Object();
public static final String RPF_ROOT_PATH = "rpf.RootPath";
public static final String RPF_DATA_SERIES_ID = "rpf.DataSeriesId";
static Collection<Tile> createTopLevelTiles(AVList params)
{
if (params == null)
{
String message = Logging.getMessage("nullValue.LayerConfigParams");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
LevelSet levels = new LevelSet(initParams(params));
Sector sector = levels.getSector();
Angle dLat = levels.getLevelZeroTileDelta().getLatitude();
Angle dLon = levels.getLevelZeroTileDelta().getLongitude();
// Determine the row and column offset from the common World Wind global tiling origin.
Level level = levels.getFirstLevel();
int firstRow = Tile.computeRow(level.getTileDelta().getLatitude(), sector.getMinLatitude());
int firstCol = Tile.computeColumn(level.getTileDelta().getLongitude(), sector.getMinLongitude());
int lastRow = Tile.computeRow(level.getTileDelta().getLatitude(), sector.getMaxLatitude());
int lastCol = Tile.computeColumn(level.getTileDelta().getLongitude(), sector.getMaxLongitude());
int nLatTiles = lastRow - firstRow + 1;
int nLonTiles = lastCol - firstCol + 1;
ArrayList<Tile> topLevels = new ArrayList<Tile>(nLatTiles * nLonTiles);
Angle p1 = Tile.computeRowLatitude(firstRow, dLat);
for (int row = firstRow; row <= lastRow; row++)
{
Angle p2;
p2 = p1.add(dLat);
Angle t1 = Tile.computeColumnLongitude(firstCol, dLon);
for (int col = firstCol; col <= lastCol; col++)
{
Angle t2;
t2 = t1.add(dLon);
topLevels.add(new Tile(new Sector(p1, p2, t1, t2), level, row, col));
t1 = t2;
}
p1 = p2;
}
return topLevels;
}
static String getFileIndexCachePath(String rootPath, String dataSeriesId)
{
String path = null;
if (rootPath != null && dataSeriesId != null)
{
path = WWIO.formPath(
rootPath,
dataSeriesId,
"rpf_file_index.idx");
}
return path;
}
public static RPFTiledImageLayer fromRestorableState(String stateInXml)
{
if (stateInXml == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
return new RPFTiledImageLayer(stateInXml);
}
public RPFTiledImageLayer(String stateInXml)
{
this(xmlStateToParams(stateInXml));
RestorableSupport rs;
try
{
rs = RestorableSupport.parse(stateInXml);
}
catch (Exception e)
{
// Parsing the document specified by stateInXml failed.
String message = Logging.getMessage("generic.ExceptionAttemptingToParseStateXml", stateInXml);
Logging.logger().severe(message);
throw new IllegalArgumentException(message, e);
}
RestorableSupport.StateObject so = rs.getStateObject("avlist");
if (so != null)
{
RestorableSupport.StateObject[] avpairs = rs.getAllStateObjects(so, "");
for (RestorableSupport.StateObject avp : avpairs)
{
if (avp != null)
setValue(avp.getName(), avp.getValue());
}
}
}
public RPFTiledImageLayer(AVList params)
{
super(new LevelSet(initParams(params)));
this.creationParams = params.copy();
this.rpfGenerator = new RPFGenerator(params);
this.setValue(AVKey.CONSTRUCTION_PARAMETERS, params);
//this.setUseMipMaps(true);
this.setUseTransparentTextures(true);
this.setName(makeTitle(params));
if (!WorldWind.getMemoryCacheSet().containsCache(TextureTile.class.getName()))
{
long size = Configuration.getLongValue(AVKey.TEXTURE_IMAGE_CACHE_SIZE, 3000000L);
MemoryCache cache = new BasicMemoryCache((long) (0.85 * size), size);
cache.setName("Texture Tiles");
WorldWind.getMemoryCacheSet().addCache(TextureTile.class.getName(), cache);
}
}
private static AVList initParams(AVList params)
{
if (params == null)
{
String message = Logging.getMessage("nullValue.LayerConfigParams");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
String rootPath = params.getStringValue(RPF_ROOT_PATH);
if (rootPath == null)
{
String message = "root path is null";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
String dataSeriesId = params.getStringValue(RPF_DATA_SERIES_ID);
if (dataSeriesId == null)
{
String message = "data series ID is null";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
File file = WorldWind.getDataFileCache().newFile(getFileIndexCachePath(rootPath, dataSeriesId));
RPFFileIndex fileIndex = (RPFFileIndex) params.getValue(RPFGenerator.RPF_FILE_INDEX);
if (fileIndex == null)
{
fileIndex = initFileIndex(file);
if (fileIndex == null)
{
String message = "RPFFileIndex is null";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
params.setValue(RPFGenerator.RPF_FILE_INDEX, fileIndex);
}
// Set the imagery expiry time to the RPFFileIndex's last-modified time.
// This ensures that layer imagery always reflects whats in the RPFFileIndex.
// If the layer has been re-imported (data has been added, or data has been removed),
// then all previously created layer imagery will be expired (but not necessarily the preprocessed data).
Long expiryTime = (Long) params.getValue(AVKey.EXPIRY_TIME);
if (expiryTime == null || (file != null && file.lastModified() > expiryTime))
params.setValue(AVKey.EXPIRY_TIME, file.lastModified());
// Use a dummy value for service.
if (params.getValue(AVKey.SERVICE) == null)
params.setValue(AVKey.SERVICE, "file://" + RPFGenerator.class.getName() + "?");
// Use a dummy value for dataset-name.
if (params.getValue(AVKey.DATASET_NAME) == null)
params.setValue(AVKey.DATASET_NAME, dataSeriesId);
if (params.getValue(AVKey.LEVEL_ZERO_TILE_DELTA) == null)
{
Angle delta = Angle.fromDegrees(36);
params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new LatLon(delta, delta));
}
if (params.getValue(AVKey.TILE_WIDTH) == null)
params.setValue(AVKey.TILE_WIDTH, 512);
if (params.getValue(AVKey.TILE_HEIGHT) == null)
params.setValue(AVKey.TILE_HEIGHT, 512);
if (params.getValue(AVKey.FORMAT_SUFFIX) == null)
params.setValue(AVKey.FORMAT_SUFFIX, ".dds");
if (params.getValue(AVKey.NUM_LEVELS) == null)
params.setValue(AVKey.NUM_LEVELS, 14); // approximately 0.5 meters per pixel
if (params.getValue(AVKey.NUM_EMPTY_LEVELS) == null)
params.setValue(AVKey.NUM_EMPTY_LEVELS, 0);
params.setValue(AVKey.TILE_URL_BUILDER, new URLBuilder());
Sector sector = (Sector) params.getValue(AVKey.SECTOR);
if (sector == null)
{
if (fileIndex.getIndexProperties() != null)
sector = fileIndex.getIndexProperties().getBoundingSector();
if (sector == null)
{
String message = "RPFLayer.NoGeographicBoundingBox";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
params.setValue(AVKey.SECTOR, sector);
}
if (params.getValue(AVKey.DATA_CACHE_NAME) == null)
{
String cacheName = WWIO.formPath(rootPath, dataSeriesId);
params.setValue(AVKey.DATA_CACHE_NAME, cacheName);
}
return params;
}
private static RPFFileIndex initFileIndex(File file)
{
ByteBuffer buffer;
try
{
buffer = WWIO.mapFile(file);
}
catch (Exception e)
{
String message = "Exception while attempting to map file: " + file;
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
buffer = null;
}
RPFFileIndex fileIndex = null;
try
{
if (buffer != null)
{
fileIndex = new RPFFileIndex();
fileIndex.load(buffer);
}
}
catch (Exception e)
{
String message = "Exception while attempting to load RPFFileIndex: " + file;
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
fileIndex = null;
}
return fileIndex;
}
private static String makeTitle(AVList params)
{
StringBuilder sb = new StringBuilder();
Object o = params.getValue(RPFGenerator.RPF_FILE_INDEX);
if (o != null && o instanceof RPFFileIndex)
{
RPFFileIndex fileIndex = (RPFFileIndex) o;
if (fileIndex.getIndexProperties() != null)
{
if (fileIndex.getIndexProperties().getDescription() != null)
sb.append(fileIndex.getIndexProperties().getDescription());
else
sb.append(fileIndex.getIndexProperties().getDataSeriesIdentifier());
}
}
if (sb.length() == 0)
{
String rootPath = params.getStringValue(RPF_ROOT_PATH);
String dataSeriesId = params.getStringValue(RPF_DATA_SERIES_ID);
if (rootPath != null && dataSeriesId != null)
{
sb.append(rootPath).append(":").append(dataSeriesId);
}
}
return sb.toString();
}
private RestorableSupport makeRestorableState(AVList params)
{
RestorableSupport rs = RestorableSupport.newRestorableSupport();
// Creating a new RestorableSupport failed. RestorableSupport logged the problem, so just return null.
if (rs == null)
return null;
for (Map.Entry<String, Object> p : params.getEntries())
{
if (p.getValue() instanceof LatLon)
{
rs.addStateValueAsDouble(p.getKey() + ".Latitude", ((LatLon) p.getValue()).getLatitude().degrees);
rs.addStateValueAsDouble(p.getKey() + ".Longitude", ((LatLon) p.getValue()).getLongitude().degrees);
}
else if (p.getValue() instanceof Sector)
{
rs.addStateValueAsDouble(p.getKey() + ".MinLatitude", ((Sector) p.getValue()).getMinLatitude().degrees);
rs.addStateValueAsDouble(p.getKey() + ".MaxLatitude", ((Sector) p.getValue()).getMaxLatitude().degrees);
rs.addStateValueAsDouble(p.getKey() + ".MinLongitude",
((Sector) p.getValue()).getMinLongitude().degrees);
rs.addStateValueAsDouble(p.getKey() + ".MaxLongitude",
((Sector) p.getValue()).getMaxLongitude().degrees);
}
else if (p.getValue() instanceof URLBuilder)
{
// Intentionally left blank. URLBuilder will be created from scratch in fromRestorableState().
}
else if (p.getKey().equals(RPFGenerator.RPF_FILE_INDEX))
{
// Intentionally left blank.
}
else
{
rs.addStateValueAsString(p.getKey(), p.getValue().toString());
}
}
rs.addStateValueAsBoolean("rpf.UseTransparentTextures", this.isUseTransparentTextures());
rs.addStateValueAsBoolean("rpf.UseMipMaps", this.isUseMipMaps());
rs.addStateValueAsString("rpf.LayerName", this.getName());
rs.addStateValueAsBoolean("rpf.LayerEnabled", this.isEnabled());
RestorableSupport.StateObject so = rs.addStateObject("avlist");
for (Map.Entry<String, Object> p : this.getEntries())
{
if (p.getKey().equals(AVKey.CONSTRUCTION_PARAMETERS))
continue;
rs.addStateValueAsString(so, p.getKey(), p.getValue().toString());
}
return rs;
}
public String getRestorableState()
{
return this.makeRestorableState(this.creationParams).getStateAsXml();
}
public static AVList xmlStateToParams(String stateInXml)
{
if (stateInXml == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
RestorableSupport rs;
try
{
rs = RestorableSupport.parse(stateInXml);
}
catch (Exception e)
{
// Parsing the document specified by stateInXml failed.
String message = Logging.getMessage("generic.ExceptionAttemptingToParseStateXml", stateInXml);
Logging.logger().severe(message);
throw new IllegalArgumentException(message, e);
}
AVList params = new AVListImpl();
String s = rs.getStateValueAsString(RPF_ROOT_PATH);
if (s != null)
params.setValue(RPF_ROOT_PATH, s);
s = rs.getStateValueAsString(RPF_DATA_SERIES_ID);
if (s != null)
params.setValue(RPF_DATA_SERIES_ID, s);
s = rs.getStateValueAsString(AVKey.IMAGE_FORMAT);
if (s != null)
params.setValue(AVKey.IMAGE_FORMAT, s);
s = rs.getStateValueAsString(AVKey.DATA_CACHE_NAME);
if (s != null)
params.setValue(AVKey.DATA_CACHE_NAME, s);
s = rs.getStateValueAsString(AVKey.SERVICE);
if (s != null)
params.setValue(AVKey.SERVICE, s);
s = rs.getStateValueAsString(AVKey.TITLE);
if (s != null)
params.setValue(AVKey.TITLE, s);
s = rs.getStateValueAsString(AVKey.DATASET_NAME);
if (s != null)
params.setValue(AVKey.DATASET_NAME, s);
s = rs.getStateValueAsString(AVKey.FORMAT_SUFFIX);
if (s != null)
params.setValue(AVKey.FORMAT_SUFFIX, s);
s = rs.getStateValueAsString(AVKey.LAYER_NAMES);
if (s != null)
params.setValue(AVKey.LAYER_NAMES, s);
s = rs.getStateValueAsString(AVKey.STYLE_NAMES);
if (s != null)
params.setValue(AVKey.STYLE_NAMES, s);
Integer i = rs.getStateValueAsInteger(AVKey.NUM_EMPTY_LEVELS);
if (i != null)
params.setValue(AVKey.NUM_EMPTY_LEVELS, i);
i = rs.getStateValueAsInteger(AVKey.NUM_LEVELS);
if (i != null)
params.setValue(AVKey.NUM_LEVELS, i);
i = rs.getStateValueAsInteger(AVKey.TILE_WIDTH);
if (i != null)
params.setValue(AVKey.TILE_WIDTH, i);
i = rs.getStateValueAsInteger(AVKey.TILE_HEIGHT);
if (i != null)
params.setValue(AVKey.TILE_HEIGHT, i);
Double lat = rs.getStateValueAsDouble(AVKey.LEVEL_ZERO_TILE_DELTA + ".Latitude");
Double lon = rs.getStateValueAsDouble(AVKey.LEVEL_ZERO_TILE_DELTA + ".Longitude");
if (lat != null && lon != null)
params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, LatLon.fromDegrees(lat, lon));
Double minLat = rs.getStateValueAsDouble(AVKey.SECTOR + ".MinLatitude");
Double minLon = rs.getStateValueAsDouble(AVKey.SECTOR + ".MinLongitude");
Double maxLat = rs.getStateValueAsDouble(AVKey.SECTOR + ".MaxLatitude");
Double maxLon = rs.getStateValueAsDouble(AVKey.SECTOR + ".MaxLongitude");
if (minLat != null && minLon != null && maxLat != null && maxLon != null)
params.setValue(AVKey.SECTOR, Sector.fromDegrees(minLat, maxLat, minLon, maxLon));
params.setValue(AVKey.TILE_URL_BUILDER, new URLBuilder());
return params;
}
public void restoreState(String stateInXml)
{
String message = Logging.getMessage("RestorableSupport.RestoreRequiresConstructor");
Logging.logger().severe(message);
throw new UnsupportedOperationException(message);
}
private static class URLBuilder implements TileUrlBuilder
{
public String URLTemplate = null;
private URLBuilder()
{}
public java.net.URL getURL(Tile tile, String imageFormat) throws java.net.MalformedURLException
{
StringBuffer sb;
if (this.URLTemplate == null)
{
sb = new StringBuffer(tile.getLevel().getService());
sb.append("dataset=");
sb.append(tile.getLevel().getDataset());
sb.append("&width=");
sb.append(tile.getLevel().getTileWidth());
sb.append("&height=");
sb.append(tile.getLevel().getTileHeight());
this.URLTemplate = sb.toString();
}
else
{
sb = new StringBuffer(this.URLTemplate);
}
Sector s = tile.getSector();
sb.append("&bbox=");
sb.append(s.getMinLongitude().getDegrees());
sb.append(",");
sb.append(s.getMinLatitude().getDegrees());
sb.append(",");
sb.append(s.getMaxLongitude().getDegrees());
sb.append(",");
sb.append(s.getMaxLatitude().getDegrees());
sb.append("&"); // terminate the query string
return new java.net.URL(sb.toString().replace(" ", "%20"));
}
}
protected void forceTextureLoad(TextureTile tile)
{
final java.net.URL textureURL = WorldWind.getDataFileCache().findFile(tile.getPath(), true);
if (textureURL != null)
{
this.loadTexture(tile, textureURL);
}
}
protected void requestTexture(DrawContext dc, TextureTile tile)
{
Vec4 centroid = tile.getCentroidPoint(dc.getGlobe());
if (this.getReferencePoint() != null)
tile.setPriority(centroid.distanceTo3(this.getReferencePoint()));
RequestTask task = new RequestTask(tile, this);
this.getRequestQ().add(task);
}
private static class RequestTask extends TileTask
{
private final RPFTiledImageLayer layer;
private RequestTask(TextureTile tile, RPFTiledImageLayer layer)
{
super(tile);
this.layer = layer;
}
public void run()
{
final TextureTile tile = getTile();
// TODO: check to ensure load is still needed
final java.net.URL textureURL = WorldWind.getDataFileCache().findFile(tile.getPath(), false);
if (textureURL != null)
{
if (this.layer.loadTexture(tile, textureURL))
{
layer.getLevels().unmarkResourceAbsent(tile);
this.layer.firePropertyChange(AVKey.LAYER, null, this);
return;
}
else
{
// Assume that something's wrong with the file and delete it.
gov.nasa.worldwind.WorldWind.getDataFileCache().removeFile(textureURL);
layer.getLevels().markResourceAbsent(tile);
String message = Logging.getMessage("generic.DeletedCorruptDataFile", textureURL);
Logging.logger().info(message);
}
}
this.layer.downloadTexture(tile);
}
}
private boolean loadTexture(TextureTile tile, java.net.URL textureURL)
{
if (WWIO.isFileOutOfDate(textureURL, tile.getLevel().getExpiryTime()))
{
// The file has expired. Delete it then request download of newer.
gov.nasa.worldwind.WorldWind.getDataFileCache().removeFile(textureURL);
String message = Logging.getMessage("generic.DataFileExpired", textureURL);
Logging.logger().fine(message);
return false;
}
TextureData textureData;
synchronized (this.fileLock)
{
textureData = readTexture(textureURL, this.isUseMipMaps());
}
if (textureData == null)
return false;
tile.setTextureData(textureData);
if (tile.getLevelNumber() != 0 || !this.isRetainLevelZeroTiles())
this.addTileToCache(tile);
return true;
}
private static TextureData readTexture(java.net.URL url, boolean useMipMaps)
{
try
{
return TextureIO.newTextureData(url, useMipMaps, null);
}
catch (Exception e)
{
Logging.logger().log(
java.util.logging.Level.SEVERE, "layers.TextureLayer.ExceptionAttemptingToReadTextureFile", e);
return null;
}
}
private void addTileToCache(TextureTile tile)
{
WorldWind.getMemoryCache(TextureTile.class.getName()).add(tile.getTileKey(), tile);
}
protected void downloadTexture(final TextureTile tile)
{
RPFGenerator.RPFServiceInstance service = this.rpfGenerator.getServiceInstance();
if (service == null)
return;
java.net.URL url;
try
{
url = tile.getResourceURL();
}
catch (java.net.MalformedURLException e)
{
Logging.logger().log(java.util.logging.Level.SEVERE,
Logging.getMessage("layers.TextureLayer.ExceptionCreatingTextureUrl", tile), e);
return;
}
if (WorldWind.getRetrievalService().isAvailable())
{
Retriever retriever = new RPFRetriever(service, url, new DownloadPostProcessor(tile, this));
// Apply any overridden timeouts.
Integer srl = AVListImpl.getIntegerValue(this, AVKey.RETRIEVAL_QUEUE_STALE_REQUEST_LIMIT);
if (srl != null && srl > 0)
retriever.setStaleRequestLimit(srl);
WorldWind.getRetrievalService().runRetriever(retriever, tile.getPriority());
}
else
{
DownloadTask task = new DownloadTask(service, url, tile, this);
this.getRequestQ().add(task);
}
}
private static class DownloadPostProcessor implements RetrievalPostProcessor
{
private final TextureTile tile;
private final RPFTiledImageLayer layer;
public DownloadPostProcessor(TextureTile tile, RPFTiledImageLayer layer)
{
this.tile = tile;
this.layer = layer;
}
public ByteBuffer run(Retriever retriever)
{
if (retriever == null)
{
String msg = Logging.getMessage("nullValue.RetrieverIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
try
{
if (!retriever.getState().equals(Retriever.RETRIEVER_STATE_SUCCESSFUL))
return null;
ByteBuffer buffer = retriever.getBuffer();
if (retriever instanceof RPFRetriever)
{
RPFRetriever rpr = (RPFRetriever) retriever;
if (rpr.getResponseCode() == RPFRetriever.RESPONSE_CODE_NO_CONTENT)
{
// Mark tile as missing to avoid excessive attempts
this.layer.getLevels().markResourceAbsent(this.tile);
return null;
}
else if (rpr.getResponseCode() != RPFRetriever.RESPONSE_CODE_OK)
{
// Also mark tile as missing, but for an unknown reason.
this.layer.getLevels().markResourceAbsent(this.tile);
return null;
}
}
final File outFile = WorldWind.getDataFileCache().newFile(this.tile.getPath());
if (outFile == null)
return null;
if (outFile.exists())
return buffer;
if (buffer != null)
{
String contentType = retriever.getContentType();
if (contentType == null)
{
// TODO: logger message
return null;
}
if (contentType.contains("dds"))
{
this.layer.saveBuffer(buffer, outFile);
}
else if (outFile.getName().endsWith(".dds"))
{
// Convert to DDS and save the result.
buffer = DDSConverter.convertToDDS(buffer, contentType);
if (buffer != null)
this.layer.saveBuffer(buffer, outFile);
}
if (buffer != null)
{
this.layer.firePropertyChange(AVKey.LAYER, null, this.layer);
}
return buffer;
}
}
catch (java.io.IOException e)
{
this.layer.getLevels().markResourceAbsent(this.tile);
Logging.logger().log(java.util.logging.Level.SEVERE,
Logging.getMessage("layers.TextureLayer.ExceptionSavingRetrievedTextureFile", tile.getPath()), e);
}
return null;
}
}
private static class DownloadTask extends TileTask
{
private final RPFGenerator.RPFServiceInstance service;
private final java.net.URL url;
private final RPFTiledImageLayer layer;
private DownloadTask(RPFGenerator.RPFServiceInstance service, java.net.URL url, TextureTile tile, RPFTiledImageLayer layer)
{
super(tile);
this.service = service;
this.url = url;
this.layer = layer;
}
public void run()
{
final TextureTile tile = getTile();
try
{
ByteBuffer buffer = createImage(this.service, this.url);
if (buffer != null)
{
final File outFile = WorldWind.getDataFileCache().newFile(tile.getPath());
if (outFile != null)
{
this.layer.saveBuffer(buffer, outFile);
}
}
}
catch (Exception e)
{
Logging.logger().log(
java.util.logging.Level.SEVERE, "layers.TextureLayer.ExceptionAttemptingToCreateTileImage", e);
this.layer.getLevels().markResourceAbsent(tile);
}
}
}
private static ByteBuffer createImage(RPFGenerator.RPFServiceInstance service, java.net.URL url) throws java.io.IOException
{
ByteBuffer buffer = null;
BufferedImage bufferedImage = service.serviceRequest(url);
if (bufferedImage != null)
{
buffer = DDSConverter.convertToDxt3(bufferedImage);
}
return buffer;
}
private void saveBuffer(ByteBuffer buffer, File outFile) throws java.io.IOException
{
synchronized (this.fileLock) // sychronized with read of file in RequestTask.run()
{
WWIO.saveBuffer(buffer, outFile);
}
}
private static class TileTask implements Runnable, Comparable<TileTask>
{
private final TextureTile tile;
private TileTask(TextureTile tile)
{
this.tile = tile;
}
public final TextureTile getTile()
{
return this.tile;
}
public void run()
{
}
/**
* @param that the task to compare
* @return -1 if <code>this</code> less than <code>that</code>, 1 if greater than, 0 if equal
* @throws IllegalArgumentException if <code>that</code> is null
*/
public int compareTo(TileTask that)
{
if (that == null)
{
String msg = Logging.getMessage("nullValue.RequestTaskIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
return this.tile.getPriority() == that.tile.getPriority() ? 0 :
this.tile.getPriority() < that.tile.getPriority() ? -1 : 1;
}
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final TileTask that = (TileTask) o;
// Don't include layer in comparison so that requests are shared among layers
return !(tile != null ? !tile.equals(that.tile) : that.tile != null);
}
public int hashCode()
{
return (tile != null ? tile.hashCode() : 0);
}
public String toString()
{
return this.tile.getPath();
}
}
}