All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.standalone.OTPApplication Maven / Gradle / Ivy

package org.opentripplanner.standalone;

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.fasterxml.jackson.jaxrs.xml.JacksonXMLProvider;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import org.glassfish.jersey.CommonProperties;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import org.opentripplanner.api.common.OTPExceptionMapper;
import org.opentripplanner.api.model.JSONObjectMapperProvider;
import org.opentripplanner.api.resource.*;
import org.opentripplanner.index.GeocoderResource;
import org.opentripplanner.index.IndexAPI;
import org.slf4j.bridge.SLF4JBridgeHandler;

import javax.ws.rs.core.Application;

import java.util.Arrays;
import java.util.Map;
import java.util.Set;

/**
 * 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 OTPApplication extends Application {

    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();
    }

    /* This object groups together all the modules for a single running OTP server. */
    public final OTPServer server;

    /* If secure is true, OTP will require Basic authentication over HTTPS when accessing dangerous web services. */
    private final boolean secure;

    /**
     * The OTPServer provides entry points to OTP routing functionality for a collection of OTPRouters.
     * It provides a Java API, not an HTTP API.
     * The OTPApplication wraps an OTPServer in a Jersey (JAX-RS) Application, configuring an HTTP API.
     * @param server The OTP server to wrap
     * @param secure Should this server require authentication over HTTPS to access secure resources, e.g. /routers?
     */
    public OTPApplication (OTPServer server, boolean secure) {
        this.server = server;
        this.secure = secure;
    }

    /**
     * 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, 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() {
        Set> classes = Sets.newHashSet();
        classes.addAll(Arrays.asList(
            /* Jersey resource classes: define web services, i.e. an HTTP API. */
            PlannerResource.class,
            IndexAPI.class,
            ExternalGeocoderResource.class,
            GeocoderResource.class,
            SimpleIsochrone.class,
            TileService.class,
            BikeRental.class,
            LIsochrone.class,
            ExternalGeocoderResource.class,
            TimeGridWs.class,
            AlertPatcher.class,
            PlannerResource.class,
            SIsochrone.class,
            Routers.class,
            LegendResource.class,
            ProfileResource.class,
            SimpleIsochrone.class,
            ServerInfo.class,
            SurfaceResource.class,
            PointSetResource.class,
            GraphInspectorTileResource.class,
            ScriptResource.class,
            UpdaterStatusResource.class,
            ScenarioResource.class,
            RepeatedRaptorTestResource.class,
            /* Features and Filters: extend Jersey, manipulate requests and responses. */
            CorsFilter.class,
            MultiPartFeature.class
        ));
        
        if (this.secure) {
            // A filter that converts HTTP Basic authentication headers into a Jersey SecurityContext
            classes.add(AuthFilter.class);
            // Enforce roles annotations defined by JSR-250 (allow access to API methods based on the SecurityContext)
            classes.add(RolesAllowedDynamicFeature.class);
        }
        
        return classes;
    }

    /**
     * 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  out of method signature to avoid confusing the Guava type inference.
     */
    @Override
    public Set getSingletons() {
        return Sets.newHashSet (
            // Show exception messages in responses
            new OTPExceptionMapper(),
            // Enable Jackson JSON response serialization
            new JacksonJsonProvider(),
            // Enable Jackson XML response serialization
            new JacksonXMLProvider(),
            // Serialize POJOs (unannotated) JSON using Jackson
            new JSONObjectMapperProvider(),
            // Allow injecting the OTP server object into Jersey resource classes
            server.makeBinder()
        );
    }

    /**
     * Enabling tracing allows us to see how web resource names were matched from the client, in headers.
     * Disable auto-discovery of features because it's extremely obnoxious to debug and interacts
     * in confusing ways with manually registered features.
     */
    // @Override
    public Map getProperties() {
        Map props = Maps.newHashMap();
        props.put(ServerProperties.TRACING, Boolean.TRUE);
        props.put(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, Boolean.TRUE);
        return props;
    }

}