This is an automated email from the ASF dual-hosted git repository.

bchapuis pushed a commit to branch gdal
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git

commit 374c6858599a56dd946eba28cca059e0a777f434
Author: Bertil Chapuis <[email protected]>
AuthorDate: Sun Apr 23 12:44:02 2023 +0200

    Serve contour tiles
---
 .../java/org/apache/baremaps/cli/map/Contour.java  |  82 +++++++++++++++
 .../main/java/org/apache/baremaps/cli/map/Map.java |   2 +-
 baremaps-core/pom.xml                              |   8 +-
 .../apache/baremaps/raster/ContourTileStore.java   |  73 +++++++------
 .../main/java/org/apache/baremaps/raster/Main.java |  26 ++---
 .../org/apache/baremaps/vectortile/Feature.java    |   8 +-
 .../baremaps/vectortile/VectorTileEncoder.java     |   5 +-
 .../baremaps/vectortile/VectorTileFunctions.java   |  34 ++++--
 .../vectortile/VectorTileFunctionsTest.java        |   2 +-
 .../apache/baremaps/vectortile/VectorTileTest.java |   4 +-
 .../baremaps/vectortile/VectorTileViewer.java      |  16 +--
 .../apache/baremaps/server/ServerResources.java    | 116 +++++++++++++++++++++
 examples/contour/style.json                        |   4 +-
 examples/contour/tileset.json                      |  11 +-
 14 files changed, 304 insertions(+), 87 deletions(-)

diff --git 
a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Contour.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Contour.java
new file mode 100644
index 00000000..055456d5
--- /dev/null
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Contour.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.cli.map;
+
+import static 
io.servicetalk.data.jackson.jersey.ServiceTalkJacksonSerializerFeature.contextResolverFor;
+import static 
org.apache.baremaps.server.DefaultObjectMapper.defaultObjectMapper;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.servicetalk.http.netty.HttpServers;
+import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder;
+import java.nio.file.Path;
+import java.util.concurrent.Callable;
+import org.apache.baremaps.database.tile.TileStore;
+import org.apache.baremaps.raster.ContourTileStore;
+import org.apache.baremaps.server.CorsFilter;
+import org.apache.baremaps.server.ServerResources;
+import org.glassfish.hk2.utilities.binding.AbstractBinder;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Option;
+
+@Command(name = "contour", description = "Start a tile server with caching 
capabilities.")
+public class Contour implements Callable<Integer> {
+
+  private static final Logger logger = LoggerFactory.getLogger(Contour.class);
+
+  @Option(names = {"--cache"}, paramLabel = "CACHE", description = "The 
caffeine cache directive.")
+  private String cache = "";
+
+  @Option(names = {"--tileset"}, paramLabel = "TILESET", description = "The 
tileset file.",
+      required = true)
+  private Path tileset;
+
+  @Option(names = {"--style"}, paramLabel = "STYLE", description = "The style 
file.",
+      required = true)
+  private Path style;
+
+  @Option(names = {"--host"}, paramLabel = "HOST", description = "The host of 
the server.")
+  private String host = "localhost";
+
+  @Option(names = {"--port"}, paramLabel = "PORT", description = "The port of 
the server.")
+  private int port = 9000;
+
+  @Override
+  public Integer call() throws Exception {
+    var objectMapper = defaultObjectMapper();
+    var tileStore = new ContourTileStore();
+
+    // Configure the application
+    var application =
+        new 
ResourceConfig().register(CorsFilter.class).register(ServerResources.class)
+            .register(contextResolverFor(objectMapper)).register(new 
AbstractBinder() {
+              @Override
+              protected void configure() {
+                bind(Contour.this.tileset).to(Path.class).named("tileset");
+                bind(style).to(Path.class).named("style");
+                bind(objectMapper).to(ObjectMapper.class);
+                bind(tileStore).to(TileStore.class);
+              }
+            });
+
+    var httpService = new 
HttpJerseyRouterBuilder().buildBlockingStreaming(application);
+    var serverContext = 
HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService);
+
+    logger.info("Listening on {}", serverContext.listenAddress());
+
+    serverContext.awaitShutdown();
+    return 0;
+  }
+}
diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java 
b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java
index 0f0f1a4c..6744b00d 100644
--- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java
+++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/map/Map.java
@@ -24,7 +24,7 @@ import picocli.CommandLine.Command;
 
 @Command(name = "map", description = "Map commands.",
     subcommands = {Init.class, Export.class, Serve.class, Dev.class, 
StyleCommand.class,
-        MBTiles.class},
+        MBTiles.class, Contour.class},
     sortOptions = false)
 public class Map implements Runnable {
 
diff --git a/baremaps-core/pom.xml b/baremaps-core/pom.xml
index 4b83e635..55159841 100644
--- a/baremaps-core/pom.xml
+++ b/baremaps-core/pom.xml
@@ -110,6 +110,10 @@ limitations under the License.
       <groupId>org.apache.lucene</groupId>
       <artifactId>lucene-spatial-extras</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.gdal</groupId>
+      <artifactId>gdal</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.graalvm.js</groupId>
       <artifactId>js</artifactId>
@@ -118,10 +122,6 @@ limitations under the License.
       <groupId>org.graalvm.sdk</groupId>
       <artifactId>graal-sdk</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.gdal</groupId>
-      <artifactId>gdal</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.locationtech.jts</groupId>
       <artifactId>jts-core</artifactId>
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java 
b/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java
index 9e2b093b..bce42cd5 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/raster/ContourTileStore.java
@@ -15,23 +15,24 @@ package org.apache.baremaps.raster;
 import java.nio.ByteBuffer;
 import java.nio.file.Paths;
 import java.util.List;
+import java.util.Map;
 import java.util.Vector;
-import java.util.stream.IntStream;
 import java.util.stream.LongStream;
-
-import org.apache.baremaps.database.tile.Tile;
-import org.apache.baremaps.database.tile.TileStore;
-import org.apache.baremaps.database.tile.TileStoreException;
-import org.apache.baremaps.openstreetmap.utils.GeometryUtils;
-import org.apache.baremaps.openstreetmap.utils.ProjectionTransformer;
+import org.apache.baremaps.tilestore.TileCoord;
+import org.apache.baremaps.tilestore.TileStore;
+import org.apache.baremaps.tilestore.TileStoreException;
+import org.apache.baremaps.utils.GeometryUtils;
+import org.apache.baremaps.vectortile.Feature;
+import org.apache.baremaps.vectortile.Layer;
+import org.apache.baremaps.vectortile.VectorTileFunctions;
 import org.gdal.gdal.Dataset;
 import org.gdal.gdal.WarpOptions;
 import org.gdal.gdal.gdal;
 import org.gdal.gdalconst.gdalconstConstants;
-import org.gdal.ogr.FieldDefn;
 import org.gdal.ogr.ogr;
 import org.gdal.osr.SpatialReference;
-import org.locationtech.jts.geom.util.GeometryTransformer;
+import org.locationtech.jts.geom.Envelope;
+import org.locationtech.jts.geom.GeometryFactory;
 import org.locationtech.proj4j.ProjCoordinate;
 
 public class ContourTileStore implements TileStore, AutoCloseable {
@@ -49,52 +50,62 @@ public class ContourTileStore implements TileStore, 
AutoCloseable {
   }
 
   @Override
-  public ByteBuffer read(Tile tile) throws TileStoreException {
+  public ByteBuffer read(TileCoord tile) throws TileStoreException {
     var sourceBand = sourceDataset.GetRasterBand(1);
     var envelope = tile.envelope();
 
+    // Transform the extent to the source projection
+    var transformer = GeometryUtils.coordinateTransform(4326, 3857);
+    var min = transformer.transform(new ProjCoordinate(envelope.getMinX(), 
envelope.getMinY()),
+        new ProjCoordinate());
+    var max = transformer.transform(new ProjCoordinate(envelope.getMaxX(), 
envelope.getMaxY()),
+        new ProjCoordinate());
+    var targetEnvelope = new Envelope(min.x, max.x, min.y, max.y);
+
     // Warp the raster to the requested extent
     var rasterOptions = new WarpOptions(new Vector<>(List.of(
-            "-of", "MEM",
-            "-te", Double.toString(envelope.getMinX()), 
Double.toString(envelope.getMinY()), Double.toString(envelope.getMaxX()), 
Double.toString(envelope.getMaxY()),
-            "-te_srs", "EPSG:4326")));
-    var rasterDataset = gdal.Warp("", new Dataset[]{sourceDataset}, 
rasterOptions);
+        "-of", "MEM",
+        "-te", Double.toString(envelope.getMinX()), 
Double.toString(envelope.getMinY()),
+        Double.toString(envelope.getMaxX()), 
Double.toString(envelope.getMaxY()),
+        "-te_srs", "EPSG:4326")));
+    var rasterDataset = gdal.Warp("", new Dataset[] {sourceDataset}, 
rasterOptions);
     var rasterBand = rasterDataset.GetRasterBand(1);
 
     // Generate the contours
-    //var wkt = rasterDataset.GetProjection();
-    //var srs = new SpatialReference(wkt);
-    var srs = new SpatialReference("EPSG:4326");
+    var wkt = rasterDataset.GetProjection();
+    var srs = new SpatialReference(wkt);
     var vectorDriver = ogr.GetDriverByName("Memory");
     var vectorDataSource = vectorDriver.CreateDataSource("vector");
     var vectorLayer = vectorDataSource.CreateLayer("vector", srs, 
ogr.wkbLineString);
-    gdal.ContourGenerateEx(rasterBand, vectorLayer, new 
Vector<>(List.of("LEVEL_INTERVAL=" + 10)));
+    gdal.ContourGenerateEx(rasterBand, vectorLayer, new 
Vector<>(List.of("LEVEL_INTERVAL=" + 50)));
 
     // return the contours
-    var geometries = LongStream.range(0, vectorLayer.GetFeatureCount())
-            .mapToObj(vectorLayer::GetFeature)
-            .map(feature -> feature.GetGeometryRef())
-            .map(geometry -> GeometryUtils.deserialize(geometry.ExportToWkb()))
-            .toList();
+    var features = LongStream.range(0, vectorLayer.GetFeatureCount())
+        .mapToObj(vectorLayer::GetFeature)
+        .map(feature -> feature.GetGeometryRef())
+        .map(geometry -> GeometryUtils.deserialize(geometry.ExportToWkb()))
+        .map(geometry -> VectorTileFunctions.asVectorTileGeom(geometry, 
targetEnvelope, 4096, 0, true))
+        .map(geometry -> new Feature(null, Map.of(), geometry))
+        .toList();
+
+    var vectorTile = VectorTileFunctions.asVectorTile(
+        new org.apache.baremaps.vectortile.Tile(List.of(new Layer("contours", 
4096, features))));
 
-    var transformer = GeometryUtils.coordinateTransform(4326, 3857);
-    var min = transformer.transform(new ProjCoordinate(envelope.getMinX(), 
envelope.getMinY()), new ProjCoordinate());
-    var max = transformer.transform(new ProjCoordinate(envelope.getMaxX(), 
envelope.getMaxY()), new ProjCoordinate());
 
     rasterBand.delete();
     rasterDataset.delete();
     sourceBand.delete();
 
-    return null;
+    return vectorTile;
   }
 
   @Override
-  public void write(Tile tile, ByteBuffer blob) throws TileStoreException {
+  public void write(TileCoord tile, ByteBuffer blob) throws TileStoreException 
{
     throw new UnsupportedOperationException();
   }
 
   @Override
-  public void delete(Tile tile) throws TileStoreException {
+  public void delete(TileCoord tile) throws TileStoreException {
     throw new UnsupportedOperationException();
   }
 
@@ -105,8 +116,8 @@ public class ContourTileStore implements TileStore, 
AutoCloseable {
 
   public static void main(String[] args) throws Exception {
     var store = new ContourTileStore();
-    store.read(new Tile(8492, 5792, 14).parent());
-  }
+    store.read(new TileCoord(8492, 5792, 14).parent());
 
+  }
 
 }
diff --git a/baremaps-core/src/main/java/org/apache/baremaps/raster/Main.java 
b/baremaps-core/src/main/java/org/apache/baremaps/raster/Main.java
index f447f5c5..e7dbd691 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/raster/Main.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/raster/Main.java
@@ -26,15 +26,15 @@ import org.gdal.osr.SpatialReference;
 public class Main {
 
   public static void main(String[] args) {
-     var sourceFilename = 
Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857.tif")
-     .toAbsolutePath().toString();
-     var hillshadeFilename =
-     
Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857-hillshade.tif").toAbsolutePath()
-     .toString();
-     var outputFilename = 
Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857.shp")
-     .toAbsolutePath().toString();
-     var warpFilename = 
Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857-warp.tif")
-     .toAbsolutePath().toString();
+    var sourceFilename = 
Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857.tif")
+        .toAbsolutePath().toString();
+    var hillshadeFilename =
+        
Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857-hillshade.tif").toAbsolutePath()
+            .toString();
+    var outputFilename = 
Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857.shp")
+        .toAbsolutePath().toString();
+    var warpFilename = 
Paths.get("examples/contour/liecthenstein-aster-dem-v2-3857-warp.tif")
+        .toAbsolutePath().toString();
 
     var dem = Paths.get("examples/contour/dem.xml")
         .toAbsolutePath().toString();
@@ -44,10 +44,10 @@ public class Main {
 
     planetContour();
 
-   hillshade(sourceFilename, 1, hillshadeFilename, 45d, 315d);
-   contourEx(hillshadeFilename, 1, outputFilename, 50, 0);
-   warp(sourceFilename, warpFilename);
-   shadow(hillshadeFilename, outputFilename);
+    hillshade(sourceFilename, 1, hillshadeFilename, 45d, 315d);
+    contourEx(hillshadeFilename, 1, outputFilename, 50, 0);
+    warp(sourceFilename, warpFilename);
+    shadow(hillshadeFilename, outputFilename);
   }
 
   public static void planetContour() {
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/Feature.java 
b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/Feature.java
index 3fc3c587..7bd1d67a 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/Feature.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/Feature.java
@@ -26,7 +26,7 @@ import org.locationtech.jts.geom.Geometry;
  */
 public class Feature {
 
-  private long id;
+  private Long id;
 
   private Map<String, Object> tags;
 
@@ -44,7 +44,7 @@ public class Feature {
    * @param tags The tags of the feature.
    * @param geometry The geometry of the feature.
    */
-  public Feature(long id, Map<String, Object> tags, Geometry geometry) {
+  public Feature(Long id, Map<String, Object> tags, Geometry geometry) {
     this.id = id;
     this.tags = tags;
     this.geometry = geometry;
@@ -55,7 +55,7 @@ public class Feature {
    *
    * @return The id of the feature.
    */
-  public long getId() {
+  public Long getId() {
     return id;
   }
 
@@ -64,7 +64,7 @@ public class Feature {
    *
    * @param id The id of the feature.
    */
-  public void setId(long id) {
+  public void setId(Long id) {
     this.id = id;
   }
 
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileEncoder.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileEncoder.java
index a7c04910..0a679303 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileEncoder.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileEncoder.java
@@ -125,9 +125,10 @@ public class VectorTileEncoder {
     cy = 0;
 
     VectorTile.Tile.Feature.Builder builder = 
VectorTile.Tile.Feature.newBuilder();
-    builder.setId(feature.getId());
+    if (feature.getId() != null) {
+      builder.setId(feature.getId());
+    }
     builder.setType(encodeGeometryType(feature.getGeometry()));
-
     encodeTag(feature.getTags(), builder::addTags);
     encodeGeometry(feature.getGeometry(), builder::addGeometry);
 
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileFunctions.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileFunctions.java
index 31888d83..59a45654 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileFunctions.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/vectortile/VectorTileFunctions.java
@@ -45,14 +45,13 @@ public class VectorTileFunctions {
    * @param clipGeom A flag to clip the geometry
    * @return The transformed geometry
    */
-  public static Geometry asVectorTileGeom(Geometry geometry, Geometry 
envelope, int extent,
+  public static Geometry asVectorTileGeom(Geometry geometry, Envelope 
envelope, int extent,
       int buffer, boolean clipGeom) {
     // Scale the geometry to the extent of the tile
-    var envelopeInternal = envelope.getEnvelopeInternal();
-    double scaleX = extent / envelopeInternal.getWidth();
-    double scaleY = extent / envelopeInternal.getHeight();
+    double scaleX = extent / envelope.getWidth();
+    double scaleY = extent / envelope.getHeight();
     AffineTransformation affineTransformation = new AffineTransformation();
-    affineTransformation.translate(-envelopeInternal.getMinX(), 
-envelopeInternal.getMinY());
+    affineTransformation.translate(-envelope.getMinX(), -envelope.getMinY());
     affineTransformation.scale(scaleX, -scaleY);
     affineTransformation.translate(0, extent);
     Geometry scaledGeometry = affineTransformation.transform(geometry);
@@ -94,11 +93,16 @@ public class VectorTileFunctions {
    * @return The transformed tile
    */
   public static ByteBuffer asVectorTile(Tile vectorTile) {
-    return new VectorTileEncoder()
-        .encodeTile(vectorTile)
-        .toByteString()
-        .asReadOnlyByteBuffer();
-
+    ByteBuffer original = new VectorTileEncoder()
+            .encodeTile(vectorTile)
+            .toByteString()
+            .asReadOnlyByteBuffer();
+    ByteBuffer clone = ByteBuffer.allocate(original.capacity());
+    original.rewind();// copy from the beginning
+    clone.put(original);
+    original.rewind();
+    clone.flip();
+    return clone;
   }
 
   /**
@@ -108,10 +112,18 @@ public class VectorTileFunctions {
    * @return The transformed layer
    */
   public static ByteBuffer asVectorTileLayer(Layer layer) {
-    return new VectorTileEncoder()
+    ByteBuffer original = new VectorTileEncoder()
         .encodeLayer(layer)
         .toByteString()
         .asReadOnlyByteBuffer();
+
+    ByteBuffer clone = ByteBuffer.allocate(original.capacity());
+    original.rewind();// copy from the beginning
+    clone.put(original);
+    original.rewind();
+    clone.flip();
+
+    return clone;
   }
 
   /**
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileFunctionsTest.java
 
b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileFunctionsTest.java
index afeb8b89..181d493a 100644
--- 
a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileFunctionsTest.java
+++ 
b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileFunctionsTest.java
@@ -45,7 +45,7 @@ class VectorTileFunctionsTest {
 
     // Transform the input geometry into a vector tile geometry
     var outputGeom =
-        VectorTileFunctions.asVectorTileGeom(inputGeom, envelope, extent, 
buffer, clipGeom);
+        VectorTileFunctions.asVectorTileGeom(inputGeom, 
envelope.getEnvelopeInternal(), extent, buffer, clipGeom);
 
     // Check if the output geometry is not null
     assertNotNull(outputGeom);
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileTest.java
 
b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileTest.java
index bc8fbfa9..2f2394a9 100644
--- 
a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileTest.java
+++ 
b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileTest.java
@@ -41,9 +41,9 @@ public class VectorTileTest {
   public void endToEnd() {
     var tile = new Tile(List.of(
         new Layer("layer", 256, List.of(
-            new Feature(1, Map.of("a", 1.0, "b", "2"),
+            new Feature(1l, Map.of("a", 1.0, "b", "2"),
                 GEOMETRY_FACTORY.createPoint(new Coordinate(1, 2))),
-            new Feature(2, Map.of("c", 3.0, "d", "4"),
+            new Feature(2l, Map.of("c", 3.0, "d", "4"),
                 GEOMETRY_FACTORY.createPoint(new Coordinate(2, 3)))))));
 
     var encoded = new VectorTileEncoder().encodeTile(tile);
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileViewer.java
 
b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileViewer.java
index faada968..a4f75369 100644
--- 
a/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileViewer.java
+++ 
b/baremaps-core/src/test/java/org/apache/baremaps/vectortile/VectorTileViewer.java
@@ -19,10 +19,8 @@ package org.apache.baremaps.vectortile;
 
 import java.awt.*;
 import java.awt.Dimension;
+import java.net.URL;
 import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.zip.GZIPInputStream;
 import javax.swing.*;
 import org.locationtech.jts.geom.*;
 import org.locationtech.jts.geom.Point;
@@ -34,10 +32,14 @@ import org.locationtech.jts.geom.Polygon;
 public class VectorTileViewer {
 
   public static void main(String... args) throws Exception {
-    String arg =
-        args.length > 0 ? args[0] : 
"baremaps-core/src/test/resources/vectortile/14-8493-5795.mvt";
-    var path = Path.of(arg);
-    try (var input = new GZIPInputStream(Files.newInputStream(path))) {
+    // String arg =
+    // args.length > 0 ? args[0] : 
"baremaps-core/src/test/resources/vectortile/14-8493-5795.mvt";
+    // var path = Path.of(arg);
+    // try (var input = new GZIPInputStream(Files.newInputStream(path))) {
+
+    var url = new URL("http://localhost:9000/tiles/14/8628/5750.mvt";);
+
+    try (var input = url.openStream()) {
       var buffer = ByteBuffer.wrap(input.readAllBytes());
       var parsed = 
org.apache.baremaps.mvt.binary.VectorTile.Tile.parseFrom(buffer);
       var tile = new VectorTileDecoder().decodeTile(parsed);
diff --git 
a/baremaps-server/src/main/java/org/apache/baremaps/server/ServerResources.java 
b/baremaps-server/src/main/java/org/apache/baremaps/server/ServerResources.java
new file mode 100644
index 00000000..781dbf68
--- /dev/null
+++ 
b/baremaps-server/src/main/java/org/apache/baremaps/server/ServerResources.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.server;
+
+import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
+import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.file.Path;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.ws.rs.GET;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.baremaps.config.ConfigReader;
+import org.apache.baremaps.tilestore.TileCoord;
+import org.apache.baremaps.tilestore.TileStore;
+import org.apache.baremaps.tilestore.TileStoreException;
+import org.apache.baremaps.vectortile.style.Style;
+import org.apache.baremaps.vectortile.tileset.Tileset;
+import org.apache.baremaps.vectortile.tileset.TilesetLayer;
+
+@Singleton
[email protected]("/")
+public class ServerResources {
+
+  private final Style style;
+
+  private final Tileset tileset;
+
+  private final TileStore tileStore;
+
+  public static final String TILE_ENCODING = "gzip";
+
+  public static final String TILE_TYPE = "application/vnd.mapbox-vector-tile";
+
+  @Inject
+  public ServerResources(@Named("tileset") Path tileset, @Named("style") Path 
style,
+      TileStore tileStore, ObjectMapper objectMapper) throws IOException {
+    this.tileStore = tileStore;
+    var configReader = new ConfigReader();
+    this.style = objectMapper.readValue(configReader.read(style), Style.class);
+    this.tileset = objectMapper.readValue(configReader.read(tileset), 
Tileset.class);
+
+    // Hide the SQL queries in production
+    for (TilesetLayer layer : this.tileset.getVectorLayers()) {
+      layer.setQueries(null);
+    }
+  }
+
+  @GET
+  @javax.ws.rs.Path("style.json")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Style getStyle() {
+    return style;
+  }
+
+  @GET
+  @javax.ws.rs.Path("tiles.json")
+  @Produces(MediaType.APPLICATION_JSON)
+  public Tileset getTileset() {
+    return tileset;
+  }
+
+  @GET
+  @javax.ws.rs.Path("/tiles/{z}/{x}/{y}.mvt")
+  public Response getTile(@PathParam("z") int z, @PathParam("x") int x, 
@PathParam("y") int y) {
+    TileCoord tileCoord = new TileCoord(x, y, z);
+    try {
+      ByteBuffer blob = tileStore.read(tileCoord);
+      if (blob != null) {
+        var array = blob.array();
+        return Response.status(200) // lgtm [java/xss]
+            .header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
+            .header(CONTENT_TYPE, TILE_TYPE)
+            // .header(CONTENT_ENCODING, TILE_ENCODING)
+            .entity(array).build();
+      } else {
+        return Response.status(204).build();
+      }
+    } catch (TileStoreException ex) {
+      return Response.status(404).build();
+    }
+  }
+
+  @GET
+  @javax.ws.rs.Path("{path:.*}")
+  public Response get(@PathParam("path") String path) throws IOException {
+    if (path.equals("") || path.endsWith("/")) {
+      path += "server.html";
+    }
+    path = String.format("assets/%s", path);
+    try (InputStream inputStream = 
getClass().getClassLoader().getResourceAsStream(path)) {
+      var bytes = inputStream.readAllBytes();
+      return Response.ok().entity(bytes).build();
+    } catch (NullPointerException | IOException e) {
+      return Response.status(404).build();
+    }
+  }
+}
diff --git a/examples/contour/style.json b/examples/contour/style.json
index 16047415..bb982ecc 100644
--- a/examples/contour/style.json
+++ b/examples/contour/style.json
@@ -14,10 +14,10 @@
       "background-color" : "rgba(255, 255, 255, 1)"
     }
   }, {
-    "id" : "aster_dem",
+    "id" : "contours",
     "type" : "line",
     "source" : "baremaps",
-    "source-layer" : "aster_dem",
+    "source-layer" : "contours",
     "layout" : {
       "line-cap" : "round",
       "line-join" : "round"
diff --git a/examples/contour/tileset.json b/examples/contour/tileset.json
index 74307e7b..2d729bdb 100644
--- a/examples/contour/tileset.json
+++ b/examples/contour/tileset.json
@@ -5,24 +5,17 @@
     47.166,
     14.0
   ],
-  "bounds": [
-    9.471078,
-    47.04774,
-    9.636217,
-    47.27128
-  ],
   "tiles": [
     "http://localhost:9000/tiles/{z}/{x}/{y}.mvt";
   ],
   "database": 
"jdbc:postgresql://localhost:5432/baremaps?&user=baremaps&password=baremaps",
   "vector_layers": [
     {
-      "id": "aster_dem",
+      "id": "contours",
       "queries": [
         {
           "minzoom": 0,
-          "maxzoom": 20,
-          "sql": "SELECT ogc_fid, jsonb_build_object('elevation', 
elevation::text), wkb_geometry FROM aster_dem"
+          "maxzoom": 20
         }
       ]
     }

Reply via email to