001package gu.sql2java;
002
003import static com.google.common.base.Preconditions.checkArgument;
004import static com.google.common.base.Preconditions.checkNotNull;
005import static gu.sql2java.SimpleLog.log;
006import static gu.sql2java.SimpleLog.logString;
007
008import java.lang.reflect.InvocationHandler;
009import java.lang.reflect.Proxy;
010import java.util.Collections;
011import java.util.EnumMap;
012import java.util.Map;
013import java.util.Map.Entry;
014import java.util.NoSuchElementException;
015import java.util.concurrent.TimeUnit;
016
017import com.google.common.base.Function;
018import com.google.common.base.Predicate;
019import com.google.common.collect.ImmutableMap;
020import com.google.common.collect.Iterables;
021import com.google.common.collect.Maps;
022import gu.sql2java.Constant.JdbcProperty;
023import gu.sql2java.Constant.UpdateStrategy;
024
025/**
026 * 数据库操作实例({@link TableManager})管理类
027 * @author guyadong
028 *
029 */
030public class Managers {
031        /**
032         * 设置是否输出调试信息标志
033         */
034        private static boolean debug = false;
035        private Managers() {
036        }
037
038        private static final ImmutableMap<String, TableManager<? extends BaseBean>> 
039        tableManagerInstances = loadTableManager();
040        private static final  ImmutableMap<Class<?>, TableManager<? extends BaseBean>> 
041        tableManagerTypeMaps = asTypeMap(tableManagerInstances);
042        private static final  ImmutableMap<Class<?>, TableManager<? extends BaseBean>> 
043        tableManagerBeanTypeMaps = asBeanTypeMap(tableManagerInstances);
044        private static final  Map<Class<?>, TableManager<? extends BaseBean>> cacheManagers = Maps.newHashMap();
045        private static final  Map<Class<?>, TableManager<? extends BaseBean>> cacheBeanTypeManagers = Maps.newHashMap();
046        private static final  Map<String, TableManager<? extends BaseBean>> cacheNameManagers = Maps.newHashMap();
047
048        /**
049         * @return 返回所有数据库操作实例(非cache)
050         */
051        public static ImmutableMap<String, TableManager<? extends BaseBean>> getTableManagers() {
052                return tableManagerInstances;
053        }
054
055        /**
056         * SPI(Service Provider Interface)机制加载 {@link TableManager}所有实例
057         * @return 表名和 {@link TableManager}实例的映射对象 
058         */
059        private static ImmutableMap<String, TableManager<? extends BaseBean>> loadTableManager() {          
060                ImmutableMap.Builder<String, TableManager<? extends BaseBean>> builder = ImmutableMap.builder();
061                for(RowMetaData data:RowMetaData.tableMetadata.values()){
062                        TableManager<?> manager = TableManagerDecorator.makeInterfaceInstance(new BaseTableManager<>(data.tablename));
063                        builder.put(data.tablename,     manager);
064                        if(debug){
065                                log("TableManagerDecorator instance create for {} ",data.tablename);
066                        }
067                }
068                return builder.build();
069        }
070
071        private static final ImmutableMap<Class<?>, TableManager<? extends BaseBean>> asTypeMap(Map<String, TableManager<? extends BaseBean>>input){
072                return Maps.uniqueIndex(input.values(), new Function<TableManager<? extends BaseBean>,Class<?>>(){
073                        @Override
074                        public Class<?> apply(TableManager<? extends BaseBean> input) {
075                                for(Class<?> clazz:input.getClass().getInterfaces()){
076                                        for(Class<?> c:clazz.getInterfaces()){
077                                                if(c.equals(TableManager.class)){
078                                                        return clazz;
079                                                }
080                                        }
081                                }
082                                throw new IllegalStateException(logString("NOT FOUND immplements interface class for %s ", input.getClass()));
083                        }});
084        }
085
086        private static final ImmutableMap<Class<?>, TableManager<? extends BaseBean>> asBeanTypeMap(Map<String, TableManager<? extends BaseBean>>input){
087                return Maps.uniqueIndex(input.values(), new Function<TableManager<? extends BaseBean>,Class<?>>(){
088        
089                        @Override
090                        public Class<?> apply(TableManager<? extends BaseBean> input) {
091                                if(input instanceof BaseTableManager){
092                                        return ((BaseTableManager<?>)input).metaData.beanType;
093                                }else if(Proxy.isProxyClass(input.getClass())){
094                                        InvocationHandler handler = Proxy.getInvocationHandler(input);
095                                        checkArgument(handler instanceof TableManagerDecorator,"UNKNOW HANDLER %s",handler.getClass() );
096                                        return ((TableManagerDecorator<?>)handler).metaData.beanType;
097                                }
098                                throw new IllegalArgumentException(logString("UNKNOW SUPPORTED TableManager instance %s",input.getClass()));
099                        }});
100        }
101
102        /** 
103         * 根据表操作接口类型返回数据库操作实例(非cache)
104         * @param interfaceClass  接口类型
105         * @return {@link TableManager}实例,找不到则抛出异常
106         */
107        @SuppressWarnings("unchecked")
108        public static final <M extends TableManager<?>>M 
109        getTableManager(Class<M>interfaceClass) {
110                TableManager<? extends BaseBean> manager = tableManagerTypeMaps.get(interfaceClass);
111                return checkNotNull((M) manager,"INVALID manager type %s",interfaceClass);
112        }
113
114        /**
115         * 根据表记录类型返回数据库操作实例(非cache)
116         * @param beanType java bean type
117         * @return {@link TableManager}实例,找不到则抛出异常
118         */
119        @SuppressWarnings("unchecked")
120        public static final <T extends BaseBean,M extends TableManager<T>>M 
121        getTableManagerByBeanType(Class<T>beanType) {
122                TableManager<? extends BaseBean> manager = tableManagerBeanTypeMaps.get(beanType);
123                return checkNotNull((M) manager,"INVALID bean type %s",beanType);
124        }
125
126        /**
127         * 根据表名返回数据库操作实例(非cache)
128         * @param tablename table name
129         * @return {@link TableManager}实例,找不到则抛出异常
130         */
131        @SuppressWarnings("unchecked")
132        public static final <M extends TableManager<?>>M 
133        getTableManager(String tablename) {
134                TableManager<? extends BaseBean> manager = tableManagerInstances.get(tablename);
135                return checkNotNull((M) manager,"INVALID tablename %s",tablename);
136        }
137
138        /**
139         * 根据表名返回数据库操作实例(非cache)
140         * @param tablename table name
141         * @return {@link BaseTableManager}实例,找不到则抛出异常
142         */
143        @SuppressWarnings("unchecked")
144        public static final <M extends BaseTableManager<?>>M 
145        getBaseTableManager(String tablename) {
146                return (M) baseManagerOf(getTableManager(tablename));
147        }
148
149    /**
150     * 注册cache manager<br>
151     * @param tablename table name
152     * @param updateStrategy cache update strategy,{@link Constant#DEFAULT_STRATEGY} be used if {@code null}
153     * @param maximumSize maximum capacity of cache ,{@link Constant#DEFAULT_CACHE_MAXIMUMSIZE } be used if {@code null} or <=0,see also {@link CacheBuilder#maximumSize(long)}
154     * @param duration cache data expired time,{@link Constant#DEFAULT_DURATION} be used if {@code null} or <=0,see also {@link CacheBuilder#expireAfterWrite(long, TimeUnit)}
155     * @param unit time unit for {@code duration},{@link Constant#DEFAULT_TIME_UNIT} be used if {@code null},see also {@link CacheBuilder#expireAfterWrite(long, TimeUnit)}
156     */
157        public static synchronized final <I extends TableManager<?>>
158        void registerCacheManager(
159                        String tablename,
160                        UpdateStrategy updateStrategy,
161                        long maximumSize, 
162                        long duration, 
163                        TimeUnit unit){
164                TableManager<?> cacheManager = CacheManager.makeCacheInstance(tablename, updateStrategy, maximumSize, duration, unit);
165                BaseTableManager<?> manager = baseManagerOf(cacheManager);
166                cacheManagers.put(manager.metaData.managerInterfaceClass, cacheManager);
167                cacheNameManagers.put(manager.metaData.tablename, cacheManager);
168                cacheBeanTypeManagers.put(manager.metaData.beanType, cacheManager);
169                if(debug){
170                        log("REGISTER CACHE MANAGER {}",cacheManager);
171                }
172        }
173
174        /**
175         * @return 返回所有支持缓存的数据库操作实例
176         * @see CacheManager
177         */
178        public static Map<Class<?>, TableManager<? extends BaseBean>> getCacheManagers() {
179                return Collections.unmodifiableMap(cacheManagers);
180        }
181
182        /**
183         * 根据目标类型返回对应的支持缓存的 {@link TableManager}实例
184         * @param interfaceClass 目标接口类型
185         * @return {@link TableManager}实例
186         * @throws NoSuchElementException 找不到时抛出异常
187         */
188        @SuppressWarnings("unchecked")
189        public static final <M extends TableManager<? extends BaseBean>>M 
190        getCacheManager(final Class<M>interfaceClass) throws NoSuchElementException {
191                checkArgument(interfaceClass != null,"targetType is null");
192                TableManager<? extends BaseBean> manager;
193                if(null != (manager = cacheManagers.get(interfaceClass))){
194                        return (M) manager;
195                }
196                return (M) Iterables.find(cacheManagers.values(), new Predicate<TableManager<?>>() {
197        
198                        @Override
199                        public boolean apply(TableManager<?> input) {
200                                return interfaceClass.isInstance(input);
201                        }
202                });
203        }
204
205        /**
206         * 根据表记录类型返回支持缓存的数据库操作实例
207         * @param beanType java bean type
208         * @return {@link TableManager}实例,找不到时抛出异常
209         */
210        @SuppressWarnings("unchecked")
211        public static final <B extends BaseBean> TableManager<B>  
212        getCacheManagerByBeanType(Class<?> beanType)  {
213                TableManager<? extends BaseBean> manager = cacheBeanTypeManagers.get(beanType);
214                return ( TableManager<B>) checkNotNull(manager,"INVALID bean type %s",beanType);
215        }
216
217        /**
218         * 根据表名返回支持缓存的数据库操作实例
219         * @param tablename
220         * @return {@link TableManager}实例,找不到时抛出异常
221         */
222        @SuppressWarnings("unchecked")
223        public static final <B extends BaseBean> TableManager<B> 
224        getCacheManager(String tablename)  {
225                TableManager<? extends BaseBean> manager = cacheNameManagers.get(tablename);
226                return (TableManager<B>) checkNotNull(manager,"INVALID table name %s",tablename);
227        }
228
229        /**
230         * 根据表记录类型返回数据库操作实例<br>
231         * 优先返回支持缓存的数据库操作实例(cache)
232         * @param interfaceClass 接口类
233         * @return {@link TableManager}实例,找不到时抛出异常
234         */
235        public static <M extends TableManager<? extends BaseBean>>M 
236        instanceOf(Class<M>interfaceClass) {
237            try {
238                return getCacheManager(interfaceClass);
239            } catch (Exception e) {
240                return getTableManager(interfaceClass);
241            } 
242        }
243
244        /**
245         * 根据表名返回数据库操作实例<br>
246         * 优先返回支持缓存的数据库操作实例(cache)
247         * @param tablename table name
248         * @return {@link TableManager}实例,找不到时抛出异常
249         */
250        public static <B extends BaseBean>TableManager<B> managerOf(String tablename) {
251            try {
252                return getCacheManager(tablename);
253            } catch (Exception e) {
254                return getTableManager(tablename);
255            } 
256        }
257
258        /**
259         * 将数据库操作实例转换对应的{@link BaseTableManager}实例<br>
260         * @param manager
261         * @return {@link BaseTableManager}实例,转换失败时抛出异常
262         */
263        @SuppressWarnings({ "unchecked", "rawtypes" })
264        static <B extends BaseBean>BaseTableManager<B> baseManagerOf(TableManager<B> manager){
265                checkArgument(manager != null,"manager is null");
266                if(manager instanceof BaseTableManager){
267                        return (BaseTableManager<B>) manager;
268                }else if(Proxy.isProxyClass(manager.getClass())){
269                        InvocationHandler handler = Proxy.getInvocationHandler(manager);
270                        checkArgument(handler instanceof TableManagerDecorator,"UNKNOW HANDLER TYPE %s",manager.getClass());
271                        return ((TableManagerDecorator)handler).delegate;
272                }else {
273                        throw new IllegalArgumentException(logString("UNKNOW TableManager instance type %s",manager.getClass()));
274                }
275        }
276
277        /**
278         * 根据表名返回对应的{@link BaseTableManager}实例
279         * 优先返回支持缓存的数据库操作实例(cache)
280         * @param tablename table name
281         * @return {@link BaseTableManager}实例,找不到时抛出异常
282         */
283        @SuppressWarnings("unchecked")
284        static <B extends BaseBean>BaseTableManager<B> baseManagerOf(String tablename) {
285            return baseManagerOf((TableManager<B>)managerOf(tablename)); 
286        }
287
288        /**
289         * 根据数据表名(驼峰命名格式)返回对应的{@link TableManager}实例<br>
290         * 优先返回支持缓存的数据库操作实例(cache)
291         * @param coreClass
292         * @return {@link TableManager}实例,找不到时抛出异常
293         */
294        public static  <B extends BaseBean>TableManager<B> managerOfCoreClass(String coreClass) {
295                String tablename = RowMetaData.getRowMetaDataByCoreClassName(coreClass).tablename;
296                try {
297                return getCacheManager(tablename);
298            } catch (Exception e) {
299                return getTableManager(tablename);
300            } 
301        }
302
303        /**
304         * 根据表记录类型返回数据库操作实例(非cache)<br>
305         * 优先返回支持缓存的数据库操作实例
306         * @param beanType java bean type
307         * @return {@link TableManager}实例,找不到时抛出异常
308         */
309        public static <B extends BaseBean>TableManager<B> managerOf(Class<B> beanType) {
310            try {
311                return getCacheManagerByBeanType(beanType);
312            } catch (Exception e) {
313                return getTableManagerByBeanType(beanType);
314            } 
315        }
316        public enum Module{
317                MANAGER,CACHE,DECORATOR,MANAGERS,BASETABLEMANAGER
318        }
319        /**
320         * set debug flag that determine if output log message,default : false
321         * @param debug flag for debug message output
322         * @param modules modules array to be set debug flag,all modules used if be null or empty
323         */
324        public static void setDebug(boolean debug,Module... modules){
325                if(modules == null || modules.length == 0){
326                        modules = Module.values();
327                } 
328                for(Module module:modules){
329                        if(null != module){
330                                switch (module) {
331                                case MANAGER:
332                                        Manager.getInstance().setDebug(debug);
333                                        break;
334                                case CACHE:
335                                        ColumnCache.setDebug(debug);
336                                        break;
337                                case DECORATOR:
338                                        TableManagerDecorator.setDebug(debug);
339                                        break;
340                                case MANAGERS:
341                                        Managers.debug = debug;
342                                        break;
343                                case BASETABLEMANAGER:
344                                        BaseTableManager.setDebug(debug);
345                                        break;
346                                default:
347                                        break;
348                                }
349                        }
350                }
351        }
352
353        /**
354         * inject properties to {@link Manager#databaseProperties}<br>
355         * be effected only while called before initializing singleton instance 
356         * @param properties
357         * @see JdbcProperty
358         */
359        public static final void injectProperties(Map<String,String> properties){
360            if(null != properties){
361                EnumMap<JdbcProperty, String> enumMap = new EnumMap<JdbcProperty,String>(JdbcProperty.class);
362                JdbcProperty property;
363                for(Entry<String, String> entry:properties.entrySet()){
364                    if(null != (property = JdbcProperty.fromKey(entry.getKey()))){
365                        enumMap.put(property, entry.getValue());
366                    }
367                }
368                Manager.injectProperties(enumMap);
369            }
370        }
371        
372        /**
373         * @return singleton instance of {@link Manager} as {@link SqlRunner} instance
374         */
375        public static SqlRunner getSqlRunner(){
376                return Manager.getInstance();
377        }
378}