
play.db.ebean.orm.DefaultEbeanConfig Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2009-2014 Typesafe Inc.
*/
package play.db.ebean.orm;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigOrigin;
import io.ebean.EbeanServerFactory;
import io.ebean.config.*;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.scanners.TypeElementsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import play.Environment;
import play.api.PlayException;
import play.db.DBApi;
import scala.Option;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import java.util.*;
import java.util.stream.Collectors;
import static java.lang.Class.forName;
/**
* Ebean server configuration.
*
* @since 14.11.27
*/
@Singleton
public class DefaultEbeanConfig implements EbeanConfig {
/**
* Default server name.
*
* @since 14.11.27
*/
private final String defaultServer;
/**
* Server configuration.
*
* @since 14.11.27
*/
private final Map serverConfigs;
/**
* Build a pre-configured instance.
*
* @param defaultServer The server name (eg: "default")
* @param serverConfigs The server configuration
* @since 14.11.27
*/
public DefaultEbeanConfig(final String defaultServer, final Map serverConfigs) {
this.defaultServer = defaultServer;
this.serverConfigs = serverConfigs;
}
@Override
public String defaultServer() {
return this.defaultServer;
}
@Override
public Map serverConfigs() {
return this.serverConfigs;
}
/**
* EbeanConfigParser.
*
* @since 14.11.27
*/
@Singleton
public static class EbeanConfigParser implements Provider {
/**
* @since 14.11.27
*/
private final Config configuration;
/**
* @since 14.11.27
*/
private final Environment environment;
/**
* @since 14.11.27
*/
private final DBApi dbApi;
/**
* Build a pre-configured configuration parser.
*
* @param configuration The current Play configuration
* @param environment The current Play environment
* @param dbApi DB API for managing application databases
* @since 14.11.27
*/
@Inject
public EbeanConfigParser(final Config configuration, final Environment environment, final DBApi dbApi) {
this.configuration = configuration;
this.environment = environment;
this.dbApi = dbApi;
}
@Override
public EbeanConfig get() {
return this.parse();
}
/**
* Throw a "Configuration error" exception.
*
* @param origin The configuration file containing the error
* @param message The message to print on top of the page
* @param t The current exception
* @since 17.07.06
*/
private void throwConfigurationException(final Option origin, final String message, final Throwable t) {
throw new PlayException.ExceptionSource(
"Configuration error",
message,
t
) {
@Override
public Integer line() {
if (origin.nonEmpty()) {
return origin
.get()
.lineNumber();
}
return null;
}
@Override
public Integer position() {
return null;
}
@Override
public String input() {
if (origin.nonEmpty()) {
return origin.get().url().toString();
}
return null;
}
@Override
public String sourceName() {
if (origin.nonEmpty()) {
return origin.get().filename();
}
return null;
}
};
}
/**
* Reads the configuration and creates configuration for Ebean servers.
*
* @return A configuration for Ebean servers
* @since 14.11.27
*/
EbeanConfig parse() {
final Map serverConfigs = new HashMap<>();
if (this.configuration.hasPathOrNull("ebean.clustering")) {
final Config playEbeanClusteringCfg = this.configuration.getConfig("ebean.clustering");
if (playEbeanClusteringCfg.hasPath("isActive") && playEbeanClusteringCfg.getBoolean("isActive")) {
final ContainerConfig containerConfig = new ContainerConfig();
final Properties properties = new Properties();
if (playEbeanClusteringCfg.hasPath("currentNode")) {
properties.setProperty(
"ebean.cluster.localHostPort",
playEbeanClusteringCfg.getString("currentNode")
);
}
if (playEbeanClusteringCfg.hasPath("members")) {
properties.setProperty(
"ebean.cluster.members",
playEbeanClusteringCfg.getStringList("members")
.stream()
.map(String::trim)
.collect(Collectors.joining(","))
);
}
containerConfig.setActive(true);
containerConfig.setProperties(properties);
EbeanServerFactory.initialiseContainer(containerConfig);
}
}
if (this.configuration.hasPathOrNull("ebean.servers")) {
final Config playEbeanSrvCfg = this.configuration.getConfig("ebean.servers");
playEbeanSrvCfg.root().keySet().forEach(serverName -> {
final Config ebeanServerConfig = playEbeanSrvCfg.getConfig(serverName);
final ServerConfig serverConfig = new ServerConfig();
serverConfig.setName(serverName);
serverConfig.loadFromProperties();
if (serverName.compareTo("default") == 0) {
serverConfig.setDefaultServer(true);
} else {
serverConfig.setDefaultServer(false);
}
if (ebeanServerConfig.hasPath("settings")) {
try {
final Config playEbeanSrvSettingsCfg = ebeanServerConfig.getConfig("settings");
if (playEbeanSrvSettingsCfg.hasPath("onlyUseDocStore") && ebeanServerConfig.hasPath("docstore")) {
if (playEbeanSrvSettingsCfg.getBoolean("onlyUseDocStore")) {
serverConfig.setDocStoreOnly(true);
} else {
serverConfig.setDocStoreOnly(false);
this.setServerConfigDataSource(serverName, serverConfig);
}
} else {
this.setServerConfigDataSource(serverName, serverConfig);
}
if (playEbeanSrvSettingsCfg.hasPath("allQuotedIdentifiers")) {
serverConfig.setAllQuotedIdentifiers(
playEbeanSrvSettingsCfg.getBoolean("allQuotedIdentifiers")
);
}
if (playEbeanSrvSettingsCfg.hasPath("encryptKeyManager")) {
final EncryptKeyManager encryptKeyManager = (EncryptKeyManager) serverConfig
.getClassLoadConfig()
.newInstance(playEbeanSrvSettingsCfg.getString("encryptKeyManager"));
serverConfig.setEncryptKeyManager(encryptKeyManager);
}
if (playEbeanSrvSettingsCfg.hasPath("currentUserProvider")) {
final CurrentUserProvider currentUserProvider = (CurrentUserProvider) serverConfig
.getClassLoadConfig()
.newInstance(playEbeanSrvSettingsCfg.getString("currentUserProvider"));
serverConfig.setCurrentUserProvider(currentUserProvider);
}
if (playEbeanSrvSettingsCfg.hasPath("currentTenantProvider")) {
final CurrentTenantProvider currentTenantProvider = (CurrentTenantProvider) serverConfig
.getClassLoadConfig()
.newInstance(playEbeanSrvSettingsCfg.getString("currentTenantProvider"));
serverConfig.setCurrentTenantProvider(currentTenantProvider);
}
if (playEbeanSrvSettingsCfg.hasPath("disableL2Cache")) {
serverConfig.setDisableL2Cache(
playEbeanSrvSettingsCfg.getBoolean("disableL2Cache")
);
}
} catch (final Exception ex) {
final Option origin = this.configuration.hasPath("ebean.servers" + serverName + ".settings") ?
Option.apply(this.configuration.getValue("ebean.servers" + serverName + ".settings").origin()) :
Option.apply(this.configuration.root().origin());
throwConfigurationException(origin, ex.getMessage(), ex);
}
} else {
serverConfig.setDocStoreOnly(false);
this.setServerConfigDataSource(serverName, serverConfig);
}
if (ebeanServerConfig.hasPath("enhancement")) {
final Set classes = new HashSet<>();
ebeanServerConfig.getStringList("enhancement").stream().map(String::trim).forEach(load -> {
if (load.endsWith(".*")) {
final String packageName = load.substring(0, load.length() - 2);
final Reflections reflections = new Reflections(
new ConfigurationBuilder()
.addUrls(ClasspathHelper.forPackage(packageName, environment.classLoader()))
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(packageName + ".")))
.setScanners(new TypeElementsScanner(), new TypeAnnotationsScanner(), new SubTypesScanner())
);
classes.addAll(
reflections
.getStore()
.get(TypeElementsScanner.class.getSimpleName())
.keySet()
);
} else {
classes.add(load);
}
});
this.addModelClassesToServerConfig(serverName, serverConfig, classes);
}
if (ebeanServerConfig.hasPath("docstore")) {
try {
forName("io.ebeanservice.elastic.ElasticDocumentStore");
} catch (ClassNotFoundException ex) {
final Option origin = this.configuration.hasPath("ebean.servers" + serverName + ".docstore") ?
Option.apply(this.configuration.getValue("ebean.servers" + serverName + ".docstore").origin()) :
Option.apply(this.configuration.root().origin());
throwConfigurationException(origin, ex.getMessage(), ex);
}
try {
final Config playEbeanSrvDocStoreCfg = ebeanServerConfig.getConfig("docstore");
final DocStoreConfig docStoreConfig = new DocStoreConfig();
if (playEbeanSrvDocStoreCfg.hasPath("url")) {
docStoreConfig.setUrl(playEbeanSrvDocStoreCfg.getString("url"));
} else {
docStoreConfig.setUrl("http://127.0.0.1:9200");
}
if (playEbeanSrvDocStoreCfg.hasPath("active")) {
docStoreConfig.setActive(playEbeanSrvDocStoreCfg.getBoolean("active"));
}
if (playEbeanSrvDocStoreCfg.hasPath("generateMapping")) {
docStoreConfig.setGenerateMapping(playEbeanSrvDocStoreCfg.getBoolean("generateMapping"));
}
if (playEbeanSrvDocStoreCfg.hasPath("dropCreate")) {
docStoreConfig.setDropCreate(playEbeanSrvDocStoreCfg.getBoolean("dropCreate"));
}
if (playEbeanSrvDocStoreCfg.hasPath("create")) {
docStoreConfig.setCreate(playEbeanSrvDocStoreCfg.getBoolean("create"));
}
if (playEbeanSrvDocStoreCfg.hasPath("pathToResources")) {
docStoreConfig.setPathToResources(playEbeanSrvDocStoreCfg.getString("pathToResources"));
} else {
docStoreConfig.setPathToResources("conf");
}
if (playEbeanSrvDocStoreCfg.hasPath("allowAllCertificates")) {
docStoreConfig.setAllowAllCertificates(playEbeanSrvDocStoreCfg.getBoolean("allowAllCertificates"));
} else {
docStoreConfig.setAllowAllCertificates(false);
}
serverConfig.setDocStoreConfig(docStoreConfig);
} catch (final Exception ex) {
final Option origin = this.configuration.hasPath("ebean.servers" + serverName + ".docstore") ?
Option.apply(this.configuration.getValue("ebean.servers" + serverName + ".docstore").origin()) :
Option.apply(this.configuration.root().origin());
throwConfigurationException(origin, ex.getMessage(), ex);
}
}
if (ebeanServerConfig.hasPath("extra-config")) {
ebeanServerConfig.getStringList("extra-config").forEach(className -> {
try {
final EbeanServerExtraConfig esac = (EbeanServerExtraConfig) forName(
className,
true,
this.environment.classLoader()
).newInstance();
esac.applyExtraConfiguration(serverConfig, this.configuration);
} catch (final ClassNotFoundException | IllegalAccessException | InstantiationException ex) {
ex.printStackTrace();
}
});
}
serverConfigs.put(serverName, serverConfig);
});
} else {
throw new RuntimeException("Bad play-ebean configuration, check your configuration file");
}
return new DefaultEbeanConfig("default", serverConfigs);
}
/**
* Set the datasource from DB API to the ebean server configuration.
*
* @param key The server name
* @param serverConfig The server configuration to apply
* @since 14.11.27
*/
private void setServerConfigDataSource(final String key, final ServerConfig serverConfig) {
try {
serverConfig.setDataSource(
new WrappingDatasource(
this.dbApi
.getDatabase(key)
.getDataSource()
)
);
} catch (Exception ex) {
final Option origin = this.configuration.hasPath("ebean.servers." + key) ?
Option.apply(this.configuration.getValue("ebean.servers." + key).origin()) :
Option.apply(this.configuration.root().origin());
throwConfigurationException(origin, ex.getMessage(), ex);
}
}
/**
* Add model classes to server configuration.
*
* @param key The server name
* @param serverConfig The server configuration
* @param classes The class to add
* @since 14.11.27
*/
private void addModelClassesToServerConfig(final String key, final ServerConfig serverConfig,
final Set classes) {
for (final String clazz : classes) {
try {
serverConfig.addClass(forName(clazz, true, this.environment.classLoader()));
} catch (Throwable ex) {
final Option origin = this.configuration.hasPath("ebean.servers." + key) ?
Option.apply(this.configuration.getValue("ebean.servers." + key).origin()) :
Option.apply(this.configuration.root().origin());
throwConfigurationException(
origin,
"Cannot register class [" + clazz + "] in Ebean server",
ex
);
}
}
}
/**
* DataSource
wrapper to ensure that every retrieved
* connection has auto-commit disabled.
*
* @since 14.11.27
*/
static class WrappingDatasource implements javax.sql.DataSource {
/**
* @since 14.11.27
*/
final javax.sql.DataSource wrapped;
/**
* Build a default instance.
*
* @param wrapped The {@code DataSource} object to wrap
* @since 14.11.27
*/
WrappingDatasource(final javax.sql.DataSource wrapped) {
this.wrapped = wrapped;
}
/**
* Wrap the connection. This method ensure that the given
* connection have 'auto-commit' set to {@code false}.
*
* @param connection The SQL connection
* @return The SQL connection with 'auto-commit' set to {@code false}
* @throws java.sql.SQLException If a database connection error occurs
* @since 14.11.27
*/
java.sql.Connection wrap(final java.sql.Connection connection) throws java.sql.SQLException {
connection.setAutoCommit(false);
return connection;
}
@Override
public java.sql.Connection getConnection() throws java.sql.SQLException {
return this.wrap(this.wrapped.getConnection());
}
@Override
public java.sql.Connection getConnection(final String username, final String password) throws java.sql.SQLException {
return this.wrap(this.wrapped.getConnection(username, password));
}
@Override
public int getLoginTimeout() throws java.sql.SQLException {
return this.wrapped.getLoginTimeout();
}
@Override
public void setLoginTimeout(final int seconds) throws java.sql.SQLException {
this.wrapped.setLoginTimeout(seconds);
}
@Override
public java.io.PrintWriter getLogWriter() throws java.sql.SQLException {
return this.wrapped.getLogWriter();
}
@Override
public void setLogWriter(final java.io.PrintWriter out) throws java.sql.SQLException {
this.wrapped.setLogWriter(out);
}
@Override
public boolean isWrapperFor(final Class> iface) throws java.sql.SQLException {
return this.wrapped.isWrapperFor(iface);
}
@Override
public T unwrap(final Class iface) throws java.sql.SQLException {
return this.wrapped.unwrap(iface);
}
@Override
public java.util.logging.Logger getParentLogger() {
return null;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy