All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gu.sql2java.Managers Maven / Gradle / Ivy

There is a newer version: 5.2.0
Show newest version
package gu.sql2java;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static gu.sql2java.SimpleLog.log;
import static gu.sql2java.SimpleLog.logString;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import gu.sql2java.Constant.JdbcProperty;

/**
 * 数据库操作实例({@link TableManager})管理类
 * @author guyadong
 *
 */
public class Managers implements Constant{
	/**
	 * 设置是否输出调试信息标志
	 */
	private static boolean debug = false;
	private Managers() {
	}

	private static final ImmutableMap> 
	tableManagerInstances = loadTableManager();
	private static final  ImmutableMap, TableManager> 
	tableManagerTypeMaps = asTypeMap(tableManagerInstances);
	private static final  ImmutableMap, TableManager> 
	tableManagerBeanTypeMaps = asBeanTypeMap(tableManagerInstances);
	private static final  Map, TableManager> cacheManagers = Maps.newHashMap();
	private static final  Map, TableManager> cacheBeanTypeManagers = Maps.newHashMap();
	private static final  Map> cacheNameManagers = Maps.newHashMap();

	/**
	 * @return 返回所有数据库操作实例(非cache)
	 */
	public static ImmutableMap> getTableManagers() {
		return tableManagerInstances;
	}

	/**
	 * SPI(Service Provider Interface)机制加载 {@link TableManager}所有实例
	 * @return 表名和 {@link TableManager}实例的映射对象 
	 */
	private static ImmutableMap> loadTableManager() {		
		ImmutableMap.Builder> builder = ImmutableMap.builder();
		for(RowMetaData data:RowMetaData.tableMetadata.values()){
			try {
				TableManager manager = TableManagerDecorator.makeInterfaceInstance(new BaseTableManager<>(data.tablename));
				builder.put(data.tablename,	manager);
				if(debug){
					log("TableManagerDecorator instance create for {} ",data.tablename);
				}
			} catch (RuntimeException e) {
				if(debug){
					log("FAIL TO create manager for  {} caused by {}",data.tablename,e.getMessage());
				}
			}
		}
		return builder.build();
	}

	private static final ImmutableMap, TableManager> asTypeMap(Map>input){
		return Maps.uniqueIndex(input.values(), new Function,Class>(){
			@Override
			public Class apply(TableManager input) {
				for(Class clazz:input.getClass().getInterfaces()){
					if(TableManager.class.isAssignableFrom(clazz)) {
						return clazz;
					}
				}
				throw new IllegalStateException(logString("NOT FOUND immplements interface class for %s ", input.getClass()));
			}});
	}

	private static final ImmutableMap, TableManager> asBeanTypeMap(Map>input){
		return Maps.uniqueIndex(input.values(), new Function,Class>(){
	
			@Override
			public Class apply(TableManager input) {
				if(input instanceof BaseTableManager){
					return ((BaseTableManager)input).metaData.beanType;
				}else if(Proxy.isProxyClass(input.getClass())){
					InvocationHandler handler = Proxy.getInvocationHandler(input);
					checkArgument(handler instanceof TableManagerDecorator,"UNKNOW HANDLER %s",handler.getClass() );
					return ((TableManagerDecorator)handler).metaData.beanType;
				}
				throw new IllegalArgumentException(logString("UNKNOW SUPPORTED TableManager instance %s",input.getClass()));
			}});
	}

	/** 
	 * 根据表操作接口类型返回数据库操作实例(非cache)
	 * @param interfaceClass  接口类型
	 * @return {@link TableManager}实例,找不到则抛出异常
	 */
	@SuppressWarnings("unchecked")
	public static final >M 
	getTableManager(ClassinterfaceClass) {
		TableManager manager = tableManagerTypeMaps.get(interfaceClass);
		return checkNotNull((M) manager,"INVALID manager type %s",interfaceClass);
	}

	/**
	 * 根据表记录类型返回数据库操作实例(非cache)
	 * @param beanType java bean type
	 * @return {@link TableManager}实例,找不到则抛出异常
	 */
	@SuppressWarnings("unchecked")
	public static final >M 
	getTableManagerByBeanType(ClassbeanType) {
		TableManager manager = tableManagerBeanTypeMaps.get(beanType);
		return checkNotNull((M) manager,"INVALID bean type %s",beanType);
	}

	/**
	 * 根据表名返回数据库操作实例(非cache)
	 * @param tablename table name
	 * @return {@link TableManager}实例,找不到则抛出异常
	 */
	@SuppressWarnings("unchecked")
	public static final >M 
	getTableManager(String tablename) {
		TableManager manager = tableManagerInstances.get(tablename);
		return checkNotNull((M) manager,"INVALID tablename %s",tablename);
	}

	/**
	 * 根据表名返回数据库操作实例(非cache)
	 * @param tablename table name
	 * @return {@link BaseTableManager}实例,找不到则抛出异常
	 */
	@SuppressWarnings("unchecked")
	public static final >M 
	getBaseTableManager(String tablename) {
		return (M) baseManagerOf((TableManager)getTableManager(tablename));
	}

    /**
     * 注册cache manager
* @param tablename table name * @param updateStrategy cache update strategy,{@link gu.sql2java.Constant#DEFAULT_STRATEGY} be used if {@code null} * @param maximumSize maximum capacity of cache ,{@link gu.sql2java.Constant#DEFAULT_CACHE_MAXIMUMSIZE } be used if {@code null} or <=0,see also {@link com.google.common.cache.CacheBuilder#maximumSize(long)} * @param duration cache data expired time,{@link gu.sql2java.Constant#DEFAULT_DURATION} be used if {@code null} or <=0,see also {@link com.google.common.cache.CacheBuilder#expireAfterAccess(long, TimeUnit)} * @param unit time unit for {@code duration},{@link gu.sql2java.Constant#DEFAULT_TIME_UNIT} be used if {@code null},see also {@link com.google.common.cache.CacheBuilder#expireAfterAccess(long, TimeUnit)} */ public static synchronized final > void registerCacheManager( String tablename, UpdateStrategy updateStrategy, long maximumSize, long duration, TimeUnit unit){ TableManager cacheManager = CacheManager.makeCacheInstance(tablename, updateStrategy, maximumSize, duration, unit); BaseTableManager manager = baseManagerOf(cacheManager); cacheManagers.put(manager.metaData.managerInterfaceClass, cacheManager); cacheNameManagers.put(manager.metaData.tablename, cacheManager); cacheBeanTypeManagers.put(manager.metaData.beanType, cacheManager); if(debug){ log("REGISTER CACHE MANAGER {}",cacheManager); } } /** * @return 返回所有支持缓存的数据库操作实例 * @see CacheManager */ public static Map, TableManager> getCacheManagers() { return Collections.unmodifiableMap(cacheManagers); } /** * 根据目标类型返回对应的支持缓存的 {@link TableManager}实例 * @param interfaceClass 目标接口类型 * @return {@link TableManager}实例 * @throws NoSuchElementException 找不到时抛出异常 */ @SuppressWarnings("unchecked") public static final >M getCacheManager(final ClassinterfaceClass) throws NoSuchElementException { checkArgument(interfaceClass != null,"targetType is null"); TableManager manager; if(null != (manager = cacheManagers.get(interfaceClass))){ return (M) manager; } return (M) Iterables.find(cacheManagers.values(), new Predicate>() { @Override public boolean apply(TableManager input) { return interfaceClass.isInstance(input); } }); } /** * 根据表记录类型返回支持缓存的数据库操作实例 * @param beanType java bean type * @return {@link TableManager}实例,找不到时抛出异常 */ @SuppressWarnings("unchecked") public static final TableManager getCacheManagerByBeanType(Class beanType) { TableManager manager = cacheBeanTypeManagers.get(beanType); return ( TableManager) checkNotNull(manager,"INVALID bean type %s",beanType); } /** * 根据表名返回支持缓存的数据库操作实例 * @param tablename * @return {@link TableManager}实例,找不到时抛出异常 */ @SuppressWarnings("unchecked") public static final TableManager getCacheManager(String tablename) { TableManager manager = cacheNameManagers.get(tablename); return (TableManager) checkNotNull(manager,"INVALID table name %s",tablename); } /** * 根据表记录类型返回支持缓存的数据库操作实例 * @param beanType java bean type * @return {@link CacheManager}实例,找不到时返回{@code null} * @since 3.30.0 */ @SuppressWarnings({ "rawtypes" }) public static final CacheManager getCacheManagerByBeanTypeOrNull(Class beanType) { TableManager manager = cacheBeanTypeManagers.get(beanType); if(null != manager) { TableManagerDecorator handler = (TableManagerDecorator) Proxy.getInvocationHandler(manager); return (CacheManager) handler.delegate; } return null; } /** * 根据表名返回支持缓存的数据库操作实例 * @param tablename * @return {@link CacheManager}实例,找不到时返回{@code null} * @since 3.30.0 */ @SuppressWarnings({ "rawtypes" }) public static final CacheManager getCacheManagerOrNull(String tablename) { TableManager manager = cacheNameManagers.get(tablename); if(null != manager) { TableManagerDecorator handler = (TableManagerDecorator) Proxy.getInvocationHandler(manager); return (CacheManager) handler.delegate; } return null; } /** * 根据表记录类型返回数据库操作实例
* 优先返回支持缓存的数据库操作实例(cache) * @param interfaceClass 接口类 * @return {@link TableManager}实例,找不到时抛出异常 */ public static >M instanceOf(ClassinterfaceClass) { try { return getCacheManager(interfaceClass); } catch (Exception e) { return getTableManager(interfaceClass); } } /** * 根据表名返回数据库操作实例
* 优先返回支持缓存的数据库操作实例(cache) * @param tablename table name * @return {@link TableManager}实例,找不到时抛出异常 */ public static TableManager managerOf(String tablename) { try { return getCacheManager(tablename); } catch (Exception e) { return getTableManager(tablename); } } /** * 将数据库操作实例转换对应的{@link BaseTableManager}实例
* @param manager * @return {@link BaseTableManager}实例,转换失败时抛出异常 */ @SuppressWarnings({ "unchecked", "rawtypes" }) static BaseTableManager baseManagerOf(TableManager manager){ checkArgument(manager != null,"manager is null"); if(manager instanceof BaseTableManager){ return (BaseTableManager) manager; }else if(Proxy.isProxyClass(manager.getClass())){ InvocationHandler handler = Proxy.getInvocationHandler(manager); checkArgument(handler instanceof TableManagerDecorator,"UNKNOW HANDLER TYPE %s",manager.getClass()); return ((TableManagerDecorator)handler).delegate; }else { throw new IllegalArgumentException(logString("UNKNOW TableManager instance type %s",manager.getClass())); } } /** * 从数据库操作接口类获取对应的{@link BaseTableManager}实例
* @param interfaceClass * @return {@link BaseTableManager}实例,转换失败时抛出异常 */ static >BaseTableManager baseManagerOf(Class interfaceClass){ return baseManagerOf(instanceOf(interfaceClass)); } /** * 根据表名返回对应的{@link BaseTableManager}实例 * 优先返回支持缓存的数据库操作实例(cache) * @param tablename table name * @return {@link BaseTableManager}实例,找不到时抛出异常 */ @SuppressWarnings("unchecked") static BaseTableManager baseManagerOf(String tablename) { return baseManagerOf((TableManager)managerOf(tablename)); } /** * 根据数据表名(驼峰命名格式)返回对应的{@link TableManager}实例
* 优先返回支持缓存的数据库操作实例(cache) * @param coreClass * @param alias 别名 * @return {@link TableManager}实例,找不到时抛出异常 * @deprecated never used */ public static TableManager managerOfCoreClass(String coreClass, String alias) { String tablename = RowMetaData.getRowMetaDataByCoreClassName(coreClass, alias).tablename; try { return getCacheManager(tablename); } catch (Exception e) { return getTableManager(tablename); } } /** * 根据表记录类型返回数据库操作实例
* 优先返回支持缓存的数据库操作实例 * @param beanType java bean type * @return {@link TableManager}实例,找不到时抛出异常 */ public static TableManager managerOf(Class beanType) { try { return getCacheManagerByBeanType(beanType); } catch (Exception e) { return getTableManagerByBeanType(beanType); } } public enum Module{ MANAGER,CACHE,DECORATOR,MANAGERS,BASETABLEMANAGER } /** * set debug flag that determine if output log message,default : false * @param debug flag for debug message output * @param modules modules array to be set debug flag,all modules used if be null or empty */ public static void setDebug(boolean debug,Module... modules){ if(modules == null || modules.length == 0){ modules = Module.values(); } for(Module module:modules){ if(null != module){ switch (module) { case MANAGER: DataSourceConfig.setDebugOutput(debug); break; case CACHE: ColumnCache.setDebug(debug); break; case DECORATOR: TableManagerDecorator.setDebug(debug); break; case MANAGERS: Managers.debug = debug; break; case BASETABLEMANAGER: BaseTableManager.setDebug(debug); break; default: break; } } } } /** * set flags for check if WHRE SQL is legal * @param whereCheckFlag */ public static void setWhereCheckFlag(int whereCheckFlag) { BaseTableManager.setWhereCheckFlag(whereCheckFlag); } /** * set debug flag that determine if output log message for Manager instance named {@code alias},default : false * @param alias alias name * @param debug debug flag * @deprecated */ public static void setDebugOfManager(String alias,boolean debug){ // DO NOTHING } /** * 对所有{@link JdbcProperty}定义的属性如果值不为String则删除 * @param properties * @return always properties */ @SuppressWarnings({ "rawtypes"}) private static Map cleanNotString(Map properties){ if(null != properties){ for(JdbcProperty property : JdbcProperty.values()){ if(!(properties.get(property.key) instanceof String)){ properties.remove(property.key); } if(!property.isGlobal()){ String key = property.withPrefix("debug."); if(!(properties.get(key) instanceof String)){ properties.remove(key); } key = property.withPrefix("work."); if(!(properties.get(key) instanceof String)){ properties.remove(key); } } } } return properties; } /** * 对配置参数进行归一化处理
* 对于{@link JdbcProperty}定义的所有属性进行归一化处理,如果有带'work.','debug.'前缀的属性,则优先使用, * 如果有不带前缀的属性,则将属性名根据'debug'标志改为'work.'或'debug.'前缀的属性
* 比如: 如果同时存在jdbc.url, work.jdbc.url这两个定义,且debug标志为false(未定义时默认为false),则删除jdbc.url定义 * 如果只存在jdbc.url定义,且debug标志为false(未定义时默认为false),则将之改为work.jdbc.url * @param properties * @return new Map instance */ @SuppressWarnings({ "rawtypes", "unchecked" }) static final Map normailze(Map properties){ HashMap m = new HashMap(properties); if(null != properties){ cleanNotString(m); if(!m.containsKey(JdbcProperty.DEBUG.key)){ m.put(JdbcProperty.DEBUG.key, "false"); } boolean isDebug = Boolean.valueOf((String) m.get(JdbcProperty.DEBUG.key)); String prefix = isDebug?"debug.":"work."; for(JdbcProperty property : JdbcProperty.values()){ // 跳过所有全局属性 if(!property.isGlobal()){ if(m.containsKey(property.key)){ Object value = m.remove(property.key); if(!m.containsKey(property.withPrefix(prefix))){ // 有前缀的属性未定义时使用无前缀的属性代替 m.put(property.withPrefix(prefix), value); }else{ // 有前缀的属性优先 } } } } } return m; } /** * inject properties to {@link DataSourceConfig#databaseProperties}
* be effected only while called before initializing singleton instance * @param properties * @param prefix the prefix of properties,ignore if {@code null} * @see JdbcProperty */ @SuppressWarnings("rawtypes") public static final void injectProperties(Map properties, String prefix){ DataSourceConfig.injectProperties(DataSourceConfig.asEnumMap(properties, prefix)); } /** * short cut of {@link #injectProperties(Map, String)} */ @SuppressWarnings("rawtypes") public static final void injectProperties(Map properties){ injectProperties(properties, null); } /** * @return singleton instance of {@link Manager} as {@link SqlRunner} instance */ public static SqlRunner getSqlRunner(){ return Manager.getInstance(); } /** * @param alias alias name of connection * @return singleton instance of {@link Manager} as {@link SqlRunner} instance for alias */ public static SqlRunner getSqlRunner(String alias){ Manager manager = managerInstanceOfAlias(alias); return manager == null ? getSqlRunner() : manager; } /** * get Manager instance with jdbcUrl * @param jdbcUrl JDBC connect string * @return Manager instance OR null if not found */ public static Manager managerInstanceOf(String jdbcUrl){ return null == jdbcUrl ? null : Manager.managers.get(jdbcUrl); } /** * get Manager instance with alias * @param alias alias name of JDBC connection * @return Manager instance OR null if not found */ public static Manager managerInstanceOfAlias(String alias){ if(Strings.isNullOrEmpty(alias)){ alias = DEFAULT_ALIAS; } return Manager.aliasManagers.get(alias); } /** * create Manager instance with properties * @param properties * @return Manager instance */ @SuppressWarnings({ "rawtypes" }) public static synchronized Manager createInstance(Map properties){ properties = normailze(checkNotNull(properties, "properties is null")); String alias = DataSourceConfig.parseValue(properties, JdbcProperty.ALIAS); Manager manager = null; if(!Strings.isNullOrEmpty(alias)){ manager = managerInstanceOfAlias(alias); if( null != manager){ return manager; }else{ DataSourceConfig config = DataSourceConfig.createConfig(asProperties(properties)); return new Manager(config); } } String jdbcUrl = checkNotNull(DataSourceConfig.parseValue(properties, JdbcProperty.JDBC_URL), "JDBC connect string is not defined"); manager = managerInstanceOf(jdbcUrl); if(manager == null){ manager = new Manager(asProperties(properties)); } return manager; } public static Manager createInstance(EnumMap properties){ return createInstance(asProperties(properties)); } @SuppressWarnings({ "unchecked", "rawtypes" }) private static Properties asProperties(Map properties){ if(properties instanceof Properties){ return (Properties)properties; } Properties props = new Properties(); if(null != properties){ props.putAll(properties); } return props; } /** * convert {@link EnumMap } properties to {@link Properties}
* @param input input properties */ private static final Properties asProperties(EnumMap input){ Properties properties = new Properties(); DataSourceConfig.injectToProperties(properties, input); return properties; } }