io.ebeaninternal.server.core.InternalConfiguration Maven / Gradle / Ivy
package io.ebeaninternal.server.core;
import com.fasterxml.jackson.core.JsonFactory;
import io.ebean.DatabaseBuilder;
import io.ebean.ExpressionFactory;
import io.ebean.annotation.Platform;
import io.ebean.cache.*;
import io.ebean.config.*;
import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbHistorySupport;
import io.ebean.event.changelog.ChangeLogListener;
import io.ebean.event.changelog.ChangeLogPrepare;
import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.plugin.Plugin;
import io.ebean.plugin.SpiServer;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.autotune.AutoTuneService;
import io.ebeaninternal.server.autotune.AutoTuneServiceProvider;
import io.ebeaninternal.server.autotune.NoAutoTuneService;
import io.ebeaninternal.server.cache.*;
import io.ebeaninternal.server.changelog.DefaultChangeLogListener;
import io.ebeaninternal.server.changelog.DefaultChangeLogPrepare;
import io.ebeaninternal.server.changelog.DefaultChangeLogRegister;
import io.ebeaninternal.server.cluster.ClusterManager;
import io.ebeaninternal.server.core.bootup.BootupClasses;
import io.ebeaninternal.server.core.timezone.*;
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
import io.ebeaninternal.server.deploy.parse.DeployCreateProperties;
import io.ebeaninternal.server.deploy.parse.DeployUtil;
import io.ebeaninternal.server.dto.DtoBeanManager;
import io.ebeaninternal.server.expression.DefaultExpressionFactory;
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
import io.ebeaninternal.server.expression.platform.DbExpressionHandlerFactory;
import io.ebeaninternal.server.logger.DLogManager;
import io.ebeaninternal.server.logger.DLoggerFactory;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.persist.DefaultPersister;
import io.ebeaninternal.server.persist.platform.MultiValueBind;
import io.ebeaninternal.server.persist.platform.PostgresMultiValueBind;
import io.ebeaninternal.server.query.*;
import io.ebeaninternal.server.json.DJsonContext;
import io.ebeaninternal.server.transaction.*;
import io.ebeaninternal.server.type.DefaultTypeManager;
import io.ebeaninternal.server.type.TypeManager;
import java.util.*;
import static java.lang.System.Logger.Level.*;
/**
* Used to extend the DatabaseConfig with additional objects used to configure and
* construct an Database.
*/
public final class InternalConfiguration {
private static final System.Logger log = CoreLog.internal;
private final TableModState tableModState;
private final boolean online;
private final DatabaseBuilder.Settings config;
private final BootupClasses bootupClasses;
private final DatabasePlatform databasePlatform;
private final TypeManager typeManager;
private final DtoBeanManager dtoBeanManager;
private final ClockService clockService;
private final DataTimeZone dataTimeZone;
private final Binder binder;
private final DeployCreateProperties deployCreateProperties;
private final DeployUtil deployUtil;
private final BeanDescriptorManager beanDescriptorManager;
private final CQueryEngine cQueryEngine;
private final ClusterManager clusterManager;
private final SpiCacheManager cacheManager;
private final ServerCachePlugin serverCachePlugin;
private final boolean jacksonCorePresent;
private final ExpressionFactory expressionFactory;
private final SpiBackgroundExecutor backgroundExecutor;
private final JsonFactory jsonFactory;
private final List plugins = new ArrayList<>();
private final MultiValueBind multiValueBind;
private final SpiLogManager logManager;
private final ExtraMetrics extraMetrics = new ExtraMetrics();
private ServerCacheNotify cacheNotify;
private boolean localL2Caching;
InternalConfiguration(boolean online, ClusterManager clusterManager, SpiBackgroundExecutor backgroundExecutor,
DatabaseBuilder.Settings config, BootupClasses bootupClasses) {
this.online = online;
this.config = config;
this.jacksonCorePresent = config.getClassLoadConfig().isJacksonCorePresent();
this.clockService = new ClockService(config.settings().getClock());
this.tableModState = new TableModState();
this.logManager = initLogManager();
this.jsonFactory = config.getJsonFactory();
this.clusterManager = clusterManager;
this.backgroundExecutor = backgroundExecutor;
this.bootupClasses = bootupClasses;
this.databasePlatform = config.getDatabasePlatform();
this.expressionFactory = initExpressionFactory(config);
this.typeManager = new DefaultTypeManager(config, bootupClasses);
this.multiValueBind = createMultiValueBind(databasePlatform.platform());
this.deployCreateProperties = new DeployCreateProperties(typeManager);
this.deployUtil = new DeployUtil(typeManager, config);
this.serverCachePlugin = initServerCachePlugin();
this.cacheManager = initCacheManager();
this.dtoBeanManager = new DtoBeanManager(typeManager);
this.beanDescriptorManager = new BeanDescriptorManager(this);
Map asOfTableMapping = beanDescriptorManager.deploy();
beanDescriptorManager.scheduleBackgroundTrim();
this.dataTimeZone = initDataTimeZone();
this.binder = getBinder(typeManager, databasePlatform, dataTimeZone);
this.cQueryEngine = new CQueryEngine(config, databasePlatform, binder, asOfTableMapping);
}
public boolean isJacksonCorePresent() {
return jacksonCorePresent;
}
private S service(Class cls) {
S service = config.getServiceObject(cls);
if (service != null) {
return service;
} else {
return ServiceUtil.service(cls);
}
}
private SpiLogManager initLogManager() {
// allow plugin - i.e. capture executed SQL for testing/asserts
SpiLoggerFactory loggerFactory = service(SpiLoggerFactory.class);
if (loggerFactory == null) {
loggerFactory = new DLoggerFactory();
}
SpiLogger sql = loggerFactory.create("io.ebean.SQL");
SpiLogger sum = loggerFactory.create("io.ebean.SUM");
SpiLogger txn = loggerFactory.create("io.ebean.TXN");
return new DLogManager(sql, sum, txn);
}
/**
* Create and return the ExpressionFactory based on configuration and database platform.
*/
private ExpressionFactory initExpressionFactory(DatabaseBuilder.Settings config) {
boolean nativeIlike = config.isExpressionNativeIlike() && databasePlatform.supportsNativeIlike();
return new DefaultExpressionFactory(config.isExpressionEqualsWithNullAsNoop(), nativeIlike);
}
ClockService getClockService() {
return clockService;
}
public ExtraMetrics getExtraMetrics() {
return extraMetrics;
}
/**
* Check if this is a SpiServerPlugin and if so 'collect' it to give the complete list
* later on the DefaultServer for late call to configure().
*/
public T plugin(T maybePlugin) {
if (maybePlugin instanceof Plugin) {
plugins.add((Plugin) maybePlugin);
}
return maybePlugin;
}
/**
* Return the list of plugins we collected during construction.
*/
public List getPlugins() {
// find additional plugins via ServiceLoader ...
for (Plugin plugin : ServiceLoader.load(Plugin.class)) {
if (!plugins.contains(plugin)) {
plugins.add(plugin);
}
}
return plugins;
}
/**
* Return the ChangeLogPrepare to use with a default implementation if none defined.
*/
public ChangeLogPrepare changeLogPrepare(ChangeLogPrepare prepare) {
return plugin((prepare != null) ? prepare : new DefaultChangeLogPrepare());
}
/**
* Return the ChangeLogRegister to use with a default implementation if none defined.
*/
public ChangeLogRegister changeLogRegister(ChangeLogRegister register) {
boolean includeInserts = config.isChangeLogIncludeInserts();
return plugin((register != null) ? register : new DefaultChangeLogRegister(includeInserts));
}
/**
* Return the ChangeLogListener to use with a default implementation if none defined.
*/
public ChangeLogListener changeLogListener(ChangeLogListener listener) {
return plugin((listener != null) ? listener : jacksonCorePresent ? new DefaultChangeLogListener() : null);
}
/**
* For 'As Of' queries return the number of bind variables per predicate.
*/
private Binder getBinder(TypeManager typeManager, DatabasePlatform databasePlatform, DataTimeZone dataTimeZone) {
DbExpressionHandler jsonHandler = getDbExpressionHandler(databasePlatform);
DbHistorySupport historySupport = databasePlatform.historySupport();
if (historySupport == null) {
return new Binder(typeManager, logManager, 0, false, jsonHandler, dataTimeZone, multiValueBind);
}
return new Binder(typeManager, logManager, historySupport.getBindCount(), historySupport.isStandardsBased(), jsonHandler, dataTimeZone, multiValueBind);
}
/**
* Return the JSON expression handler for the given database platform.
*/
private DbExpressionHandler getDbExpressionHandler(DatabasePlatform databasePlatform) {
return DbExpressionHandlerFactory.from(databasePlatform);
}
private MultiValueBind createMultiValueBind(Platform platform) {
// only Postgres at this stage
if (platform.base() == Platform.POSTGRES || platform.base() == Platform.YUGABYTE || platform.base() == Platform.COCKROACH) {
return new PostgresMultiValueBind();
}
return new MultiValueBind();
}
SpiJsonContext createJsonContext(SpiEbeanServer server) {
return jacksonCorePresent ? new DJsonContext(server, jsonFactory, typeManager) : null;
}
AutoTuneService createAutoTuneService(SpiEbeanServer server) {
final AutoTuneServiceProvider provider = service(AutoTuneServiceProvider.class);
return provider == null ? new NoAutoTuneService() : provider.create(server, config);
}
DtoQueryEngine createDtoQueryEngine() {
return new DtoQueryEngine(binder);
}
RelationalQueryEngine createRelationalQueryEngine() {
return new DefaultRelationalQueryEngine(binder, config.getDatabaseBooleanTrue(), config.getPlatformConfig().getDbUuid().useBinaryOptimized());
}
OrmQueryEngine createOrmQueryEngine() {
return new DefaultOrmQueryEngine(cQueryEngine, binder);
}
Persister createPersister(SpiEbeanServer server) {
return new DefaultPersister(server, binder, beanDescriptorManager);
}
public SpiCacheManager getCacheManager() {
return cacheManager;
}
public BootupClasses getBootupClasses() {
return bootupClasses;
}
private Platform getPlatform() {
return getDatabasePlatform().platform();
}
public DatabasePlatform getDatabasePlatform() {
return config.getDatabasePlatform();
}
public DatabaseBuilder.Settings getConfig() {
return config;
}
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
public Binder getBinder() {
return binder;
}
BeanDescriptorManager getBeanDescriptorManager() {
return beanDescriptorManager;
}
public DeployCreateProperties getDeployCreateProperties() {
return deployCreateProperties;
}
public DeployUtil getDeployUtil() {
return deployUtil;
}
CQueryEngine getCQueryEngine() {
return cQueryEngine;
}
public SpiBackgroundExecutor getBackgroundExecutor() {
return backgroundExecutor;
}
public GeneratedPropertyFactory getGeneratedPropertyFactory() {
boolean offlineMode = config.isDbOffline() || DbOffline.isSet();
return new GeneratedPropertyFactory(offlineMode, config, bootupClasses.getIdGenerators());
}
/**
* Create the TransactionManager taking into account autoCommit mode.
*/
TransactionManager createTransactionManager(SpiServer server) {
TransactionScopeManager scopeManager = createTransactionScopeManager();
boolean notifyL2CacheInForeground = cacheManager.isLocalL2Caching() || config.isNotifyL2CacheInForeground();
TransactionManagerOptions options =
new TransactionManagerOptions(server, notifyL2CacheInForeground, config, scopeManager, clusterManager, backgroundExecutor,
beanDescriptorManager, dataSource(), profileHandler(), logManager,
tableModState, cacheNotify, clockService);
return new TransactionManager(options);
}
private SpiProfileHandler profileHandler() {
ProfilingConfig profilingConfig = config.getProfilingConfig();
if (!profilingConfig.isEnabled()) {
return new NoopProfileHandler();
}
SpiProfileHandler handler = service(SpiProfileHandler.class);
if (handler == null) {
handler = new DefaultProfileHandler(profilingConfig);
}
return plugin(handler);
}
/**
* Return the DataSource supplier based on the tenancy mode.
*/
private DataSourceSupplier dataSource() {
switch (config.getTenantMode()) {
case DB:
case DB_WITH_MASTER:
return new MultiTenantDbSupplier(config.getCurrentTenantProvider(), config.getTenantDataSourceProvider());
case SCHEMA:
return new MultiTenantDbSchemaSupplier(config.getCurrentTenantProvider(), config.getDataSource(), config.getReadOnlyDataSource(), config.getTenantSchemaProvider());
case CATALOG:
return new MultiTenantDbCatalogSupplier(config.getCurrentTenantProvider(), config.getDataSource(), config.getReadOnlyDataSource(), config.getTenantCatalogProvider());
default:
return new SimpleDataSourceProvider(config.getDataSource(), config.getReadOnlyDataSource());
}
}
/**
* Create the TransactionScopeManager taking into account JTA or external transaction manager.
*/
private TransactionScopeManager createTransactionScopeManager() {
ExternalTransactionManager externalTransactionManager = config.getExternalTransactionManager();
if (externalTransactionManager == null && config.isUseJtaTransactionManager()) {
externalTransactionManager = new JtaTransactionManager();
}
if (externalTransactionManager != null) {
log.log(INFO, "Using Transaction Manager {0}", externalTransactionManager.getClass());
return new ExternalTransactionScopeManager(externalTransactionManager);
} else {
return new DefaultTransactionScopeManager();
}
}
/**
* Create the DataTimeZone implementation to use.
*/
private DataTimeZone initDataTimeZone() {
String tz = config.getDataTimeZone();
if ("NoTimeZone".equals(tz)) {
return new NoDataTimeZone();
}
if (tz == null) {
if (isMySql(getPlatform())) {
return new MySqlDataTimeZone();
}
return new NoDataTimeZone();
}
if (getPlatform().base() == Platform.ORACLE) {
return new OracleDataTimeZone(tz);
} else {
return new SimpleDataTimeZone(tz);
}
}
private boolean isMySql(Platform platform) {
return platform.base() == Platform.MYSQL;
}
public DataTimeZone getDataTimeZone() {
return dataTimeZone;
}
public ServerCacheManager cacheManager() {
return new DefaultCacheAdapter(cacheManager);
}
/**
* Return the slow query warning limit in micros.
*/
long getSlowQueryMicros() {
long millis = config.getSlowQueryMillis();
return (millis < 1) ? Long.MAX_VALUE : millis * 1000L;
}
/**
* Return the SlowQueryListener with a default that logs a warning message.
*/
SlowQueryListener getSlowQueryListener() {
long millis = config.getSlowQueryMillis();
if (millis < 1) {
return null;
}
SlowQueryListener listener = config.getSlowQueryListener();
if (listener == null) {
listener = service(SlowQueryListener.class);
if (listener == null) {
listener = new DefaultSlowQueryListener();
}
}
return listener;
}
/**
* Return the platform specific MultiValue bind support.
*/
public MultiValueBind getMultiValueBind() {
return multiValueBind;
}
DtoBeanManager getDtoBeanManager() {
return dtoBeanManager;
}
SpiLogManager getLogManager() {
return logManager;
}
private ServerCachePlugin initServerCachePlugin() {
if (config.isLocalOnlyL2Cache()) {
localL2Caching = true;
return new DefaultServerCachePlugin();
}
ServerCachePlugin plugin = config.getServerCachePlugin();
if (plugin == null) {
ServiceLoader cacheFactories = ServiceLoader.load(ServerCachePlugin.class);
Iterator iterator = cacheFactories.iterator();
if (iterator.hasNext()) {
// use the cacheFactory (via classpath service loader)
plugin = iterator.next();
log.log(DEBUG, "using ServerCacheFactory {0}", plugin.getClass());
} else {
// use the built in default l2 caching which is local cache based
localL2Caching = true;
plugin = new DefaultServerCachePlugin();
}
}
return plugin;
}
/**
* Create and return the CacheManager.
*/
private SpiCacheManager initCacheManager() {
if (!online || config.isDisableL2Cache()) {
// use local only L2 cache implementation as placeholder
return new DefaultServerCacheManager();
}
ServerCacheFactory factory = serverCachePlugin.create(config, backgroundExecutor);
ServerCacheNotifyPlugin notifyPlugin = service(ServerCacheNotifyPlugin.class);
if (notifyPlugin != null) {
// plugin supplied so use that to send notifications
cacheNotify = notifyPlugin.create(config);
} else {
cacheNotify = factory.createCacheNotify(tableModState);
}
// reasonable default settings are for a cache per bean type
ServerCacheOptions beanOptions = new ServerCacheOptions();
beanOptions.setMaxSize(config.getCacheMaxSize());
beanOptions.setMaxIdleSecs(config.getCacheMaxIdleTime());
beanOptions.setMaxSecsToLive(config.getCacheMaxTimeToLive());
// reasonable default settings for the query cache per bean type
ServerCacheOptions queryOptions = new ServerCacheOptions();
queryOptions.setMaxSize(config.getQueryCacheMaxSize());
queryOptions.setMaxIdleSecs(config.getQueryCacheMaxIdleTime());
queryOptions.setMaxSecsToLive(config.getQueryCacheMaxTimeToLive());
CacheManagerOptions builder = new CacheManagerOptions(clusterManager, config, localL2Caching)
.with(beanOptions, queryOptions)
.with(factory, tableModState);
return new DefaultServerCacheManager(builder);
}
public QueryPlanManager initQueryPlanManager(TransactionManager transactionManager) {
if (!config.isQueryPlanEnable()) {
return QueryPlanManager.NOOP;
}
long threshold = config.getQueryPlanThresholdMicros();
return new CQueryPlanManager(transactionManager, threshold, queryPlanLogger(databasePlatform.platform()), extraMetrics);
}
/**
* Returns the logger to log query plans for the given platform.
*/
QueryPlanLogger queryPlanLogger(Platform platform) {
switch (platform.base()) {
case SQLSERVER:
return new QueryPlanLoggerSqlServer();
case ORACLE:
return new QueryPlanLoggerOracle();
case POSTGRES:
return new QueryPlanLoggerExplain("explain (analyze, buffers) ");
case YUGABYTE:
return new QueryPlanLoggerExplain("explain (analyze, buffers, dist) ");
default:
return new QueryPlanLoggerExplain("explain ");
}
}
/**
* Return the DDL generator.
*/
public SpiDdlGenerator initDdlGenerator(SpiEbeanServer server) {
final SpiDdlGeneratorProvider service = service(SpiDdlGeneratorProvider.class);
return service == null ? new NoopDdl(server.config().isDdlRun()) : service.generator(server);
}
private static class NoopDdl implements SpiDdlGenerator {
private final boolean ddlRun;
NoopDdl(boolean ddlRun) {
this.ddlRun = ddlRun;
}
@Override
public void execute(boolean online) {
if (online && ddlRun) {
CoreLog.log.log(ERROR, "Configured to run DDL but ebean-ddl-generator is not in the classpath (or ebean-test in the test classpath?)");
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy