package kickr; import kickr.db.dao.AccessTokenDAO; import kickr.config.KickrConfiguration; import io.dropwizard.Application; import io.dropwizard.assets.AssetsBundle; import io.dropwizard.db.DataSourceFactory; import io.dropwizard.flyway.FlywayBundle; import io.dropwizard.flyway.FlywayFactory; import io.dropwizard.forms.MultiPartBundle; import io.dropwizard.hibernate.HibernateBundle; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import io.dropwizard.views.ViewBundle; import java.util.EnumSet; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.servlet.DispatcherType; import kickr.cli.AnalyzeCommand; import kickr.cli.SetupCommand; import kickr.web.NotAuthorizedErrorHandler; import kickr.web.api.UserResource; import kickr.web.api.MatchResource; import kickr.web.api.PlayerResource; import kickr.web.api.RootResource; import kickr.web.api.ScoreResource; import kickr.web.api.TableResource; import kickr.web.api.administration.AdminResource; import kickr.db.dao.FoosballTableDAO; import kickr.db.dao.GameDAO; import kickr.db.dao.MatchDAO; import kickr.db.dao.PlayerDAO; import kickr.db.dao.ScoreDAO; import kickr.db.dao.UserDAO; import kickr.db.entity.FoosballTable; import kickr.db.entity.Game; import kickr.db.entity.Match; import kickr.db.entity.Player; import kickr.db.entity.Score; import kickr.db.entity.ScoreChange; import kickr.db.entity.user.AccessToken; import kickr.db.entity.user.User; import kickr.search.ElasticSearch; import kickr.search.SearchIndexer; import kickr.security.UserSecurityContextFactory; import kickr.security.service.AuthenticationService; import kickr.security.service.CredentialsService; import kickr.service.MatchService; import kickr.service.RatingService; import kickr.web.CharsetResponseFilter; import kickr.web.ConstraintViolationExceptionHandler; import kickr.web.NotFoundErrorHandler; import org.eclipse.jetty.servlet.FilterHolder; import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature; import org.hibernate.SessionFactory; import support.form.FormDataReaderWriter; import support.transactional.WithTransaction; import support.security.SecurityContextFactory; import support.security.SecurityContextInitializer; import support.security.auth.AuthFactory; public class KickrApplication extends Application<KickrConfiguration> { private static final int ONE_SECOND = 1000; private static final int FIVETEEN_MINUTES = ONE_SECOND * 60 * 15; // static public static void main(String[] args) throws Exception { new KickrApplication().run(args); } // instance private HibernateBundle<KickrConfiguration> hibernateBundle; private ElasticSearch elasticSearch; private SessionFactory sessionFactory; private PlayerDAO playerDao; private MatchDAO matchDao; private GameDAO gameDao; private ScoreDAO scoreDao; private FoosballTableDAO tableDao; private AccessTokenDAO accessTokenDao; private UserDAO userDao; private MatchService matchService; private CredentialsService credentialsService; private AuthenticationService authenticationService; private RatingService ratingService; private ScheduledExecutorService executorService; @Override public String getName() { return "kickr"; } public static HibernateBundle<KickrConfiguration> createHibernateBundle() { return new HibernateBundle<KickrConfiguration>( FoosballTable.class, Game.class, Match.class, Player.class, Score.class, ScoreChange.class, User.class, AccessToken.class) { @Override public DataSourceFactory getDataSourceFactory(KickrConfiguration configuration) { return configuration.getDataSourceFactory(); } }; } @Override public void initialize(Bootstrap<KickrConfiguration> bootstrap) { hibernateBundle = createHibernateBundle(); bootstrap.addBundle(new MultiPartBundle()); bootstrap.addBundle(new ViewBundle<KickrConfiguration>() { }); bootstrap.addBundle(new AssetsBundle("/assets", "/assets")); bootstrap.addBundle(hibernateBundle); bootstrap.addBundle(new FlywayBundle<KickrConfiguration>() { @Override public DataSourceFactory getDataSourceFactory(KickrConfiguration configuration) { return configuration.getDataSourceFactory(); } @Override public FlywayFactory getFlywayFactory(KickrConfiguration configuration) { return configuration.getFlywayFactory(); } }); bootstrap.addCommand(new SetupCommand()); bootstrap.addCommand(new AnalyzeCommand()); } @Override public void run(KickrConfiguration configuration, Environment environment) throws Exception { this.executorService = environment.lifecycle().scheduledExecutorService("scheduled-pool-%d").build(); this.elasticSearch = new ElasticSearch(configuration.getElasticConfiguration()); this.sessionFactory = hibernateBundle.getSessionFactory(); this.playerDao = new PlayerDAO(sessionFactory); this.matchDao = new MatchDAO(sessionFactory); this.gameDao = new GameDAO(sessionFactory); this.scoreDao = new ScoreDAO(sessionFactory); this.tableDao = new FoosballTableDAO(sessionFactory); this.accessTokenDao = new AccessTokenDAO(sessionFactory); this.userDao = new UserDAO(sessionFactory); WithTransaction transactional = new WithTransaction(sessionFactory); this.matchService = new MatchService(matchDao, gameDao, playerDao, tableDao); this.credentialsService = new CredentialsService(); this.authenticationService = new AuthenticationService(credentialsService, userDao, accessTokenDao); this.ratingService = new RatingService(matchDao, scoreDao, configuration.getRatingConfiguration()); // schedule update of ratings executorService.scheduleWithFixedDelay(() -> { transactional.run(() -> { ratingService.calculateNewRatings(); }); }, ONE_SECOND, FIVETEEN_MINUTES, TimeUnit.MILLISECONDS); // user management SecurityContextFactory<User> securityContextFactory = new UserSecurityContextFactory("kickr", transactional, authenticationService); environment.jersey().register(new SecurityContextInitializer(securityContextFactory)); environment.jersey().register(new RolesAllowedDynamicFeature()); environment.jersey().register(AuthFactory.binder(new AuthFactory<>(User.class))); // resources environment.jersey().register(new NotAuthorizedErrorHandler()); environment.jersey().register(new NotFoundErrorHandler()); environment.jersey().register(new ConstraintViolationExceptionHandler()); environment.jersey().register(new CharsetResponseFilter()); environment.jersey().register(new RootResource(authenticationService)); environment.jersey().register(new MatchResource(matchService, matchDao, playerDao, environment.getValidator())); environment.jersey().register(new ScoreResource(scoreDao)); environment.jersey().register(new PlayerResource(playerDao)); environment.jersey().register(new TableResource(tableDao)); environment.jersey().register(new AdminResource(ratingService, tableDao, playerDao, sessionFactory)); environment.jersey().register(new FormDataReaderWriter(environment.getValidator())); environment.jersey().register(new UserResource()); SearchIndexer searchIndexer = new SearchIndexer(matchDao, elasticSearch, environment.getObjectMapper()); executorService.schedule(() -> { transactional.run(() -> { try { searchIndexer.index(); } catch (Exception e) { System.err.println("Failed to index"); e.printStackTrace(System.err); } }); }, 10, TimeUnit.SECONDS); environment.lifecycle().manage(elasticSearch); // cross origin requests FilterHolder corsFilter = environment.getApplicationContext() .addFilter("org.eclipse.jetty.servlets.CrossOriginFilter", "/", EnumSet.of(DispatcherType.REQUEST)); corsFilter.setInitParameter("allowedOrigins", "*"); corsFilter.setInitParameter("allowedHeaders", "X-Requested-With,Content-Type,Accept,Origin"); } }