CMSgov/dpc-app

View on GitHub
dpc-api/src/main/java/gov/cms/dpc/api/DPCAPIModule.java

Summary

Maintainability
A
0 mins
Test Coverage
A
96%
package gov.cms.dpc.api;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import com.codahale.metrics.MetricRegistry;
import com.google.inject.Binder;
import com.google.inject.Provides;
import com.google.inject.name.Named;
import gov.cms.dpc.api.auth.jwt.IJTICache;
import gov.cms.dpc.api.converters.ChecksumConverterProvider;
import gov.cms.dpc.api.converters.HttpRangeHeaderParamConverterProvider;
import gov.cms.dpc.api.core.FileManager;
import gov.cms.dpc.api.jdbi.IpAddressDAO;
import gov.cms.dpc.api.jdbi.PublicKeyDAO;
import gov.cms.dpc.api.jdbi.TokenDAO;
import gov.cms.dpc.api.resources.v1.*;
import gov.cms.dpc.api.tasks.GenerateKeyPair;
import gov.cms.dpc.api.tasks.keys.DeletePublicKey;
import gov.cms.dpc.api.tasks.keys.ListPublicKeys;
import gov.cms.dpc.api.tasks.keys.UploadPublicKey;
import gov.cms.dpc.api.tasks.tokens.DeleteToken;
import gov.cms.dpc.api.tasks.tokens.GenerateClientTokens;
import gov.cms.dpc.api.tasks.tokens.ListClientTokens;
import gov.cms.dpc.common.annotations.APIV1;
import gov.cms.dpc.common.annotations.ExportPath;
import gov.cms.dpc.common.annotations.JobTimeout;
import gov.cms.dpc.common.annotations.ServiceBaseURL;
import gov.cms.dpc.common.hibernate.auth.DPCAuthHibernateBundle;
import gov.cms.dpc.common.hibernate.auth.DPCAuthManagedSessionFactory;
import gov.cms.dpc.macaroons.MacaroonBakery;
import gov.cms.dpc.macaroons.annotations.PublicURL;
import gov.cms.dpc.macaroons.config.TokenPolicy;
import gov.cms.dpc.macaroons.thirdparty.IThirdPartyKeyStore;
import gov.cms.dpc.macaroons.thirdparty.MemoryThirdPartyKeyStore;
import gov.cms.dpc.queue.service.DataService;
import io.dropwizard.hibernate.UnitOfWorkAwareProxyFactory;
import io.jsonwebtoken.SigningKeyResolverAdapter;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.vyarus.dropwizard.guice.module.support.DropwizardAwareModule;

import javax.inject.Singleton;

public class DPCAPIModule extends DropwizardAwareModule<DPCAPIConfiguration> {

    private static final Logger logger = LoggerFactory.getLogger(DPCAPIModule.class);

    private final DPCAuthHibernateBundle<DPCAPIConfiguration> authHibernateBundle;

    DPCAPIModule(DPCAuthHibernateBundle<DPCAPIConfiguration> authHibernateBundle) {
        this.authHibernateBundle = authHibernateBundle;
    }

    @Override
    public void configure() {
        Binder binder = binder();
        // V1 Resources
        binder.bind(BaseResource.class);
        binder.bind(DataResource.class);
        binder.bind(DefinitionResource.class);
        binder.bind(EndpointResource.class);
        binder.bind(GroupResource.class);
        binder.bind(JobResource.class);
        binder.bind(PatientResource.class);
        binder.bind(PractitionerResource.class);

        // DAO
        binder.bind(PublicKeyDAO.class);
        binder.bind(TokenDAO.class);
        binder.bind(IpAddressDAO.class);

        // Tasks
        binder.bind(GenerateClientTokens.class);
        binder.bind(GenerateKeyPair.class);
        binder.bind(ListClientTokens.class);
        binder.bind(DeleteToken.class);
        binder.bind(UploadPublicKey.class);
        binder.bind(ListPublicKeys.class);
        binder.bind(DeletePublicKey.class);

        binder.bind(FileManager.class);
        binder.bind(HttpRangeHeaderParamConverterProvider.class);
        binder.bind(ChecksumConverterProvider.class);

        binder.bind(DataService.class);

        // Healthchecks
        // Additional health-checks can be added here
        // By default, Dropwizard adds a check for Hibernate and each additional database (e.g. auth, queue, etc)
        // We also get the JobQueueStatus by default, even though it always return healthy
    }

    // Since the KeyResource requires access to the Auth DB, we have to manually do the creation and resource injection,
    // in order to ensure that the @UnitOfWork annotations are tied to the correct SessionFactory
    @Provides
    public KeyResource provideKeyResource(PublicKeyDAO dao) {
        return new UnitOfWorkAwareProxyFactory(authHibernateBundle)
                .create(KeyResource.class, new Class<?>[]{PublicKeyDAO.class}, new Object[]{dao});
    }

    @Provides
    public TokenResource provideTokenResource(TokenDAO dao, MacaroonBakery bakery, SigningKeyResolverAdapter resolver, IJTICache cache, @APIV1 String publicURL) {
        return new UnitOfWorkAwareProxyFactory(authHibernateBundle)
                .create(TokenResource.class,
                        new Class<?>[]{TokenDAO.class,
                                MacaroonBakery.class,
                                TokenPolicy.class,
                                SigningKeyResolverAdapter.class,
                                IJTICache.class,
                                String.class},
                        new Object[]{dao,
                                bakery,
                                this.configuration().getTokenPolicy(),
                                resolver,
                                cache, publicURL});
    }

    @Provides
    public IpAddressResource provideIpAddressResource(IpAddressDAO dao) {
        return new UnitOfWorkAwareProxyFactory(authHibernateBundle)
            .create(IpAddressResource.class, new Class<?>[]{IpAddressDAO.class}, new Object[]{dao});
    }

    @Provides
    public OrganizationResource provideOrganizationResource(@Named("attribution") IGenericClient client, TokenDAO tokenDAO, PublicKeyDAO keyDAO) {
        return new UnitOfWorkAwareProxyFactory(authHibernateBundle)
                .create(OrganizationResource.class,
                        new Class<?>[]{IGenericClient.class,
                        TokenDAO.class,
                        PublicKeyDAO.class},
                        new Object[]{client, tokenDAO, keyDAO});
    }

    @Provides
    @Singleton
    public MetricRegistry provideMetricRegistry() {
        return environment().metrics();
    }

    @Provides
    @ExportPath
    public String provideExportPath() {
        return configuration().getExportPath();
    }

    @Provides
    @ServiceBaseURL
    public String provideBaseURL() {
        return configuration().getPublicURL();
    }

    @Provides
    @APIV1
    public String provideV1URL() {
        return configuration().getPublicURL() + "/v1";
    }

    @Provides
    @PublicURL
    public String providePublicURL(@ServiceBaseURL String baseURL) {
        return baseURL;
    }

    @Provides
    @Singleton
    IThirdPartyKeyStore thirdPartyKeyStore() {
        return new MemoryThirdPartyKeyStore();
    }

    @Provides
    TokenPolicy providePolicy() {
        return configuration().getTokenPolicy();
    }

    @Provides
    // We can suppress this because the SessionFactory is managed
    @SuppressWarnings("CloseableProvides")
    SessionFactory provideSessionFactory(DPCAuthManagedSessionFactory factory) {
        return factory.getSessionFactory();
    }

    @Provides
    @Singleton
    @Named("attribution")
    public IGenericClient provideFHIRClient(FhirContext ctx) {
        String attributionUrl = configuration().getAttributionURL();
        logger.info("Connecting to attribution server at {}.", attributionUrl);
        ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
        IGenericClient client = ctx.newRestfulGenericClient(attributionUrl);
        client.registerInterceptor(new RequestIdHeaderInterceptor());
        return client;
    }

    @Provides
    @JobTimeout
    public int provideJobTimeoutInSeconds() {
        return configuration().getJobTimeoutInSeconds();
    }
}