001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package com.mybatisflex.core;
017
018import com.mybatisflex.annotation.InsertListener;
019import com.mybatisflex.annotation.KeyType;
020import com.mybatisflex.annotation.Listener;
021import com.mybatisflex.annotation.SetListener;
022import com.mybatisflex.annotation.UpdateListener;
023import com.mybatisflex.core.datasource.FlexDataSource;
024import com.mybatisflex.core.dialect.DbType;
025import com.mybatisflex.core.exception.FlexAssert;
026import org.apache.ibatis.session.Configuration;
027import org.apache.ibatis.session.SqlSessionFactory;
028
029import javax.sql.DataSource;
030import java.util.List;
031import java.util.Map;
032import java.util.concurrent.ConcurrentHashMap;
033import java.util.stream.Collectors;
034
035/**
036 * 全局配置文件
037 */
038public class FlexGlobalConfig {
039
040    /**
041     * 启动是否打印 banner 和 版本号
042     */
043    private boolean printBanner = true;
044
045    /**
046     * 默认使用 Mysql 数据库类型
047     */
048    private DbType dbType = DbType.MYSQL;
049
050    /**
051     * Mybatis 配置
052     */
053    private Configuration configuration;
054
055    /**
056     * 创建好的 sqlSessionFactory
057     */
058    private SqlSessionFactory sqlSessionFactory;
059
060    /**
061     * 全局的 ID 生成策略配置,当 @Id 未配置 或者 配置 KeyType 为 None 时
062     * 使用当前全局配置
063     */
064    private KeyConfig keyConfig;
065
066    /**
067     * entity 的监听器
068     */
069    private Map<Class<?>, SetListener> entitySetListeners = new ConcurrentHashMap<>();
070    private Map<Class<?>, UpdateListener> entityUpdateListeners = new ConcurrentHashMap<>();
071    private Map<Class<?>, InsertListener> entityInsertListeners = new ConcurrentHashMap<>();
072
073
074    /**
075     * 逻辑删除的相关配置
076     */
077    private Object normalValueOfLogicDelete = FlexConsts.LOGIC_DELETE_NORMAL;
078    private Object deletedValueOfLogicDelete = FlexConsts.LOGIC_DELETE_DELETED;
079
080    /**
081     * 分页查询时,默认每页显示的数据数量。
082     */
083    private int defaultPageSize = 10;
084
085
086    /**
087     * 默认的 Relation 注解查询深度
088     */
089    private int defaultRelationQueryDepth = 2;
090
091    /**
092     * 默认的逻辑删除字段,允许设置 {@code null} 忽略匹配。
093     */
094    private String logicDeleteColumn;
095
096    /**
097     * 默认的多租户字段,允许设置 {@code null} 忽略匹配。
098     */
099    private String tenantColumn;
100
101    /**
102     * 默认的乐观锁字段,允许设置 {@code null} 忽略匹配。
103     */
104    private String versionColumn;
105
106    public boolean isPrintBanner() {
107        return printBanner;
108    }
109
110    public void setPrintBanner(boolean printBanner) {
111        this.printBanner = printBanner;
112    }
113
114    public DbType getDbType() {
115        return dbType;
116    }
117
118    public void setDbType(DbType dbType) {
119        this.dbType = dbType;
120    }
121
122    public Configuration getConfiguration() {
123        return configuration;
124    }
125
126    public void setConfiguration(Configuration configuration) {
127        this.configuration = configuration;
128        DataSource dataSource = configuration.getEnvironment().getDataSource();
129        if (dataSource instanceof FlexDataSource) {
130            this.dbType = ((FlexDataSource) dataSource).getDefaultDbType();
131        }
132    }
133
134    public SqlSessionFactory getSqlSessionFactory() {
135        return sqlSessionFactory;
136    }
137
138    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
139        this.sqlSessionFactory = sqlSessionFactory;
140    }
141
142    public KeyConfig getKeyConfig() {
143        return keyConfig;
144    }
145
146    public void setKeyConfig(KeyConfig keyConfig) {
147        this.keyConfig = keyConfig;
148    }
149
150    public Map<Class<?>, SetListener> getEntitySetListeners() {
151        return entitySetListeners;
152    }
153
154    public void setEntitySetListeners(Map<Class<?>, SetListener> entitySetListeners) {
155        this.entitySetListeners = entitySetListeners;
156    }
157
158    public Map<Class<?>, UpdateListener> getEntityUpdateListeners() {
159        return entityUpdateListeners;
160    }
161
162    public void setEntityUpdateListeners(Map<Class<?>, UpdateListener> entityUpdateListeners) {
163        this.entityUpdateListeners = entityUpdateListeners;
164    }
165
166    public Map<Class<?>, InsertListener> getEntityInsertListeners() {
167        return entityInsertListeners;
168    }
169
170    public void setEntityInsertListeners(Map<Class<?>, InsertListener> entityInsertListeners) {
171        this.entityInsertListeners = entityInsertListeners;
172    }
173
174    public void registerSetListener(SetListener listener, Class<?>... classes) {
175        for (Class<?> aClass : classes) {
176            entitySetListeners.put(aClass, listener);
177        }
178    }
179
180    public void registerUpdateListener(UpdateListener listener, Class<?>... classes) {
181        for (Class<?> aClass : classes) {
182            entityUpdateListeners.put(aClass, listener);
183        }
184    }
185
186    public void registerInsertListener(InsertListener listener, Class<?>... classes) {
187        for (Class<?> aClass : classes) {
188            entityInsertListeners.put(aClass, listener);
189        }
190    }
191
192    public SetListener getSetListener(Class<?> entityClass) {
193        return entitySetListeners.get(entityClass);
194    }
195
196    /**
197     * 获取支持该 {@code entityClass} 的set监听器
198     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
199     *
200     * @param entityClass 实体class
201     * @return UpdateListener
202     */
203    public List<SetListener> getSupportedSetListener(Class<?> entityClass) {
204        return this.findSupportedListeners(entityClass, this.entitySetListeners);
205    }
206
207    public UpdateListener getUpdateListener(Class<?> entityClass) {
208        return entityUpdateListeners.get(entityClass);
209    }
210
211    /**
212     * 查找支持该 {@code entityClass} 的监听器
213     * @param entityClass 实体class
214     * @param listenerMap 监听器map
215     * @return 符合条件的监听器
216     * @param <T> 监听器类型
217     */
218    public <T extends Listener> List<T> findSupportedListeners(Class<?> entityClass, Map<Class<?>, T> listenerMap) {
219        return listenerMap.entrySet().stream()
220            .filter(entry -> entry.getKey().isAssignableFrom(entityClass))
221            .map(Map.Entry::getValue)
222            .collect(Collectors.toList());
223    }
224
225    /**
226     * 获取支持该 {@code entityClass} 的update监听器
227     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
228     *
229     * @param entityClass 实体class
230     * @return UpdateListener
231     */
232    public List<UpdateListener> getSupportedUpdateListener(Class<?> entityClass) {
233        return this.findSupportedListeners(entityClass, this.entityUpdateListeners);
234    }
235
236
237    public InsertListener getInsertListener(Class<?> entityClass) {
238        return entityInsertListeners.get(entityClass);
239    }
240
241    /**
242     * 获取支持该 {@code entityClass} 的insert监听器
243     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
244     *
245     * @param entityClass 实体class
246     * @return InsertListener
247     */
248    public List<InsertListener> getSupportedInsertListener(Class<?> entityClass) {
249        return this.findSupportedListeners(entityClass, this.entityInsertListeners);
250    }
251
252    public Object getNormalValueOfLogicDelete() {
253        return normalValueOfLogicDelete;
254    }
255
256    public void setNormalValueOfLogicDelete(Object normalValueOfLogicDelete) {
257        FlexAssert.notNull(normalValueOfLogicDelete, "normalValueOfLogicDelete");
258        this.normalValueOfLogicDelete = normalValueOfLogicDelete;
259    }
260
261    public Object getDeletedValueOfLogicDelete() {
262        return deletedValueOfLogicDelete;
263    }
264
265    public void setDeletedValueOfLogicDelete(Object deletedValueOfLogicDelete) {
266        FlexAssert.notNull(deletedValueOfLogicDelete, "deletedValueOfLogicDelete");
267        this.deletedValueOfLogicDelete = deletedValueOfLogicDelete;
268    }
269
270    public int getDefaultPageSize() {
271        return defaultPageSize;
272    }
273
274    public void setDefaultPageSize(int defaultPageSize) {
275        this.defaultPageSize = defaultPageSize;
276    }
277
278    public int getDefaultRelationQueryDepth() {
279        return defaultRelationQueryDepth;
280    }
281
282    public void setDefaultRelationQueryDepth(int defaultRelationQueryDepth) {
283        this.defaultRelationQueryDepth = defaultRelationQueryDepth;
284    }
285
286    public String getLogicDeleteColumn() {
287        return logicDeleteColumn;
288    }
289
290    public void setLogicDeleteColumn(String logicDeleteColumn) {
291        this.logicDeleteColumn = logicDeleteColumn;
292    }
293
294    public String getTenantColumn() {
295        return tenantColumn;
296    }
297
298    public void setTenantColumn(String tenantColumn) {
299        this.tenantColumn = tenantColumn;
300    }
301
302    public String getVersionColumn() {
303        return versionColumn;
304    }
305
306    public void setVersionColumn(String versionColumn) {
307        this.versionColumn = versionColumn;
308    }
309
310    public FlexDataSource getDataSource() {
311        return (FlexDataSource) getConfiguration().getEnvironment().getDataSource();
312    }
313
314    public static ConcurrentHashMap<String, FlexGlobalConfig> getGlobalConfigs() {
315        return globalConfigs;
316    }
317
318    public static void setGlobalConfigs(ConcurrentHashMap<String, FlexGlobalConfig> globalConfigs) {
319        FlexGlobalConfig.globalConfigs = globalConfigs;
320    }
321
322
323    /**
324     * 对应的是 注解 {@link com.mybatisflex.annotation.Id} 的配置
325     */
326    public static class KeyConfig {
327
328        private KeyType keyType;
329        private String value;
330        private boolean before = true;
331
332        public KeyType getKeyType() {
333            return keyType;
334        }
335
336        public void setKeyType(KeyType keyType) {
337            this.keyType = keyType;
338        }
339
340        public String getValue() {
341            return value;
342        }
343
344        public void setValue(String value) {
345            this.value = value;
346        }
347
348        public boolean isBefore() {
349            return before;
350        }
351
352        public void setBefore(boolean before) {
353            this.before = before;
354        }
355
356    }
357
358
359    /////static factory methods/////
360    private static ConcurrentHashMap<String, FlexGlobalConfig> globalConfigs = new ConcurrentHashMap<>();
361    private static FlexGlobalConfig defaultConfig = new FlexGlobalConfig();
362
363    public static FlexGlobalConfig getDefaultConfig() {
364        return defaultConfig;
365    }
366
367    public static void setDefaultConfig(FlexGlobalConfig config) {
368        if (config == null) {
369            throw new NullPointerException("config must not be null.");
370        }
371        defaultConfig = config;
372    }
373
374    public static FlexGlobalConfig getConfig(Configuration configuration) {
375        return getConfig(configuration.getEnvironment().getId());
376    }
377
378    public static FlexGlobalConfig getConfig(String environmentId) {
379        return globalConfigs.get(environmentId);
380    }
381
382
383    /**
384     * 设置全局配置
385     *
386     * @param id        环境id
387     * @param config    全局配置
388     * @param isDefault 自动指定默认全局配置(在多源时,方便由注解指定默认源)
389     */
390    public static synchronized void setConfig(String id, FlexGlobalConfig config, boolean isDefault) {
391        if (isDefault) {
392            defaultConfig.setSqlSessionFactory(config.sqlSessionFactory);
393            defaultConfig.setConfiguration(config.configuration);
394        }
395
396        globalConfigs.put(id, isDefault ? defaultConfig : config);
397    }
398
399}