From 27e5d871af4062cc3c7672088becc155f4841101 Mon Sep 17 00:00:00 2001 From: Gabriel Roldan Date: Mon, 26 Aug 2024 14:45:29 -0300 Subject: [PATCH] Replace long[] arrays by a TileIndex abstraction Dealing with `long[]` everywhere and knowing it means `{x,y,z}` is tiring. Introducing a `TileIndex` abstraction improves the semantics, and at the same time allows to save memory on TileObject by storing the coordinates as internal long,long,int fields and saving the object reference to a `long` array. --- > This is a **proposal**. Can we please stop using `long[]` everywhere? > If accepted, there would be more places to get rid of `long` arrays > and introduce higher level abstractions (e.g. `TileRangeInterator`) --- .../arcgis/layer/ArcGISCacheLayer.java | 19 ++-- .../geowebcache/conveyor/ConveyorTile.java | 23 ++-- .../filter/request/CircularExtentFilter.java | 8 +- .../filter/request/RasterFilter.java | 72 +++++++------ .../filter/security/SecurityDispatcher.java | 2 +- .../java/org/geowebcache/grid/GridSet.java | 13 ++- .../java/org/geowebcache/grid/GridSubset.java | 33 +++--- .../grid/OutsideCoverageException.java | 19 ++++ .../java/org/geowebcache/layer/TileLayer.java | 14 ++- .../org/geowebcache/layer/wms/WMSLayer.java | 31 +++--- .../layer/wms/WMSSourceHelper.java | 2 +- .../java/org/geowebcache/seed/SeedTask.java | 3 +- .../java/org/geowebcache/service/Service.java | 4 +- .../storage/BlobStoreListener.java | 18 ++-- .../storage/BlobStoreListenerList.java | 29 +++-- .../org/geowebcache/storage/TileIndex.java | 101 ++++++++++++++++++ .../org/geowebcache/storage/TileObject.java | 101 ++++++++++++++---- .../file/DefaultFilePathGenerator.java | 7 +- .../blobstore/file/XYZFilePathFilter.java | 2 +- .../blobstore/file/XYZFilePathGenerator.java | 9 +- .../blobstore/memory/MemoryBlobStore.java | 2 +- .../memory/guava/GuavaCacheProvider.java | 8 +- .../org/geowebcache/util/ResponseUtils.java | 8 +- .../org/geowebcache/util/TMSKeyBuilder.java | 11 +- .../GeoWebCacheDispatcherTest.java | 7 +- .../security/SecurityDispatcherTest.java | 21 ++-- .../geowebcache/layer/wms/WMSLayerTest.java | 28 ++--- .../org/geowebcache/seed/SeedTaskTest.java | 2 +- .../geowebcache/storage/BlobStoreTest.java | 6 +- .../service/gmaps/GMapsConverter.java | 3 +- .../service/mgmaps/MGMapsConverter.java | 3 +- .../service/kml/ConveyorKMLTile.java | 11 +- .../geowebcache/service/kml/KMZHelper.java | 3 +- .../mbtiles/layer/MBTilesLayer.java | 9 +- .../mbtiles/layer/MBTilesLayerTest.java | 7 +- .../AbstractS3BlobStoreIntegrationTest.java | 12 +-- .../geowebcache/sqlite/MbtilesBlobStore.java | 30 ++---- .../geowebcache/service/tms/TMSService.java | 17 +-- .../service/tms/TMSServiceTest.java | 9 +- .../geowebcache/service/ve/VEConverter.java | 3 +- .../geowebcache/service/wms/WMSService.java | 3 +- .../geowebcache/service/wms/WMSTileFuser.java | 11 +- .../service/wms/WMSServiceTest.java | 15 ++- .../service/wmts/WMTSGetFeatureInfo.java | 2 +- .../geowebcache/service/wmts/WMTSService.java | 9 +- .../service/wmts/WMTSServiceTest.java | 9 +- 46 files changed, 481 insertions(+), 278 deletions(-) create mode 100644 geowebcache/core/src/main/java/org/geowebcache/storage/TileIndex.java diff --git a/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/layer/ArcGISCacheLayer.java b/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/layer/ArcGISCacheLayer.java index 1caeb04b5..2184a5dc2 100644 --- a/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/layer/ArcGISCacheLayer.java +++ b/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/layer/ArcGISCacheLayer.java @@ -51,6 +51,7 @@ import org.geowebcache.layer.ExpirationRule; import org.geowebcache.mime.MimeException; import org.geowebcache.mime.MimeType; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.GWCVars; /** @@ -268,18 +269,18 @@ public ConveyorTile getTile(final ConveyorTile tile) if (storageFormat.equals(CacheStorageInfo.COMPACT_FORMAT_CODE) || storageFormat.equals(CacheStorageInfo.COMPACT_FORMAT_CODE_V2)) { - final long[] tileIndex = tile.getTileIndex(); + final TileIndex tileIndex = tile.getIndex(); final String gridSetId = tile.getGridSetId(); final GridSubset gridSubset = this.getGridSubset(gridSetId); GridSet gridSet = gridSubset.getGridSet(); - final int zoom = (int) tileIndex[2]; + final int zoom = tileIndex.getZ(); Grid grid = gridSet.getGrid(zoom); long coverageMaxY = grid.getNumTilesHigh() - 1; - final int col = (int) tileIndex[0]; - final int row = (int) (coverageMaxY - tileIndex[1]); + final int col = (int) tileIndex.getX(); + final int row = (int) (coverageMaxY - tileIndex.getY()); tileContent = compactCache.getBundleFileResource(zoom, row, col); @@ -298,7 +299,7 @@ public ConveyorTile getTile(final ConveyorTile tile) } else { tile.setCacheResult(CacheResult.MISS); if (!setLayerBlankTile(tile)) { - throw new OutsideCoverageException(tile.getTileIndex(), 0, 0); + throw new OutsideCoverageException(tile.getIndex().getZ(), 0, 0); } } @@ -370,12 +371,12 @@ private boolean setLayerBlankTile(ConveyorTile tile) { private String getTilePath(final ConveyorTile tile) { final MimeType mimeType = tile.getMimeType(); - final long[] tileIndex = tile.getTileIndex(); + final TileIndex tileIndex = tile.getIndex(); final String gridSetId = tile.getGridSetId(); final GridSubset gridSubset = this.getGridSubset(gridSetId); GridSet gridSet = gridSubset.getGridSet(); - final int z = (int) tileIndex[2]; + final int z = tileIndex.getZ(); Grid grid = gridSet.getGrid(z); @@ -383,10 +384,10 @@ private String getTilePath(final ConveyorTile tile) { // long coverageMinY = coverage[1]; long coverageMaxY = grid.getNumTilesHigh() - 1; - final long x = tileIndex[0]; + final long x = tileIndex.getX(); // invert the order of the requested Y ordinate, since ArcGIS caches are top-left to // bottom-right, and GWC computes tiles in bottom-left to top-right order - final long y = (coverageMaxY - tileIndex[1]); + final long y = (coverageMaxY - tileIndex.getY()); String level = (this.hexZoom) ? Integer.toHexString(z) : Integer.toString(z); level = zeroPadder(level, 2); diff --git a/geowebcache/core/src/main/java/org/geowebcache/conveyor/ConveyorTile.java b/geowebcache/core/src/main/java/org/geowebcache/conveyor/ConveyorTile.java index 0baf3e2c7..a3ddb428c 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/conveyor/ConveyorTile.java +++ b/geowebcache/core/src/main/java/org/geowebcache/conveyor/ConveyorTile.java @@ -28,6 +28,7 @@ import org.geowebcache.mime.MimeType; import org.geowebcache.storage.StorageBroker; import org.geowebcache.storage.StorageException; +import org.geowebcache.storage.TileIndex; import org.geowebcache.storage.TileObject; /** Represents a request for a tile and carries the information needed to complete it. */ @@ -72,7 +73,7 @@ public ConveyorTile( StorageBroker sb, String layerId, String gridSetId, - long[] tileIndex, + TileIndex tileIndex, MimeType mimeType, Map fullParameters, Map filteringParameters, @@ -95,7 +96,7 @@ public ConveyorTile( StorageBroker sb, String layerId, String gridSetId, - long[] tileIndex, + TileIndex tileIndex, MimeType mimeType, Map filteringParameters, HttpServletRequest servletReq, @@ -104,18 +105,11 @@ public ConveyorTile( super(layerId, sb, servletReq, servletResp); this.gridSetId = gridSetId; - long[] idx = new long[3]; - - if (tileIndex != null) { - idx[0] = tileIndex[0]; - idx[1] = tileIndex[1]; - idx[2] = tileIndex[2]; - } - super.mimeType = mimeType; this.filteringParameters = filteringParameters; + TileIndex idx = tileIndex == null ? null : TileIndex.copyOf(tileIndex); stObj = TileObject.createQueryTileObject( layerId, idx, gridSetId, mimeType.getFormat(), filteringParameters); @@ -180,6 +174,10 @@ public long[] getTileIndex() { return stObj.getXYZ(); } + public TileIndex getIndex() { + return stObj.getIndex(); + } + public synchronized GridSubset getGridSubset() { if (gridSubset == null && gridSetId != null) { gridSubset = tileLayer.getGridSubset(gridSetId); @@ -248,7 +246,6 @@ public boolean retrieve(long maxAge) throws GeoWebCacheException { public String toString() { StringBuilder str = new StringBuilder(); str.append("ConveyorTile["); - long[] idx = stObj.getXYZ(); if (getLayerId() != null) { str.append(getLayerId()).append(" "); @@ -258,9 +255,7 @@ public String toString() { str.append(gridSetId).append(" "); } - if (idx != null && idx.length == 3) { - str.append("{" + idx[0] + "," + idx[1] + "," + idx[2] + "} "); - } + str.append("{" + stObj.getX() + "," + stObj.getY() + "," + stObj.getZ() + "} "); if (this.mimeType != null) { str.append(this.mimeType.getFormat()); diff --git a/geowebcache/core/src/main/java/org/geowebcache/filter/request/CircularExtentFilter.java b/geowebcache/core/src/main/java/org/geowebcache/filter/request/CircularExtentFilter.java index 8a2cdc46d..8a155fa0a 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/filter/request/CircularExtentFilter.java +++ b/geowebcache/core/src/main/java/org/geowebcache/filter/request/CircularExtentFilter.java @@ -18,6 +18,7 @@ import org.geowebcache.conveyor.ConveyorTile; import org.geowebcache.grid.GridSubset; import org.geowebcache.layer.TileLayer; +import org.geowebcache.storage.TileIndex; /** * This is a test filter for the new request filter core. @@ -38,7 +39,8 @@ public void apply(ConveyorTile convTile) throws RequestFilterException { // SRS srs = convTile.getSRS(); GridSubset gridSubset = tl.getGridSubset(convTile.getGridSetId()); - int z = (int) convTile.getTileIndex()[2]; + TileIndex tileIndex = convTile.getIndex(); + int z = tileIndex.getZ(); long[] gridCoverage = gridSubset.getCoverage(z); // Figure out the radius @@ -58,8 +60,8 @@ public void apply(ConveyorTile convTile) throws RequestFilterException { long midX = gridCoverage[0] + width / 2; long midY = gridCoverage[1] + height / 2; - long xDist = midX - convTile.getTileIndex()[0]; - long yDist = midY - convTile.getTileIndex()[1]; + long xDist = midX - tileIndex.getX(); + long yDist = midY - tileIndex.getY(); long rad = Math.round(Math.sqrt(xDist * xDist + yDist * yDist)); diff --git a/geowebcache/core/src/main/java/org/geowebcache/filter/request/RasterFilter.java b/geowebcache/core/src/main/java/org/geowebcache/filter/request/RasterFilter.java index 4f0b04739..36ed2929f 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/filter/request/RasterFilter.java +++ b/geowebcache/core/src/main/java/org/geowebcache/filter/request/RasterFilter.java @@ -26,6 +26,7 @@ import org.geowebcache.grid.GridSubset; import org.geowebcache.grid.OutsideCoverageException; import org.geowebcache.layer.TileLayer; +import org.geowebcache.storage.TileIndex; /** * A raster filter allows to optimize data loading by avoiding the generation of requests and the @@ -109,51 +110,54 @@ public void setDebug(Boolean debug) { @Override public void apply(ConveyorTile convTile) throws RequestFilterException { - long[] idx = convTile.getTileIndex().clone(); String gridSetId = convTile.getGridSetId(); // Basic bounds test first try { - convTile.getGridSubset().checkCoverage(idx); + convTile.getGridSubset().checkCoverage(convTile.getIndex()); } catch (OutsideCoverageException oce) { throw new BlankTileException(this); } + long x = convTile.getIndex().getX(); + long y = convTile.getIndex().getY(); + int z = convTile.getIndex().getZ(); int zoomDiff = 0; // Three scenarios below: // 1. z is too low , upsample if resampling is enabled // 2. z is within range, downsample one level and apply // 3. z is too large , downsample - if (zoomStart != null && idx[2] < zoomStart) { + if (zoomStart != null && z < zoomStart) { if (resample == null || !resample) { // Filter does not apply, zoomlevel is too low return; } else { // Upsample - zoomDiff = (int) (idx[2] - zoomStart); - idx[0] = idx[0] << (-1 * zoomDiff); - idx[1] = idx[1] << (-1 * zoomDiff); - idx[2] = zoomStart; + zoomDiff = z - zoomStart; + x = (x << (-1 * zoomDiff)); + y = (y << (-1 * zoomDiff)); + z = zoomStart; } - } else if (idx[2] < zoomStop) { + } else if (z < zoomStop) { // Sample one level higher - idx[0] = idx[0] * 2; - idx[1] = idx[1] * 2; - idx[2] = idx[2] + 1; + x = x * 2; + y = y * 2; + z = z + 1; } else { // Reduce to highest supported resolution - zoomDiff = (int) (idx[2] - zoomStop); - idx[0] = idx[0] >> zoomDiff; - idx[1] = idx[1] >> zoomDiff; - idx[2] = zoomStop; + zoomDiff = z - zoomStop; + x = x >> zoomDiff; + y = y >> zoomDiff; + z = zoomStop; } + TileIndex idx = TileIndex.valueOf(x, y, z); if (matrices == null || matrices.get(gridSetId) == null - || matrices.get(gridSetId)[(int) idx[2]] == null) { + || matrices.get(gridSetId)[idx.getZ()] == null) { try { - setMatrix(convTile.getLayer(), gridSetId, (int) idx[2], false); + setMatrix(convTile.getLayer(), gridSetId, idx.getZ(), false); } catch (Exception e) { log.log( Level.SEVERE, @@ -162,14 +166,14 @@ public void apply(ConveyorTile convTile) throws RequestFilterException { + ", " + gridSetId + ", " - + idx[2] + + idx.getZ() + " : " + e.getMessage()); throw new RequestFilterException( this, 500, "Failed while trying to load filter for " - + idx[2] + + idx.getZ() + ", please check the logs"); } } @@ -229,14 +233,14 @@ public void initialize(TileLayer layer) throws GeoWebCacheException { } /** Performs a lookup against an internal raster. */ - private boolean lookup(GridSubset grid, long[] idx) { - BufferedImage mat = matrices.get(grid.getName())[(int) idx[2]]; + private boolean lookup(GridSubset grid, TileIndex idx) { + BufferedImage mat = matrices.get(grid.getName())[idx.getZ()]; - long[] gridCoverage = grid.getCoverage((int) idx[2]); + long[] gridCoverage = grid.getCoverage(idx.getZ()); // Changing index to top left hand origin - long x = idx[0] - gridCoverage[0]; - long y = gridCoverage[3] - idx[1]; + long x = idx.getX() - gridCoverage[0]; + long y = gridCoverage[3] - idx.getY(); return (mat.getRaster().getSample((int) x, (int) y, 0) == 0); } @@ -245,14 +249,14 @@ private boolean lookup(GridSubset grid, long[] idx) { * Performs a lookup against an internal raster. The sampling is actually done against 4 pixels, * idx should already have been modified to use one level higher than strictly necessary. */ - private boolean lookupQuad(GridSubset grid, long[] idx) { - BufferedImage mat = matrices.get(grid.getName())[(int) idx[2]]; + private boolean lookupQuad(GridSubset grid, TileIndex idx) { + BufferedImage mat = matrices.get(grid.getName())[idx.getZ()]; - long[] gridCoverage = grid.getCoverage((int) idx[2]); + long[] gridCoverage = grid.getCoverage(idx.getZ()); // Changing index to top left hand origin - int baseX = (int) (idx[0] - gridCoverage[0]); - int baseY = (int) (gridCoverage[3] - idx[1]); + int baseX = (int) (idx.getX() - gridCoverage[0]); + int baseY = (int) (gridCoverage[3] - idx.getY()); int width = mat.getWidth(); int height = mat.getHeight(); @@ -298,16 +302,16 @@ private boolean lookupQuad(GridSubset grid, long[] idx) { return hasData; } - private boolean lookupSubsample(GridSubset grid, long[] idx, int zoomDiff) { - BufferedImage mat = matrices.get(grid.getName())[(int) idx[2]]; + private boolean lookupSubsample(GridSubset grid, TileIndex idx, int zoomDiff) { + BufferedImage mat = matrices.get(grid.getName())[idx.getZ()]; int sampleChange = 1 << (-1 * zoomDiff); - long[] gridCoverage = grid.getCoverage((int) idx[2]); + long[] gridCoverage = grid.getCoverage(idx.getZ()); // Changing index to top left hand origin - int baseX = (int) (idx[0] - gridCoverage[0]); - int baseY = (int) (gridCoverage[3] - idx[1]); + int baseX = (int) (idx.getX() - gridCoverage[0]); + int baseY = (int) (gridCoverage[3] - idx.getY()); int width = mat.getWidth(); int height = mat.getHeight(); diff --git a/geowebcache/core/src/main/java/org/geowebcache/filter/security/SecurityDispatcher.java b/geowebcache/core/src/main/java/org/geowebcache/filter/security/SecurityDispatcher.java index 6b8ae0065..665252bf0 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/filter/security/SecurityDispatcher.java +++ b/geowebcache/core/src/main/java/org/geowebcache/filter/security/SecurityDispatcher.java @@ -50,7 +50,7 @@ public void checkSecurity(final ConveyorTile tile) final BoundingBox bounds; final SRS srs; if (Objects.nonNull(gridSubset)) { - bounds = gridSubset.boundsFromIndex(tile.getTileIndex()); + bounds = gridSubset.boundsFromIndex(tile.getIndex()); srs = gridSubset.getSRS(); } else { bounds = null; diff --git a/geowebcache/core/src/main/java/org/geowebcache/grid/GridSet.java b/geowebcache/core/src/main/java/org/geowebcache/grid/GridSet.java index b4cdf6029..986e01236 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/grid/GridSet.java +++ b/geowebcache/core/src/main/java/org/geowebcache/grid/GridSet.java @@ -20,6 +20,7 @@ import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.geowebcache.config.Info; +import org.geowebcache.storage.TileIndex; /** A grid set configuration */ public class GridSet implements Info { @@ -110,15 +111,19 @@ void setResolutionsPreserved(boolean resolutionsPreserved) { } public BoundingBox boundsFromIndex(long[] tileIndex) { - final int tileZ = (int) tileIndex[2]; + return boundsFromIndex(TileIndex.valueOf(tileIndex)); + } + + public BoundingBox boundsFromIndex(TileIndex tileIndex) { + final int tileZ = tileIndex.getZ(); Grid grid = getGrid(tileZ); - final long tileX = tileIndex[0]; + final long tileX = tileIndex.getX(); final long tileY; if (yBaseToggle) { - tileY = tileIndex[1] - grid.getNumTilesHigh(); + tileY = tileIndex.getY() - grid.getNumTilesHigh(); } else { - tileY = tileIndex[1]; + tileY = tileIndex.getY(); } double width = grid.getResolution() * getTileWidth(); diff --git a/geowebcache/core/src/main/java/org/geowebcache/grid/GridSubset.java b/geowebcache/core/src/main/java/org/geowebcache/grid/GridSubset.java index fcdf8e8e8..d9fbc1c54 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/grid/GridSubset.java +++ b/geowebcache/core/src/main/java/org/geowebcache/grid/GridSubset.java @@ -22,6 +22,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.geowebcache.GeoWebCacheException; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.ServletUtils; /** A GridSubSet is a GridSet + a coverage area */ @@ -77,6 +78,10 @@ public BoundingBox boundsFromIndex(long[] tileIndex) { return getGridSet().boundsFromIndex(tileIndex); } + public BoundingBox boundsFromIndex(TileIndex tileIndex) { + return getGridSet().boundsFromIndex(tileIndex); + } + /** * Finds the spatial bounding box of a rectangular group of tiles. * @@ -95,6 +100,10 @@ public long[] closestRectangle(BoundingBox rectangleBounds) { return gridSet.closestRectangle(rectangleBounds); } + public boolean covers(long[] index) { + return covers(TileIndex.valueOf(index)); + } + /** * Indicates whether this gridsubset coverage contains the given tile * @@ -102,33 +111,33 @@ public long[] closestRectangle(BoundingBox rectangleBounds) { * @return {@code true} if {@code index} is inside this grid subset's coverage, {@code false} * otherwise */ - public boolean covers(long[] index) { - final int level = (int) index[2]; + public boolean covers(TileIndex index) { + final int level = index.getZ(); final long[] coverage = getCoverage(level); if (coverage == null) { return false; } - if (index[0] >= coverage[0] - && index[0] <= coverage[2] - && index[1] >= coverage[1] - && index[1] <= coverage[3]) { + if (index.getX() >= coverage[0] + && index.getX() <= coverage[2] + && index.getY() >= coverage[1] + && index.getY() <= coverage[3]) { return true; } return false; } - public void checkCoverage(long[] index) throws OutsideCoverageException { + public void checkCoverage(TileIndex index) throws OutsideCoverageException { if (covers(index)) { return; } - if (index[2] < getZoomStart() || index[2] > getZoomStop()) { - throw new OutsideCoverageException(index, getZoomStart(), getZoomStop()); + if (index.getZ() < getZoomStart() || index.getZ() > getZoomStop()) { + throw new OutsideCoverageException(index.getZ(), getZoomStart(), getZoomStop()); } - long[] coverage = getCoverage((int) index[2]); + long[] coverage = getCoverage(index.getZ()); throw new OutsideCoverageException(index, coverage); } @@ -255,7 +264,7 @@ public long[] getCoverageIntersection(int level, BoundingBox reqBounds) { return gridCoverage.getIntersection(reqRectangle); } - public long getGridIndex(String gridId) { + public int getGridIndex(String gridId) { final int zoomStart = getZoomStart(); final int zoomStop = getZoomStop(); @@ -266,7 +275,7 @@ public long getGridIndex(String gridId) { } } - return -1L; + return -1; } public String[] getGridNames() { diff --git a/geowebcache/core/src/main/java/org/geowebcache/grid/OutsideCoverageException.java b/geowebcache/core/src/main/java/org/geowebcache/grid/OutsideCoverageException.java index 7fd4d85b2..396095b77 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/grid/OutsideCoverageException.java +++ b/geowebcache/core/src/main/java/org/geowebcache/grid/OutsideCoverageException.java @@ -16,6 +16,7 @@ import java.util.Arrays; import org.geowebcache.GeoWebCacheException; +import org.geowebcache.storage.TileIndex; public class OutsideCoverageException extends GeoWebCacheException { /** */ @@ -32,6 +33,17 @@ public OutsideCoverageException(long[] index, long firstLevel, long lastLevel) { + "]"); } + public OutsideCoverageException(int zoomLevel, long firstLevel, long lastLevel) { + super( + "Zoom level was " + + zoomLevel + + ", but value has to be in [" + + firstLevel + + "," + + lastLevel + + "]"); + } + public OutsideCoverageException(long[] index, long[] coverage) { super( "Coverage [minx,miny,maxx,maxy] is " @@ -39,4 +51,11 @@ public OutsideCoverageException(long[] index, long[] coverage) { + ", index [x,y,z] is " + Arrays.toString(index)); } + + public OutsideCoverageException(TileIndex index, long[] coverage) { + super( + String.format( + "Coverage [minx,miny,maxx,maxy] is %s, index [x,y,z] is %s", + Arrays.toString(coverage), TileIndex.toString(index))); + } } diff --git a/geowebcache/core/src/main/java/org/geowebcache/layer/TileLayer.java b/geowebcache/core/src/main/java/org/geowebcache/layer/TileLayer.java index dc069bff5..09638f6d2 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/layer/TileLayer.java +++ b/geowebcache/core/src/main/java/org/geowebcache/layer/TileLayer.java @@ -16,7 +16,6 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -50,6 +49,7 @@ import org.geowebcache.mime.FormatModifier; import org.geowebcache.mime.MimeType; import org.geowebcache.storage.StorageException; +import org.geowebcache.storage.TileIndex; import org.geowebcache.storage.TileObject; import org.geowebcache.util.GWCVars; import org.geowebcache.util.ServletUtils; @@ -493,17 +493,17 @@ protected void saveTiles(MetaTile metaTile, ConveyorTile tileProto, long request throws GeoWebCacheException { final long[][] gridPositions = metaTile.getTilesGridPositions(); - final long[] gridLoc = tileProto.getTileIndex(); + final TileIndex gridLoc = tileProto.getIndex(); final GridSubset gridSubset = getGridSubset(tileProto.getGridSetId()); - final int zoomLevel = (int) gridLoc[2]; + final int zoomLevel = gridLoc.getZ(); final boolean store = this.getExpireCache(zoomLevel) != GWCVars.CACHE_DISABLE_CACHE; Resource resource; boolean encode; for (int i = 0; i < gridPositions.length; i++) { - final long[] gridPos = gridPositions[i]; - if (Arrays.equals(gridLoc, gridPos)) { + final TileIndex gridPos = TileIndex.valueOf(gridPositions[i]); + if (gridLoc.isSameTileIndex(gridPos)) { // Is this the one we need to save? then don't use the buffer or it'll be overridden // by the next tile resource = getImageBuffer(WMS_BUFFER2); @@ -528,12 +528,10 @@ protected void saveTiles(MetaTile metaTile, ConveyorTile tileProto, long request "metaTile.writeTileToStream returned false, no tiles saved"); } if (store) { - long[] idx = {gridPos[0], gridPos[1], gridPos[2]}; - TileObject tile = TileObject.createCompleteTileObject( this.getName(), - idx, + gridPos, tileProto.getGridSetId(), tileProto.getMimeType().getFormat(), tileProto.getParameters(), diff --git a/geowebcache/core/src/main/java/org/geowebcache/layer/wms/WMSLayer.java b/geowebcache/core/src/main/java/org/geowebcache/layer/wms/WMSLayer.java index cae8e4ebb..2e818e952 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/layer/wms/WMSLayer.java +++ b/geowebcache/core/src/main/java/org/geowebcache/layer/wms/WMSLayer.java @@ -53,6 +53,7 @@ import org.geowebcache.mime.FormatModifier; import org.geowebcache.mime.MimeType; import org.geowebcache.mime.XMLMime; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.GWCVars; import org.geowebcache.util.URLs; @@ -267,7 +268,7 @@ public ConveyorTile getTile(ConveyorTile tile) String tileGridSetId = tile.getGridSetId(); - long[] gridLoc = tile.getTileIndex(); + TileIndex gridLoc = tile.getIndex(); GridSubset gridSubset = getGridSubset(tileGridSetId); // Final preflight check, throws exception if necessary @@ -275,7 +276,7 @@ public ConveyorTile getTile(ConveyorTile tile) ConveyorTile returnTile; - tile.setMetaTileCacheOnly(!gridSubset.shouldCacheAtZoom(gridLoc[2])); + tile.setMetaTileCacheOnly(!gridSubset.shouldCacheAtZoom(gridLoc.getZ())); try { if (tryCacheFetch(tile)) { returnTile = finalizeTile(tile); @@ -298,7 +299,7 @@ public ConveyorTile getTile(ConveyorTile tile) public void seedTile(ConveyorTile tile, boolean tryCache) throws GeoWebCacheException, IOException { GridSubset gridSubset = getGridSubset(tile.getGridSetId()); - if (gridSubset.shouldCacheAtZoom(tile.getTileIndex()[2])) { + if (gridSubset.shouldCacheAtZoom(tile.getIndex().getZ())) { if (tile.getMimeType().supportsTiling() && (metaWidthHeight[0] > 1 || metaWidthHeight[1] > 1)) { getMetatilingReponse(tile, tryCache); @@ -398,21 +399,23 @@ private ConveyorTile getMetatilingReponse(ConveyorTile tile, boolean tryCache) private String buildLockKey(ConveyorTile tile, WMSMetaTile metaTile) { StringBuilder metaKey = new StringBuilder(); - final long[] tileIndex; + final TileIndex tileIndex; if (metaTile != null) { - tileIndex = metaTile.getMetaGridPos(); + tileIndex = TileIndex.valueOf(metaTile.getMetaGridPos()); metaKey.append("meta_"); } else { - tileIndex = tile.getTileIndex(); + tileIndex = tile.getIndex(); metaKey.append("tile_"); } - long x = tileIndex[0]; - long y = tileIndex[1]; - long z = tileIndex[2]; metaKey.append(tile.getLayerId()); metaKey.append("_").append(tile.getGridSetId()); - metaKey.append("_").append(x).append("_").append(y).append("_").append(z); + metaKey.append("_") + .append(tileIndex.getX()) + .append("_") + .append(tileIndex.getY()) + .append("_") + .append(tileIndex.getZ()); if (tile.getParametersId() != null) { metaKey.append("_").append(tile.getParametersId()); } @@ -430,7 +433,7 @@ private String buildLockKey(ConveyorTile tile, WMSMetaTile metaTile) { private ConveyorTile getNonMetatilingReponse(ConveyorTile tile, boolean tryCache) throws GeoWebCacheException { // String debugHeadersStr = null; - long[] gridLoc = tile.getTileIndex(); + TileIndex gridLoc = tile.getIndex(); String lockKey = buildLockKey(tile, null); Lock lock = null; @@ -454,7 +457,7 @@ private ConveyorTile getNonMetatilingReponse(ConveyorTile tile, boolean tryCache tile = doNonMetatilingRequest(tile); if (tile.getStatus() > 299 - || this.getExpireCache((int) gridLoc[2]) != GWCVars.CACHE_DISABLE_CACHE) { + || this.getExpireCache(gridLoc.getZ()) != GWCVars.CACHE_DISABLE_CACHE) { tile.persist(); } @@ -473,7 +476,7 @@ private ConveyorTile getNonMetatilingReponse(ConveyorTile tile, boolean tryCache } public boolean tryCacheFetch(ConveyorTile tile) { - int expireCache = this.getExpireCache((int) tile.getTileIndex()[2]); + int expireCache = this.getExpireCache(tile.getIndex().getZ()); if (expireCache != GWCVars.CACHE_DISABLE_CACHE) { try { return tile.retrieve(expireCache * 1000L); @@ -507,7 +510,7 @@ private ConveyorTile finalizeTile(ConveyorTile tile) { } if (tile.servletResp != null) { - setExpirationHeader(tile.servletResp, (int) tile.getTileIndex()[2]); + setExpirationHeader(tile.servletResp, tile.getIndex().getZ()); } return tile; diff --git a/geowebcache/core/src/main/java/org/geowebcache/layer/wms/WMSSourceHelper.java b/geowebcache/core/src/main/java/org/geowebcache/layer/wms/WMSSourceHelper.java index 922f17c25..75587caa7 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/layer/wms/WMSSourceHelper.java +++ b/geowebcache/core/src/main/java/org/geowebcache/layer/wms/WMSSourceHelper.java @@ -67,7 +67,7 @@ public void makeRequest(ConveyorTile tile, Resource target) throws GeoWebCacheEx wmsParams.put("WIDTH", String.valueOf(gridSubset.getTileWidth())); // strBuilder.append("&TILED=").append(requestTiled); - BoundingBox bbox = gridSubset.boundsFromIndex(tile.getTileIndex()); + BoundingBox bbox = gridSubset.boundsFromIndex(tile.getIndex()); wmsParams.put("BBOX", bbox.toString()); diff --git a/geowebcache/core/src/main/java/org/geowebcache/seed/SeedTask.java b/geowebcache/core/src/main/java/org/geowebcache/seed/SeedTask.java index 9a52a447a..db772d7b9 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/seed/SeedTask.java +++ b/geowebcache/core/src/main/java/org/geowebcache/seed/SeedTask.java @@ -30,6 +30,7 @@ import org.geowebcache.layer.TileLayer; import org.geowebcache.layer.wms.WMSLayer; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.storage.TileRange; import org.geowebcache.storage.TileRangeIterator; import org.geowebcache.util.Sleeper; @@ -127,7 +128,7 @@ protected void doActionInternal() throws GeoWebCacheException, InterruptedExcept storageBroker, layerName, tr.getGridSetId(), - gridLoc, + TileIndex.valueOf(gridLoc), tr.getMimeType(), fullParameters, null, diff --git a/geowebcache/core/src/main/java/org/geowebcache/service/Service.java b/geowebcache/core/src/main/java/org/geowebcache/service/Service.java index 8413b0329..6a79b49e2 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/service/Service.java +++ b/geowebcache/core/src/main/java/org/geowebcache/service/Service.java @@ -116,11 +116,11 @@ protected static void writeTileResponse( TileLayer layer = conv.getLayer(); if (layer != null) { - layer.setExpirationHeader(conv.servletResp, (int) conv.getTileIndex()[2]); + layer.setExpirationHeader(conv.servletResp, conv.getIndex().getZ()); } if (writeExpiration) { - conv.getLayer().setExpirationHeader(response, (int) conv.getTileIndex()[2]); + conv.getLayer().setExpirationHeader(response, conv.getIndex().getZ()); } response.setContentType(mimeStr); diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/BlobStoreListener.java b/geowebcache/core/src/main/java/org/geowebcache/storage/BlobStoreListener.java index 9f082a2dd..318617faa 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/storage/BlobStoreListener.java +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/BlobStoreListener.java @@ -34,9 +34,9 @@ public interface BlobStoreListener { * @param blobFormat {@link MimeType#getFormat() format name} of the mime type for the stored * tile * @param parametersId {@link TileObject#getParametersId() parameters id} for the stored tile - * @param x X ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile - * @param y Y ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile - * @param z Z ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile + * @param x X ordinate of the {@link TileObject#getX()} grid location for the stored tile + * @param y Y ordinate of the {@link TileObject#getY()} grid location for the stored tile + * @param z Z ordinate of the {@link TileObject#getZ()} grid location for the stored tile * @param blobSize the actual storage size the blob uses in the blob store's backend storage; * which may or may not equal to the encoded tile size, depending on the storage mechanism */ @@ -58,9 +58,9 @@ void tileStored( * @param blobFormat {@link MimeType#getFormat() format name} of the mime type for the stored * tile * @param parametersId {@link TileObject#getParametersId() parameters id} for the stored tile - * @param x X ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile - * @param y Y ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile - * @param z Z ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile + * @param x X ordinate of the {@link TileObject#getX()} grid location for the stored tile + * @param y Y ordinate of the {@link TileObject#getY()} grid location for the stored tile + * @param z Z ordinate of the {@link TileObject#getZ()} grid location for the stored tile * @param blobSize the actual blob size freed from the blob store's backend storage; which may * or may not equal to the encoded tile size, depending on the storage mechanism */ @@ -82,9 +82,9 @@ void tileDeleted( * @param blobFormat {@link MimeType#getFormat() format name} of the mime type for the stored * tile * @param parametersId {@link TileObject#getParametersId() parameters id} for the stored tile - * @param x X ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile - * @param y Y ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile - * @param z Z ordinate of the {@link TileObject#getXYZ() grid location} for the stored tile + * @param x X ordinate of the {@link TileObject#getX()} grid location for the stored tile + * @param y Y ordinate of the {@link TileObject#getY()} grid location for the stored tile + * @param z Z ordinate of the {@link TileObject#getZ()} grid location for the stored tile * @param blobSize the actual storage size the blob uses in the blob store's backend storage; * which may or may not equal to the encoded tile size, depending on the storage mechanism * @param oldSize the size of the replaced blob diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/BlobStoreListenerList.java b/geowebcache/core/src/main/java/org/geowebcache/storage/BlobStoreListenerList.java index 1f5c8a554..b1ae452fe 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/storage/BlobStoreListenerList.java +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/BlobStoreListenerList.java @@ -86,15 +86,16 @@ public void sendTileDeleted( public void sendTileDeleted(final TileObject stObj) { - final long[] xyz = stObj.getXYZ(); + long x = stObj.getX(); + long y = stObj.getY(); + int z = stObj.getZ(); final String layerName = stObj.getLayerName(); final String gridSetId = stObj.getGridSetId(); final String blobFormat = stObj.getBlobFormat(); final String paramsId = stObj.getParametersId(); final int blobSize = stObj.getBlobSize(); - sendTileDeleted( - layerName, gridSetId, blobFormat, paramsId, xyz[0], xyz[1], (int) xyz[2], blobSize); + sendTileDeleted(layerName, gridSetId, blobFormat, paramsId, x, y, z, blobSize); } public void sendTileStored( @@ -115,15 +116,16 @@ public void sendTileStored( public void sendTileStored(final TileObject stObj) { - final long[] xyz = stObj.getXYZ(); + long x = stObj.getX(); + long y = stObj.getY(); + int z = stObj.getZ(); final String layerName = stObj.getLayerName(); final String gridSetId = stObj.getGridSetId(); final String blobFormat = stObj.getBlobFormat(); final String paramsId = stObj.getParametersId(); final int blobSize = stObj.getBlobSize(); - sendTileStored( - layerName, gridSetId, blobFormat, paramsId, xyz[0], xyz[1], (int) xyz[2], blobSize); + sendTileStored(layerName, gridSetId, blobFormat, paramsId, x, y, z, blobSize); } public void sendTileUpdated( @@ -153,22 +155,15 @@ public void sendTileUpdated( public void sendTileUpdated(final TileObject stObj, final long oldSize) { - final long[] xyz = stObj.getXYZ(); + long x = stObj.getX(); + long y = stObj.getY(); + int z = stObj.getZ(); final String layerName = stObj.getLayerName(); final String gridSetId = stObj.getGridSetId(); final String blobFormat = stObj.getBlobFormat(); final String paramsId = stObj.getParametersId(); final int blobSize = stObj.getBlobSize(); - sendTileUpdated( - layerName, - gridSetId, - blobFormat, - paramsId, - xyz[0], - xyz[1], - (int) xyz[2], - blobSize, - oldSize); + sendTileUpdated(layerName, gridSetId, blobFormat, paramsId, x, y, z, blobSize, oldSize); } } diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/TileIndex.java b/geowebcache/core/src/main/java/org/geowebcache/storage/TileIndex.java new file mode 100644 index 000000000..3d97f1d58 --- /dev/null +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/TileIndex.java @@ -0,0 +1,101 @@ +/** + * This program is free software: you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + *

This program 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 Lesser General Public License along with this + * program. If not, see . + * + *

Copyright 2024 + */ +package org.geowebcache.storage; + +import java.util.Objects; + +public interface TileIndex { + + long getX(); + + long getY(); + + int getZ(); + + default boolean isSameTileIndex(TileIndex index) { + return null != index + && getX() == index.getX() + && getY() == index.getY() + && getZ() == index.getZ(); + } + + static TileIndex newInstance() { + return new DefaultTileIndex(); + } + + static TileIndex valueOf(long[] tileIndex) { + return valueOf(tileIndex[0], tileIndex[1], (int) tileIndex[2]); + } + + static TileIndex valueOf(long x, long y, int z) { + return new DefaultTileIndex(x, y, z); + } + + static TileIndex copyOf(TileIndex index) { + return valueOf(index.getX(), index.getY(), index.getZ()); + } + + static class DefaultTileIndex implements TileIndex { + private long x; + private long y; + private int z; + + DefaultTileIndex() {} + + DefaultTileIndex(long x, long y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public long getX() { + return x; + } + + @Override + public long getY() { + return y; + } + + @Override + public int getZ() { + return z; + } + + @Override + public String toString() { + return TileIndex.toString(this); + } + + @Override + public int hashCode() { + return Objects.hash(x, y, z); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + DefaultTileIndex other = (DefaultTileIndex) obj; + return x == other.x && y == other.y && z == other.z; + } + } + + static String toString(TileIndex index) { + return String.format("[%d, %d, %d]", index.getX(), index.getY(), index.getZ()); + } +} diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/TileObject.java b/geowebcache/core/src/main/java/org/geowebcache/storage/TileObject.java index bdb7c0a75..219c6282f 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/storage/TileObject.java +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/TileObject.java @@ -14,8 +14,8 @@ */ package org.geowebcache.storage; +import com.google.common.annotations.VisibleForTesting; import java.io.Serializable; -import java.util.Arrays; import java.util.Map; import org.geowebcache.grid.GridSet; import org.geowebcache.io.Resource; @@ -31,17 +31,19 @@ public class TileObject extends StorageObject implements Serializable { public static final String TYPE = "tile"; - Resource blob; + private Resource blob; - String parameters_id = null; + private String parameters_id = null; - long[] xyz; + private long x; + private long y; + private int z; - String layer_name; + private String layer_name; - Map parameters; + private Map parameters; - String gridSetId; + private String gridSetId; public static TileObject createQueryTileObject( String layerName, @@ -49,10 +51,27 @@ public static TileObject createQueryTileObject( String gridSetId, String format, Map parameters) { + + TileIndex index = xyz == null ? null : TileIndex.valueOf(xyz); + + return createQueryTileObject(layerName, index, gridSetId, format, parameters); + } + + public static TileObject createQueryTileObject( + String layerName, + TileIndex xyz, + String gridSetId, + String format, + Map parameters) { + TileObject obj = new TileObject(); obj.layer_name = layerName; - obj.xyz = xyz; + if (xyz != null) { + obj.x = xyz.getX(); + obj.y = xyz.getY(); + obj.z = xyz.getZ(); + } obj.gridSetId = gridSetId; obj.blob_format = format; obj.parameters = parameters; @@ -67,13 +86,20 @@ public static TileObject createCompleteTileObject( String format, Map parameters, Resource blob) { - TileObject obj = new TileObject(); - obj.layer_name = layerName; - obj.xyz = xyz; - obj.gridSetId = gridSetId; - obj.blob_format = format; - obj.parameters = parameters; + TileIndex index = xyz == null ? null : TileIndex.valueOf(xyz); + return createCompleteTileObject(layerName, index, gridSetId, format, parameters, blob); + } + + public static TileObject createCompleteTileObject( + String layerName, + TileIndex xyz, + String gridSetId, + String format, + Map parameters, + Resource blob) { + + TileObject obj = createQueryTileObject(layerName, xyz, gridSetId, format, parameters); if (blob == null) { obj.blob_size = -1; @@ -118,13 +144,48 @@ public void setParametersId(String parameters_id) { this.parameters_id = parameters_id; } - public long[] getXYZ() { - return xyz; + public TileIndex getIndex() { + return TileIndex.valueOf(x, y, z); + } + + public long getX() { + return x; + } + + public long getY() { + return y; + } + + public int getZ() { + return z; } - // public int getSrs() { - // return srs; - // } + @VisibleForTesting + public TileObject setX(long x) { + this.x = x; + return this; + } + + @VisibleForTesting + public TileObject setY(long y) { + this.y = y; + return this; + } + + @VisibleForTesting + public TileObject setZ(int z) { + this.z = z; + return this; + } + + /** + * To be deprecated, use individual methods {@link #getX()}, {@link #getY()}, {@link #getZ()} + * + * @return a newly allocated array with the x,y,z values + */ + public long[] getXYZ() { + return new long[] {x, y, z}; + } public String getLayerName() { return layer_name; @@ -141,6 +202,6 @@ public String getType() { @Override public String toString() { - return "[" + layer_name + "," + gridSetId + ",{" + Arrays.toString(xyz) + "}]"; + return String.format("[%s,%s,{%d,%d,%d}]", layer_name, gridSetId, x, y, z); } } diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/DefaultFilePathGenerator.java b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/DefaultFilePathGenerator.java index 33e082e39..130345509 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/DefaultFilePathGenerator.java +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/DefaultFilePathGenerator.java @@ -54,10 +54,9 @@ public DefaultFilePathGenerator(String cacheRoot) { */ @Override public File tilePath(TileObject tile, MimeType mimeType) { - final long[] tileIndex = tile.getXYZ(); - long x = tileIndex[0]; - long y = tileIndex[1]; - long z = tileIndex[2]; + long x = tile.getX(); + long y = tile.getY(); + int z = tile.getZ(); StringBuilder path = new StringBuilder(256); diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/XYZFilePathFilter.java b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/XYZFilePathFilter.java index 4059e468a..05102f945 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/XYZFilePathFilter.java +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/XYZFilePathFilter.java @@ -148,7 +148,7 @@ private boolean acceptFileName(File parent, String name) { long x = Long.parseLong(parent.getName()); int z = Integer.parseInt(parent.getParentFile().getName()); // adjust y based on the tms vs slippy convention - y = generator.getY(tr.getLayerName(), tr.getGridSetId(), x, y, z); + y = generator.getY(tr.getLayerName(), tr.getGridSetId(), y, z); return tr.contains(x, y, z); } catch (Exception e) { diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/XYZFilePathGenerator.java b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/XYZFilePathGenerator.java index 05451f7f6..56f264988 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/XYZFilePathGenerator.java +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/file/XYZFilePathGenerator.java @@ -73,10 +73,9 @@ public XYZFilePathGenerator( */ @Override public File tilePath(TileObject tile, MimeType mimeType) throws GeoWebCacheException { - final long[] tileIndex = tile.getXYZ(); - long x = tileIndex[0]; - int z = (int) tileIndex[2]; - long y = getY(tile.getLayerName(), tile.getGridSetId(), x, tileIndex[1], z); + long x = tile.getX(); + int z = tile.getZ(); + long y = getY(tile.getLayerName(), tile.getGridSetId(), tile.getY(), z); StringBuilder path = new StringBuilder(256); String fileExtension = mimeType.getFileExtension(); @@ -114,7 +113,7 @@ public File tilePath(TileObject tile, MimeType mimeType) throws GeoWebCacheExcep * slippy). One method is all it needs only because the TMS vs Slippy conventions have * symmetrical map, e.g., the same extact operation goes both directions */ - protected long getY(String layerName, String gridSetId, long x, long y, int z) + protected long getY(String layerName, String gridSetId, long y, int z) throws GeoWebCacheException { if (convention == Convention.TMS) { return y; diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/memory/MemoryBlobStore.java b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/memory/MemoryBlobStore.java index 4e5847e65..786a099d9 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/memory/MemoryBlobStore.java +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/memory/MemoryBlobStore.java @@ -507,7 +507,7 @@ private TileObject getByteResourceTile(TileObject obj) throws StorageException { TileObject cached = TileObject.createCompleteTileObject( obj.getLayerName(), - obj.getXYZ(), + obj.getIndex(), obj.getGridSetId(), obj.getBlobFormat(), obj.getParameters(), diff --git a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/memory/guava/GuavaCacheProvider.java b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/memory/guava/GuavaCacheProvider.java index b476fef1f..cacd1e664 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/memory/guava/GuavaCacheProvider.java +++ b/geowebcache/core/src/main/java/org/geowebcache/storage/blobstore/memory/guava/GuavaCacheProvider.java @@ -505,7 +505,13 @@ public static String generateTileKey(TileObject obj) { .append(SEPARATOR) .append(obj.getGridSetId()) .append(SEPARATOR) - .append(Arrays.toString(obj.getXYZ())) + .append('[') + .append(obj.getX()) + .append(',') + .append(obj.getY()) + .append(',') + .append(obj.getZ()) + .append(']') .append(SEPARATOR) .append(obj.getBlobFormat()); diff --git a/geowebcache/core/src/main/java/org/geowebcache/util/ResponseUtils.java b/geowebcache/core/src/main/java/org/geowebcache/util/ResponseUtils.java index 5a1a7dc14..71135cd31 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/util/ResponseUtils.java +++ b/geowebcache/core/src/main/java/org/geowebcache/util/ResponseUtils.java @@ -22,7 +22,6 @@ import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; -import java.util.Arrays; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; @@ -48,6 +47,7 @@ import org.geowebcache.mime.ImageMime; import org.geowebcache.stats.RuntimeStats; import org.geowebcache.storage.DefaultStorageFinder; +import org.geowebcache.storage.TileIndex; import org.springframework.http.MediaType; /** @@ -128,8 +128,8 @@ private static void writeData(ConveyorTile tile, RuntimeStats runtimeStats) thro String mimeType = tile.getMimeType().getMimeType(blob); servletResp.setHeader("geowebcache-cache-result", String.valueOf(cacheResult)); - servletResp.setHeader("geowebcache-tile-index", Arrays.toString(tile.getTileIndex())); - long[] tileIndex = tile.getTileIndex(); + TileIndex tileIndex = tile.getIndex(); + servletResp.setHeader("geowebcache-tile-index", TileIndex.toString(tileIndex)); TileLayer layer = tile.getLayer(); GridSubset gridSubset = layer.getGridSubset(tile.getGridSetId()); BoundingBox tileBounds = gridSubset.boundsFromIndex(tileIndex); @@ -190,7 +190,7 @@ private static void writeEmpty( tile.servletResp.setHeader("geowebcache-message", message); TileLayer layer = tile.getLayer(); if (layer != null) { - layer.setExpirationHeader(tile.servletResp, (int) tile.getTileIndex()[2]); + layer.setExpirationHeader(tile.servletResp, tile.getIndex().getZ()); if (layer.useETags()) { String ifNoneMatch = tile.servletReq.getHeader("If-None-Match"); diff --git a/geowebcache/core/src/main/java/org/geowebcache/util/TMSKeyBuilder.java b/geowebcache/core/src/main/java/org/geowebcache/util/TMSKeyBuilder.java index c7b1f81f9..c6c832502 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/util/TMSKeyBuilder.java +++ b/geowebcache/core/src/main/java/org/geowebcache/util/TMSKeyBuilder.java @@ -86,7 +86,6 @@ public String forTile(TileObject obj) { checkNotNull(obj.getLayerName()); checkNotNull(obj.getGridSetId()); checkNotNull(obj.getBlobFormat()); - checkNotNull(obj.getXYZ()); String layer = layerId(obj.getLayerName()); String gridset = obj.getGridSetId(); @@ -101,9 +100,7 @@ public String forTile(TileObject obj) { obj.setParametersId(parametersId); } } - Long x = Long.valueOf(obj.getXYZ()[0]); - Long y = Long.valueOf(obj.getXYZ()[1]); - Long z = Long.valueOf(obj.getXYZ()[2]); + String extension; try { String format = obj.getBlobFormat(); @@ -125,9 +122,9 @@ public String forTile(TileObject obj) { gridset, shortFormat, parametersId, - z, - x, - y + "." + extension); + obj.getZ(), + obj.getX(), + obj.getY() + "." + extension); return key; } diff --git a/geowebcache/core/src/test/java/org/geowebcache/GeoWebCacheDispatcherTest.java b/geowebcache/core/src/test/java/org/geowebcache/GeoWebCacheDispatcherTest.java index 17f657ce4..cabd23be4 100644 --- a/geowebcache/core/src/test/java/org/geowebcache/GeoWebCacheDispatcherTest.java +++ b/geowebcache/core/src/test/java/org/geowebcache/GeoWebCacheDispatcherTest.java @@ -37,6 +37,7 @@ import org.geowebcache.storage.BlobStoreAggregator; import org.geowebcache.storage.DefaultStorageFinder; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.junit.Rule; import org.junit.Test; import org.springframework.http.HttpStatus; @@ -116,7 +117,7 @@ public void testRequestNoSecurity() throws Exception { sb, "testLayer", "testGrid", - new long[] {1, 2, 3}, + TileIndex.valueOf(1, 2, 3), ImageMime.png, Collections.emptyMap(), request, @@ -132,7 +133,7 @@ public void testRequestNoSecurity() throws Exception { EasyMock.expect(layer.getTile(conv)).andReturn(conv).once(); EasyMock.expect(layer.getGridSubset("testGrid")).andStubReturn(subset); EasyMock.expect(layer.useETags()).andStubReturn(false); - EasyMock.expect(subset.boundsFromIndex(EasyMock.aryEq(new long[] {1, 2, 3}))) + EasyMock.expect(subset.boundsFromIndex(EasyMock.eq(TileIndex.valueOf(1, 2, 3)))) .andStubReturn(new BoundingBox(10, 20, 30, 40)); EasyMock.expect(subset.getName()).andStubReturn("testGrid"); EasyMock.expect(subset.getSRS()).andStubReturn(srs); @@ -194,7 +195,7 @@ public void testRequestFail() throws Exception { sb, "testLayer", "testGrid", - new long[] {1, 2, 3}, + TileIndex.valueOf(1, 2, 3), ImageMime.png, Collections.emptyMap(), request, diff --git a/geowebcache/core/src/test/java/org/geowebcache/filter/security/SecurityDispatcherTest.java b/geowebcache/core/src/test/java/org/geowebcache/filter/security/SecurityDispatcherTest.java index 28acf6596..1b2e3c2e4 100644 --- a/geowebcache/core/src/test/java/org/geowebcache/filter/security/SecurityDispatcherTest.java +++ b/geowebcache/core/src/test/java/org/geowebcache/filter/security/SecurityDispatcherTest.java @@ -23,6 +23,7 @@ import org.geowebcache.grid.GridSubset; import org.geowebcache.grid.SRS; import org.geowebcache.layer.TileLayer; +import org.geowebcache.storage.TileIndex; import org.junit.Rule; import org.junit.Test; @@ -48,8 +49,8 @@ public void testOneFilterPass() throws Exception { EasyMock.expect(conv.getLayer()).andStubReturn(layer); EasyMock.expect(conv.getGridSubset()).andStubReturn(subset); - EasyMock.expect(conv.getTileIndex()).andStubReturn(new long[] {1, 2, 3}); - EasyMock.expect(subset.boundsFromIndex(EasyMock.aryEq(new long[] {1, 2, 3}))) + EasyMock.expect(conv.getIndex()).andStubReturn(TileIndex.valueOf(1, 2, 3)); + EasyMock.expect(subset.boundsFromIndex(EasyMock.eq(TileIndex.valueOf(1, 2, 3)))) .andStubReturn(bbox); EasyMock.expect(subset.getSRS()).andStubReturn(srs); @@ -81,8 +82,8 @@ public void testOneFilterFail() throws Exception { EasyMock.expect(conv.getLayer()).andStubReturn(layer); EasyMock.expect(conv.getGridSubset()).andStubReturn(subset); - EasyMock.expect(conv.getTileIndex()).andStubReturn(new long[] {1, 2, 3}); - EasyMock.expect(subset.boundsFromIndex(EasyMock.aryEq(new long[] {1, 2, 3}))) + EasyMock.expect(conv.getIndex()).andStubReturn(TileIndex.valueOf(1, 2, 3)); + EasyMock.expect(subset.boundsFromIndex(EasyMock.eq(TileIndex.valueOf(1, 2, 3)))) .andStubReturn(bbox); EasyMock.expect(subset.getSRS()).andStubReturn(srs); @@ -115,8 +116,8 @@ public void testTwoFilterPass() throws Exception { EasyMock.expect(conv.getLayer()).andStubReturn(layer); EasyMock.expect(conv.getGridSubset()).andStubReturn(subset); - EasyMock.expect(conv.getTileIndex()).andStubReturn(new long[] {1, 2, 3}); - EasyMock.expect(subset.boundsFromIndex(EasyMock.aryEq(new long[] {1, 2, 3}))) + EasyMock.expect(conv.getIndex()).andStubReturn(TileIndex.valueOf(1, 2, 3)); + EasyMock.expect(subset.boundsFromIndex(EasyMock.eq(TileIndex.valueOf(1, 2, 3)))) .andStubReturn(bbox); EasyMock.expect(subset.getSRS()).andStubReturn(srs); @@ -152,8 +153,8 @@ public void testTwoFilterFail() throws Exception { EasyMock.expect(conv.getLayer()).andStubReturn(layer); EasyMock.expect(conv.getGridSubset()).andStubReturn(subset); - EasyMock.expect(conv.getTileIndex()).andStubReturn(new long[] {1, 2, 3}); - EasyMock.expect(subset.boundsFromIndex(EasyMock.aryEq(new long[] {1, 2, 3}))) + EasyMock.expect(conv.getIndex()).andStubReturn(TileIndex.valueOf(1, 2, 3)); + EasyMock.expect(subset.boundsFromIndex(EasyMock.eq(TileIndex.valueOf(1, 2, 3)))) .andStubReturn(bbox); EasyMock.expect(subset.getSRS()).andStubReturn(srs); @@ -183,8 +184,8 @@ public void testNoFilterPass() throws Exception { EasyMock.expect(conv.getLayer()).andStubReturn(layer); EasyMock.expect(conv.getGridSubset()).andStubReturn(subset); - EasyMock.expect(conv.getTileIndex()).andStubReturn(new long[] {1, 2, 3}); - EasyMock.expect(subset.boundsFromIndex(EasyMock.aryEq(new long[] {1, 2, 3}))) + EasyMock.expect(conv.getIndex()).andStubReturn(TileIndex.valueOf(1, 2, 3)); + EasyMock.expect(subset.boundsFromIndex(EasyMock.eq(TileIndex.valueOf(1, 2, 3)))) .andStubReturn(bbox); EasyMock.expect(subset.getSRS()).andStubReturn(srs); diff --git a/geowebcache/core/src/test/java/org/geowebcache/layer/wms/WMSLayerTest.java b/geowebcache/core/src/test/java/org/geowebcache/layer/wms/WMSLayerTest.java index 10bf8d4b1..effedb521 100644 --- a/geowebcache/core/src/test/java/org/geowebcache/layer/wms/WMSLayerTest.java +++ b/geowebcache/core/src/test/java/org/geowebcache/layer/wms/WMSLayerTest.java @@ -93,6 +93,7 @@ import org.geowebcache.seed.SeedRequest; import org.geowebcache.seed.TileBreeder; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.storage.TileObject; import org.geowebcache.storage.TileRange; import org.geowebcache.storage.TileRangeIterator; @@ -149,7 +150,7 @@ public void testSeedMetaTiled() throws Exception { mockStorageBroker, layerId, gridSetId, - gridLoc, + TileIndex.valueOf(gridLoc), mimeType, null, servletReq, @@ -182,10 +183,9 @@ public void testSeedJpegPngMetaTiled() throws Exception { assertNotNull(to.getBlob()); assertTrue(to.getBlob().getSize() > 0); String format = ImageMime.jpegPng.getMimeType(to.getBlob()); - long[] xyz = to.getXYZ(); - assertEquals(10, xyz[2]); + assertEquals(10, to.getZ()); // check the ones in the full black area are jpeg, the others png - if (xyz[0] == 900 || xyz[1] == 602) { + if (to.getX() == 900 || to.getY() == 602) { assertEquals("image/jpeg", format); } else { assertEquals("image/png", format); @@ -206,10 +206,10 @@ public void testSeedJpegPng8MetaTiled() throws Exception { assertNotNull(to.getBlob()); assertTrue(to.getBlob().getSize() > 0); String format = ImageMime.jpegPng8.getMimeType(to.getBlob()); - long[] xyz = to.getXYZ(); - assertEquals(10, xyz[2]); + + assertEquals(10, to.getZ()); // check the ones in the full black area are jpeg, the others png - if (xyz[0] == 900 || xyz[1] == 602) { + if (to.getX() == 900 || to.getY() == 602) { assertEquals("image/jpeg", format); } else { assertEquals("image/png", format); @@ -235,14 +235,14 @@ public void testSeedJpegPng8GrayAlphaMetaTiled() throws Exception { assertNotNull(to.getBlob()); assertTrue(to.getBlob().getSize() > 0); String format = ImageMime.jpegPng8.getMimeType(to.getBlob()); - long[] xyz = to.getXYZ(); - assertEquals(10, xyz[2]); + + assertEquals(10, to.getZ()); try (InputStream is = to.getBlob().getInputStream()) { BufferedImage image = ImageIO.read(is); // check the ones in the full black area are jpeg, the others png - if (xyz[0] == 900 || xyz[1] == 602) { + if (to.getX() == 900 || to.getY() == 602) { // it's a gray assertEquals(1, image.getColorModel().getNumComponents()); assertEquals("image/jpeg", format); @@ -288,7 +288,7 @@ public void checkJpegPng( mockStorageBroker, layerId, gridSetId, - gridLoc, + TileIndex.valueOf(gridLoc), mimeType, null, servletReq, @@ -412,7 +412,7 @@ public HttpResponse executeRequest( mockStorageBroker, layerId, gridSetId, - gridLoc, + TileIndex.valueOf(gridLoc), mimeType, null, servletReq, @@ -579,7 +579,7 @@ private void seedTiles(StorageBroker storageBroker, TileRange tr, final WMSLayer storageBroker, layerName, tr.getGridSetId(), - gridLoc, + TileIndex.valueOf(gridLoc), tr.getMimeType(), fullParameters, null, @@ -615,7 +615,7 @@ private List getTiles( storageBroker, layerName, tr.getGridSetId(), - gridLoc, + TileIndex.valueOf(gridLoc), tr.getMimeType(), fullParameters, null, diff --git a/geowebcache/core/src/test/java/org/geowebcache/seed/SeedTaskTest.java b/geowebcache/core/src/test/java/org/geowebcache/seed/SeedTaskTest.java index 4beabb1d9..032568190 100644 --- a/geowebcache/core/src/test/java/org/geowebcache/seed/SeedTaskTest.java +++ b/geowebcache/core/src/test/java/org/geowebcache/seed/SeedTaskTest.java @@ -338,7 +338,7 @@ public void testSeedStoredTiles() throws Exception { } } for (TileObject obj : storedTiles) { - tileKeys.add(new Tuple<>(obj.getXYZ()[0], obj.getXYZ()[1], obj.getXYZ()[2])); + tileKeys.add(new Tuple<>(obj.getX(), obj.getY(), (long) obj.getZ())); } Assert.assertEquals(expectedTiles, tileKeys); diff --git a/geowebcache/core/src/test/java/org/geowebcache/storage/BlobStoreTest.java b/geowebcache/core/src/test/java/org/geowebcache/storage/BlobStoreTest.java index 6a539f66d..612a2e05c 100644 --- a/geowebcache/core/src/test/java/org/geowebcache/storage/BlobStoreTest.java +++ b/geowebcache/core/src/test/java/org/geowebcache/storage/BlobStoreTest.java @@ -169,7 +169,7 @@ public void testTilRangeDelete() throws Exception { // starting x and x + tos.length should have data, the remaining should not TileObject firstTO = TileObject.createQueryTileObject( - layerName, tos[0].xyz, srs.toString(), mime.getFormat(), parameters); + layerName, tos[0].getIndex(), srs.toString(), mime.getFormat(), parameters); fbs.get(firstTO); try (InputStream is = firstTO.getBlob().getInputStream(); InputStream is2 = bytes.getInputStream()) { @@ -178,7 +178,7 @@ public void testTilRangeDelete() throws Exception { TileObject lastTO = TileObject.createQueryTileObject( layerName, - tos[tos.length - 1].xyz, + tos[tos.length - 1].getIndex(), srs.toString(), mime.getFormat(), parameters); @@ -191,7 +191,7 @@ public void testTilRangeDelete() throws Exception { TileObject midTO = TileObject.createQueryTileObject( layerName, - tos[(tos.length - 1) / 2].xyz, + tos[(tos.length - 1) / 2].getIndex(), srs.toString(), mime.getFormat(), parameters); diff --git a/geowebcache/gmaps/src/main/java/org/geowebcache/service/gmaps/GMapsConverter.java b/geowebcache/gmaps/src/main/java/org/geowebcache/service/gmaps/GMapsConverter.java index 65064a8b3..90a999f2e 100644 --- a/geowebcache/gmaps/src/main/java/org/geowebcache/service/gmaps/GMapsConverter.java +++ b/geowebcache/gmaps/src/main/java/org/geowebcache/service/gmaps/GMapsConverter.java @@ -27,6 +27,7 @@ import org.geowebcache.service.Service; import org.geowebcache.service.ServiceException; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.ServletUtils; /** Class to convert from Google Maps coordinates into the internal representation of a tile. */ @@ -95,7 +96,7 @@ public ConveyorTile getConveyor(HttpServletRequest request, HttpServletResponse sb, layerId, gsb.getWorldEpsg3857().getName(), - gridLoc, + TileIndex.valueOf(gridLoc), mimeType, filteringParameters, request, diff --git a/geowebcache/gmaps/src/main/java/org/geowebcache/service/mgmaps/MGMapsConverter.java b/geowebcache/gmaps/src/main/java/org/geowebcache/service/mgmaps/MGMapsConverter.java index 515efb61c..d7aa87ed1 100644 --- a/geowebcache/gmaps/src/main/java/org/geowebcache/service/mgmaps/MGMapsConverter.java +++ b/geowebcache/gmaps/src/main/java/org/geowebcache/service/mgmaps/MGMapsConverter.java @@ -27,6 +27,7 @@ import org.geowebcache.service.Service; import org.geowebcache.service.ServiceException; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.ServletUtils; /** Class to convert from Google Maps coordinates into the internal representation of a tile. */ @@ -86,7 +87,7 @@ public ConveyorTile getConveyor(HttpServletRequest request, HttpServletResponse sb, layerId, gsb.getWorldEpsg3857().getName(), - gridLoc, + TileIndex.valueOf(gridLoc), mimeType, null, request, diff --git a/geowebcache/kml/src/main/java/org/geowebcache/service/kml/ConveyorKMLTile.java b/geowebcache/kml/src/main/java/org/geowebcache/service/kml/ConveyorKMLTile.java index b3494b302..ab92d276d 100644 --- a/geowebcache/kml/src/main/java/org/geowebcache/service/kml/ConveyorKMLTile.java +++ b/geowebcache/kml/src/main/java/org/geowebcache/service/kml/ConveyorKMLTile.java @@ -20,6 +20,7 @@ import org.geowebcache.conveyor.ConveyorTile; import org.geowebcache.mime.MimeType; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; public class ConveyorKMLTile extends ConveyorTile { public ConveyorKMLTile( @@ -32,7 +33,15 @@ public ConveyorKMLTile( HttpServletRequest servletReq, HttpServletResponse servletResp) { - super(sb, layerId, gridSetId, tileIndex, mimeType, fullParameters, servletReq, servletResp); + super( + sb, + layerId, + gridSetId, + TileIndex.valueOf(tileIndex), + mimeType, + fullParameters, + servletReq, + servletResp); } String urlPrefix = null; diff --git a/geowebcache/kml/src/main/java/org/geowebcache/service/kml/KMZHelper.java b/geowebcache/kml/src/main/java/org/geowebcache/service/kml/KMZHelper.java index d905cf72a..d28ef4b23 100644 --- a/geowebcache/kml/src/main/java/org/geowebcache/service/kml/KMZHelper.java +++ b/geowebcache/kml/src/main/java/org/geowebcache/service/kml/KMZHelper.java @@ -35,6 +35,7 @@ import org.geowebcache.mime.XMLMime; import org.geowebcache.service.ServiceException; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; /** * Just a helper class for KMZ experimentation stuff @@ -76,7 +77,7 @@ public static long[][] filterGridLocs( sb, tileLayer.getName(), gridSetId, - linkGridLock, + TileIndex.valueOf(linkGridLock), mime, null, null, diff --git a/geowebcache/mbtiles/src/main/java/org/geowebcache/mbtiles/layer/MBTilesLayer.java b/geowebcache/mbtiles/src/main/java/org/geowebcache/mbtiles/layer/MBTilesLayer.java index b709494ac..365ac1d03 100644 --- a/geowebcache/mbtiles/src/main/java/org/geowebcache/mbtiles/layer/MBTilesLayer.java +++ b/geowebcache/mbtiles/src/main/java/org/geowebcache/mbtiles/layer/MBTilesLayer.java @@ -50,6 +50,7 @@ import org.geowebcache.mime.ApplicationMime; import org.geowebcache.mime.ImageMime; import org.geowebcache.mime.MimeType; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.GWCVars; /** @@ -223,16 +224,16 @@ private HashMap createGridSubsets(final GridSetBroker gridSe @Override public ConveyorTile getTile(final ConveyorTile tile) throws IOException, GeoWebCacheException { - long[] tileIndex = tile.getTileIndex(); + TileIndex tileIndex = tile.getIndex(); // check request is within coverage String tileGridSetId = tile.getGridSetId(); GridSubset gridSubset = getGridSubset(tileGridSetId); gridSubset.checkCoverage(tileIndex); - int zl = (int) tileIndex[2]; - int row = (int) tileIndex[1]; - int column = (int) tileIndex[0]; + int zl = tileIndex.getZ(); + int row = (int) tileIndex.getY(); + int column = (int) tileIndex.getX(); MBTilesTile loadedTile = mbTilesFile.loadTile(zl, column, row); byte[] content = loadedTile.getData(); if (content != null) { diff --git a/geowebcache/mbtiles/src/test/java/org/geowebcache/mbtiles/layer/MBTilesLayerTest.java b/geowebcache/mbtiles/src/test/java/org/geowebcache/mbtiles/layer/MBTilesLayerTest.java index 3c0790a24..6732839fc 100644 --- a/geowebcache/mbtiles/src/test/java/org/geowebcache/mbtiles/layer/MBTilesLayerTest.java +++ b/geowebcache/mbtiles/src/test/java/org/geowebcache/mbtiles/layer/MBTilesLayerTest.java @@ -53,6 +53,7 @@ import org.geowebcache.layer.meta.TileJSON; import org.geowebcache.layer.meta.VectorLayerMetadata; import org.geowebcache.mime.ApplicationMime; +import org.geowebcache.storage.TileIndex; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -168,7 +169,7 @@ public void testLayerConfigValues() throws GeoWebCacheException, IOException { null, testLayer.getId(), subset.getName(), - new long[] {4L, 4L, 3L}, + TileIndex.valueOf(4L, 4L, 3), ApplicationMime.mapboxVector, null, null, @@ -239,7 +240,7 @@ public void testOutsideRange() throws GeoWebCacheException, IOException { null, testLayer.getId(), "EPSG:900913", - new long[] {38L, 42L, 6L}, + TileIndex.valueOf(38L, 42L, 6), ApplicationMime.mapboxVector, null, null, @@ -261,7 +262,7 @@ public void testEmptyTile() throws GeoWebCacheException, IOException { null, testLayer.getId(), "EPSG:900913", - new long[] {38L, 39L, 6L}, + TileIndex.valueOf(38L, 39L, 6), ApplicationMime.mapboxVector, null, null, diff --git a/geowebcache/s3storage/src/test/java/org/geowebcache/s3/AbstractS3BlobStoreIntegrationTest.java b/geowebcache/s3storage/src/test/java/org/geowebcache/s3/AbstractS3BlobStoreIntegrationTest.java index 4d29f538a..2dbd2f526 100644 --- a/geowebcache/s3storage/src/test/java/org/geowebcache/s3/AbstractS3BlobStoreIntegrationTest.java +++ b/geowebcache/s3storage/src/test/java/org/geowebcache/s3/AbstractS3BlobStoreIntegrationTest.java @@ -188,22 +188,22 @@ public void testDelete() throws MimeException, StorageException { blobStore.put(tile); - tile.getXYZ()[0] = 21; + tile.setX(21); blobStore.put(tile); - tile.getXYZ()[0] = 22; + tile.setX(22); blobStore.put(tile); tile = queryTile(20, 30, 12); assertTrue(blobStore.delete(tile)); - tile.getXYZ()[0] = 21; + tile.setX(21); assertTrue(blobStore.delete(tile)); BlobStoreListener listener = mock(BlobStoreListener.class); blobStore.addListener(listener); - tile.getXYZ()[0] = 22; + tile.setX(22); assertTrue(blobStore.delete(tile)); assertFalse(blobStore.delete(tile)); @@ -228,10 +228,10 @@ public void testDeleteLayer() throws Exception { blobStore.put(tile); - tile.getXYZ()[0] = 21; + tile.setX(21); blobStore.put(tile); - tile.getXYZ()[0] = 22; + tile.setX(22); blobStore.put(tile); BlobStoreListener listener = mock(BlobStoreListener.class); diff --git a/geowebcache/sqlite/src/main/java/org/geowebcache/sqlite/MbtilesBlobStore.java b/geowebcache/sqlite/src/main/java/org/geowebcache/sqlite/MbtilesBlobStore.java index c44c25837..b2f2bcc24 100644 --- a/geowebcache/sqlite/src/main/java/org/geowebcache/sqlite/MbtilesBlobStore.java +++ b/geowebcache/sqlite/src/main/java/org/geowebcache/sqlite/MbtilesBlobStore.java @@ -161,8 +161,7 @@ public void put(TileObject tile) throws StorageException { connection -> { // instantiating geotools needed objects MBTilesFile mbtiles = GeoToolsMbtilesUtils.getMBTilesFile(connection, file); - MBTilesTile gtTile = - new MBTilesTile(tile.getXYZ()[2], tile.getXYZ()[0], tile.getXYZ()[1]); + MBTilesTile gtTile = new MBTilesTile(tile.getZ(), tile.getX(), tile.getY()); try { final boolean gzipped = tileIsGzipped(tile); @@ -183,10 +182,7 @@ public void put(TileObject tile) throws StorageException { byte[] olData = null; if (!listeners.isEmpty()) { olData = - mbtiles.loadTile( - tile.getXYZ()[2], - tile.getXYZ()[0], - tile.getXYZ()[1]) + mbtiles.loadTile(tile.getZ(), tile.getX(), tile.getY()) .getData(); } // saving the tile @@ -195,9 +191,9 @@ public void put(TileObject tile) throws StorageException { // we need to store this tile create time putTileCreateTime( connection, - tile.getXYZ()[2], - tile.getXYZ()[0], - tile.getXYZ()[1], + tile.getZ(), + tile.getX(), + tile.getY(), System.currentTimeMillis()); } if (LOGGER.isLoggable(Level.FINE)) { @@ -244,10 +240,7 @@ public boolean get(final TileObject tile) throws StorageException { // loading the tile using geotools reader MBTilesTile gtTile = - mbtiles.loadTile( - tile.getXYZ()[2], - tile.getXYZ()[0], - tile.getXYZ()[1]); + mbtiles.loadTile(tile.getZ(), tile.getX(), tile.getY()); byte[] bytes = gtTile.getData(); if (gtTile.getData() != null) { @@ -335,11 +328,7 @@ public boolean delete(TileObject tile) throws StorageException { try { // getting tile old data and checking if the tile exists byte[] olData = - mbtiles.loadTile( - tile.getXYZ()[2], - tile.getXYZ()[0], - tile.getXYZ()[1]) - .getData(); + mbtiles.loadTile(tile.getZ(), tile.getX(), tile.getY()).getData(); if (olData != null) { // tile exists so let's remove the tile tile.setBlobSize(olData.length); @@ -349,10 +338,7 @@ public boolean delete(TileObject tile) throws StorageException { if (useCreateTime) { // we care about the create time so let's remove it deleteTileCreateTime( - connection, - tile.getXYZ()[2], - tile.getXYZ()[0], - tile.getXYZ()[1]); + connection, tile.getZ(), tile.getX(), tile.getY()); } if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine( diff --git a/geowebcache/tms/src/main/java/org/geowebcache/service/tms/TMSService.java b/geowebcache/tms/src/main/java/org/geowebcache/service/tms/TMSService.java index 5a0c471e1..8fd3bb67c 100644 --- a/geowebcache/tms/src/main/java/org/geowebcache/service/tms/TMSService.java +++ b/geowebcache/tms/src/main/java/org/geowebcache/service/tms/TMSService.java @@ -41,6 +41,7 @@ import org.geowebcache.service.ServiceException; import org.geowebcache.stats.RuntimeStats; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.NullURLMangler; import org.geowebcache.util.ServletUtils; import org.geowebcache.util.URLMangler; @@ -104,11 +105,13 @@ public ConveyorTile getConveyor(HttpServletRequest request, HttpServletResponse Optional> possibleSplit = splitParams(request); if (possibleSplit.isPresent()) { Map split = possibleSplit.get(); - long[] gridLoc = new long[3]; + long x; + long y; + int z; try { - gridLoc[0] = Integer.parseInt(split.get("x")); - gridLoc[1] = Integer.parseInt(split.get("y")); - gridLoc[2] = Integer.parseInt(split.get("z")); + x = Long.parseLong(split.get("x")); + y = Long.parseLong(split.get("y")); + z = Integer.parseInt(split.get("z")); } catch (NumberFormatException nfe) { throw new ServiceException( "Unable to parse number " + nfe.getMessage() + " from " + pathInfo); @@ -130,6 +133,7 @@ public ConveyorTile getConveyor(HttpServletRequest request, HttpServletResponse throw new ServiceException( "Unable to determine requested format based on extension " + fileExtension); } + TileIndex gridLoc = TileIndex.valueOf(x, y, z); try { TileLayer tileLayer = tld.getTileLayer(layerId); GridSubset gridSubset = tileLayer.getGridSubset(gridSetId); @@ -138,8 +142,9 @@ public ConveyorTile getConveyor(HttpServletRequest request, HttpServletResponse } if (hasFlipY(request)) { - final long tilesHigh = gridSubset.getNumTilesHigh((int) gridLoc[2]); - gridLoc[1] = tilesHigh - gridLoc[1] - 1; + final long tilesHigh = gridSubset.getNumTilesHigh(z); + y = tilesHigh - y - 1; + gridLoc = TileIndex.valueOf(x, y, z); } gridSubset.checkCoverage(gridLoc); diff --git a/geowebcache/tms/src/test/java/org/geowebcache/service/tms/TMSServiceTest.java b/geowebcache/tms/src/test/java/org/geowebcache/service/tms/TMSServiceTest.java index 594f58412..55bc3e70d 100644 --- a/geowebcache/tms/src/test/java/org/geowebcache/service/tms/TMSServiceTest.java +++ b/geowebcache/tms/src/test/java/org/geowebcache/service/tms/TMSServiceTest.java @@ -34,6 +34,7 @@ import org.geowebcache.mime.MimeType; import org.geowebcache.stats.RuntimeStats; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.URLMangler; import org.junit.Assert; import org.junit.Before; @@ -464,10 +465,10 @@ private void testGetTile(boolean flipY) throws Exception { Assert.assertNotNull(conv); assertThat(conv, instanceOf(ConveyorTile.class)); ConveyorTile tile = (ConveyorTile) conv; - final long[] tileIndex = tile.getTileIndex(); - Assert.assertEquals(column, tileIndex[0]); + final TileIndex tileIndex = tile.getIndex(); + Assert.assertEquals(column, tileIndex.getX()); Assert.assertEquals( - row, flipY ? ((int) Math.pow(2, level) - tileIndex[1] - 1) : tileIndex[1]); - Assert.assertEquals(level, tileIndex[2]); + row, flipY ? ((int) Math.pow(2, level) - tileIndex.getY() - 1) : tileIndex.getY()); + Assert.assertEquals(level, tileIndex.getZ()); } } diff --git a/geowebcache/ve/src/main/java/org/geowebcache/service/ve/VEConverter.java b/geowebcache/ve/src/main/java/org/geowebcache/service/ve/VEConverter.java index a9a7138ff..c4b0e7d8e 100644 --- a/geowebcache/ve/src/main/java/org/geowebcache/service/ve/VEConverter.java +++ b/geowebcache/ve/src/main/java/org/geowebcache/service/ve/VEConverter.java @@ -30,6 +30,7 @@ import org.geowebcache.service.Service; import org.geowebcache.service.ServiceException; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.ServletUtils; /** Class to convert from Virtual Earth quad keys to the internal representation of a tile. */ @@ -87,7 +88,7 @@ public ConveyorTile getConveyor(HttpServletRequest request, HttpServletResponse sb, layerId, gsb.getWorldEpsg3857().getName(), - gridLoc, + TileIndex.valueOf(gridLoc), mimeType, null, request, diff --git a/geowebcache/wms/src/main/java/org/geowebcache/service/wms/WMSService.java b/geowebcache/wms/src/main/java/org/geowebcache/service/wms/WMSService.java index 00b2372f7..ef5e0d520 100644 --- a/geowebcache/wms/src/main/java/org/geowebcache/service/wms/WMSService.java +++ b/geowebcache/wms/src/main/java/org/geowebcache/service/wms/WMSService.java @@ -57,6 +57,7 @@ import org.geowebcache.service.ServiceException; import org.geowebcache.stats.RuntimeStats; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.NullURLMangler; import org.geowebcache.util.ServletUtils; import org.geowebcache.util.URLMangler; @@ -292,7 +293,7 @@ public ConveyorTile getConveyor(HttpServletRequest request, HttpServletResponse sb, layers, gridSubset.getName(), - tileIndex, + TileIndex.valueOf(tileIndex), mimeType, fullParameters, request, diff --git a/geowebcache/wms/src/main/java/org/geowebcache/service/wms/WMSTileFuser.java b/geowebcache/wms/src/main/java/org/geowebcache/service/wms/WMSTileFuser.java index 698397a75..08cc2950a 100644 --- a/geowebcache/wms/src/main/java/org/geowebcache/service/wms/WMSTileFuser.java +++ b/geowebcache/wms/src/main/java/org/geowebcache/service/wms/WMSTileFuser.java @@ -53,6 +53,7 @@ import org.geowebcache.mime.MimeType; import org.geowebcache.stats.RuntimeStats; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.AccountingOutputStream; import org.geowebcache.util.IOUtils; import org.geowebcache.util.ServletUtils; @@ -595,7 +596,7 @@ protected void renderCanvas() long startx = srcRectangle[0]; for (long gridx = startx; gridx <= srcRectangle[2]; gridx++) { - long[] gridLoc = {gridx, gridy, srcIdx}; + TileIndex gridLoc = TileIndex.valueOf(gridx, gridy, srcIdx); ConveyorTile tile = new ConveyorTile( @@ -681,13 +682,7 @@ protected void renderCanvas() } // Render the tile on the big canvas - log.fine( - "drawImage(subtile," - + canvasx - + "," - + canvasy - + ",null) " - + Arrays.toString(gridLoc)); + log.fine("drawImage(subtile," + canvasx + "," + canvasy + ",null) " + gridLoc); bufferedImageWrapper.drawImage(tileImg, canvasx, canvasy); } diff --git a/geowebcache/wms/src/test/java/org/geowebcache/service/wms/WMSServiceTest.java b/geowebcache/wms/src/test/java/org/geowebcache/service/wms/WMSServiceTest.java index 3b2d3239d..1155da880 100644 --- a/geowebcache/wms/src/test/java/org/geowebcache/service/wms/WMSServiceTest.java +++ b/geowebcache/wms/src/test/java/org/geowebcache/service/wms/WMSServiceTest.java @@ -5,7 +5,6 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -54,6 +53,7 @@ import org.geowebcache.mime.XMLMime; import org.geowebcache.stats.RuntimeStats; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.NullURLMangler; import org.geowebcache.util.PropertyRule; import org.hamcrest.Matchers; @@ -147,13 +147,12 @@ protected void testMultipleCrsMatchingGridSubsets( assertEquals(expectedGridset, tileRequest.getGridSetId()); assertEquals("image/png", tileRequest.getMimeType().getMimeType()); - assertArrayEquals( - "Expected " - + Arrays.toString(tileIndex) - + " got " - + Arrays.toString(tileRequest.getTileIndex()), - tileIndex, - tileRequest.getTileIndex()); + + TileIndex expected = TileIndex.valueOf(tileIndex); + TileIndex actual = tileRequest.getIndex(); + assertTrue( + "Expected " + TileIndex.toString(expected) + " got " + TileIndex.toString(actual), + expected.isSameTileIndex(actual)); } private TileLayer mockTileLayer(String layerName, List gridSetNames) throws Exception { diff --git a/geowebcache/wmts/src/main/java/org/geowebcache/service/wmts/WMTSGetFeatureInfo.java b/geowebcache/wmts/src/main/java/org/geowebcache/service/wmts/WMTSGetFeatureInfo.java index 151b03a28..63eeb402e 100644 --- a/geowebcache/wmts/src/main/java/org/geowebcache/service/wmts/WMTSGetFeatureInfo.java +++ b/geowebcache/wmts/src/main/java/org/geowebcache/service/wmts/WMTSGetFeatureInfo.java @@ -89,7 +89,7 @@ protected void writeResponse(RuntimeStats stats) throws OWSException { Resource data = null; try { - BoundingBox bbox = convTile.getGridSubset().boundsFromIndex(convTile.getTileIndex()); + BoundingBox bbox = convTile.getGridSubset().boundsFromIndex(convTile.getIndex()); data = layer.getFeatureInfo( convTile, diff --git a/geowebcache/wmts/src/main/java/org/geowebcache/service/wmts/WMTSService.java b/geowebcache/wmts/src/main/java/org/geowebcache/service/wmts/WMTSService.java index 549ab94a5..733821309 100644 --- a/geowebcache/wmts/src/main/java/org/geowebcache/service/wmts/WMTSService.java +++ b/geowebcache/wmts/src/main/java/org/geowebcache/service/wmts/WMTSService.java @@ -48,6 +48,7 @@ import org.geowebcache.service.Service; import org.geowebcache.stats.RuntimeStats; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.NullURLMangler; import org.geowebcache.util.ServletUtils; import org.geowebcache.util.URLMangler; @@ -489,7 +490,7 @@ private ConveyorTile getTile( throw new OWSException( 400, "MissingParameterValue", "TILEMATRIX", "No TILEMATRIX specified"); } - long z = gridSubset.getGridIndex(tileMatrix); + int z = gridSubset.getGridIndex(tileMatrix); if (z < 0) { throw new OWSException( @@ -502,7 +503,7 @@ private ConveyorTile getTile( throw new OWSException(400, "MissingParameterValue", "TILEROW", "No TILEROW specified"); } - final long tilesHigh = gridSubset.getNumTilesHigh((int) z); + final long tilesHigh = gridSubset.getNumTilesHigh(z); long y = tilesHigh - Long.parseLong(tileRow) - 1; @@ -512,7 +513,7 @@ private ConveyorTile getTile( } long x = Long.parseLong(tileCol); - long[] gridCov = gridSubset.getCoverage((int) z); + long[] gridCov = gridSubset.getCoverage(z); if (x < gridCov[0] || x > gridCov[2]) { throw new OWSException( @@ -533,7 +534,7 @@ private ConveyorTile getTile( "Row " + tileRow + " is out of range, min: " + minRow + " max:" + maxRow); } - long[] tileIndex = {x, y, z}; + TileIndex tileIndex = TileIndex.valueOf(x, y, z); try { gridSubset.checkCoverage(tileIndex); diff --git a/geowebcache/wmts/src/test/java/org/geowebcache/service/wmts/WMTSServiceTest.java b/geowebcache/wmts/src/test/java/org/geowebcache/service/wmts/WMTSServiceTest.java index 3d65c4733..55ccea6df 100644 --- a/geowebcache/wmts/src/test/java/org/geowebcache/service/wmts/WMTSServiceTest.java +++ b/geowebcache/wmts/src/test/java/org/geowebcache/service/wmts/WMTSServiceTest.java @@ -84,6 +84,7 @@ import org.geowebcache.service.OWSException; import org.geowebcache.stats.RuntimeStats; import org.geowebcache.storage.StorageBroker; +import org.geowebcache.storage.TileIndex; import org.geowebcache.util.NullURLMangler; import org.geowebcache.util.URLs; import org.junit.Before; @@ -1370,7 +1371,9 @@ public void testGetFeature() throws Exception { when(subset.getName()).thenReturn("testGridset"); when(subset.getGridSet()).thenReturn(set); - when(subset.boundsFromIndex(any())).thenReturn(new BoundingBox(0, 0, 180, 90)); + when(subset.boundsFromIndex(any(TileIndex.class))) + .thenReturn(new BoundingBox(0, 0, 180, 90)); + when(subset.boundsFromIndex(any(long[].class))).thenReturn(new BoundingBox(0, 0, 180, 90)); when(set.getTileHeight()).thenReturn(256); when(set.getTileWidth()).thenReturn(256); @@ -1408,7 +1411,7 @@ public void testGetFeature() throws Exception { + XMLMime.gml.getMimeType()); when(subset.getNumTilesHigh(2)).thenReturn(7L); - when(subset.getGridIndex("testGridset:2")).thenReturn(2L); + when(subset.getGridIndex("testGridset:2")).thenReturn(2); when(subset.getCoverage(2)).thenReturn(new long[] {1, 1, 8, 8}); Conveyor conv = service.getConveyor(req, resp); @@ -1489,7 +1492,7 @@ public void testGetFeatureSecure() throws Exception { + XMLMime.gml.getMimeType()); when(subset.getNumTilesHigh(2)).thenReturn(7L); - when(subset.getGridIndex("testGridset:2")).thenReturn(2L); + when(subset.getGridIndex("testGridset:2")).thenReturn(2); when(subset.getCoverage(2)).thenReturn(new long[] {1, 1, 8, 8}); Conveyor conv = service.getConveyor(req, resp);