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