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