package org.bitionaire.elbombillo.account;
import io.dropwizard.Application;
import io.dropwizard.auth.AuthFactory;
import io.dropwizard.auth.basic.BasicAuthFactory;
import io.dropwizard.client.JerseyClientBuilder;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.jdbi.DBIFactory;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.federecio.dropwizard.swagger.SwaggerBundle;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.bitionaire.elbombillo.account.core.auth.AccountServiceAuthenticator;
import org.bitionaire.elbombillo.account.core.auth.AccountServiceCaller;
import org.bitionaire.elbombillo.account.core.registry.AccountServiceLifecycleListener;
import org.bitionaire.elbombillo.account.health.ServiceRegistryHealthCheck;
import org.bitionaire.elbombillo.account.persistence.dao.AccountDAO;
import org.bitionaire.elbombillo.account.resources.AccountResource;
import org.bitionaire.elbombillo.account.tasks.ServiceRegistryTask;
import org.flywaydb.core.Flyway;
import org.glassfish.jersey.linking.DeclarativeLinkingFeature;
import org.skife.jdbi.v2.DBI;
import javax.ws.rs.client.Client;
/**
* This application provides RESTful interfaces to manage user accounts.
* <p />
* All initialization steps are documented within the {@link #run(AccountServiceConfiguration, Environment)} method.
*/
@Slf4j
public class AccountServiceApplication extends Application<AccountServiceConfiguration> {
/**
* Main entry point.
* <p />
* The configuration for this application is represented by an instance of {@link AccountServiceConfiguration} and should
* be provided as a command line argument.
*
* @param args the command line arguments
* @throws Exception throw on any occurring exception within a call of {@link #run(AccountServiceConfiguration, Environment)}
*/
public static void main(final String... args) throws Exception {
new AccountServiceApplication().run(args);
}
@Override
public void initialize(final Bootstrap<AccountServiceConfiguration> bootstrap) {
bootstrap.addBundle(new SwaggerBundle<AccountServiceConfiguration>() {
@Override
protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(final AccountServiceConfiguration configuration) {
return configuration.getSwaggerBundleConfiguration();
}
});
}
@Override
public void run(final AccountServiceConfiguration configuration, final Environment environment) throws Exception {
final DataSourceFactory database = configuration.getDatabase();
this.executeDatabaseMigrations(database);
// create DBI instance
final DBIFactory factory = new DBIFactory();
final DBI jdbi = factory.build(environment, database, "postgresql");
// create a HTTP client
final Client client = new JerseyClientBuilder(environment).using(configuration.getHttpClient()).build("httpClient");
// setup listener which will register this service within the service registry
final AccountServiceLifecycleListener accountServiceLifecycleListener = new AccountServiceLifecycleListener(configuration.getServiceInformation(), configuration.getRegistryService(), client);
environment.lifecycle().addServerLifecycleListener(accountServiceLifecycleListener);
environment.healthChecks().register("registry", new ServiceRegistryHealthCheck(accountServiceLifecycleListener));
environment.admin().addTask(new ServiceRegistryTask(accountServiceLifecycleListener));
// enable the linking feature of jersey
environment.jersey().getResourceConfig().packages(getClass().getPackage().getName()).register(DeclarativeLinkingFeature.class);
// register authenticator
environment.jersey().register(AuthFactory.binder(new BasicAuthFactory<>(
new AccountServiceAuthenticator(configuration.getServiceInformation()), "Realm", AccountServiceCaller.class))
);
// register REST resources
environment.jersey().register(new AccountResource(jdbi.onDemand(AccountDAO.class)));
}
/**
* All database migrations (e.g. creation of tables) will be executed on call of this method.
* <p />
* The migrations are located within the resources of this application in the directory {@code db/migration} and are
* ordered by a naming pattern.
* <p />
* You will find more information about the library that executes those migrations and the behaviour <a href="http://flywaydb.org/documentation/">here</a>.
*
* @param database the database on which all migrations will be applied
* @throws org.flywaydb.core.api.FlywayException if the migration fails
*/
private void executeDatabaseMigrations(final DataSourceFactory database) {
final Flyway flyway = new Flyway();
flyway.setDataSource(database.getUrl(), database.getUser(), database.getPassword());
log.debug("execute database migrations");
flyway.migrate();
log.info("database migrations successfully executed");
}
}