/**
* Copyright (C) 2012 the original author or authors.
*
* 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 ninja.ebean;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DATASOURCE_DATABASE_DRIVER;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DATASOURCE_DATABASE_URL;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DATASOURCE_HEARTBEAT_SQL;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DATASOURCE_MAX_CONNECTIONS;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DATASOURCE_MIN_CONNECTIONS;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DATASOURCE_NAME;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DATASOURCE_PASSWORD;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DATASOURCE_USERNAME;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DDL_GENERATE;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DDL_RUN;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DDL_INIT_SQL;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_DDL_SEED_SQL;
import static ninja.ebean.NinjaEbeanProperties.EBEAN_MODELS;
import ninja.utils.NinjaProperties;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.EbeanServerFactory;
import com.avaje.ebean.config.DataSourceConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.LinkedHashSet;
import java.util.Set;
import org.slf4j.Logger;
/**
* This is an internal class of Ninja Ebeans support. It is responsible for
* creating db connections and shutting them down upon server start / stop.
* <p>
* As end-user you should NOT use this method directly. Instead simply inject
* EbeanServer into the class you want to use. The interface EbeanServer is
* configured by this class and provided by a provider.
* <p>
*/
@Singleton
public class NinjaEbeanServerLifecycle {
private EbeanServer ebeanServer;
private final NinjaProperties ninjaProperties;
private final Logger logger;
@Inject
public NinjaEbeanServerLifecycle(Logger logger,
NinjaProperties ninjaProperties) {
this.logger = logger;
this.ninjaProperties = ninjaProperties;
startServer();
}
/**
* This method reads the configuration properties from
* your application.conf file and configures Ebean accordingly.
*
*/
public final void startServer(){
logger.info("Starting Ebeans Module.");
// /////////////////////////////////////////////////////////////////////
// Setup basic parameters
// /////////////////////////////////////////////////////////////////////
boolean ebeanDdlGenerate = ninjaProperties.getBooleanWithDefault(
EBEAN_DDL_GENERATE, false);
boolean ebeanDdlRun = ninjaProperties.getBooleanWithDefault(
EBEAN_DDL_RUN, false);
String ebeanDdlInitSql = ninjaProperties.get(EBEAN_DDL_INIT_SQL);
String ebeanDdlSeedSql = ninjaProperties.get(EBEAN_DDL_SEED_SQL);
String ebeanDatasourceName = ninjaProperties.getWithDefault(
EBEAN_DATASOURCE_NAME, "default");
String ebeanDatasourceUserName = ninjaProperties.getWithDefault(
EBEAN_DATASOURCE_USERNAME, "test");
String ebeanDatasourcePassword = ninjaProperties.getWithDefault(
EBEAN_DATASOURCE_PASSWORD, "test");
String ebeanDatasourceDatabaseUrl = ninjaProperties.getWithDefault(
EBEAN_DATASOURCE_DATABASE_URL,
"jdbc:h2:mem:tests;DB_CLOSE_DELAY=-1");
String ebeanDatasourceDatabaseDriver = ninjaProperties.getWithDefault(
EBEAN_DATASOURCE_DATABASE_DRIVER, "org.h2.Driver");
int ebeanDatasourceMinConnections = ninjaProperties
.getIntegerWithDefault(EBEAN_DATASOURCE_MIN_CONNECTIONS, 1);
int ebeanDatasourceMaxConnections = ninjaProperties
.getIntegerWithDefault(EBEAN_DATASOURCE_MAX_CONNECTIONS, 25);
String ebeanDatasourceHeartbeatSql = ninjaProperties.getWithDefault(
EBEAN_DATASOURCE_HEARTBEAT_SQL, "select 1");
ServerConfig serverConfig = new ServerConfig();
serverConfig.setName(ebeanDatasourceName);
serverConfig.loadFromProperties();
// Define DataSource parameters
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDriver(ebeanDatasourceDatabaseDriver);
dataSourceConfig.setUsername(ebeanDatasourceUserName);
dataSourceConfig.setPassword(ebeanDatasourcePassword);
dataSourceConfig.setUrl(ebeanDatasourceDatabaseUrl);
dataSourceConfig.setMinConnections(ebeanDatasourceMinConnections);
dataSourceConfig.setMaxConnections(ebeanDatasourceMaxConnections);
dataSourceConfig.setHeartbeatSql(ebeanDatasourceHeartbeatSql);
serverConfig.setDataSourceConfig(dataSourceConfig);
// set DDL options...
serverConfig.setDdlGenerate(ebeanDdlGenerate);
serverConfig.setDdlRun(ebeanDdlRun);
serverConfig.setDdlInitSql(ebeanDdlInitSql);
serverConfig.setDdlSeedSql(ebeanDdlSeedSql);
serverConfig.setDefaultServer(true);
serverConfig.setRegister(true);
// split models configuration into classes & packages
Set<String> packageNames = new LinkedHashSet<>();
Set<Class<?>> entityClasses = new LinkedHashSet<>();
// models always added by default
packageNames.add("models");
// add manually listed classes from the property
String[] manuallyListedModels = ninjaProperties.getStringArray(EBEAN_MODELS);
if (manuallyListedModels != null) {
for (String model: manuallyListedModels) {
if (model.endsWith(".*")) {
// strip off .* at end
String packageName = model.substring(0, model.length() - 2);
packageNames.add(packageName);
} else {
try {
entityClasses.add(Class.forName(model));
} catch (ClassNotFoundException e) {
throw new RuntimeException(
"Configuration error. Class listed/discovered via " + EBEAN_MODELS + " not found: " + model);
}
}
}
}
// if any packages were specified the reflections library MUST be available
if (!packageNames.isEmpty()) {
for (String packageName : packageNames) {
Set<String> packageClasses
= ReflectionsHelper.findAllClassesInPackage(packageName);
logger.info("Searched and found " + packageClasses.size() + " classes in package " + packageName);
for (String packageClass : packageClasses) {
try {
entityClasses.add(Class.forName(packageClass));
} catch (ClassNotFoundException e) {
// should be impossible since Reflections just found 'em
throw new RuntimeException("Something fishy happenend. Unable to find class " + packageClass);
}
}
}
}
for (Class<?> entityClass : entityClasses) {
serverConfig.addClass(entityClass);
}
// create the EbeanServer instance
ebeanServer = createEbeanServer(serverConfig);
// Activate the Ebean shutdown manager (disconnects from db, shuts down all threads and so on)
ShutdownManager.touch();
}
/**
* Creates the Ebean server with the prepared server config. Provides a
* last chance to modify the config in a subclass if you'd like to customize
* the config further.
*
* @param serverConfig The prepared server config
* @return The newly created Ebean server
*/
public EbeanServer createEbeanServer(ServerConfig serverConfig) {
return EbeanServerFactory.create(serverConfig);
}
public EbeanServer getEbeanServer() {
return ebeanServer;
}
}