diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..9eeecb0d9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,78 @@ +# Java sources +*.java text diff=java +*.kt text diff=java +*.groovy text diff=java +*.scala text diff=java +*.gradle text diff=java +*.gradle.kts text diff=java + +# These files are text and should be normalized (Convert crlf => lf) +*.css text diff=css +*.scss text diff=css +*.sass text +*.df text +*.htm text diff=html +*.html text diff=html +*.js text +*.jsp text +*.jspf text +*.jspx text +*.properties text +*.tld text +*.tag text +*.tagx text +*.xml text +*.xsd text +*.sld text +*.csv text +*.jjt text +*.prj text +*.apt text +*.md text +*.pgw text +*.jgw text +*.txt text +*.rst text + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.class binary +*.dll binary +*.ear binary +*.jar binary +*.so binary +*.war binary +*.jks binary +*.shp binary +*.shx binary +*.dbf binary +*.qix binary +*.fix binary +*.tiff binary +*.tif binary +*.jpg binary +*.jpeg binary +*.png binary +*.zip binary +*.pdf binary +*.db binary +*.ecw binary +*.fgb binary +*.gif binary +*.gpkg binary +*.grb2 binary +*.grib2 binary +*.gz binary +*.img binary +*.jgrass binary +*.jp2 binary +*.mbtiles binary +*.msk binary +*.ovr binary +*.pbf binary +*.pdf binary +*.sid binary +*.tpk binary +*.ttf binary +*.wkb binary + diff --git a/appveyor.yml b/appveyor.yml index 44d900181..061eb953a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,10 +1,10 @@ -version: 1.0.{build} -branches: - only: - - master -cache: - - C:\Users\appveyor\.m2\ -> geowebcache\pom.xml -build_script: - - cmd: | - cd geowebcache - mvn install -T2 -Dall -fae -U +version: 1.0.{build} +branches: + only: + - master +cache: + - C:\Users\appveyor\.m2\ -> geowebcache\pom.xml +build_script: + - cmd: | + cd geowebcache + mvn install -T2 -Dall -fae -U diff --git a/documentation/en/user/source/configuration/layers/selectivezoom.rst b/documentation/en/user/source/configuration/layers/selectivezoom.rst index d7f73d37d..868e2d3d6 100644 --- a/documentation/en/user/source/configuration/layers/selectivezoom.rst +++ b/documentation/en/user/source/configuration/layers/selectivezoom.rst @@ -1,4 +1,4 @@ -.. _configuration.layers.selectivezoomlevel: +.. _configuration.layers.selectivezoomlevel: Selective zoom level caching ============================ diff --git a/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/compact/ArcGISCompactCache.java b/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/compact/ArcGISCompactCache.java index 990db67c0..223bc335d 100644 --- a/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/compact/ArcGISCompactCache.java +++ b/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/compact/ArcGISCompactCache.java @@ -1,121 +1,121 @@ -/** - * 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 2019 - */ -package org.geowebcache.arcgis.compact; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.geowebcache.io.Resource; - -/** - * Abstract base class for ArcGIS compact caches. - * - * @author Bjoern Saxe - */ -public abstract class ArcGISCompactCache { - private static final Log logger = LogFactory.getLog(ArcGISCompactCache.class); - - protected static final String BUNDLX_EXT = ".bundlx"; - - protected static final String BUNDLE_EXT = ".bundle"; - - protected static final int BUNDLX_MAXIDX = 128; - - protected String pathToCacheRoot = ""; - - /** - * Get Resource object for tile. - * - * @param zoom Zoom level. - * @param row Row of tile. - * @param col Column of tile. - * @return Resource object associated with tile image data if tile exists; null otherwise. - */ - public abstract Resource getBundleFileResource(int zoom, int row, int col); - - /** - * Build path to a bundle from zoom, col, and row without file extension. - * - * @param zoom Zoom levl - * @param row Row - * @param col Column - * @return String containing complete path without file extension in the form of - * .../Lzz/RrrrrCcccc with the number of c and r at least 4. - */ - protected String buildBundleFilePath(int zoom, int row, int col) { - StringBuilder bundlePath = new StringBuilder(pathToCacheRoot); - - int baseRow = (row / BUNDLX_MAXIDX) * BUNDLX_MAXIDX; - int baseCol = (col / BUNDLX_MAXIDX) * BUNDLX_MAXIDX; - - String zoomStr = Integer.toString(zoom); - if (zoomStr.length() < 2) zoomStr = "0" + zoomStr; - - StringBuilder rowStr = new StringBuilder(Integer.toHexString(baseRow)); - StringBuilder colStr = new StringBuilder(Integer.toHexString(baseCol)); - - // column and rows are at least 4 characters long - final int padding = 4; - - while (colStr.length() < padding) colStr.insert(0, "0"); - - while (rowStr.length() < padding) rowStr.insert(0, "0"); - - bundlePath - .append("L") - .append(zoomStr) - .append(File.separatorChar) - .append("R") - .append(rowStr) - .append("C") - .append(colStr); - - return bundlePath.toString(); - } - - /** - * Read from a file that uses little endian byte order. - * - * @param filePath Path to file - * @param offset Read at offset - * @param length Read length bytes - * @return ByteBuffer that contains read bytes and has byte order set to little endian. The - * length of the byte buffer is multiple of 4, so getInt() and getLong() can be used even - * when fewer bytes are read. - */ - protected ByteBuffer readFromLittleEndianFile(String filePath, long offset, int length) { - ByteBuffer result = null; - - try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { - file.seek(offset); - // pad to multiples of 4 so we can use getInt() and getLong() - int padding = 4 - (length % 4); - byte[] data = new byte[length + padding]; - - if (file.read(data, 0, length) != length) - throw new IOException("not enough bytes read or reached end of file"); - - result = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN); - } catch (IOException e) { - logger.warn("Failed to read from little endian file", e); - } - - return result; - } -} +/** + * 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 2019 + */ +package org.geowebcache.arcgis.compact; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geowebcache.io.Resource; + +/** + * Abstract base class for ArcGIS compact caches. + * + * @author Bjoern Saxe + */ +public abstract class ArcGISCompactCache { + private static final Log logger = LogFactory.getLog(ArcGISCompactCache.class); + + protected static final String BUNDLX_EXT = ".bundlx"; + + protected static final String BUNDLE_EXT = ".bundle"; + + protected static final int BUNDLX_MAXIDX = 128; + + protected String pathToCacheRoot = ""; + + /** + * Get Resource object for tile. + * + * @param zoom Zoom level. + * @param row Row of tile. + * @param col Column of tile. + * @return Resource object associated with tile image data if tile exists; null otherwise. + */ + public abstract Resource getBundleFileResource(int zoom, int row, int col); + + /** + * Build path to a bundle from zoom, col, and row without file extension. + * + * @param zoom Zoom levl + * @param row Row + * @param col Column + * @return String containing complete path without file extension in the form of + * .../Lzz/RrrrrCcccc with the number of c and r at least 4. + */ + protected String buildBundleFilePath(int zoom, int row, int col) { + StringBuilder bundlePath = new StringBuilder(pathToCacheRoot); + + int baseRow = (row / BUNDLX_MAXIDX) * BUNDLX_MAXIDX; + int baseCol = (col / BUNDLX_MAXIDX) * BUNDLX_MAXIDX; + + String zoomStr = Integer.toString(zoom); + if (zoomStr.length() < 2) zoomStr = "0" + zoomStr; + + StringBuilder rowStr = new StringBuilder(Integer.toHexString(baseRow)); + StringBuilder colStr = new StringBuilder(Integer.toHexString(baseCol)); + + // column and rows are at least 4 characters long + final int padding = 4; + + while (colStr.length() < padding) colStr.insert(0, "0"); + + while (rowStr.length() < padding) rowStr.insert(0, "0"); + + bundlePath + .append("L") + .append(zoomStr) + .append(File.separatorChar) + .append("R") + .append(rowStr) + .append("C") + .append(colStr); + + return bundlePath.toString(); + } + + /** + * Read from a file that uses little endian byte order. + * + * @param filePath Path to file + * @param offset Read at offset + * @param length Read length bytes + * @return ByteBuffer that contains read bytes and has byte order set to little endian. The + * length of the byte buffer is multiple of 4, so getInt() and getLong() can be used even + * when fewer bytes are read. + */ + protected ByteBuffer readFromLittleEndianFile(String filePath, long offset, int length) { + ByteBuffer result = null; + + try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { + file.seek(offset); + // pad to multiples of 4 so we can use getInt() and getLong() + int padding = 4 - (length % 4); + byte[] data = new byte[length + padding]; + + if (file.read(data, 0, length) != length) + throw new IOException("not enough bytes read or reached end of file"); + + result = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN); + } catch (IOException e) { + logger.warn("Failed to read from little endian file", e); + } + + return result; + } +} diff --git a/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/compact/BundleFileResource.java b/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/compact/BundleFileResource.java index 97f033f18..c465340d5 100644 --- a/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/compact/BundleFileResource.java +++ b/geowebcache/arcgiscache/src/main/java/org/geowebcache/arcgis/compact/BundleFileResource.java @@ -1,105 +1,105 @@ -/** - * 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 2019 - */ -package org.geowebcache.arcgis.compact; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.channels.FileChannel; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.geowebcache.io.Resource; - -/** @author Bjoern Saxe */ -public class BundleFileResource implements Resource { - private static Log log = LogFactory.getLog(BundleFileResource.class); - - private final String bundleFilePath; - - private final long tileOffset; - - private final int tileSize; - - public BundleFileResource(String bundleFilePath, long tileOffset, int tileSize) { - this.bundleFilePath = bundleFilePath; - this.tileOffset = tileOffset; - this.tileSize = tileSize; - } - - /** @see org.geowebcache.io.Resource#getSize() */ - public long getSize() { - return tileSize; - } - - /** @see org.geowebcache.io.Resource#transferTo(WritableByteChannel) */ - @SuppressWarnings("PMD.EmptyWhileStmt") - public long transferTo(WritableByteChannel target) throws IOException { - try (FileInputStream fin = new FileInputStream(new File(bundleFilePath)); - FileChannel in = fin.getChannel()) { - final long size = tileSize; - long written = 0; - while ((written += in.transferTo(tileOffset + written, size, target)) < size) ; - return size; - } - } - - /** - * Not supported for ArcGIS caches as they are read only. - * - * @see org.geowebcache.io.Resource#transferFrom(ReadableByteChannel) - */ - public long transferFrom(ReadableByteChannel channel) throws IOException { - // unsupported - return 0; - } - - /** @see org.geowebcache.io.Resource#getInputStream() */ - public InputStream getInputStream() throws IOException { - FileInputStream fis = new FileInputStream(bundleFilePath); - long skipped = fis.skip(tileOffset); - if (skipped != tileOffset) { - log.error( - "tried to skip to tile offset " - + tileOffset - + " in " - + bundleFilePath - + " but skipped " - + skipped - + " instead."); - } - return fis; - } - - /** - * Not supported for ArcGIS caches as they are read only. - * - * @see org.geowebcache.io.Resource#getOutputStream() - */ - public OutputStream getOutputStream() throws IOException { - // unsupported - return null; - } - - /** @see org.geowebcache.io.Resource#getLastModified() */ - public long getLastModified() { - File f = new File(bundleFilePath); - - return f.lastModified(); - } -} +/** + * 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 2019 + */ +package org.geowebcache.arcgis.compact; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.geowebcache.io.Resource; + +/** @author Bjoern Saxe */ +public class BundleFileResource implements Resource { + private static Log log = LogFactory.getLog(BundleFileResource.class); + + private final String bundleFilePath; + + private final long tileOffset; + + private final int tileSize; + + public BundleFileResource(String bundleFilePath, long tileOffset, int tileSize) { + this.bundleFilePath = bundleFilePath; + this.tileOffset = tileOffset; + this.tileSize = tileSize; + } + + /** @see org.geowebcache.io.Resource#getSize() */ + public long getSize() { + return tileSize; + } + + /** @see org.geowebcache.io.Resource#transferTo(WritableByteChannel) */ + @SuppressWarnings("PMD.EmptyWhileStmt") + public long transferTo(WritableByteChannel target) throws IOException { + try (FileInputStream fin = new FileInputStream(new File(bundleFilePath)); + FileChannel in = fin.getChannel()) { + final long size = tileSize; + long written = 0; + while ((written += in.transferTo(tileOffset + written, size, target)) < size) ; + return size; + } + } + + /** + * Not supported for ArcGIS caches as they are read only. + * + * @see org.geowebcache.io.Resource#transferFrom(ReadableByteChannel) + */ + public long transferFrom(ReadableByteChannel channel) throws IOException { + // unsupported + return 0; + } + + /** @see org.geowebcache.io.Resource#getInputStream() */ + public InputStream getInputStream() throws IOException { + FileInputStream fis = new FileInputStream(bundleFilePath); + long skipped = fis.skip(tileOffset); + if (skipped != tileOffset) { + log.error( + "tried to skip to tile offset " + + tileOffset + + " in " + + bundleFilePath + + " but skipped " + + skipped + + " instead."); + } + return fis; + } + + /** + * Not supported for ArcGIS caches as they are read only. + * + * @see org.geowebcache.io.Resource#getOutputStream() + */ + public OutputStream getOutputStream() throws IOException { + // unsupported + return null; + } + + /** @see org.geowebcache.io.Resource#getLastModified() */ + public long getLastModified() { + File f = new File(bundleFilePath); + + return f.lastModified(); + } +} diff --git a/geowebcache/arcgiscache/src/test/java/org/geowebcache/arcgis/compact/ArcGISCompactCacheTest.java b/geowebcache/arcgiscache/src/test/java/org/geowebcache/arcgis/compact/ArcGISCompactCacheTest.java index f82c5b0f2..77ba4926f 100755 --- a/geowebcache/arcgiscache/src/test/java/org/geowebcache/arcgis/compact/ArcGISCompactCacheTest.java +++ b/geowebcache/arcgiscache/src/test/java/org/geowebcache/arcgis/compact/ArcGISCompactCacheTest.java @@ -1,183 +1,183 @@ -package org.geowebcache.arcgis.compact; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.net.URL; -import org.geowebcache.io.Resource; -import org.junit.Assert; -import org.junit.Test; - -/** - * Unit test for ArcGIS compact cache classes. Available data in supplied test caches: - * - *
10.0 - 10.2 cache - * - *
zoom level | min row | max row | min col | max col | | | | 5 | 10 | 13 | 4 | 10 | | | | 6 | 22 - * | 28 | 10 | 21 - * - *
- image format is JPEG - tile size for (5,12,7) is 6342 bytes - tile size for (6,25,17) is - * 6308 bytes - * - *
10.3 cache - * - *
zoom level | min row | max row | min col | max col | | | | 4 | 5 | 6 | 2 | 5 | | | | 5 | 10 | - * 13 | 4 | 10 - * - *
- image format is JPEG - tile size for (4,5,4) is 7288 bytes - tile size for (5,11,5) is 6055 - * bytes - * - *
Not verifiable with this unit test because the supplied test cache is too small: - * - *
- zoom levels can contain more than one .bundle/.bundlx file - row and column numbers have at - * least 4 digits in bundle file name, but with really big caches row and column numbers can have - * more than 4 digits - * - * @author Bjoern Saxe - */ -public class ArcGISCompactCacheTest { - private static final byte[] JFIFHeader = { - (byte) 0xFF, - (byte) 0xD8, - (byte) 0xFF, - (byte) 0xE0, - 0x00, - 0x10, - 0x4A, - 0x46, - 0x49, - 0x46, - 0x00, - 0x01 - }; - - @Test - public void testCompactCacheV1() throws Exception { - URL url = getClass().getResource("/compactcache/_alllayers/"); - ArcGISCompactCache cache = new ArcGISCompactCacheV1(url.toURI().getPath()); - - Assert.assertNotNull(cache); - - Assert.assertNull(cache.getBundleFileResource(5, -1, -1)); - Assert.assertNull(cache.getBundleFileResource(4, 10, 4)); - Assert.assertNull(cache.getBundleFileResource(7, 22, 10)); - - Assert.assertNull(cache.getBundleFileResource(5, 0, 0)); - Assert.assertNotNull(cache.getBundleFileResource(5, 10, 4)); - Assert.assertNotNull(cache.getBundleFileResource(5, 13, 10)); - Assert.assertNotNull(cache.getBundleFileResource(5, 12, 7)); - - Assert.assertNull(cache.getBundleFileResource(6, 0, 0)); - Assert.assertNotNull(cache.getBundleFileResource(6, 22, 10)); - Assert.assertNotNull(cache.getBundleFileResource(6, 22, 10)); - Assert.assertNotNull(cache.getBundleFileResource(6, 25, 17)); - } - - @Test - public void testCompactCacheV2() throws Exception { - URL url = getClass().getResource("/compactcacheV2/_alllayers/"); - ArcGISCompactCache cache = new ArcGISCompactCacheV2(url.toURI().getPath()); - - Assert.assertNotNull(cache); - - Assert.assertNull(cache.getBundleFileResource(5, -1, -1)); - Assert.assertNull(cache.getBundleFileResource(3, 5, 2)); - Assert.assertNull(cache.getBundleFileResource(4, 4, 1)); - Assert.assertNull(cache.getBundleFileResource(4, 7, 6)); - Assert.assertNull(cache.getBundleFileResource(5, 9, 4)); - Assert.assertNull(cache.getBundleFileResource(6, 13, 11)); - - Assert.assertNotNull(cache.getBundleFileResource(4, 5, 2)); - Assert.assertNotNull(cache.getBundleFileResource(4, 5, 4)); - Assert.assertNotNull(cache.getBundleFileResource(4, 6, 5)); - Assert.assertNotNull(cache.getBundleFileResource(5, 10, 4)); - Assert.assertNotNull(cache.getBundleFileResource(5, 11, 9)); - Assert.assertNotNull(cache.getBundleFileResource(5, 13, 10)); - } - - @Test - public void testBundleFileResourceV1() throws Exception { - URL url = getClass().getResource("/compactcache/_alllayers/"); - ArcGISCompactCache cache = new ArcGISCompactCacheV1(url.toURI().getPath()); - - Assert.assertNotNull(cache); - - Resource resource = cache.getBundleFileResource(5, 12, 7); - Assert.assertNotNull(resource); - Assert.assertEquals(6342, resource.getSize()); - - File f = new File("5_12_7.jpg"); - try (FileOutputStream fos = new FileOutputStream(f)) { - resource.transferTo(fos.getChannel()); - } - - Assert.assertTrue(startsWithJPEGHeader(f)); - - f.delete(); - - resource = cache.getBundleFileResource(6, 25, 17); - Assert.assertNotNull(resource); - Assert.assertEquals(6308, resource.getSize()); - - f = new File("6_25_17.jpg"); - try (FileOutputStream fos = new FileOutputStream(f)) { - resource.transferTo(fos.getChannel()); - } - - Assert.assertTrue(startsWithJPEGHeader(f)); - - f.delete(); - } - - @Test - public void testBundleFileResourceV2() throws Exception { - URL url = getClass().getResource("/compactcacheV2/_alllayers/"); - ArcGISCompactCache cache = new ArcGISCompactCacheV2(url.toURI().getPath()); - - Assert.assertNotNull(cache); - - Resource resource = cache.getBundleFileResource(4, 5, 4); - Assert.assertNotNull(resource); - Assert.assertEquals(7288, resource.getSize()); - - File f = new File("4_5_4.jpg"); - try (FileOutputStream fos = new FileOutputStream(f)) { - resource.transferTo(fos.getChannel()); - } - - Assert.assertTrue(startsWithJPEGHeader(f)); - - f.delete(); - - resource = cache.getBundleFileResource(5, 11, 5); - Assert.assertNotNull(resource); - Assert.assertEquals(6055, resource.getSize()); - - f = new File("5_11_5.jpg"); - try (FileOutputStream fos = new FileOutputStream(f)) { - resource.transferTo(fos.getChannel()); - } - - Assert.assertTrue(startsWithJPEGHeader(f)); - - f.delete(); - } - - private boolean startsWithJPEGHeader(File f) { - try (FileInputStream fis = new FileInputStream(f); ) { - - byte[] fileHeader = new byte[JFIFHeader.length]; - - fis.read(fileHeader, 0, JFIFHeader.length); - fis.close(); - - for (int i = 0; i < fileHeader.length; i++) { - if (fileHeader[i] != JFIFHeader[i]) return false; - } - } catch (Exception e) { - return false; - } - - return true; - } -} +package org.geowebcache.arcgis.compact; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.net.URL; +import org.geowebcache.io.Resource; +import org.junit.Assert; +import org.junit.Test; + +/** + * Unit test for ArcGIS compact cache classes. Available data in supplied test caches: + * + *
10.0 - 10.2 cache + * + *
zoom level | min row | max row | min col | max col | | | | 5 | 10 | 13 | 4 | 10 | | | | 6 | 22 + * | 28 | 10 | 21 + * + *
- image format is JPEG - tile size for (5,12,7) is 6342 bytes - tile size for (6,25,17) is + * 6308 bytes + * + *
10.3 cache + * + *
zoom level | min row | max row | min col | max col | | | | 4 | 5 | 6 | 2 | 5 | | | | 5 | 10 | + * 13 | 4 | 10 + * + *
- image format is JPEG - tile size for (4,5,4) is 7288 bytes - tile size for (5,11,5) is 6055 + * bytes + * + *
Not verifiable with this unit test because the supplied test cache is too small: + * + *
- zoom levels can contain more than one .bundle/.bundlx file - row and column numbers have at + * least 4 digits in bundle file name, but with really big caches row and column numbers can have + * more than 4 digits + * + * @author Bjoern Saxe + */ +public class ArcGISCompactCacheTest { + private static final byte[] JFIFHeader = { + (byte) 0xFF, + (byte) 0xD8, + (byte) 0xFF, + (byte) 0xE0, + 0x00, + 0x10, + 0x4A, + 0x46, + 0x49, + 0x46, + 0x00, + 0x01 + }; + + @Test + public void testCompactCacheV1() throws Exception { + URL url = getClass().getResource("/compactcache/_alllayers/"); + ArcGISCompactCache cache = new ArcGISCompactCacheV1(url.toURI().getPath()); + + Assert.assertNotNull(cache); + + Assert.assertNull(cache.getBundleFileResource(5, -1, -1)); + Assert.assertNull(cache.getBundleFileResource(4, 10, 4)); + Assert.assertNull(cache.getBundleFileResource(7, 22, 10)); + + Assert.assertNull(cache.getBundleFileResource(5, 0, 0)); + Assert.assertNotNull(cache.getBundleFileResource(5, 10, 4)); + Assert.assertNotNull(cache.getBundleFileResource(5, 13, 10)); + Assert.assertNotNull(cache.getBundleFileResource(5, 12, 7)); + + Assert.assertNull(cache.getBundleFileResource(6, 0, 0)); + Assert.assertNotNull(cache.getBundleFileResource(6, 22, 10)); + Assert.assertNotNull(cache.getBundleFileResource(6, 22, 10)); + Assert.assertNotNull(cache.getBundleFileResource(6, 25, 17)); + } + + @Test + public void testCompactCacheV2() throws Exception { + URL url = getClass().getResource("/compactcacheV2/_alllayers/"); + ArcGISCompactCache cache = new ArcGISCompactCacheV2(url.toURI().getPath()); + + Assert.assertNotNull(cache); + + Assert.assertNull(cache.getBundleFileResource(5, -1, -1)); + Assert.assertNull(cache.getBundleFileResource(3, 5, 2)); + Assert.assertNull(cache.getBundleFileResource(4, 4, 1)); + Assert.assertNull(cache.getBundleFileResource(4, 7, 6)); + Assert.assertNull(cache.getBundleFileResource(5, 9, 4)); + Assert.assertNull(cache.getBundleFileResource(6, 13, 11)); + + Assert.assertNotNull(cache.getBundleFileResource(4, 5, 2)); + Assert.assertNotNull(cache.getBundleFileResource(4, 5, 4)); + Assert.assertNotNull(cache.getBundleFileResource(4, 6, 5)); + Assert.assertNotNull(cache.getBundleFileResource(5, 10, 4)); + Assert.assertNotNull(cache.getBundleFileResource(5, 11, 9)); + Assert.assertNotNull(cache.getBundleFileResource(5, 13, 10)); + } + + @Test + public void testBundleFileResourceV1() throws Exception { + URL url = getClass().getResource("/compactcache/_alllayers/"); + ArcGISCompactCache cache = new ArcGISCompactCacheV1(url.toURI().getPath()); + + Assert.assertNotNull(cache); + + Resource resource = cache.getBundleFileResource(5, 12, 7); + Assert.assertNotNull(resource); + Assert.assertEquals(6342, resource.getSize()); + + File f = new File("5_12_7.jpg"); + try (FileOutputStream fos = new FileOutputStream(f)) { + resource.transferTo(fos.getChannel()); + } + + Assert.assertTrue(startsWithJPEGHeader(f)); + + f.delete(); + + resource = cache.getBundleFileResource(6, 25, 17); + Assert.assertNotNull(resource); + Assert.assertEquals(6308, resource.getSize()); + + f = new File("6_25_17.jpg"); + try (FileOutputStream fos = new FileOutputStream(f)) { + resource.transferTo(fos.getChannel()); + } + + Assert.assertTrue(startsWithJPEGHeader(f)); + + f.delete(); + } + + @Test + public void testBundleFileResourceV2() throws Exception { + URL url = getClass().getResource("/compactcacheV2/_alllayers/"); + ArcGISCompactCache cache = new ArcGISCompactCacheV2(url.toURI().getPath()); + + Assert.assertNotNull(cache); + + Resource resource = cache.getBundleFileResource(4, 5, 4); + Assert.assertNotNull(resource); + Assert.assertEquals(7288, resource.getSize()); + + File f = new File("4_5_4.jpg"); + try (FileOutputStream fos = new FileOutputStream(f)) { + resource.transferTo(fos.getChannel()); + } + + Assert.assertTrue(startsWithJPEGHeader(f)); + + f.delete(); + + resource = cache.getBundleFileResource(5, 11, 5); + Assert.assertNotNull(resource); + Assert.assertEquals(6055, resource.getSize()); + + f = new File("5_11_5.jpg"); + try (FileOutputStream fos = new FileOutputStream(f)) { + resource.transferTo(fos.getChannel()); + } + + Assert.assertTrue(startsWithJPEGHeader(f)); + + f.delete(); + } + + private boolean startsWithJPEGHeader(File f) { + try (FileInputStream fis = new FileInputStream(f); ) { + + byte[] fileHeader = new byte[JFIFHeader.length]; + + fis.read(fileHeader, 0, JFIFHeader.length); + fis.close(); + + for (int i = 0; i < fileHeader.length; i++) { + if (fileHeader[i] != JFIFHeader[i]) return false; + } + } catch (Exception e) { + return false; + } + + return true; + } +} diff --git a/geowebcache/core/src/main/java/org/geowebcache/seed/TruncateAllRequest.java b/geowebcache/core/src/main/java/org/geowebcache/seed/TruncateAllRequest.java index 2179a3607..031abe9c9 100644 --- a/geowebcache/core/src/main/java/org/geowebcache/seed/TruncateAllRequest.java +++ b/geowebcache/core/src/main/java/org/geowebcache/seed/TruncateAllRequest.java @@ -1,105 +1,105 @@ -/** - * 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 Truncated All Layers Truncated Layers:"
- + getTrucatedLayersList().toString()
- + " " + content + " 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 Truncated All Layers Truncated Layers:"
+ + getTrucatedLayersList().toString()
+ + " " + content + "