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