/*
* Copyright 2015 MovingBlocks
*
* 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 org.terasology.web;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.mvc.freemarker.FreemarkerMvcFeature;
import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.web.artifactory.ArtifactoryRepo;
import org.terasology.web.db.DataBase;
import org.terasology.web.db.JooqDatabase;
import org.terasology.web.geo.GeoLocationService;
import org.terasology.web.geo.dbip.GeoLocationServiceDbIp;
import org.terasology.web.io.GsonMessageBodyHandler;
import org.terasology.web.model.ModuleListModelImpl;
import org.terasology.web.model.ServerListModel;
import org.terasology.web.model.ServerListModelImpl;
import org.terasology.web.servlet.AboutServlet;
import org.terasology.web.servlet.ModuleServlet;
import org.terasology.web.servlet.ServerServlet;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
/**
*/
public final class JettyMain {
private static final Logger logger = LoggerFactory.getLogger(JettyMain.class);
private JettyMain() {
// no instances
}
/**
* @param args ignored
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String portEnv = System.getenv("PORT");
if (portEnv == null) {
portEnv = "8080";
logger.warn("Environment variable 'PORT' not defined - using default {}", portEnv);
}
Integer port = Integer.valueOf(portEnv);
String dbEnv = System.getenv("DATABASE_URL");
if (dbEnv == null) {
logger.error("Environment variable 'DATABASE_URL' not defined!");
return;
}
URI dbUri = new URI(dbEnv);
String secret = System.getenv("EDIT_SECRET");
if (secret == null) {
logger.error("Environment variable 'EDIT_SECRET' not defined!");
return;
}
String dbIpApiKey = System.getenv("DBIP_API_KEY");
if (dbIpApiKey == null) {
logger.warn("Environment variable 'DBIP_API_KEY' not defined - geo location lookup not available");
}
String username = dbUri.getUserInfo().split(":")[0];
String password = dbUri.getUserInfo().split(":")[1];
int dbPort = dbUri.getPort();
String host = "http://artifactory.terasology.org/artifactory";
String releaseRepo = "terasology-release-local";
String snapshotRepo = "terasology-snapshot-local";
String modGroup = "org.terasology.modules";
String engineGroup = "org.terasology.engine";
Path cacheFolder = Paths.get("cache", "modules");
ModuleListModelImpl moduleListModel = new ModuleListModelImpl(cacheFolder);
Path releaseRepoFolder = cacheFolder.resolve(releaseRepo);
Path snapshotRepoFolder = cacheFolder.resolve(snapshotRepo);
// add module repos
moduleListModel.addRepository(ArtifactoryRepo.release(host, releaseRepo, modGroup, releaseRepoFolder));
moduleListModel.addRepository(ArtifactoryRepo.snapshot(host, snapshotRepo, modGroup, snapshotRepoFolder));
// add engine repos
moduleListModel.addRepository(ArtifactoryRepo.release(host, releaseRepo, engineGroup, releaseRepoFolder));
moduleListModel.addRepository(ArtifactoryRepo.snapshot(host, snapshotRepo, engineGroup, snapshotRepoFolder));
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://" + dbUri.getHost() + ":" + dbPort + dbUri.getPath());
config.setUsername(username);
config.setPassword(password);
config.addDataSourceProperty("sslmode", "require");
config.setMaximumPoolSize(3);
config.setMinimumIdle(1);
GeoLocationService geoService = new GeoLocationServiceDbIp(dbIpApiKey);
// this is mostly for I18nMap, but can have an influence on other
// string formats. Note that metainfo.ftl explicitly sets the locale to
// define the date format.
Locale.setDefault(Locale.ENGLISH);
try (HikariDataSource ds = new HikariDataSource(config)) {
DataBase dataBase = new JooqDatabase(ds, geoService);
ServerListModel serverListModel = new ServerListModelImpl(dataBase, "servers", secret);
Server server = createServer(port.intValue(),
new AboutServlet(),
new ServerServlet(serverListModel), // the server list servlet
new ModuleServlet(moduleListModel)); // the module list servlet
server.start();
logger.info("Server started on port {}!", port);
new Thread(moduleListModel::updateAllModules).start();
server.join();
}
}
public static Server createServer(int port, Object... servlets) throws Exception {
Server server = new Server(port);
ResourceHandler logFileResourceHandler = new ResourceHandler();
logFileResourceHandler.setDirectoriesListed(true);
logFileResourceHandler.setResourceBase("logs");
ContextHandler logContext = new ContextHandler("/logs"); // the server uri path
logContext.setHandler(logFileResourceHandler);
ResourceHandler webResourceHandler = new ResourceHandler();
webResourceHandler.setDirectoriesListed(false);
webResourceHandler.setResourceBase("web");
ContextHandler webContext = new ContextHandler("/"); // the server uri path
webContext.setHandler(webResourceHandler);
ResourceConfig rc = new ResourceConfig();
rc.register(new GsonMessageBodyHandler()); // register JSON serializer
rc.register(FreemarkerMvcFeature.class);
for (Object servlet : servlets) {
rc.register(servlet);
}
ServletContextHandler jerseyContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
jerseyContext.setContextPath("/");
jerseyContext.setResourceBase("templates");
jerseyContext.addServlet(new ServletHolder(new ServletContainer(rc)), "/*");
HandlerList handlers = new HandlerList();
handlers.addHandler(logContext);
handlers.addHandler(webContext);
handlers.addHandler(jerseyContext);
server.setHandler(handlers);
return server;
}
}