
org.opentripplanner.standalone.server.OTPWebApplication Maven / Gradle / Ivy
package org.opentripplanner.standalone.server;
import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.binder.jersey.server.DefaultJerseyTagsProvider;
import io.micrometer.core.instrument.binder.jersey.server.MetricsApplicationEventListener;
import io.micrometer.prometheusmetrics.PrometheusConfig;
import io.micrometer.prometheusmetrics.PrometheusMeterRegistry;
import jakarta.ws.rs.container.ContainerResponseFilter;
import jakarta.ws.rs.core.Application;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.internal.inject.Binder;
import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJsonProvider;
import org.opentripplanner.api.common.OTPExceptionMapper;
import org.opentripplanner.apis.APIEndpoints;
import org.opentripplanner.ext.restapi.serialization.JSONObjectMapperProvider;
import org.opentripplanner.framework.application.OTPFeature;
import org.opentripplanner.standalone.api.OtpServerRequestContext;
import org.slf4j.bridge.SLF4JBridgeHandler;
/**
* A JAX-RS Application subclass which provides hard-wired configuration of an OTP server. Avoids
* auto-scanning of any kind, and keeps injection to a bare minimum using HK2, the injection library
* Jersey itself uses.
*
* Jersey has its own ResourceConfig class which is a subclass of Application. We can get away with
* not using any Jersey-specific "conveniences" and stick with stock JAX-RS.
*/
public class OTPWebApplication extends Application {
/* This object groups together all the modules for a single running OTP server. */
private final Supplier contextProvider;
private final List> customFilters;
static {
// Remove existing handlers attached to the j.u.l root logger
SLF4JBridgeHandler.removeHandlersForRootLogger();
// Bridge j.u.l (used by Jersey) to the SLF4J root logger, so all logging goes through the same
// API
SLF4JBridgeHandler.install();
}
public OTPWebApplication(
OTPWebApplicationParameters parameters,
Supplier contextProvider
) {
this.contextProvider = contextProvider;
this.customFilters = createCustomFilters(parameters.traceParameters());
}
/**
* This method registers classes with Jersey to define web resources and enable custom features.
* These are classes (not instances) that will be instantiated by Jersey for each request (they
* are request-scoped). Types that have been confirmed to work are: annotated resources, {@code
* ContextResolver} implementation, ContainerResponseFilter and
* ContainerRequestFilter. Note that the listed classes do not need to be annotated with @Provider
* -- that is for scanning config.
*/
@Override
public Set> getClasses() {
// Add API Endpoints defined in the api package
Set> classes = new HashSet<>(APIEndpoints.listAPIEndpoints());
classes.addAll(resolveFilterClasses());
return classes;
}
/**
* Features and Filters: extend Jersey, manipulate requests and responses.
*/
private Set> resolveFilterClasses() {
var set = new HashSet>();
set.addAll(customFilters);
set.add(CorsFilter.class);
set.add(EtagRequestFilter.class);
set.add(VaryRequestFilter.class);
return set;
}
/**
* Like getClasses, this method declares web resources, providers, and features to the JAX-RS
* implementation. However, these are single instances that will be reused for all requests (they
* are singleton-scoped).
*
* See https://jersey.java.net/apidocs/latest/jersey/javax/ws/rs/core/Application.html#getSingletons()
* Leave {@code