/* * Copyright (c) 2015 Shervin Asgari * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package no.asgari.civilization.server.application; import com.codahale.metrics.MetricRegistry; import com.google.common.base.Strings; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilderSpec; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.mongodb.BasicDBObject; import com.mongodb.DB; import com.mongodb.DBObject; import com.mongodb.MongoClient; import com.mongodb.MongoClientURI; import io.dropwizard.Application; import io.dropwizard.assets.AssetsBundle; import io.dropwizard.auth.basic.BasicCredentials; import io.dropwizard.java8.Java8Bundle; import io.dropwizard.java8.auth.AuthFactory; import io.dropwizard.java8.auth.CachingAuthenticator; import io.dropwizard.java8.auth.basic.BasicAuthFactory; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import lombok.extern.log4j.Log4j; import no.asgari.civilization.server.model.Chat; import no.asgari.civilization.server.model.PBF; import no.asgari.civilization.server.model.Player; import no.asgari.civilization.server.resource.AdminResource; import no.asgari.civilization.server.resource.AuthResource; import no.asgari.civilization.server.resource.DrawResource; import no.asgari.civilization.server.resource.GameResource; import no.asgari.civilization.server.resource.PlayerResource; import org.eclipse.jetty.servlets.CrossOriginFilter; import org.glassfish.hk2.utilities.Binder; import org.mongojack.JacksonDBCollection; import javax.servlet.DispatcherType; import javax.servlet.FilterRegistration; import java.util.EnumSet; import java.util.List; import java.util.concurrent.TimeUnit; import static org.eclipse.jetty.servlets.CrossOriginFilter.ALLOWED_HEADERS_PARAM; import static org.eclipse.jetty.servlets.CrossOriginFilter.ALLOWED_METHODS_PARAM; import static org.eclipse.jetty.servlets.CrossOriginFilter.ALLOWED_ORIGINS_PARAM; import static org.eclipse.jetty.servlets.CrossOriginFilter.ALLOW_CREDENTIALS_PARAM; import static org.eclipse.jetty.servlets.CrossOriginFilter.EXPOSED_HEADERS_PARAM; @Log4j @SuppressWarnings("unchecked") public class CivilizationApplication extends Application<CivilizationConfiguration> { public static void main(String[] args) throws Exception { if (args == null || args.length == 0) { new CivilizationApplication().run("server", "src/main/resources/config.yml"); } else { new CivilizationApplication().run(args); } } @Override public void initialize(Bootstrap<CivilizationConfiguration> bootstrap) { bootstrap.addBundle(new Java8Bundle()); bootstrap.addBundle(new AssetsBundle()); } @Override public void run(CivilizationConfiguration configuration, Environment environment) throws Exception { DB db; MongoClient mongo; if (!Strings.isNullOrEmpty(configuration.mongodbUser) && !Strings.isNullOrEmpty(configuration.mongodbPassword)) { MongoClientURI clientURI = new MongoClientURI("mongodb://" + configuration.mongodbUser + ":" + configuration.mongodbPassword + "@" + configuration.mongohost + ":" + configuration.mongoport + "/" + configuration.mongodb); mongo = new MongoClient(clientURI); db = mongo.getDB(clientURI.getDatabase()); } else { mongo = new MongoClient(configuration.mongohost, configuration.mongoport); db = mongo.getDB(configuration.mongodb); } MongoManaged mongoManaged = new MongoManaged(mongo); environment.lifecycle().manage(mongoManaged); JacksonDBCollection<Player, String> playerCollection = JacksonDBCollection.wrap(db.getCollection(Player.COL_NAME), Player.class, String.class); //JacksonDBCollection<PBF, String> pbfCollection = JacksonDBCollection.wrap(db.getCollection(PBF.COL_NAME), PBF.class, String.class); JacksonDBCollection<Chat, String> chatCollection = JacksonDBCollection.wrap(db.getCollection(Chat.COL_NAME), Chat.class, String.class); createUniqueIndexForPlayer(playerCollection); createUsernameCache(playerCollection); //createUniqueIndexForPBF(pbfCollection); createIndexForChat(chatCollection); //createItemCache(); //TODO Have to rewrite the code to make it work, right now everyone gets same number and same draws //healtcheck environment.healthChecks().register("MongoHealthCheck", new MongoHealthCheck(mongo)); //Resources environment.jersey().register(new GameResource(db)); environment.jersey().register(new AuthResource(db)); environment.jersey().register(new PlayerResource(db)); environment.jersey().register(new DrawResource(db)); environment.jersey().register(new AdminResource(db)); //Authenticator CachingAuthenticator<BasicCredentials, Player> cachingAuthenticator = new CachingAuthenticator<>( new MetricRegistry(), new CivAuthenticator(db), CacheBuilderSpec.parse("expireAfterWrite=120m") ); //Authentication binder Binder authBinder = AuthFactory.binder(new BasicAuthFactory<>(cachingAuthenticator, "civilization", Player.class)); //Authentication environment.jersey().register(authBinder); // Configure CORS parameters FilterRegistration.Dynamic filter = environment.servlets().addFilter("CORSFilter", CrossOriginFilter.class); filter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, environment.getApplicationContext().getContextPath() + "api/*"); filter.setInitParameter(ALLOWED_METHODS_PARAM, "GET,PUT,POST,OPTIONS,DELETE"); filter.setInitParameter(ALLOWED_ORIGINS_PARAM, "*"); filter.setInitParameter(ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,authorization"); filter.setInitParameter(ALLOW_CREDENTIALS_PARAM, "true"); filter.setInitParameter(EXPOSED_HEADERS_PARAM, "Content-Type,Authorization,X-Requested-With,Content-Length,Accept,Origin,Location,Accept-Content-Encoding"); } private void createUsernameCache(JacksonDBCollection<Player, String> playerCollection) { LoadingCache<String, String> usernameCache = CacheBuilder.newBuilder() .expireAfterWrite(2, TimeUnit.HOURS) .maximumSize(100) .removalListener(lis -> log.debug("Removing " + lis.toString() + " from the usernameCache")) .build(new CacheLoader<String, String>() { public String load(String playerId) { return playerCollection.findOneById(playerId).getUsername(); } }); CivSingleton.instance().setPlayerCache(usernameCache); } private void createUniqueIndexForPlayer(JacksonDBCollection<Player, String> playerCollection) { List<DBObject> indexInfos = playerCollection.getIndexInfo(); if (indexInfos.isEmpty()) { playerCollection.createIndex(new BasicDBObject(Player.USERNAME, 1), new BasicDBObject("unique", true)); playerCollection.createIndex(new BasicDBObject(Player.EMAIL, 1), new BasicDBObject("unique", true)); } } /*private void createUniqueIndexForPBF(JacksonDBCollection<PBF, String> pbfCollection) { if (pbfCollection.getIndexInfo().isEmpty()) { pbfCollection.createIndex(new BasicDBObject(PBF.NAME, 1), new BasicDBObject("unique", true)); } }*/ private void createIndexForChat(JacksonDBCollection<Chat, String> chatCollection) { if (chatCollection.getIndexInfo().isEmpty()) { chatCollection.createIndex(new BasicDBObject(Chat.PBFID, 1)); } } }