protected static boolean hasTileETag(TileStoreEntry tile, HttpMapSource mapSource)
     throws IOException {
   String eTag = tile.geteTag();
   if (eTag == null || eTag.length() == 0) {
     log.warn("ETag check not possible: " + "tile in tilestore does not contain ETag attribute");
     return true;
   }
   HttpURLConnection conn =
       mapSource.getTileUrlConnection(tile.getZoom(), tile.getX(), tile.getY());
   conn.setRequestMethod("HEAD");
   conn.setRequestProperty("Accept", ACCEPT);
   String onlineETag = conn.getHeaderField("ETag");
   if (onlineETag == null || onlineETag.length() == 0) return true;
   return (onlineETag.equals(eTag));
 }
 /**
  * Performs a <code>HEAD</code> request for retrieving the <code>LastModified</code> header value.
  */
 protected static boolean isTileNewer(TileStoreEntry tile, HttpMapSource mapSource)
     throws IOException {
   long oldLastModified = tile.getTimeLastModified();
   if (oldLastModified <= 0) {
     log.warn(
         "Tile age comparison not possible: "
             + "tile in tilestore does not contain lastModified attribute");
     return true;
   }
   HttpURLConnection conn =
       mapSource.getTileUrlConnection(tile.getZoom(), tile.getX(), tile.getY());
   conn.setRequestMethod("HEAD");
   conn.setRequestProperty("Accept", ACCEPT);
   long newLastModified = conn.getLastModified();
   if (newLastModified == 0) return true;
   return (newLastModified > oldLastModified);
 }
  public static byte[] updateStoredTile(TileStoreEntry tile, HttpMapSource mapSource)
      throws UnrecoverableDownloadException, IOException, InterruptedException {
    final int x = tile.getX();
    final int y = tile.getY();
    final int zoom = tile.getZoom();
    final HttpMapSource.TileUpdate tileUpdate = mapSource.getTileUpdate();

    switch (tileUpdate) {
      case ETag:
        {
          boolean unchanged = hasTileETag(tile, mapSource);
          if (unchanged) {
            if (log.isTraceEnabled())
              log.trace("Data unchanged on server (eTag): " + mapSource + " " + tile);
            return null;
          }
          break;
        }
      case LastModified:
        {
          boolean isNewer = isTileNewer(tile, mapSource);
          if (!isNewer) {
            if (log.isTraceEnabled())
              log.trace("Data unchanged on server (LastModified): " + mapSource + " " + tile);
            return null;
          }
          break;
        }
    }
    HttpURLConnection conn = mapSource.getTileUrlConnection(zoom, x, y);
    if (conn == null)
      throw new UnrecoverableDownloadException(
          "Tile x="
              + x
              + " y="
              + y
              + " zoom="
              + zoom
              + " is not a valid tile in map source "
              + mapSource);

    if (log.isTraceEnabled()) log.trace(String.format("Checking %s %s", mapSource.getName(), tile));

    prepareConnection(conn);

    boolean conditionalRequest = false;

    switch (tileUpdate) {
      case IfNoneMatch:
        {
          if (tile.geteTag() != null) {
            conn.setRequestProperty("If-None-Match", tile.geteTag());
            conditionalRequest = true;
          }
          break;
        }
      case IfModifiedSince:
        {
          if (tile.getTimeLastModified() > 0) {
            conn.setIfModifiedSince(tile.getTimeLastModified());
            conditionalRequest = true;
          }
          break;
        }
    }

    conn.connect();

    Settings s = Settings.getInstance();

    int code = conn.getResponseCode();

    if (conditionalRequest && code == HttpURLConnection.HTTP_NOT_MODIFIED) {
      // Data unchanged on server
      if (s.tileStoreEnabled) {
        tile.update(conn.getExpiration());
        TileStore.getInstance().putTile(tile, mapSource);
      }
      if (log.isTraceEnabled()) log.trace("Data unchanged on server: " + mapSource + " " + tile);
      return null;
    }
    byte[] data = loadBodyDataInBuffer(conn);

    if (code != HttpURLConnection.HTTP_OK) throw new DownloadFailedException(conn, code);

    checkContentType(conn, data);
    checkContentLength(conn, data);

    String eTag = conn.getHeaderField("ETag");
    long timeLastModified = conn.getLastModified();
    long timeExpires = conn.getExpiration();

    Utilities.checkForInterruption();
    TileImageType imageType = Utilities.getImageType(data);
    if (imageType == null)
      throw new UnrecoverableDownloadException("The returned image is of unknown format");
    if (s.tileStoreEnabled) {
      TileStore.getInstance()
          .putTileData(data, x, y, zoom, mapSource, timeLastModified, timeExpires, eTag);
    }
    Utilities.checkForInterruption();
    return data;
  }