private void renderReadyTiles(
      Graphics2D destination,
      IProgressMonitor monitor,
      WMTRenderJob renderJob,
      RasterSymbolizer style,
      int tileWorth,
      int thisid,
      Map<String, Tile> tiles,
      Set<String> notRenderedTiles,
      Set<String> renderedTiles)
      throws Exception {
    for (String key : tiles.keySet()) {
      checkCancelState(monitor, thisid, false);

      Tile tile = tiles.get(key);
      if (tile != null
          && tile.getBufferedImage() != null
          && tile.getTileState() != WMSTile.INERROR) {
        try {
          renderedTiles.add(key);
          renderTile(destination, (WMTTile) tile, style, renderJob);
        } catch (Exception exc) {
          WMTPlugin.log(
              "[BasicWMTRender.render] renderTile failed (1): " + tile.getId(), exc); // $NON-NLS-1$
        }
        monitor.worked(tileWorth); // inc the monitor work by 1 tile
      } else {
        // set the tile blank (removing any previous content) and add it
        // to be drawn later
        notRenderedTiles.add(key);
        renderBlankTile(destination, (WMTTile) tile, renderJob);
      }
    }
  }
    public void notifyTileReady(net.refractions.udig.catalog.wmsc.server.Tile tile) {
      // set the area that needs updating
      // setRenderBounds(tile.getBounds());

      // if the rendering is already in a rendering state, queue this tile
      // to draw and tell the renderer more data is ready,
      // otherwise create a new rendering thread (which will check the tiles afresh)
      int currentState = getState();
      if ((currentState == RENDERING || currentState == STARTING)) {
        // queue the tile to draw
        try {
          tilesToDraw_queue.put(tile);
          if (testing) {
            System.out.println("added to queue: " + tile.getId()); // $NON-NLS-1$
          }
        } catch (InterruptedException e) {
          WMTPlugin.log("Error while added tile to queue.", e); // $NON-NLS-1$
        }
      } else {
        if (testing) {
          System.out.println("RENDER_REQUEST: " + tile.getId()); // $NON-NLS-1$
        }
        setState(RENDER_REQUEST); // start a new rendering thread
      }
    }
 /**
  * Fetch the name of the file for the given tile
  *
  * @param tile
  * @param filetype
  * @return
  */
 @Override
 public String getTileFileName(Tile tile, String filetype) {
   return WMTTileImageReadWriter.pathCombine(
       getTileDirectoryPath(tile), tile.getPosition() + "." + filetype); // $NON-NLS-1$
 }
  private void renderNotRenderedTiles(
      Graphics2D destination,
      IProgressMonitor monitor,
      WMTRenderJob renderJob,
      TileRange range,
      RasterSymbolizer style,
      int tileWorth,
      int thisid,
      Set<String> notRenderedTiles,
      Set<String> renderedTiles)
      throws Exception {
    checkCancelState(monitor, thisid, false);

    // set the listener on the tile range
    range.addListener(listener);

    // load the missing tiles by sending requests for them
    range.loadTiles(monitor);

    // block until all the missing tiles have come through (and draw them
    // as they are added to the blocking queue
    while (!notRenderedTiles.isEmpty()) {
      // check that the rendering is not canceled
      checkCancelState(monitor, thisid, true);

      if (testing) {
        System.out.println("BLOCKED: " + thisid); // $NON-NLS-1$
        System.out.println(
            "waiting on: " + notRenderedTiles.size() + " tiles"); // $NON-NLS-1$ //$NON-NLS-2$
      }

      Tile tile = null;
      try {
        Object element = null;

        /* get the next tile that is ready to render,
         * check after 1 sec if the rendering was canceled
         */
        while ((element = tilesToDraw_queue.poll(1000, TimeUnit.MILLISECONDS)) == null) {
          checkCancelState(monitor, thisid, true);
        }

        tile = (Tile) element;

        if (testing) {
          System.out.println("removed from queue: " + tile.getId()); // $NON-NLS-1$
        }
      } catch (InterruptedException ex) {
        if (testing) {
          System.out.println("InterruptedException trying to take: " + ex); // $NON-NLS-1$
        }
      }

      if (testing) {
        System.out.println("UNBLOCKED!!!: " + thisid); // $NON-NLS-1$
      }

      // check that the rendering is not canceled again after block
      checkCancelState(monitor, thisid, true);

      // check that the tile's bounds are within the current
      // context's bounds (if it's not, don't bother drawing it) and also
      // only draw tiles that haven't already been drawn (panning fast
      // can result in listeners being notified the same tile is ready multiple
      // times but we don't want to draw it more than once per render cycle)
      // ReferencedEnvelope viewbounds = getContext().getViewportModel().getBounds();

      ReferencedEnvelope viewbounds =
          renderJob.projectMapToTileCrs(context.getViewportModel().getBounds());

      if (tile != null
          && tile.getBufferedImage() != null
          && viewbounds != null
          && viewbounds.intersects(tile.getBounds())
          && !renderedTiles.contains(tile.getId())
          && notRenderedTiles.contains(tile.getId())) {
        try {
          renderedTiles.add(tile.getId());
          renderTile(destination, (WMTTile) tile, style, renderJob);

        } catch (Exception exc) {
          WMTPlugin.log(
              "[BasicWMTRender.render] renderTile failed (2): " + tile.getId(), exc); // $NON-NLS-1$
        }
        monitor.worked(tileWorth); // inc the monitor work by 1 tile
        setState(RENDERING); // tell renderer new data is ready
      }

      // remove the tile from the not rendered list regardless
      // of whether it was actually drawn (this is to prevent
      // this render cycle from blocking endlessly waiting for tiles
      // that either didn't return or had some error)
      notRenderedTiles.remove(tile.getId());
    }
  }