blob: b791c03ee7540b02c3d2e39d2843aeeb6677685c [file] [log] [blame]
/*
* 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 com.github.benmanes.caffeine.cache.CaffeineSpec;
import io.servicetalk.http.netty.HttpServers;
import io.servicetalk.http.router.jersey.HttpJerseyRouterBuilder;
import java.nio.file.Path;
import java.util.concurrent.Callable;
import javax.sql.DataSource;
import org.apache.baremaps.cli.Options;
import org.apache.baremaps.database.PostgresUtils;
import org.apache.baremaps.database.tile.PostgresTileStore;
import org.apache.baremaps.database.tile.TileCache;
import org.apache.baremaps.database.tile.TileStore;
import org.apache.baremaps.mvt.tileset.Tileset;
import org.apache.baremaps.server.ConfigReader;
import org.apache.baremaps.server.CorsFilter;
import org.apache.baremaps.server.SearchResources;
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.Mixin;
import picocli.CommandLine.Option;
@Command(name = "serve", description = "Start a tile server with caching capabilities.")
public class Serve implements Callable<Integer> {
private static final Logger logger = LoggerFactory.getLogger(Serve.class);
@Mixin
private Options options;
@Option(names = {"--database"}, paramLabel = "DATABASE",
description = "The JDBC url of Postgres.", required = true)
private String database;
@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 configReader = new ConfigReader();
var tileset = objectMapper.readValue(configReader.read(this.tileset), Tileset.class);
var caffeineSpec = CaffeineSpec.parse(cache);
var datasource = PostgresUtils.dataSource(database);
var tileStore = new PostgresTileStore(datasource, tileset);
var tileCache = new TileCache(tileStore, caffeineSpec);
// Configure the application
var application =
new ResourceConfig()
.register(CorsFilter.class)
.register(SearchResources.class)
.register(ServerResources.class)
.register(contextResolverFor(objectMapper))
.register(new AbstractBinder() {
@Override
protected void configure() {
bind(Serve.this.tileset).to(Path.class).named("tileset");
bind(style).to(Path.class).named("style");
bind(tileCache).to(TileStore.class);
bind(datasource).to(DataSource.class);
bind(objectMapper).to(ObjectMapper.class);
}
});
var httpService = new HttpJerseyRouterBuilder().buildBlockingStreaming(application);
var serverContext = HttpServers.forPort(port).listenBlockingStreamingAndAwait(httpService);
logger.info("Listening on {}", serverContext.listenAddress());
serverContext.awaitShutdown();
return 0;
}
}