潘志宝
2024-11-29 56dba6294342aa571197298669d04618b4f7258f
提交 | 用户 | 时间
e7c126 1 /* Licensed under the Apache License, Version 2.0 (the "License");
H 2  * you may not use this file except in compliance with the License.
3  * You may obtain a copy of the License at
4  *
5  *      http://www.apache.org/licenses/LICENSE-2.0
6  *
7  * Unless required by applicable law or agreed to in writing, software
8  * distributed under the License is distributed on an "AS IS" BASIS,
9  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10  * See the License for the specific language governing permissions and
11  * limitations under the License.
12  */
13 package org.flowable.common.engine.impl;
14
15 import java.io.InputStream;
16 import java.io.InputStreamReader;
17 import java.io.Reader;
18 import java.sql.Connection;
19 import java.sql.DatabaseMetaData;
20 import java.sql.PreparedStatement;
21 import java.sql.ResultSet;
22 import java.sql.SQLException;
23 import java.time.Duration;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32 import java.util.ServiceLoader;
33 import java.util.Set;
34
35 import javax.naming.InitialContext;
36 import javax.sql.DataSource;
37
38 import org.apache.commons.lang3.StringUtils;
39 import org.apache.ibatis.builder.xml.XMLConfigBuilder;
40 import org.apache.ibatis.builder.xml.XMLMapperBuilder;
41 import org.apache.ibatis.datasource.pooled.PooledDataSource;
42 import org.apache.ibatis.mapping.Environment;
43 import org.apache.ibatis.plugin.Interceptor;
44 import org.apache.ibatis.session.Configuration;
45 import org.apache.ibatis.session.SqlSessionFactory;
46 import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
47 import org.apache.ibatis.transaction.TransactionFactory;
48 import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
49 import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
50 import org.apache.ibatis.type.ArrayTypeHandler;
51 import org.apache.ibatis.type.BigDecimalTypeHandler;
52 import org.apache.ibatis.type.BlobInputStreamTypeHandler;
53 import org.apache.ibatis.type.BlobTypeHandler;
54 import org.apache.ibatis.type.BooleanTypeHandler;
55 import org.apache.ibatis.type.ByteTypeHandler;
56 import org.apache.ibatis.type.ClobTypeHandler;
57 import org.apache.ibatis.type.DateOnlyTypeHandler;
58 import org.apache.ibatis.type.DateTypeHandler;
59 import org.apache.ibatis.type.DoubleTypeHandler;
60 import org.apache.ibatis.type.FloatTypeHandler;
61 import org.apache.ibatis.type.IntegerTypeHandler;
62 import org.apache.ibatis.type.JdbcType;
63 import org.apache.ibatis.type.LongTypeHandler;
64 import org.apache.ibatis.type.NClobTypeHandler;
65 import org.apache.ibatis.type.NStringTypeHandler;
66 import org.apache.ibatis.type.ShortTypeHandler;
67 import org.apache.ibatis.type.SqlxmlTypeHandler;
68 import org.apache.ibatis.type.StringTypeHandler;
69 import org.apache.ibatis.type.TimeOnlyTypeHandler;
70 import org.apache.ibatis.type.TypeHandlerRegistry;
71 import org.flowable.common.engine.api.FlowableException;
72 import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
73 import org.flowable.common.engine.api.delegate.event.FlowableEventDispatcher;
74 import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
75 import org.flowable.common.engine.api.engine.EngineLifecycleListener;
76 import org.flowable.common.engine.impl.agenda.AgendaOperationRunner;
77 import org.flowable.common.engine.impl.cfg.CommandExecutorImpl;
78 import org.flowable.common.engine.impl.cfg.IdGenerator;
79 import org.flowable.common.engine.impl.cfg.TransactionContextFactory;
80 import org.flowable.common.engine.impl.cfg.standalone.StandaloneMybatisTransactionContextFactory;
81 import org.flowable.common.engine.impl.db.CommonDbSchemaManager;
82 import org.flowable.common.engine.impl.db.DbSqlSessionFactory;
83 import org.flowable.common.engine.impl.db.LogSqlExecutionTimePlugin;
84 import org.flowable.common.engine.impl.db.MybatisTypeAliasConfigurator;
85 import org.flowable.common.engine.impl.db.MybatisTypeHandlerConfigurator;
86 import org.flowable.common.engine.impl.db.SchemaManager;
87 import org.flowable.common.engine.impl.event.EventDispatchAction;
88 import org.flowable.common.engine.impl.event.FlowableEventDispatcherImpl;
89 import org.flowable.common.engine.impl.interceptor.Command;
90 import org.flowable.common.engine.impl.interceptor.CommandConfig;
91 import org.flowable.common.engine.impl.interceptor.CommandContextFactory;
92 import org.flowable.common.engine.impl.interceptor.CommandContextInterceptor;
93 import org.flowable.common.engine.impl.interceptor.CommandExecutor;
94 import org.flowable.common.engine.impl.interceptor.CommandInterceptor;
95 import org.flowable.common.engine.impl.interceptor.CrDbRetryInterceptor;
96 import org.flowable.common.engine.impl.interceptor.DefaultCommandInvoker;
97 import org.flowable.common.engine.impl.interceptor.LogInterceptor;
98 import org.flowable.common.engine.impl.interceptor.SessionFactory;
99 import org.flowable.common.engine.impl.interceptor.TransactionContextInterceptor;
100 import org.flowable.common.engine.impl.lock.LockManager;
101 import org.flowable.common.engine.impl.lock.LockManagerImpl;
102 import org.flowable.common.engine.impl.logging.LoggingListener;
103 import org.flowable.common.engine.impl.logging.LoggingSession;
104 import org.flowable.common.engine.impl.logging.LoggingSessionFactory;
105 import org.flowable.common.engine.impl.persistence.GenericManagerFactory;
106 import org.flowable.common.engine.impl.persistence.StrongUuidGenerator;
107 import org.flowable.common.engine.impl.persistence.cache.EntityCache;
108 import org.flowable.common.engine.impl.persistence.cache.EntityCacheImpl;
109 import org.flowable.common.engine.impl.persistence.entity.ByteArrayEntityManager;
110 import org.flowable.common.engine.impl.persistence.entity.ByteArrayEntityManagerImpl;
111 import org.flowable.common.engine.impl.persistence.entity.Entity;
112 import org.flowable.common.engine.impl.persistence.entity.PropertyEntityManager;
113 import org.flowable.common.engine.impl.persistence.entity.PropertyEntityManagerImpl;
114 import org.flowable.common.engine.impl.persistence.entity.TableDataManager;
115 import org.flowable.common.engine.impl.persistence.entity.TableDataManagerImpl;
116 import org.flowable.common.engine.impl.persistence.entity.data.ByteArrayDataManager;
117 import org.flowable.common.engine.impl.persistence.entity.data.PropertyDataManager;
118 import org.flowable.common.engine.impl.persistence.entity.data.impl.MybatisByteArrayDataManager;
119 import org.flowable.common.engine.impl.persistence.entity.data.impl.MybatisPropertyDataManager;
120 import org.flowable.common.engine.impl.runtime.Clock;
121 import org.flowable.common.engine.impl.service.CommonEngineServiceImpl;
122 import org.flowable.common.engine.impl.util.DefaultClockImpl;
123 import org.flowable.common.engine.impl.util.IoUtil;
124 import org.flowable.common.engine.impl.util.ReflectUtil;
125 import org.flowable.eventregistry.api.EventRegistryEventConsumer;
126 import org.slf4j.Logger;
127 import org.slf4j.LoggerFactory;
128
129 import com.fasterxml.jackson.databind.ObjectMapper;
130 import com.fasterxml.jackson.databind.SerializationFeature;
131
132 public abstract class AbstractEngineConfiguration {
133
134     protected final Logger logger = LoggerFactory.getLogger(getClass());
135
136     /** The tenant id indicating 'no tenant' */
137     public static final String NO_TENANT_ID = "";
138
139     /**
140      * Checks the version of the DB schema against the library when the form engine is being created and throws an exception if the versions don't match.
141      */
142     public static final String DB_SCHEMA_UPDATE_FALSE = "false";
143     public static final String DB_SCHEMA_UPDATE_CREATE = "create";
144     public static final String DB_SCHEMA_UPDATE_CREATE_DROP = "create-drop";
145
146     /**
147      * Creates the schema when the form engine is being created and drops the schema when the form engine is being closed.
148      */
149     public static final String DB_SCHEMA_UPDATE_DROP_CREATE = "drop-create";
150
151     /**
152      * Upon building of the process engine, a check is performed and an update of the schema is performed if it is necessary.
153      */
154     public static final String DB_SCHEMA_UPDATE_TRUE = "true";
155
156     protected boolean forceCloseMybatisConnectionPool = true;
157
158     protected String databaseType;
159     protected String jdbcDriver = "org.h2.Driver";
160     protected String jdbcUrl = "jdbc:h2:tcp://localhost/~/flowable";
161     protected String jdbcUsername = "sa";
162     protected String jdbcPassword = "";
163     protected String dataSourceJndiName;
164     protected int jdbcMaxActiveConnections = 16;
165     protected int jdbcMaxIdleConnections = 8;
166     protected int jdbcMaxCheckoutTime;
167     protected int jdbcMaxWaitTime;
168     protected boolean jdbcPingEnabled;
169     protected String jdbcPingQuery;
170     protected int jdbcPingConnectionNotUsedFor;
171     protected int jdbcDefaultTransactionIsolationLevel;
172     protected DataSource dataSource;
173     protected SchemaManager commonSchemaManager;
174     protected SchemaManager schemaManager;
175     protected Command<Void> schemaManagementCmd;
176
177     protected String databaseSchemaUpdate = DB_SCHEMA_UPDATE_FALSE;
178
179     /**
180      * Whether to use a lock when performing the database schema create or update operations.
181      */
182     protected boolean useLockForDatabaseSchemaUpdate = false;
183
184     protected String xmlEncoding = "UTF-8";
185
186     // COMMAND EXECUTORS ///////////////////////////////////////////////
187
188     protected CommandExecutor commandExecutor;
189     protected Collection<? extends CommandInterceptor> defaultCommandInterceptors;
190     protected CommandConfig defaultCommandConfig;
191     protected CommandConfig schemaCommandConfig;
192     protected CommandContextFactory commandContextFactory;
193     protected CommandInterceptor commandInvoker;
194
195     protected AgendaOperationRunner agendaOperationRunner = (commandContext, runnable) -> runnable.run();
196
197     protected List<CommandInterceptor> customPreCommandInterceptors;
198     protected List<CommandInterceptor> customPostCommandInterceptors;
199     protected List<CommandInterceptor> commandInterceptors;
200
201     protected Map<String, AbstractEngineConfiguration> engineConfigurations = new HashMap<>();
202     protected Map<String, AbstractServiceConfiguration> serviceConfigurations = new HashMap<>();
203
204     protected ClassLoader classLoader;
205     /**
206      * Either use Class.forName or ClassLoader.loadClass for class loading. See http://forums.activiti.org/content/reflectutilloadclass-and-custom- classloader
207      */
208     protected boolean useClassForNameClassLoading = true;
209
210     protected List<EngineLifecycleListener> engineLifecycleListeners;
211
212     // Event Registry //////////////////////////////////////////////////
213     protected Map<String, EventRegistryEventConsumer> eventRegistryEventConsumers = new HashMap<>();
214
215     // MYBATIS SQL SESSION FACTORY /////////////////////////////////////
216
217     protected boolean isDbHistoryUsed = true;
218     protected DbSqlSessionFactory dbSqlSessionFactory;
219     protected SqlSessionFactory sqlSessionFactory;
220     protected TransactionFactory transactionFactory;
221     protected TransactionContextFactory transactionContextFactory;
222
223     /**
224      * If set to true, enables bulk insert (grouping sql inserts together). Default true.
225      * For some databases (eg DB2+z/OS) needs to be set to false.
226      */
227     protected boolean isBulkInsertEnabled = true;
228
229     /**
230      * Some databases have a limit of how many parameters one sql insert can have (eg SQL Server, 2000 params (!= insert statements) ). Tweak this parameter in case of exceptions indicating too much
231      * is being put into one bulk insert, or make it higher if your database can cope with it and there are inserts with a huge amount of data.
232      * <p>
233      * By default: 100 (55 for mssql server as it has a hard limit of 2000 parameters in a statement)
234      */
235     protected int maxNrOfStatementsInBulkInsert = 100;
236
237     public int DEFAULT_MAX_NR_OF_STATEMENTS_BULK_INSERT_SQL_SERVER = 55; // currently Execution has most params (35). 2000 / 35 = 57.
238
239     protected String mybatisMappingFile;
240     protected Set<Class<?>> customMybatisMappers;
241     protected Set<String> customMybatisXMLMappers;
242     protected List<Interceptor> customMybatisInterceptors;
243
244     protected Set<String> dependentEngineMyBatisXmlMappers;
245     protected List<MybatisTypeAliasConfigurator> dependentEngineMybatisTypeAliasConfigs;
246     protected List<MybatisTypeHandlerConfigurator> dependentEngineMybatisTypeHandlerConfigs;
247
248     // SESSION FACTORIES ///////////////////////////////////////////////
249     protected List<SessionFactory> customSessionFactories;
250     protected Map<Class<?>, SessionFactory> sessionFactories;
251
252     protected boolean enableEventDispatcher = true;
253     protected FlowableEventDispatcher eventDispatcher;
254     protected List<FlowableEventListener> eventListeners;
255     protected Map<String, List<FlowableEventListener>> typedEventListeners;
256     protected List<EventDispatchAction> additionalEventDispatchActions;
257
258     protected LoggingListener loggingListener;
259
260     protected boolean transactionsExternallyManaged;
261
262     /**
263      * Flag that can be set to configure or not a relational database is used. This is useful for custom implementations that do not use relational databases at all.
264      *
265      * If true (default), the {@link AbstractEngineConfiguration#getDatabaseSchemaUpdate()} value will be used to determine what needs to happen wrt the database schema.
266      *
267      * If false, no validation or schema creation will be done. That means that the database schema must have been created 'manually' before but the engine does not validate whether the schema is
268      * correct. The {@link AbstractEngineConfiguration#getDatabaseSchemaUpdate()} value will not be used.
269      */
270     protected boolean usingRelationalDatabase = true;
271
272     /**
273      * Flag that can be set to configure whether or not a schema is used. This is useful for custom implementations that do not use relational databases at all.
274      * Setting {@link #usingRelationalDatabase} to true will automatically imply using a schema.
275      */
276     protected boolean usingSchemaMgmt = true;
277
278     /**
279      * Allows configuring a database table prefix which is used for all runtime operations of the process engine. For example, if you specify a prefix named 'PRE1.', Flowable will query for executions
280      * in a table named 'PRE1.ACT_RU_EXECUTION_'.
281      *
282      * <p>
283      * <strong>NOTE: the prefix is not respected by automatic database schema management. If you use {@link AbstractEngineConfiguration#DB_SCHEMA_UPDATE_CREATE_DROP} or
284      * {@link AbstractEngineConfiguration#DB_SCHEMA_UPDATE_TRUE}, Flowable will create the database tables using the default names, regardless of the prefix configured here.</strong>
285      */
286     protected String databaseTablePrefix = "";
287
288     /**
289      * Escape character for doing wildcard searches.
290      *
291      * This will be added at then end of queries that include for example a LIKE clause. For example: SELECT * FROM table WHERE column LIKE '%\%%' ESCAPE '\';
292      */
293     protected String databaseWildcardEscapeCharacter;
294
295     /**
296      * database catalog to use
297      */
298     protected String databaseCatalog = "";
299
300     /**
301      * In some situations you want to set the schema to use for table checks / generation if the database metadata doesn't return that correctly, see https://jira.codehaus.org/browse/ACT-1220,
302      * https://jira.codehaus.org/browse/ACT-1062
303      */
304     protected String databaseSchema;
305
306     /**
307      * Set to true in case the defined databaseTablePrefix is a schema-name, instead of an actual table name prefix. This is relevant for checking if Flowable-tables exist, the databaseTablePrefix
308      * will not be used here - since the schema is taken into account already, adding a prefix for the table-check will result in wrong table-names.
309      */
310     protected boolean tablePrefixIsSchema;
311
312     /**
313      * Set to true if the latest version of a definition should be retrieved, ignoring a possible parent deployment id value
314      */
315     protected boolean alwaysLookupLatestDefinitionVersion;
316
317     /**
318      * Set to true if by default lookups should fallback to the default tenant (an empty string by default or a defined tenant value)
319      */
320     protected boolean fallbackToDefaultTenant;
321
322     /**
323      * Default tenant provider that is executed when looking up definitions, in case the global or local fallback to default tenant value is true
324      */
325     protected DefaultTenantProvider defaultTenantProvider = (tenantId, scope, scopeKey) -> NO_TENANT_ID;
326
327     /**
328      * Enables the MyBatis plugin that logs the execution time of sql statements.
329      */
330     protected boolean enableLogSqlExecutionTime;
331
332     protected Properties databaseTypeMappings = getDefaultDatabaseTypeMappings();
333
334     /**
335      * Duration between the checks when acquiring a lock.
336      */
337     protected Duration lockPollRate = Duration.ofSeconds(10);
338
339     /**
340      * Duration to wait for the DB Schema lock before giving up.
341      */
342     protected Duration schemaLockWaitTime = Duration.ofMinutes(5);
343
344     // DATA MANAGERS //////////////////////////////////////////////////////////////////
345
346     protected PropertyDataManager propertyDataManager;
347     protected ByteArrayDataManager byteArrayDataManager;
348     protected TableDataManager tableDataManager;
349
350     // ENTITY MANAGERS ////////////////////////////////////////////////////////////////
351
352     protected PropertyEntityManager propertyEntityManager;
353     protected ByteArrayEntityManager byteArrayEntityManager;
354
355     protected List<EngineDeployer> customPreDeployers;
356     protected List<EngineDeployer> customPostDeployers;
357     protected List<EngineDeployer> deployers;
358
359     // CONFIGURATORS ////////////////////////////////////////////////////////////
360
361     protected boolean enableConfiguratorServiceLoader = true; // Enabled by default. In certain environments this should be set to false (eg osgi)
362     protected List<EngineConfigurator> configurators; // The injected configurators
363     protected List<EngineConfigurator> allConfigurators; // Including auto-discovered configurators
364     protected EngineConfigurator idmEngineConfigurator;
365     protected EngineConfigurator eventRegistryConfigurator;
366
367     public static final String PRODUCT_NAME_POSTGRES = "PostgreSQL";
368     public static final String PRODUCT_NAME_CRDB = "CockroachDB";
369
370     public static final String DATABASE_TYPE_H2 = "h2";
371     public static final String DATABASE_TYPE_HSQL = "hsql";
372     public static final String DATABASE_TYPE_MYSQL = "mysql";
373     public static final String DATABASE_TYPE_ORACLE = "oracle";
374     public static final String DATABASE_TYPE_POSTGRES = "postgres";
375     public static final String DATABASE_TYPE_MSSQL = "mssql";
376     public static final String DATABASE_TYPE_DB2 = "db2";
377     public static final String DATABASE_TYPE_COCKROACHDB = "cockroachdb";
378
379     public static Properties getDefaultDatabaseTypeMappings() {
380         Properties databaseTypeMappings = new Properties();
381         databaseTypeMappings.setProperty("H2", DATABASE_TYPE_H2);
382         databaseTypeMappings.setProperty("HSQL Database Engine", DATABASE_TYPE_HSQL);
383         databaseTypeMappings.setProperty("MySQL", DATABASE_TYPE_MYSQL);
384         databaseTypeMappings.setProperty("MariaDB", DATABASE_TYPE_MYSQL);
385         databaseTypeMappings.setProperty("Oracle", DATABASE_TYPE_ORACLE);
386         databaseTypeMappings.setProperty(PRODUCT_NAME_POSTGRES, DATABASE_TYPE_POSTGRES);
387         databaseTypeMappings.setProperty("Microsoft SQL Server", DATABASE_TYPE_MSSQL);
388         databaseTypeMappings.setProperty(DATABASE_TYPE_DB2, DATABASE_TYPE_DB2);
389         databaseTypeMappings.setProperty("DB2", DATABASE_TYPE_DB2);
390         databaseTypeMappings.setProperty("DB2/NT", DATABASE_TYPE_DB2);
391         databaseTypeMappings.setProperty("DB2/NT64", DATABASE_TYPE_DB2);
392         databaseTypeMappings.setProperty("DB2 UDP", DATABASE_TYPE_DB2);
393         databaseTypeMappings.setProperty("DB2/LINUX", DATABASE_TYPE_DB2);
394         databaseTypeMappings.setProperty("DB2/LINUX390", DATABASE_TYPE_DB2);
395         databaseTypeMappings.setProperty("DB2/LINUXX8664", DATABASE_TYPE_DB2);
396         databaseTypeMappings.setProperty("DB2/LINUXZ64", DATABASE_TYPE_DB2);
397         databaseTypeMappings.setProperty("DB2/LINUXPPC64", DATABASE_TYPE_DB2);
398         databaseTypeMappings.setProperty("DB2/LINUXPPC64LE", DATABASE_TYPE_DB2);
399         databaseTypeMappings.setProperty("DB2/400 SQL", DATABASE_TYPE_DB2);
400         databaseTypeMappings.setProperty("DB2/6000", DATABASE_TYPE_DB2);
401         databaseTypeMappings.setProperty("DB2 UDB iSeries", DATABASE_TYPE_DB2);
402         databaseTypeMappings.setProperty("DB2/AIX64", DATABASE_TYPE_DB2);
403         databaseTypeMappings.setProperty("DB2/HPUX", DATABASE_TYPE_DB2);
404         databaseTypeMappings.setProperty("DB2/HP64", DATABASE_TYPE_DB2);
405         databaseTypeMappings.setProperty("DB2/SUN", DATABASE_TYPE_DB2);
406         databaseTypeMappings.setProperty("DB2/SUN64", DATABASE_TYPE_DB2);
407         databaseTypeMappings.setProperty("DB2/PTX", DATABASE_TYPE_DB2);
408         databaseTypeMappings.setProperty("DB2/2", DATABASE_TYPE_DB2);
409         databaseTypeMappings.setProperty("DB2 UDB AS400", DATABASE_TYPE_DB2);
410         databaseTypeMappings.setProperty(PRODUCT_NAME_CRDB, DATABASE_TYPE_COCKROACHDB);
411         databaseTypeMappings.setProperty("DM DBMS", DATABASE_TYPE_ORACLE); // dhb52: DM support
412         return databaseTypeMappings;
413     }
414
415     protected Map<Object, Object> beans;
416
417     protected IdGenerator idGenerator;
418     protected boolean usePrefixId;
419
420     protected Clock clock;
421     protected ObjectMapper objectMapper;
422
423     // Variables
424
425     public static final int DEFAULT_GENERIC_MAX_LENGTH_STRING = 4000;
426     public static final int DEFAULT_ORACLE_MAX_LENGTH_STRING = 2000;
427
428     /**
429      * Define a max length for storing String variable types in the database. Mainly used for the Oracle NVARCHAR2 limit of 2000 characters
430      */
431     protected int maxLengthStringVariableType = -1;
432
433     protected void initEngineConfigurations() {
434         addEngineConfiguration(getEngineCfgKey(), getEngineScopeType(), this);
435     }
436
437     // DataSource
438     // ///////////////////////////////////////////////////////////////
439
440     protected void initDataSource() {
441         if (dataSource == null) {
442             if (dataSourceJndiName != null) {
443                 try {
444                     dataSource = (DataSource) new InitialContext().lookup(dataSourceJndiName);
445                 } catch (Exception e) {
446                     throw new FlowableException("couldn't lookup datasource from " + dataSourceJndiName + ": " + e.getMessage(), e);
447                 }
448
449             } else if (jdbcUrl != null) {
450                 if ((jdbcDriver == null) || (jdbcUsername == null)) {
451                     throw new FlowableException("DataSource or JDBC properties have to be specified in a process engine configuration");
452                 }
453
454                 logger.debug("initializing datasource to db: {}", jdbcUrl);
455
456                 if (logger.isInfoEnabled()) {
457                     logger.info("Configuring Datasource with following properties (omitted password for security)");
458                     logger.info("datasource driver : {}", jdbcDriver);
459                     logger.info("datasource url : {}", jdbcUrl);
460                     logger.info("datasource user name : {}", jdbcUsername);
461                 }
462
463                 PooledDataSource pooledDataSource = new PooledDataSource(this.getClass().getClassLoader(), jdbcDriver, jdbcUrl, jdbcUsername, jdbcPassword);
464
465                 if (jdbcMaxActiveConnections > 0) {
466                     pooledDataSource.setPoolMaximumActiveConnections(jdbcMaxActiveConnections);
467                 }
468                 if (jdbcMaxIdleConnections > 0) {
469                     pooledDataSource.setPoolMaximumIdleConnections(jdbcMaxIdleConnections);
470                 }
471                 if (jdbcMaxCheckoutTime > 0) {
472                     pooledDataSource.setPoolMaximumCheckoutTime(jdbcMaxCheckoutTime);
473                 }
474                 if (jdbcMaxWaitTime > 0) {
475                     pooledDataSource.setPoolTimeToWait(jdbcMaxWaitTime);
476                 }
477                 if (jdbcPingEnabled) {
478                     pooledDataSource.setPoolPingEnabled(true);
479                     if (jdbcPingQuery != null) {
480                         pooledDataSource.setPoolPingQuery(jdbcPingQuery);
481                     }
482                     pooledDataSource.setPoolPingConnectionsNotUsedFor(jdbcPingConnectionNotUsedFor);
483                 }
484                 if (jdbcDefaultTransactionIsolationLevel > 0) {
485                     pooledDataSource.setDefaultTransactionIsolationLevel(jdbcDefaultTransactionIsolationLevel);
486                 }
487                 dataSource = pooledDataSource;
488             }
489         }
490
491         if (databaseType == null) {
492             initDatabaseType();
493         }
494     }
495
496     public void initDatabaseType() {
497         Connection connection = null;
498         try {
499             connection = dataSource.getConnection();
500             DatabaseMetaData databaseMetaData = connection.getMetaData();
501             String databaseProductName = databaseMetaData.getDatabaseProductName();
502             logger.debug("database product name: '{}'", databaseProductName);
503
504             // CRDB does not expose the version through the jdbc driver, so we need to fetch it through version().
505             if (PRODUCT_NAME_POSTGRES.equalsIgnoreCase(databaseProductName)) {
506                 try (PreparedStatement preparedStatement = connection.prepareStatement("select version() as version;");
507                      ResultSet resultSet = preparedStatement.executeQuery()) {
508                     String version = null;
509                     if (resultSet.next()) {
510                         version = resultSet.getString("version");
511                     }
512
513                     if (StringUtils.isNotEmpty(version) && version.toLowerCase().startsWith(PRODUCT_NAME_CRDB.toLowerCase())) {
514                         databaseProductName = PRODUCT_NAME_CRDB;
515                         logger.info("CockroachDB version '{}' detected", version);
516                     }
517                 }
518             }
519
520             databaseType = databaseTypeMappings.getProperty(databaseProductName);
521             if (databaseType == null) {
522                 throw new FlowableException("couldn't deduct database type from database product name '" + databaseProductName + "'");
523             }
524             logger.debug("using database type: {}", databaseType);
525
526         } catch (SQLException e) {
527             throw new RuntimeException("Exception while initializing Database connection", e);
528         } finally {
529             try {
530                 if (connection != null) {
531                     connection.close();
532                 }
533             } catch (SQLException e) {
534                 logger.error("Exception while closing the Database connection", e);
535             }
536         }
537
538         // Special care for MSSQL, as it has a hard limit of 2000 params per statement (incl bulk statement).
539         // Especially with executions, with 100 as default, this limit is passed.
540         if (DATABASE_TYPE_MSSQL.equals(databaseType)) {
541             maxNrOfStatementsInBulkInsert = DEFAULT_MAX_NR_OF_STATEMENTS_BULK_INSERT_SQL_SERVER;
542         }
543     }
544
545     public void initSchemaManager() {
546         if (this.commonSchemaManager == null) {
547             this.commonSchemaManager = new CommonDbSchemaManager();
548         }
549     }
550
551     // session factories ////////////////////////////////////////////////////////
552
553     public void addSessionFactory(SessionFactory sessionFactory) {
554         sessionFactories.put(sessionFactory.getSessionType(), sessionFactory);
555     }
556
557     public void initCommandContextFactory() {
558         if (commandContextFactory == null) {
559             commandContextFactory = new CommandContextFactory();
560         }
561     }
562
563     public void initTransactionContextFactory() {
564         if (transactionContextFactory == null) {
565             transactionContextFactory = new StandaloneMybatisTransactionContextFactory();
566         }
567     }
568
569     public void initCommandExecutors() {
570         initDefaultCommandConfig();
571         initSchemaCommandConfig();
572         initCommandInvoker();
573         initCommandInterceptors();
574         initCommandExecutor();
575     }
576
577
578     public void initDefaultCommandConfig() {
579         if (defaultCommandConfig == null) {
580             defaultCommandConfig = new CommandConfig();
581         }
582     }
583
584     public void initSchemaCommandConfig() {
585         if (schemaCommandConfig == null) {
586             schemaCommandConfig = new CommandConfig();
587         }
588     }
589
590     public void initCommandInvoker() {
591         if (commandInvoker == null) {
592             commandInvoker = new DefaultCommandInvoker();
593         }
594     }
595
596     public void initCommandInterceptors() {
597         if (commandInterceptors == null) {
598             commandInterceptors = new ArrayList<>();
599             if (customPreCommandInterceptors != null) {
600                 commandInterceptors.addAll(customPreCommandInterceptors);
601             }
602             commandInterceptors.addAll(getDefaultCommandInterceptors());
603             if (customPostCommandInterceptors != null) {
604                 commandInterceptors.addAll(customPostCommandInterceptors);
605             }
606             commandInterceptors.add(commandInvoker);
607         }
608     }
609
610     public Collection<? extends CommandInterceptor> getDefaultCommandInterceptors() {
611         if (defaultCommandInterceptors == null) {
612             List<CommandInterceptor> interceptors = new ArrayList<>();
613             interceptors.add(new LogInterceptor());
614
615             if (DATABASE_TYPE_COCKROACHDB.equals(databaseType)) {
616                 interceptors.add(new CrDbRetryInterceptor());
617             }
618
619             CommandInterceptor transactionInterceptor = createTransactionInterceptor();
620             if (transactionInterceptor != null) {
621                 interceptors.add(transactionInterceptor);
622             }
623
624             if (commandContextFactory != null) {
625                 String engineCfgKey = getEngineCfgKey();
626                 CommandContextInterceptor commandContextInterceptor = new CommandContextInterceptor(commandContextFactory,
627                     classLoader, useClassForNameClassLoading, clock, objectMapper);
628                 engineConfigurations.put(engineCfgKey, this);
629                 commandContextInterceptor.setEngineCfgKey(engineCfgKey);
630                 commandContextInterceptor.setEngineConfigurations(engineConfigurations);
631                 interceptors.add(commandContextInterceptor);
632             }
633
634             if (transactionContextFactory != null) {
635                 interceptors.add(new TransactionContextInterceptor(transactionContextFactory));
636             }
637
638             List<CommandInterceptor> additionalCommandInterceptors = getAdditionalDefaultCommandInterceptors();
639             if (additionalCommandInterceptors != null) {
640                 interceptors.addAll(additionalCommandInterceptors);
641             }
642
643             defaultCommandInterceptors = interceptors;
644         }
645         return defaultCommandInterceptors;
646     }
647
648     public abstract String getEngineCfgKey();
649
650     public abstract String getEngineScopeType();
651
652     public List<CommandInterceptor> getAdditionalDefaultCommandInterceptors() {
653         return null;
654     }
655
656     public void initCommandExecutor() {
657         if (commandExecutor == null) {
658             CommandInterceptor first = initInterceptorChain(commandInterceptors);
659             commandExecutor = new CommandExecutorImpl(getDefaultCommandConfig(), first);
660         }
661     }
662
663     public CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {
664         if (chain == null || chain.isEmpty()) {
665             throw new FlowableException("invalid command interceptor chain configuration: " + chain);
666         }
667         for (int i = 0; i < chain.size() - 1; i++) {
668             chain.get(i).setNext(chain.get(i + 1));
669         }
670         return chain.get(0);
671     }
672
673     public abstract CommandInterceptor createTransactionInterceptor();
674
675
676     public void initBeans() {
677         if (beans == null) {
678             beans = new HashMap<>();
679         }
680     }
681
682     // id generator
683     // /////////////////////////////////////////////////////////////
684
685     public void initIdGenerator() {
686         if (idGenerator == null) {
687             idGenerator = new StrongUuidGenerator();
688         }
689     }
690
691     public void initObjectMapper() {
692         if (objectMapper == null) {
693             objectMapper = new ObjectMapper();
694             objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
695         }
696     }
697
698     public void initClock() {
699         if (clock == null) {
700             clock = new DefaultClockImpl();
701         }
702     }
703
704     // Data managers ///////////////////////////////////////////////////////////
705
706     public void initDataManagers() {
707         if (propertyDataManager == null) {
708             propertyDataManager = new MybatisPropertyDataManager(idGenerator);
709         }
710
711         if (byteArrayDataManager == null) {
712             byteArrayDataManager = new MybatisByteArrayDataManager(idGenerator);
713         }
714     }
715
716     // Entity managers //////////////////////////////////////////////////////////
717
718     public void initEntityManagers() {
719         if (propertyEntityManager == null) {
720             propertyEntityManager = new PropertyEntityManagerImpl(this, propertyDataManager);
721         }
722
723         if (byteArrayEntityManager == null) {
724             byteArrayEntityManager = new ByteArrayEntityManagerImpl(byteArrayDataManager, getEngineCfgKey(), this::getEventDispatcher);
725         }
726
727         if (tableDataManager == null) {
728             tableDataManager = new TableDataManagerImpl(this);
729         }
730     }
731
732     // services
733     // /////////////////////////////////////////////////////////////////
734
735     protected void initService(Object service) {
736         if (service instanceof CommonEngineServiceImpl) {
737             ((CommonEngineServiceImpl) service).setCommandExecutor(commandExecutor);
738         }
739     }
740
741     // myBatis SqlSessionFactory
742     // ////////////////////////////////////////////////
743
744     public void initSessionFactories() {
745         if (sessionFactories == null) {
746             sessionFactories = new HashMap<>();
747
748             if (usingRelationalDatabase) {
749                 initDbSqlSessionFactory();
750             }
751
752             addSessionFactory(new GenericManagerFactory(EntityCache.class, EntityCacheImpl.class));
753
754             if (isLoggingSessionEnabled()) {
755                 if (!sessionFactories.containsKey(LoggingSession.class)) {
756                     LoggingSessionFactory loggingSessionFactory = new LoggingSessionFactory();
757                     loggingSessionFactory.setLoggingListener(loggingListener);
758                     loggingSessionFactory.setObjectMapper(objectMapper);
759                     sessionFactories.put(LoggingSession.class, loggingSessionFactory);
760                 }
761             }
762
763             commandContextFactory.setSessionFactories(sessionFactories);
764
765         } else {
766             if (usingRelationalDatabase) {
767                 initDbSqlSessionFactoryEntitySettings();
768             }
769         }
770
771         if (customSessionFactories != null) {
772             for (SessionFactory sessionFactory : customSessionFactories) {
773                 addSessionFactory(sessionFactory);
774             }
775         }
776     }
777
778     public void initDbSqlSessionFactory() {
779         if (dbSqlSessionFactory == null) {
780             dbSqlSessionFactory = createDbSqlSessionFactory();
781         }
782         dbSqlSessionFactory.setDatabaseType(databaseType);
783         dbSqlSessionFactory.setSqlSessionFactory(sqlSessionFactory);
784         dbSqlSessionFactory.setDbHistoryUsed(isDbHistoryUsed);
785         dbSqlSessionFactory.setDatabaseTablePrefix(databaseTablePrefix);
786         dbSqlSessionFactory.setTablePrefixIsSchema(tablePrefixIsSchema);
787         dbSqlSessionFactory.setDatabaseCatalog(databaseCatalog);
788         dbSqlSessionFactory.setDatabaseSchema(databaseSchema);
789         dbSqlSessionFactory.setMaxNrOfStatementsInBulkInsert(maxNrOfStatementsInBulkInsert);
790
791         initDbSqlSessionFactoryEntitySettings();
792
793         addSessionFactory(dbSqlSessionFactory);
794     }
795
796     public DbSqlSessionFactory createDbSqlSessionFactory() {
797         return new DbSqlSessionFactory(usePrefixId);
798     }
799
800     protected abstract void initDbSqlSessionFactoryEntitySettings();
801
802     protected void defaultInitDbSqlSessionFactoryEntitySettings(List<Class<? extends Entity>> insertOrder, List<Class<? extends Entity>> deleteOrder) {
803         if (insertOrder != null) {
804             for (Class<? extends Entity> clazz : insertOrder) {
805                 dbSqlSessionFactory.getInsertionOrder().add(clazz);
806
807                 if (isBulkInsertEnabled) {
808                     dbSqlSessionFactory.getBulkInserteableEntityClasses().add(clazz);
809                 }
810             }
811         }
812
813         if (deleteOrder != null) {
814             for (Class<? extends Entity> clazz : deleteOrder) {
815                 dbSqlSessionFactory.getDeletionOrder().add(clazz);
816             }
817         }
818     }
819
820     public void initTransactionFactory() {
821         if (transactionFactory == null) {
822             if (transactionsExternallyManaged) {
823                 transactionFactory = new ManagedTransactionFactory();
824                 Properties properties = new Properties();
825                 properties.put("closeConnection", "false");
826                 this.transactionFactory.setProperties(properties);
827             } else {
828                 transactionFactory = new JdbcTransactionFactory();
829             }
830         }
831     }
832
833     public void initSqlSessionFactory() {
834         if (sqlSessionFactory == null) {
835             InputStream inputStream = null;
836             try {
837                 inputStream = getMyBatisXmlConfigurationStream();
838
839                 Environment environment = new Environment("default", transactionFactory, dataSource);
840                 Reader reader = new InputStreamReader(inputStream);
841                 Properties properties = new Properties();
842                 properties.put("prefix", databaseTablePrefix);
843
844                 String wildcardEscapeClause = "";
845                 if ((databaseWildcardEscapeCharacter != null) && (databaseWildcardEscapeCharacter.length() != 0)) {
846                     wildcardEscapeClause = " escape '" + databaseWildcardEscapeCharacter + "'";
847                 }
848                 properties.put("wildcardEscapeClause", wildcardEscapeClause);
849
850                 // set default properties
851                 properties.put("limitBefore", "");
852                 properties.put("limitAfter", "");
853                 properties.put("limitBetween", "");
854                 properties.put("limitBeforeNativeQuery", "");
855                 properties.put("limitAfterNativeQuery", "");
856                 properties.put("blobType", "BLOB");
857                 properties.put("boolValue", "TRUE");
858
859                 if (databaseType != null) {
860                     properties.load(getResourceAsStream(pathToEngineDbProperties()));
861                 }
862
863                 Configuration configuration = initMybatisConfiguration(environment, reader, properties);
864                 sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
865
866             } catch (Exception e) {
867                 throw new FlowableException("Error while building ibatis SqlSessionFactory: " + e.getMessage(), e);
868             } finally {
869                 IoUtil.closeSilently(inputStream);
870             }
871         } else {
872             // This is needed when the SQL Session Factory is created by another engine.
873             // When custom XML Mappers are registered with this engine they need to be loaded in the configuration as well
874             applyCustomMybatisCustomizations(sqlSessionFactory.getConfiguration());
875         }
876     }
877
878     public String pathToEngineDbProperties() {
879         return "org/flowable/common/db/properties/" + databaseType + ".properties";
880     }
881
882     public Configuration initMybatisConfiguration(Environment environment, Reader reader, Properties properties) {
883         XMLConfigBuilder parser = new XMLConfigBuilder(reader, "", properties);
884         Configuration configuration = parser.getConfiguration();
885
886         if (databaseType != null) {
887             configuration.setDatabaseId(databaseType);
888         }
889
890         configuration.setEnvironment(environment);
891
892         initMybatisTypeHandlers(configuration);
893         initCustomMybatisInterceptors(configuration);
894         if (isEnableLogSqlExecutionTime()) {
895             initMyBatisLogSqlExecutionTimePlugin(configuration);
896         }
897
898         configuration = parseMybatisConfiguration(parser);
899         return configuration;
900     }
901
902     public void initCustomMybatisMappers(Configuration configuration) {
903         if (getCustomMybatisMappers() != null) {
904             for (Class<?> clazz : getCustomMybatisMappers()) {
905                 if (!configuration.hasMapper(clazz)) {
906                     configuration.addMapper(clazz);
907                 }
908             }
909         }
910     }
911
912     public void initMybatisTypeHandlers(Configuration configuration) {
913         // When mapping into Map<String, Object> there is currently a problem with MyBatis.
914         // It will return objects which are driver specific.
915         // Therefore we are registering the mappings between Object.class and the specific jdbc type here.
916         // see https://github.com/mybatis/mybatis-3/issues/2216 for more info
917         TypeHandlerRegistry handlerRegistry = configuration.getTypeHandlerRegistry();
918
919         handlerRegistry.register(Object.class, JdbcType.BOOLEAN, new BooleanTypeHandler());
920         handlerRegistry.register(Object.class, JdbcType.BIT, new BooleanTypeHandler());
921
922         handlerRegistry.register(Object.class, JdbcType.TINYINT, new ByteTypeHandler());
923
924         handlerRegistry.register(Object.class, JdbcType.SMALLINT, new ShortTypeHandler());
925
926         handlerRegistry.register(Object.class, JdbcType.INTEGER, new IntegerTypeHandler());
927
928         handlerRegistry.register(Object.class, JdbcType.FLOAT, new FloatTypeHandler());
929
930         handlerRegistry.register(Object.class, JdbcType.DOUBLE, new DoubleTypeHandler());
931
932         handlerRegistry.register(Object.class, JdbcType.CHAR, new StringTypeHandler());
933         handlerRegistry.register(Object.class, JdbcType.CLOB, new ClobTypeHandler());
934         handlerRegistry.register(Object.class, JdbcType.VARCHAR, new StringTypeHandler());
935         handlerRegistry.register(Object.class, JdbcType.LONGVARCHAR, new StringTypeHandler());
936         handlerRegistry.register(Object.class, JdbcType.NVARCHAR, new NStringTypeHandler());
937         handlerRegistry.register(Object.class, JdbcType.NCHAR, new NStringTypeHandler());
938         handlerRegistry.register(Object.class, JdbcType.NCLOB, new NClobTypeHandler());
939
940         handlerRegistry.register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
941
942         handlerRegistry.register(Object.class, JdbcType.BIGINT, new LongTypeHandler());
943
944         handlerRegistry.register(Object.class, JdbcType.REAL, new BigDecimalTypeHandler());
945         handlerRegistry.register(Object.class, JdbcType.DECIMAL, new BigDecimalTypeHandler());
946         handlerRegistry.register(Object.class, JdbcType.NUMERIC, new BigDecimalTypeHandler());
947
948         handlerRegistry.register(Object.class, JdbcType.BLOB, new BlobInputStreamTypeHandler());
949         handlerRegistry.register(Object.class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
950
951         handlerRegistry.register(Object.class, JdbcType.DATE, new DateOnlyTypeHandler());
952         handlerRegistry.register(Object.class, JdbcType.TIME, new TimeOnlyTypeHandler());
953         handlerRegistry.register(Object.class, JdbcType.TIMESTAMP, new DateTypeHandler());
954
955         handlerRegistry.register(Object.class, JdbcType.SQLXML, new SqlxmlTypeHandler());
956     }
957
958     public void initCustomMybatisInterceptors(Configuration configuration) {
959         if (customMybatisInterceptors!=null){
960             for (Interceptor interceptor :customMybatisInterceptors){
961                 configuration.addInterceptor(interceptor);
962             }
963         }
964     }
965
966     public void initMyBatisLogSqlExecutionTimePlugin(Configuration configuration) {
967         configuration.addInterceptor(new LogSqlExecutionTimePlugin());
968     }
969
970     public Configuration parseMybatisConfiguration(XMLConfigBuilder parser) {
971         Configuration configuration = parser.parse();
972
973         applyCustomMybatisCustomizations(configuration);
974         return configuration;
975     }
976
977     protected void applyCustomMybatisCustomizations(Configuration configuration) {
978         initCustomMybatisMappers(configuration);
979
980         if (dependentEngineMybatisTypeAliasConfigs != null) {
981             for (MybatisTypeAliasConfigurator typeAliasConfig : dependentEngineMybatisTypeAliasConfigs) {
982                 typeAliasConfig.configure(configuration.getTypeAliasRegistry());
983             }
984         }
985         if (dependentEngineMybatisTypeHandlerConfigs != null) {
986             for (MybatisTypeHandlerConfigurator typeHandlerConfig : dependentEngineMybatisTypeHandlerConfigs) {
987                 typeHandlerConfig.configure(configuration.getTypeHandlerRegistry());
988             }
989         }
990
991         parseDependentEngineMybatisXMLMappers(configuration);
992         parseCustomMybatisXMLMappers(configuration);
993     }
994
995     public void parseCustomMybatisXMLMappers(Configuration configuration) {
996         if (getCustomMybatisXMLMappers() != null) {
997             for (String resource : getCustomMybatisXMLMappers()) {
998                 parseMybatisXmlMapping(configuration, resource);
999             }
1000         }
1001     }
1002
1003     public void parseDependentEngineMybatisXMLMappers(Configuration configuration) {
1004         if (getDependentEngineMyBatisXmlMappers() != null) {
1005             for (String resource : getDependentEngineMyBatisXmlMappers()) {
1006                 parseMybatisXmlMapping(configuration, resource);
1007             }
1008         }
1009     }
1010
1011     protected void parseMybatisXmlMapping(Configuration configuration, String resource) {
1012         // see XMLConfigBuilder.mapperElement()
1013         XMLMapperBuilder mapperParser = new XMLMapperBuilder(getResourceAsStream(resource), configuration, resource, configuration.getSqlFragments());
1014         mapperParser.parse();
1015     }
1016
1017     protected InputStream getResourceAsStream(String resource) {
1018         ClassLoader classLoader = getClassLoader();
1019         if (classLoader != null) {
1020             return getClassLoader().getResourceAsStream(resource);
1021         } else {
1022             return this.getClass().getClassLoader().getResourceAsStream(resource);
1023         }
1024     }
1025
1026     public void setMybatisMappingFile(String file) {
1027         this.mybatisMappingFile = file;
1028     }
1029
1030     public String getMybatisMappingFile() {
1031         return mybatisMappingFile;
1032     }
1033
1034     public abstract InputStream getMyBatisXmlConfigurationStream();
1035
1036     public void initConfigurators() {
1037
1038         allConfigurators = new ArrayList<>();
1039         allConfigurators.addAll(getEngineSpecificEngineConfigurators());
1040
1041         // Configurators that are explicitly added to the config
1042         if (configurators != null) {
1043             allConfigurators.addAll(configurators);
1044         }
1045
1046         // Auto discovery through ServiceLoader
1047         if (enableConfiguratorServiceLoader) {
1048             ClassLoader classLoader = getClassLoader();
1049             if (classLoader == null) {
1050                 classLoader = ReflectUtil.getClassLoader();
1051             }
1052
1053             ServiceLoader<EngineConfigurator> configuratorServiceLoader = ServiceLoader.load(EngineConfigurator.class, classLoader);
1054             int nrOfServiceLoadedConfigurators = 0;
1055             for (EngineConfigurator configurator : configuratorServiceLoader) {
1056                 allConfigurators.add(configurator);
1057                 nrOfServiceLoadedConfigurators++;
1058             }
1059
1060             if (nrOfServiceLoadedConfigurators > 0) {
1061                 logger.info("Found {} auto-discoverable Process Engine Configurator{}", nrOfServiceLoadedConfigurators, nrOfServiceLoadedConfigurators > 1 ? "s" : "");
1062             }
1063
1064             if (!allConfigurators.isEmpty()) {
1065
1066                 // Order them according to the priorities (useful for dependent
1067                 // configurator)
1068                 allConfigurators.sort(new Comparator<EngineConfigurator>() {
1069
1070                     @Override
1071                     public int compare(EngineConfigurator configurator1, EngineConfigurator configurator2) {
1072                         int priority1 = configurator1.getPriority();
1073                         int priority2 = configurator2.getPriority();
1074
1075                         if (priority1 < priority2) {
1076                             return -1;
1077                         } else if (priority1 > priority2) {
1078                             return 1;
1079                         }
1080                         return 0;
1081                     }
1082                 });
1083
1084                 // Execute the configurators
1085                 logger.info("Found {} Engine Configurators in total:", allConfigurators.size());
1086                 for (EngineConfigurator configurator : allConfigurators) {
1087                     logger.info("{} (priority:{})", configurator.getClass(), configurator.getPriority());
1088                 }
1089
1090             }
1091
1092         }
1093     }
1094
1095     public void close() {
1096         if (forceCloseMybatisConnectionPool && dataSource instanceof PooledDataSource) {
1097             /*
1098              * When the datasource is created by a Flowable engine (i.e. it's an instance of PooledDataSource),
1099              * the connection pool needs to be closed when closing the engine.
1100              * Note that calling forceCloseAll() multiple times (as is the case when running with multiple engine) is ok.
1101              */
1102             ((PooledDataSource) dataSource).forceCloseAll();
1103         }
1104     }
1105
1106     protected List<EngineConfigurator> getEngineSpecificEngineConfigurators() {
1107         // meant to be overridden if needed
1108         return Collections.emptyList();
1109     }
1110
1111     public void configuratorsBeforeInit() {
1112         for (EngineConfigurator configurator : allConfigurators) {
1113             logger.info("Executing beforeInit() of {} (priority:{})", configurator.getClass(), configurator.getPriority());
1114             configurator.beforeInit(this);
1115         }
1116     }
1117
1118     public void configuratorsAfterInit() {
1119         for (EngineConfigurator configurator : allConfigurators) {
1120             logger.info("Executing configure() of {} (priority:{})", configurator.getClass(), configurator.getPriority());
1121             configurator.configure(this);
1122         }
1123     }
1124
1125     public LockManager getLockManager(String lockName) {
1126         return new LockManagerImpl(commandExecutor, lockName, getLockPollRate(), getEngineCfgKey());
1127     }
1128
1129     // getters and setters
1130     // //////////////////////////////////////////////////////
1131
1132     public abstract String getEngineName();
1133
1134     public ClassLoader getClassLoader() {
1135         return classLoader;
1136     }
1137
1138     public AbstractEngineConfiguration setClassLoader(ClassLoader classLoader) {
1139         this.classLoader = classLoader;
1140         return this;
1141     }
1142
1143     public boolean isUseClassForNameClassLoading() {
1144         return useClassForNameClassLoading;
1145     }
1146
1147     public AbstractEngineConfiguration setUseClassForNameClassLoading(boolean useClassForNameClassLoading) {
1148         this.useClassForNameClassLoading = useClassForNameClassLoading;
1149         return this;
1150     }
1151
1152     public void addEngineLifecycleListener(EngineLifecycleListener engineLifecycleListener) {
1153         if (this.engineLifecycleListeners == null) {
1154             this.engineLifecycleListeners = new ArrayList<>();
1155         }
1156         this.engineLifecycleListeners.add(engineLifecycleListener);
1157     }
1158
1159     public List<EngineLifecycleListener> getEngineLifecycleListeners() {
1160         return engineLifecycleListeners;
1161     }
1162
1163     public AbstractEngineConfiguration setEngineLifecycleListeners(List<EngineLifecycleListener> engineLifecycleListeners) {
1164         this.engineLifecycleListeners = engineLifecycleListeners;
1165         return this;
1166     }
1167
1168     public String getDatabaseType() {
1169         return databaseType;
1170     }
1171
1172     public AbstractEngineConfiguration setDatabaseType(String databaseType) {
1173         this.databaseType = databaseType;
1174         return this;
1175     }
1176
1177     public DataSource getDataSource() {
1178         return dataSource;
1179     }
1180
1181     public AbstractEngineConfiguration setDataSource(DataSource dataSource) {
1182         this.dataSource = dataSource;
1183         return this;
1184     }
1185
1186     public SchemaManager getSchemaManager() {
1187         return schemaManager;
1188     }
1189
1190     public AbstractEngineConfiguration setSchemaManager(SchemaManager schemaManager) {
1191         this.schemaManager = schemaManager;
1192         return this;
1193     }
1194
1195     public SchemaManager getCommonSchemaManager() {
1196         return commonSchemaManager;
1197     }
1198
1199     public AbstractEngineConfiguration setCommonSchemaManager(SchemaManager commonSchemaManager) {
1200         this.commonSchemaManager = commonSchemaManager;
1201         return this;
1202     }
1203
1204     public Command<Void> getSchemaManagementCmd() {
1205         return schemaManagementCmd;
1206     }
1207
1208     public AbstractEngineConfiguration setSchemaManagementCmd(Command<Void> schemaManagementCmd) {
1209         this.schemaManagementCmd = schemaManagementCmd;
1210         return this;
1211     }
1212
1213     public String getJdbcDriver() {
1214         return jdbcDriver;
1215     }
1216
1217     public AbstractEngineConfiguration setJdbcDriver(String jdbcDriver) {
1218         this.jdbcDriver = jdbcDriver;
1219         return this;
1220     }
1221
1222     public String getJdbcUrl() {
1223         return jdbcUrl;
1224     }
1225
1226     public AbstractEngineConfiguration setJdbcUrl(String jdbcUrl) {
1227         this.jdbcUrl = jdbcUrl;
1228         return this;
1229     }
1230
1231     public String getJdbcUsername() {
1232         return jdbcUsername;
1233     }
1234
1235     public AbstractEngineConfiguration setJdbcUsername(String jdbcUsername) {
1236         this.jdbcUsername = jdbcUsername;
1237         return this;
1238     }
1239
1240     public String getJdbcPassword() {
1241         return jdbcPassword;
1242     }
1243
1244     public AbstractEngineConfiguration setJdbcPassword(String jdbcPassword) {
1245         this.jdbcPassword = jdbcPassword;
1246         return this;
1247     }
1248
1249     public int getJdbcMaxActiveConnections() {
1250         return jdbcMaxActiveConnections;
1251     }
1252
1253     public AbstractEngineConfiguration setJdbcMaxActiveConnections(int jdbcMaxActiveConnections) {
1254         this.jdbcMaxActiveConnections = jdbcMaxActiveConnections;
1255         return this;
1256     }
1257
1258     public int getJdbcMaxIdleConnections() {
1259         return jdbcMaxIdleConnections;
1260     }
1261
1262     public AbstractEngineConfiguration setJdbcMaxIdleConnections(int jdbcMaxIdleConnections) {
1263         this.jdbcMaxIdleConnections = jdbcMaxIdleConnections;
1264         return this;
1265     }
1266
1267     public int getJdbcMaxCheckoutTime() {
1268         return jdbcMaxCheckoutTime;
1269     }
1270
1271     public AbstractEngineConfiguration setJdbcMaxCheckoutTime(int jdbcMaxCheckoutTime) {
1272         this.jdbcMaxCheckoutTime = jdbcMaxCheckoutTime;
1273         return this;
1274     }
1275
1276     public int getJdbcMaxWaitTime() {
1277         return jdbcMaxWaitTime;
1278     }
1279
1280     public AbstractEngineConfiguration setJdbcMaxWaitTime(int jdbcMaxWaitTime) {
1281         this.jdbcMaxWaitTime = jdbcMaxWaitTime;
1282         return this;
1283     }
1284
1285     public boolean isJdbcPingEnabled() {
1286         return jdbcPingEnabled;
1287     }
1288
1289     public AbstractEngineConfiguration setJdbcPingEnabled(boolean jdbcPingEnabled) {
1290         this.jdbcPingEnabled = jdbcPingEnabled;
1291         return this;
1292     }
1293
1294     public int getJdbcPingConnectionNotUsedFor() {
1295         return jdbcPingConnectionNotUsedFor;
1296     }
1297
1298     public AbstractEngineConfiguration setJdbcPingConnectionNotUsedFor(int jdbcPingConnectionNotUsedFor) {
1299         this.jdbcPingConnectionNotUsedFor = jdbcPingConnectionNotUsedFor;
1300         return this;
1301     }
1302
1303     public int getJdbcDefaultTransactionIsolationLevel() {
1304         return jdbcDefaultTransactionIsolationLevel;
1305     }
1306
1307     public AbstractEngineConfiguration setJdbcDefaultTransactionIsolationLevel(int jdbcDefaultTransactionIsolationLevel) {
1308         this.jdbcDefaultTransactionIsolationLevel = jdbcDefaultTransactionIsolationLevel;
1309         return this;
1310     }
1311
1312     public String getJdbcPingQuery() {
1313         return jdbcPingQuery;
1314     }
1315
1316     public AbstractEngineConfiguration setJdbcPingQuery(String jdbcPingQuery) {
1317         this.jdbcPingQuery = jdbcPingQuery;
1318         return this;
1319     }
1320
1321     public String getDataSourceJndiName() {
1322         return dataSourceJndiName;
1323     }
1324
1325     public AbstractEngineConfiguration setDataSourceJndiName(String dataSourceJndiName) {
1326         this.dataSourceJndiName = dataSourceJndiName;
1327         return this;
1328     }
1329
1330     public CommandConfig getSchemaCommandConfig() {
1331         return schemaCommandConfig;
1332     }
1333
1334     public AbstractEngineConfiguration setSchemaCommandConfig(CommandConfig schemaCommandConfig) {
1335         this.schemaCommandConfig = schemaCommandConfig;
1336         return this;
1337     }
1338
1339     public boolean isTransactionsExternallyManaged() {
1340         return transactionsExternallyManaged;
1341     }
1342
1343     public AbstractEngineConfiguration setTransactionsExternallyManaged(boolean transactionsExternallyManaged) {
1344         this.transactionsExternallyManaged = transactionsExternallyManaged;
1345         return this;
1346     }
1347
1348     public Map<Object, Object> getBeans() {
1349         return beans;
1350     }
1351
1352     public AbstractEngineConfiguration setBeans(Map<Object, Object> beans) {
1353         this.beans = beans;
1354         return this;
1355     }
1356
1357     public IdGenerator getIdGenerator() {
1358         return idGenerator;
1359     }
1360
1361     public AbstractEngineConfiguration setIdGenerator(IdGenerator idGenerator) {
1362         this.idGenerator = idGenerator;
1363         return this;
1364     }
1365
1366     public boolean isUsePrefixId() {
1367         return usePrefixId;
1368     }
1369
1370     public AbstractEngineConfiguration setUsePrefixId(boolean usePrefixId) {
1371         this.usePrefixId = usePrefixId;
1372         return this;
1373     }
1374
1375     public String getXmlEncoding() {
1376         return xmlEncoding;
1377     }
1378
1379     public AbstractEngineConfiguration setXmlEncoding(String xmlEncoding) {
1380         this.xmlEncoding = xmlEncoding;
1381         return this;
1382     }
1383
1384     public CommandConfig getDefaultCommandConfig() {
1385         return defaultCommandConfig;
1386     }
1387
1388     public AbstractEngineConfiguration setDefaultCommandConfig(CommandConfig defaultCommandConfig) {
1389         this.defaultCommandConfig = defaultCommandConfig;
1390         return this;
1391     }
1392
1393     public CommandExecutor getCommandExecutor() {
1394         return commandExecutor;
1395     }
1396
1397     public AbstractEngineConfiguration setCommandExecutor(CommandExecutor commandExecutor) {
1398         this.commandExecutor = commandExecutor;
1399         return this;
1400     }
1401
1402     public CommandContextFactory getCommandContextFactory() {
1403         return commandContextFactory;
1404     }
1405
1406     public AbstractEngineConfiguration setCommandContextFactory(CommandContextFactory commandContextFactory) {
1407         this.commandContextFactory = commandContextFactory;
1408         return this;
1409     }
1410
1411     public CommandInterceptor getCommandInvoker() {
1412         return commandInvoker;
1413     }
1414
1415     public AbstractEngineConfiguration setCommandInvoker(CommandInterceptor commandInvoker) {
1416         this.commandInvoker = commandInvoker;
1417         return this;
1418     }
1419
1420     public AgendaOperationRunner getAgendaOperationRunner() {
1421         return agendaOperationRunner;
1422     }
1423
1424     public AbstractEngineConfiguration setAgendaOperationRunner(AgendaOperationRunner agendaOperationRunner) {
1425         this.agendaOperationRunner = agendaOperationRunner;
1426         return this;
1427     }
1428
1429     public List<CommandInterceptor> getCustomPreCommandInterceptors() {
1430         return customPreCommandInterceptors;
1431     }
1432
1433     public AbstractEngineConfiguration setCustomPreCommandInterceptors(List<CommandInterceptor> customPreCommandInterceptors) {
1434         this.customPreCommandInterceptors = customPreCommandInterceptors;
1435         return this;
1436     }
1437
1438     public List<CommandInterceptor> getCustomPostCommandInterceptors() {
1439         return customPostCommandInterceptors;
1440     }
1441
1442     public AbstractEngineConfiguration setCustomPostCommandInterceptors(List<CommandInterceptor> customPostCommandInterceptors) {
1443         this.customPostCommandInterceptors = customPostCommandInterceptors;
1444         return this;
1445     }
1446
1447     public List<CommandInterceptor> getCommandInterceptors() {
1448         return commandInterceptors;
1449     }
1450
1451     public AbstractEngineConfiguration setCommandInterceptors(List<CommandInterceptor> commandInterceptors) {
1452         this.commandInterceptors = commandInterceptors;
1453         return this;
1454     }
1455
1456     public Map<String, AbstractEngineConfiguration> getEngineConfigurations() {
1457         return engineConfigurations;
1458     }
1459
1460     public AbstractEngineConfiguration setEngineConfigurations(Map<String, AbstractEngineConfiguration> engineConfigurations) {
1461         this.engineConfigurations = engineConfigurations;
1462         return this;
1463     }
1464
1465     public void addEngineConfiguration(String key, String scopeType, AbstractEngineConfiguration engineConfiguration) {
1466         if (engineConfigurations == null) {
1467             engineConfigurations = new HashMap<>();
1468         }
1469         engineConfigurations.put(key, engineConfiguration);
1470         engineConfigurations.put(scopeType, engineConfiguration);
1471     }
1472
1473     public Map<String, AbstractServiceConfiguration> getServiceConfigurations() {
1474         return serviceConfigurations;
1475     }
1476
1477     public AbstractEngineConfiguration setServiceConfigurations(Map<String, AbstractServiceConfiguration> serviceConfigurations) {
1478         this.serviceConfigurations = serviceConfigurations;
1479         return this;
1480     }
1481
1482     public void addServiceConfiguration(String key, AbstractServiceConfiguration serviceConfiguration) {
1483         if (serviceConfigurations == null) {
1484             serviceConfigurations = new HashMap<>();
1485         }
1486         serviceConfigurations.put(key, serviceConfiguration);
1487     }
1488
1489     public Map<String, EventRegistryEventConsumer> getEventRegistryEventConsumers() {
1490         return eventRegistryEventConsumers;
1491     }
1492
1493     public AbstractEngineConfiguration setEventRegistryEventConsumers(Map<String, EventRegistryEventConsumer> eventRegistryEventConsumers) {
1494         this.eventRegistryEventConsumers = eventRegistryEventConsumers;
1495         return this;
1496     }
1497
1498     public void addEventRegistryEventConsumer(String key, EventRegistryEventConsumer eventRegistryEventConsumer) {
1499         if (eventRegistryEventConsumers == null) {
1500             eventRegistryEventConsumers = new HashMap<>();
1501         }
1502         eventRegistryEventConsumers.put(key, eventRegistryEventConsumer);
1503     }
1504
1505     public AbstractEngineConfiguration setDefaultCommandInterceptors(Collection<? extends CommandInterceptor> defaultCommandInterceptors) {
1506         this.defaultCommandInterceptors = defaultCommandInterceptors;
1507         return this;
1508     }
1509
1510     public SqlSessionFactory getSqlSessionFactory() {
1511         return sqlSessionFactory;
1512     }
1513
1514     public AbstractEngineConfiguration setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
1515         this.sqlSessionFactory = sqlSessionFactory;
1516         return this;
1517     }
1518
1519     public boolean isDbHistoryUsed() {
1520         return isDbHistoryUsed;
1521     }
1522
1523     public AbstractEngineConfiguration setDbHistoryUsed(boolean isDbHistoryUsed) {
1524         this.isDbHistoryUsed = isDbHistoryUsed;
1525         return this;
1526     }
1527
1528     public DbSqlSessionFactory getDbSqlSessionFactory() {
1529         return dbSqlSessionFactory;
1530     }
1531
1532     public AbstractEngineConfiguration setDbSqlSessionFactory(DbSqlSessionFactory dbSqlSessionFactory) {
1533         this.dbSqlSessionFactory = dbSqlSessionFactory;
1534         return this;
1535     }
1536
1537     public TransactionFactory getTransactionFactory() {
1538         return transactionFactory;
1539     }
1540
1541     public AbstractEngineConfiguration setTransactionFactory(TransactionFactory transactionFactory) {
1542         this.transactionFactory = transactionFactory;
1543         return this;
1544     }
1545
1546     public TransactionContextFactory getTransactionContextFactory() {
1547         return transactionContextFactory;
1548     }
1549
1550     public AbstractEngineConfiguration setTransactionContextFactory(TransactionContextFactory transactionContextFactory) {
1551         this.transactionContextFactory = transactionContextFactory;
1552         return this;
1553     }
1554
1555     public int getMaxNrOfStatementsInBulkInsert() {
1556         return maxNrOfStatementsInBulkInsert;
1557     }
1558
1559     public AbstractEngineConfiguration setMaxNrOfStatementsInBulkInsert(int maxNrOfStatementsInBulkInsert) {
1560         this.maxNrOfStatementsInBulkInsert = maxNrOfStatementsInBulkInsert;
1561         return this;
1562     }
1563
1564     public boolean isBulkInsertEnabled() {
1565         return isBulkInsertEnabled;
1566     }
1567
1568     public AbstractEngineConfiguration setBulkInsertEnabled(boolean isBulkInsertEnabled) {
1569         this.isBulkInsertEnabled = isBulkInsertEnabled;
1570         return this;
1571     }
1572
1573     public Set<Class<?>> getCustomMybatisMappers() {
1574         return customMybatisMappers;
1575     }
1576
1577     public AbstractEngineConfiguration setCustomMybatisMappers(Set<Class<?>> customMybatisMappers) {
1578         this.customMybatisMappers = customMybatisMappers;
1579         return this;
1580     }
1581
1582     public Set<String> getCustomMybatisXMLMappers() {
1583         return customMybatisXMLMappers;
1584     }
1585
1586     public AbstractEngineConfiguration setCustomMybatisXMLMappers(Set<String> customMybatisXMLMappers) {
1587         this.customMybatisXMLMappers = customMybatisXMLMappers;
1588         return this;
1589     }
1590
1591     public Set<String> getDependentEngineMyBatisXmlMappers() {
1592         return dependentEngineMyBatisXmlMappers;
1593     }
1594
1595     public AbstractEngineConfiguration setCustomMybatisInterceptors(List<Interceptor> customMybatisInterceptors) {
1596         this.customMybatisInterceptors = customMybatisInterceptors;
1597         return  this;
1598     }
1599
1600     public List<Interceptor> getCustomMybatisInterceptors() {
1601         return customMybatisInterceptors;
1602     }
1603
1604     public AbstractEngineConfiguration setDependentEngineMyBatisXmlMappers(Set<String> dependentEngineMyBatisXmlMappers) {
1605         this.dependentEngineMyBatisXmlMappers = dependentEngineMyBatisXmlMappers;
1606         return this;
1607     }
1608
1609     public List<MybatisTypeAliasConfigurator> getDependentEngineMybatisTypeAliasConfigs() {
1610         return dependentEngineMybatisTypeAliasConfigs;
1611     }
1612
1613     public AbstractEngineConfiguration setDependentEngineMybatisTypeAliasConfigs(List<MybatisTypeAliasConfigurator> dependentEngineMybatisTypeAliasConfigs) {
1614         this.dependentEngineMybatisTypeAliasConfigs = dependentEngineMybatisTypeAliasConfigs;
1615         return this;
1616     }
1617
1618     public List<MybatisTypeHandlerConfigurator> getDependentEngineMybatisTypeHandlerConfigs() {
1619         return dependentEngineMybatisTypeHandlerConfigs;
1620     }
1621
1622     public AbstractEngineConfiguration setDependentEngineMybatisTypeHandlerConfigs(List<MybatisTypeHandlerConfigurator> dependentEngineMybatisTypeHandlerConfigs) {
1623         this.dependentEngineMybatisTypeHandlerConfigs = dependentEngineMybatisTypeHandlerConfigs;
1624         return this;
1625     }
1626
1627     public List<SessionFactory> getCustomSessionFactories() {
1628         return customSessionFactories;
1629     }
1630
1631     public AbstractEngineConfiguration addCustomSessionFactory(SessionFactory sessionFactory) {
1632         if (customSessionFactories == null) {
1633             customSessionFactories = new ArrayList<>();
1634         }
1635         customSessionFactories.add(sessionFactory);
1636         return this;
1637     }
1638
1639     public AbstractEngineConfiguration setCustomSessionFactories(List<SessionFactory> customSessionFactories) {
1640         this.customSessionFactories = customSessionFactories;
1641         return this;
1642     }
1643
1644     public boolean isUsingRelationalDatabase() {
1645         return usingRelationalDatabase;
1646     }
1647
1648     public AbstractEngineConfiguration setUsingRelationalDatabase(boolean usingRelationalDatabase) {
1649         this.usingRelationalDatabase = usingRelationalDatabase;
1650         return this;
1651     }
1652
1653     public boolean isUsingSchemaMgmt() {
1654         return usingSchemaMgmt;
1655     }
1656
1657     public AbstractEngineConfiguration setUsingSchemaMgmt(boolean usingSchema) {
1658         this.usingSchemaMgmt = usingSchema;
1659         return this;
1660     }
1661
1662     public String getDatabaseTablePrefix() {
1663         return databaseTablePrefix;
1664     }
1665
1666     public AbstractEngineConfiguration setDatabaseTablePrefix(String databaseTablePrefix) {
1667         this.databaseTablePrefix = databaseTablePrefix;
1668         return this;
1669     }
1670
1671     public String getDatabaseWildcardEscapeCharacter() {
1672         return databaseWildcardEscapeCharacter;
1673     }
1674
1675     public AbstractEngineConfiguration setDatabaseWildcardEscapeCharacter(String databaseWildcardEscapeCharacter) {
1676         this.databaseWildcardEscapeCharacter = databaseWildcardEscapeCharacter;
1677         return this;
1678     }
1679
1680     public String getDatabaseCatalog() {
1681         return databaseCatalog;
1682     }
1683
1684     public AbstractEngineConfiguration setDatabaseCatalog(String databaseCatalog) {
1685         this.databaseCatalog = databaseCatalog;
1686         return this;
1687     }
1688
1689     public String getDatabaseSchema() {
1690         return databaseSchema;
1691     }
1692
1693     public AbstractEngineConfiguration setDatabaseSchema(String databaseSchema) {
1694         this.databaseSchema = databaseSchema;
1695         return this;
1696     }
1697
1698     public boolean isTablePrefixIsSchema() {
1699         return tablePrefixIsSchema;
1700     }
1701
1702     public AbstractEngineConfiguration setTablePrefixIsSchema(boolean tablePrefixIsSchema) {
1703         this.tablePrefixIsSchema = tablePrefixIsSchema;
1704         return this;
1705     }
1706
1707     public boolean isAlwaysLookupLatestDefinitionVersion() {
1708         return alwaysLookupLatestDefinitionVersion;
1709     }
1710
1711     public AbstractEngineConfiguration setAlwaysLookupLatestDefinitionVersion(boolean alwaysLookupLatestDefinitionVersion) {
1712         this.alwaysLookupLatestDefinitionVersion = alwaysLookupLatestDefinitionVersion;
1713         return this;
1714     }
1715
1716     public boolean isFallbackToDefaultTenant() {
1717         return fallbackToDefaultTenant;
1718     }
1719
1720     public AbstractEngineConfiguration setFallbackToDefaultTenant(boolean fallbackToDefaultTenant) {
1721         this.fallbackToDefaultTenant = fallbackToDefaultTenant;
1722         return this;
1723     }
1724
1725     /**
1726      * @return name of the default tenant
1727      * @deprecated use {@link AbstractEngineConfiguration#getDefaultTenantProvider()} instead
1728      */
1729     @Deprecated
1730     public String getDefaultTenantValue() {
1731         return getDefaultTenantProvider().getDefaultTenant(null, null, null);
1732     }
1733
1734     public AbstractEngineConfiguration setDefaultTenantValue(String defaultTenantValue) {
1735         this.defaultTenantProvider = (tenantId, scope, scopeKey) -> defaultTenantValue;
1736         return this;
1737     }
1738
1739     public DefaultTenantProvider getDefaultTenantProvider() {
1740         return defaultTenantProvider;
1741     }
1742
1743     public AbstractEngineConfiguration setDefaultTenantProvider(DefaultTenantProvider defaultTenantProvider) {
1744         this.defaultTenantProvider = defaultTenantProvider;
1745         return this;
1746     }
1747
1748     public boolean isEnableLogSqlExecutionTime() {
1749         return enableLogSqlExecutionTime;
1750     }
1751
1752     public void setEnableLogSqlExecutionTime(boolean enableLogSqlExecutionTime) {
1753         this.enableLogSqlExecutionTime = enableLogSqlExecutionTime;
1754     }
1755
1756     public Map<Class<?>, SessionFactory> getSessionFactories() {
1757         return sessionFactories;
1758     }
1759
1760     public AbstractEngineConfiguration setSessionFactories(Map<Class<?>, SessionFactory> sessionFactories) {
1761         this.sessionFactories = sessionFactories;
1762         return this;
1763     }
1764
1765     public String getDatabaseSchemaUpdate() {
1766         return databaseSchemaUpdate;
1767     }
1768
1769     public AbstractEngineConfiguration setDatabaseSchemaUpdate(String databaseSchemaUpdate) {
1770         this.databaseSchemaUpdate = databaseSchemaUpdate;
1771         return this;
1772     }
1773
1774     public boolean isUseLockForDatabaseSchemaUpdate() {
1775         return useLockForDatabaseSchemaUpdate;
1776     }
1777
1778     public AbstractEngineConfiguration setUseLockForDatabaseSchemaUpdate(boolean useLockForDatabaseSchemaUpdate) {
1779         this.useLockForDatabaseSchemaUpdate = useLockForDatabaseSchemaUpdate;
1780         return this;
1781     }
1782
1783     public boolean isEnableEventDispatcher() {
1784         return enableEventDispatcher;
1785     }
1786
1787     public AbstractEngineConfiguration setEnableEventDispatcher(boolean enableEventDispatcher) {
1788         this.enableEventDispatcher = enableEventDispatcher;
1789         return this;
1790     }
1791
1792     public FlowableEventDispatcher getEventDispatcher() {
1793         return eventDispatcher;
1794     }
1795
1796     public AbstractEngineConfiguration setEventDispatcher(FlowableEventDispatcher eventDispatcher) {
1797         this.eventDispatcher = eventDispatcher;
1798         return this;
1799     }
1800
1801     public List<FlowableEventListener> getEventListeners() {
1802         return eventListeners;
1803     }
1804
1805     public AbstractEngineConfiguration setEventListeners(List<FlowableEventListener> eventListeners) {
1806         this.eventListeners = eventListeners;
1807         return this;
1808     }
1809
1810     public Map<String, List<FlowableEventListener>> getTypedEventListeners() {
1811         return typedEventListeners;
1812     }
1813
1814     public AbstractEngineConfiguration setTypedEventListeners(Map<String, List<FlowableEventListener>> typedEventListeners) {
1815         this.typedEventListeners = typedEventListeners;
1816         return this;
1817     }
1818
1819     public List<EventDispatchAction> getAdditionalEventDispatchActions() {
1820         return additionalEventDispatchActions;
1821     }
1822
1823     public AbstractEngineConfiguration setAdditionalEventDispatchActions(List<EventDispatchAction> additionalEventDispatchActions) {
1824         this.additionalEventDispatchActions = additionalEventDispatchActions;
1825         return this;
1826     }
1827
1828     public void initEventDispatcher() {
1829         if (this.eventDispatcher == null) {
1830             this.eventDispatcher = new FlowableEventDispatcherImpl();
1831         }
1832
1833         initAdditionalEventDispatchActions();
1834
1835         this.eventDispatcher.setEnabled(enableEventDispatcher);
1836
1837         initEventListeners();
1838         initTypedEventListeners();
1839     }
1840
1841     protected void initEventListeners() {
1842         if (eventListeners != null) {
1843             for (FlowableEventListener listenerToAdd : eventListeners) {
1844                 this.eventDispatcher.addEventListener(listenerToAdd);
1845             }
1846         }
1847     }
1848
1849     protected void initAdditionalEventDispatchActions() {
1850         if (this.additionalEventDispatchActions == null) {
1851             this.additionalEventDispatchActions = new ArrayList<>();
1852         }
1853     }
1854
1855     protected void initTypedEventListeners() {
1856         if (typedEventListeners != null) {
1857             for (Map.Entry<String, List<FlowableEventListener>> listenersToAdd : typedEventListeners.entrySet()) {
1858                 // Extract types from the given string
1859                 FlowableEngineEventType[] types = FlowableEngineEventType.getTypesFromString(listenersToAdd.getKey());
1860
1861                 for (FlowableEventListener listenerToAdd : listenersToAdd.getValue()) {
1862                     this.eventDispatcher.addEventListener(listenerToAdd, types);
1863                 }
1864             }
1865         }
1866     }
1867
1868     public boolean isLoggingSessionEnabled() {
1869         return loggingListener != null;
1870     }
1871
1872     public LoggingListener getLoggingListener() {
1873         return loggingListener;
1874     }
1875
1876     public void setLoggingListener(LoggingListener loggingListener) {
1877         this.loggingListener = loggingListener;
1878     }
1879
1880     public Clock getClock() {
1881         return clock;
1882     }
1883
1884     public AbstractEngineConfiguration setClock(Clock clock) {
1885         this.clock = clock;
1886         return this;
1887     }
1888
1889     public ObjectMapper getObjectMapper() {
1890         return objectMapper;
1891     }
1892
1893     public AbstractEngineConfiguration setObjectMapper(ObjectMapper objectMapper) {
1894         this.objectMapper = objectMapper;
1895         return this;
1896     }
1897
1898     public int getMaxLengthString() {
1899         if (maxLengthStringVariableType == -1) {
1900             if ("oracle".equalsIgnoreCase(databaseType)) {
1901                 return DEFAULT_ORACLE_MAX_LENGTH_STRING;
1902             } else {
1903                 return DEFAULT_GENERIC_MAX_LENGTH_STRING;
1904             }
1905         } else {
1906             return maxLengthStringVariableType;
1907         }
1908     }
1909
1910     public int getMaxLengthStringVariableType() {
1911         return maxLengthStringVariableType;
1912     }
1913
1914     public AbstractEngineConfiguration setMaxLengthStringVariableType(int maxLengthStringVariableType) {
1915         this.maxLengthStringVariableType = maxLengthStringVariableType;
1916         return this;
1917     }
1918
1919     public PropertyDataManager getPropertyDataManager() {
1920         return propertyDataManager;
1921     }
1922
1923     public Duration getLockPollRate() {
1924         return lockPollRate;
1925     }
1926
1927     public AbstractEngineConfiguration setLockPollRate(Duration lockPollRate) {
1928         this.lockPollRate = lockPollRate;
1929         return this;
1930     }
1931
1932     public Duration getSchemaLockWaitTime() {
1933         return schemaLockWaitTime;
1934     }
1935
1936     public void setSchemaLockWaitTime(Duration schemaLockWaitTime) {
1937         this.schemaLockWaitTime = schemaLockWaitTime;
1938     }
1939
1940     public AbstractEngineConfiguration setPropertyDataManager(PropertyDataManager propertyDataManager) {
1941         this.propertyDataManager = propertyDataManager;
1942         return this;
1943     }
1944
1945     public PropertyEntityManager getPropertyEntityManager() {
1946         return propertyEntityManager;
1947     }
1948
1949     public AbstractEngineConfiguration setPropertyEntityManager(PropertyEntityManager propertyEntityManager) {
1950         this.propertyEntityManager = propertyEntityManager;
1951         return this;
1952     }
1953
1954     public ByteArrayDataManager getByteArrayDataManager() {
1955         return byteArrayDataManager;
1956     }
1957
1958     public AbstractEngineConfiguration setByteArrayDataManager(ByteArrayDataManager byteArrayDataManager) {
1959         this.byteArrayDataManager = byteArrayDataManager;
1960         return this;
1961     }
1962
1963     public ByteArrayEntityManager getByteArrayEntityManager() {
1964         return byteArrayEntityManager;
1965     }
1966
1967     public AbstractEngineConfiguration setByteArrayEntityManager(ByteArrayEntityManager byteArrayEntityManager) {
1968         this.byteArrayEntityManager = byteArrayEntityManager;
1969         return this;
1970     }
1971
1972     public TableDataManager getTableDataManager() {
1973         return tableDataManager;
1974     }
1975
1976     public AbstractEngineConfiguration setTableDataManager(TableDataManager tableDataManager) {
1977         this.tableDataManager = tableDataManager;
1978         return this;
1979     }
1980
1981     public List<EngineDeployer> getDeployers() {
1982         return deployers;
1983     }
1984
1985     public AbstractEngineConfiguration setDeployers(List<EngineDeployer> deployers) {
1986         this.deployers = deployers;
1987         return this;
1988     }
1989
1990     public List<EngineDeployer> getCustomPreDeployers() {
1991         return customPreDeployers;
1992     }
1993
1994     public AbstractEngineConfiguration setCustomPreDeployers(List<EngineDeployer> customPreDeployers) {
1995         this.customPreDeployers = customPreDeployers;
1996         return this;
1997     }
1998
1999     public List<EngineDeployer> getCustomPostDeployers() {
2000         return customPostDeployers;
2001     }
2002
2003     public AbstractEngineConfiguration setCustomPostDeployers(List<EngineDeployer> customPostDeployers) {
2004         this.customPostDeployers = customPostDeployers;
2005         return this;
2006     }
2007
2008     public boolean isEnableConfiguratorServiceLoader() {
2009         return enableConfiguratorServiceLoader;
2010     }
2011
2012     public AbstractEngineConfiguration setEnableConfiguratorServiceLoader(boolean enableConfiguratorServiceLoader) {
2013         this.enableConfiguratorServiceLoader = enableConfiguratorServiceLoader;
2014         return this;
2015     }
2016
2017     public List<EngineConfigurator> getConfigurators() {
2018         return configurators;
2019     }
2020
2021     public AbstractEngineConfiguration addConfigurator(EngineConfigurator configurator) {
2022         if (configurators == null) {
2023             configurators = new ArrayList<>();
2024         }
2025         configurators.add(configurator);
2026         return this;
2027     }
2028
2029     /**
2030      * @return All {@link EngineConfigurator} instances. Will only contain values after init of the engine.
2031      * Use the {@link #getConfigurators()} or {@link #addConfigurator(EngineConfigurator)} methods otherwise.
2032      */
2033     public List<EngineConfigurator> getAllConfigurators() {
2034         return allConfigurators;
2035     }
2036
2037     public AbstractEngineConfiguration setConfigurators(List<EngineConfigurator> configurators) {
2038         this.configurators = configurators;
2039         return this;
2040     }
2041
2042     public EngineConfigurator getIdmEngineConfigurator() {
2043         return idmEngineConfigurator;
2044     }
2045
2046     public AbstractEngineConfiguration setIdmEngineConfigurator(EngineConfigurator idmEngineConfigurator) {
2047         this.idmEngineConfigurator = idmEngineConfigurator;
2048         return this;
2049     }
2050
2051     public EngineConfigurator getEventRegistryConfigurator() {
2052         return eventRegistryConfigurator;
2053     }
2054
2055     public AbstractEngineConfiguration setEventRegistryConfigurator(EngineConfigurator eventRegistryConfigurator) {
2056         this.eventRegistryConfigurator = eventRegistryConfigurator;
2057         return this;
2058     }
2059
2060     public AbstractEngineConfiguration setForceCloseMybatisConnectionPool(boolean forceCloseMybatisConnectionPool) {
2061         this.forceCloseMybatisConnectionPool = forceCloseMybatisConnectionPool;
2062         return this;
2063     }
2064
2065     public boolean isForceCloseMybatisConnectionPool() {
2066         return forceCloseMybatisConnectionPool;
2067     }
2068 }