diff --git a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java index d1b4e78ef..522f2678e 100644 --- a/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java +++ b/baremaps-cli/src/main/java/org/apache/baremaps/cli/tdtiles/Serve.java @@ -19,16 +19,19 @@ -import io.servicetalk.http.netty.HttpServers; -import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder; +import static org.apache.baremaps.utils.ObjectMapperUtils.objectMapper; + +import com.linecorp.armeria.common.HttpHeaderNames; +import com.linecorp.armeria.common.HttpMethod; +import com.linecorp.armeria.server.Server; +import com.linecorp.armeria.server.annotation.JacksonResponseConverterFunction; +import com.linecorp.armeria.server.cors.CorsService; +import com.linecorp.armeria.server.file.FileService; +import com.linecorp.armeria.server.file.HttpFile; import java.util.concurrent.Callable; -import javax.sql.DataSource; import org.apache.baremaps.cli.Options; -import org.apache.baremaps.server.CorsFilter; import org.apache.baremaps.server.TdTilesResources; import org.apache.baremaps.utils.PostgresUtils; -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; @@ -55,24 +58,39 @@ public class Serve implements Callable { @Override public Integer call() throws Exception { + var objectMapper = objectMapper(); var datasource = PostgresUtils.createDataSource(database); - // Configure the application - var application = - new ResourceConfig().register(CorsFilter.class).register(TdTilesResources.class) - .register(new AbstractBinder() { - @Override - protected void configure() { - bind(datasource).to(DataSource.class); - } - }); + var serverBuilder = Server.builder(); + serverBuilder.http(port); + + var jsonResponseConverter = new JacksonResponseConverterFunction(objectMapper); + serverBuilder.annotatedService(new TdTilesResources(datasource), jsonResponseConverter); + + var index = HttpFile.of(ClassLoader.getSystemClassLoader(), "/tdtiles/index.html"); + serverBuilder.service("/", index.asService()); + serverBuilder.serviceUnder("/", FileService.of(ClassLoader.getSystemClassLoader(), "/tdtiles")); + + serverBuilder.decorator(CorsService.builderForAnyOrigin() + .allowRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE, + HttpMethod.OPTIONS, HttpMethod.HEAD) + .allowRequestHeaders(HttpHeaderNames.ORIGIN, HttpHeaderNames.CONTENT_TYPE, + HttpHeaderNames.ACCEPT, HttpHeaderNames.AUTHORIZATION) + .allowCredentials() + .exposeHeaders(HttpHeaderNames.LOCATION) + .newDecorator()); + + serverBuilder.disableServerHeader(); + serverBuilder.disableDateHeader(); + + var server = serverBuilder.build(); - var httpService = new HttpJerseyRouterBuilder().buildBlockingStreaming(application); - var serverContext = HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService); + var startFuture = server.start(); + startFuture.join(); - logger.info("Listening on {}", serverContext.listenAddress()); + var shutdownFuture = server.closeOnJvmShutdown(); + shutdownFuture.join(); - serverContext.awaitShutdown(); return 0; } } diff --git a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java index 8a60b8057..c67403d11 100644 --- a/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java +++ b/baremaps-server/src/main/java/org/apache/baremaps/server/TdTilesResources.java @@ -18,56 +18,58 @@ package org.apache.baremaps.server; import static com.google.common.net.HttpHeaders.*; +import static io.netty.handler.codec.http.HttpHeaders.Values.APPLICATION_JSON; +import static io.netty.handler.codec.http.HttpHeaders.Values.BINARY; +import com.linecorp.armeria.common.HttpData; +import com.linecorp.armeria.common.HttpResponse; +import com.linecorp.armeria.common.ResponseHeaders; +import com.linecorp.armeria.server.annotation.Get; +import com.linecorp.armeria.server.annotation.Param; import de.javagl.jgltf.model.NodeModel; -import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import javax.inject.Singleton; import javax.sql.DataSource; -import javax.ws.rs.GET; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; + import org.apache.baremaps.tdtiles.GltfBuilder; import org.apache.baremaps.tdtiles.TdTilesStore; import org.apache.baremaps.tdtiles.building.Building; import org.apache.baremaps.tdtiles.subtree.Availability; import org.apache.baremaps.tdtiles.subtree.Subtree; -@Singleton -@javax.ws.rs.Path("/") public class TdTilesResources { + + private static final ResponseHeaders GLB_HEADERS = ResponseHeaders.builder(200) + .add(CONTENT_TYPE, BINARY) + .add(ACCESS_CONTROL_ALLOW_ORIGIN, "*") + .build(); + + private static final ResponseHeaders JSON_HEADERS = ResponseHeaders.builder(200) + .add(CONTENT_TYPE, APPLICATION_JSON) + .add(ACCESS_CONTROL_ALLOW_ORIGIN, "*") + .build(); + private final TdTilesStore tdTilesStore; - @Inject public TdTilesResources(DataSource dataSource) { this.tdTilesStore = new TdTilesStore(dataSource); } - @GET - @javax.ws.rs.Path("/subtrees/{level}.{x}.{y}.json") - public Response getSubtree(@PathParam("level") int level, @PathParam("x") int x, - @PathParam("y") int y) { + @Get("regex:^/subtrees/(?[0-9]+).(?[0-9]+).(?[0-9]+).json") + public HttpResponse getSubtree(@Param("level") int level, @Param("x") int x, @Param("y") int y) { if (level == 18) { - return Response.ok() - .entity( - new Subtree(new Availability(false), new Availability(true), new Availability(false))) - .header(CONTENT_TYPE, "application/json").build(); + return HttpResponse.ofJson(JSON_HEADERS, + new Subtree(new Availability(false), new Availability(true), new Availability(false))); } - return Response.ok() - .entity(new Subtree(new Availability(true), new Availability(true), new Availability(true))) - .header(CONTENT_TYPE, "application/json").build(); + return HttpResponse.ofJson(JSON_HEADERS, + new Subtree(new Availability(true), new Availability(true), new Availability(true))); } - @GET - @javax.ws.rs.Path("/content/content_{level}__{x}_{y}.glb") - public Response getContent(@PathParam("level") int level, @PathParam("x") int x, - @PathParam("y") int y) throws Exception { + @Get("regex:^/content/content_(?[0-9]+)__(?[0-9]+)_(?[0-9]+).glb") + public HttpResponse getContent(@Param("level") int level, @Param("x") int x, @Param("y") int y) + throws Exception { if (level < 14) { - return Response.ok().entity( - GltfBuilder.createGltf(new ArrayList<>())).build(); + return HttpResponse.of(GLB_HEADERS, HttpData.wrap(GltfBuilder.createGltf(new ArrayList<>()))); } float[] coords = xyzToLatLonRadians(x, y, level); List nodes = new ArrayList<>(); @@ -77,23 +79,7 @@ public Response getContent(@PathParam("level") int level, @PathParam("x") int x, float tolerance = level > 17 ? 0.00001f : level > 15 ? 0.00002f : 0.00004f; nodes.add(GltfBuilder.createNode(building, tolerance)); } - return Response.ok().entity( - GltfBuilder.createGltf(nodes)).build(); - } - - @GET - @javax.ws.rs.Path("/{path:.*}") - public Response get(@PathParam("path") String path) { - if (path.equals("") || path.endsWith("/")) { - path += "index.html"; - } - path = String.format("tdtiles/%s", path); - try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) { - var bytes = inputStream.readAllBytes(); - return Response.ok().entity(bytes).build(); - } catch (IOException e) { - return Response.status(404).build(); - } + return HttpResponse.of(GLB_HEADERS, HttpData.wrap(GltfBuilder.createGltf(nodes))); } /** diff --git a/pom.xml b/pom.xml index 49ff9e30a..5c528afb0 100644 --- a/pom.xml +++ b/pom.xml @@ -93,6 +93,7 @@ limitations under the License. 5.0.1 1.52 2.16.1 + 2.0.3 1.35 1.19.0 5.10.0