001package org.cache2k.impl; 002 003/* 004 * #%L 005 * cache2k core package 006 * %% 007 * Copyright (C) 2000 - 2015 headissue GmbH, Munich 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import org.cache2k.BulkCacheSource; 026import org.cache2k.ExperimentalBulkCacheSource; 027import org.cache2k.Cache; 028import org.cache2k.CacheBuilder; 029import org.cache2k.CacheConfig; 030import org.cache2k.CacheManager; 031import org.cache2k.CacheSource; 032import org.cache2k.CacheSourceWithMetaInfo; 033import org.cache2k.RefreshController; 034 035import java.lang.reflect.Constructor; 036import java.lang.reflect.Method; 037 038/** 039 * @author Jens Wilke; created: 2013-12-06 040 */ 041@SuppressWarnings("unused") // instantiated by reflection from cache builder 042public class CacheBuilderImpl<K, T> extends CacheBuilder<K, T> { 043 044 String deriveNameFromStackTrace() { 045 Exception ex = new Exception(); 046 for (StackTraceElement e : ex.getStackTrace()) { 047 if (!e.getClassName().startsWith(this.getClass().getPackage().getName())) { 048 int idx = e.getClassName().lastIndexOf('.'); 049 String _simpleClassName = e.getClassName().substring(idx + 1); 050 String _methodName = e.getMethodName(); 051 if (_methodName.equals("<init>")) { 052 _methodName = "INIT"; 053 } 054 if (_methodName != null && _methodName.length() > 0) { 055 return _simpleClassName + "." + _methodName + "" + "." + e.getLineNumber(); 056 } 057 } 058 } 059 return null; 060 } 061 062 Object getConstructorParameter(Class<?> c) { 063 if (CacheConfig.class.isAssignableFrom(c)) { return config; } 064 if (RefreshController.class.isAssignableFrom(c)) { return refreshController; } 065 if (CacheSource.class.isAssignableFrom(c)) { return cacheSource; } 066 if (CacheSourceWithMetaInfo.class.isAssignableFrom(c)) { return cacheSourceWithMetaInfo; } 067 if (ExperimentalBulkCacheSource.class.isAssignableFrom(c)) { return experimentalBulkCacheSource; } 068 if (BulkCacheSource.class.isAssignableFrom(c)) { return bulkCacheSource; } 069 return null; 070 } 071 072 /** return the first constructor with CacheConfig as first parameter */ 073 Constructor<?> findConstructor(Class<?> c) { 074 for (Constructor ctr : c.getConstructors()) { 075 Class<?>[] pt = ctr.getParameterTypes(); 076 if (pt != null && pt.length > 0 && CacheConfig.class.isAssignableFrom(pt[0])) { 077 return ctr; 078 } 079 } 080 return null; 081 } 082 083 /** 084 * The generic wiring code is not working on android. 085 * Explicitly call the wiring methods. 086 */ 087 @SuppressWarnings("unchecked") 088 void confiugreViaSettersDirect(BaseCache c) { 089 if (cacheSource != null) { 090 c.setSource(cacheSource); 091 } 092 if (cacheSourceWithMetaInfo != null) { 093 c.setSource(cacheSourceWithMetaInfo); 094 } 095 if (refreshController != null) { 096 c.setRefreshController(refreshController); 097 } 098 if (entryExpiryCalculator != null) { 099 c.setEntryExpiryCalculator(entryExpiryCalculator); 100 } 101 if (exceptionExpiryCalculator != null) { 102 c.setExceptionExpiryCalculator(exceptionExpiryCalculator); 103 } 104 105 if (config != null) { 106 c.setCacheConfig(config); 107 } 108 if (bulkCacheSource != null) { 109 c.setBulkCacheSource(bulkCacheSource); 110 } 111 if (experimentalBulkCacheSource != null) { 112 c.setExperimentalBulkCacheSource(experimentalBulkCacheSource); 113 } 114 } 115 116 void configureViaSetters(Object o) { 117 if (o instanceof BaseCache) { 118 confiugreViaSettersDirect((BaseCache) o); 119 return; 120 } 121 try { 122 for (Method m : o.getClass().getMethods()) { 123 Class<?>[] ps = m.getParameterTypes(); 124 if (ps != null && ps.length == 1 && m.getName().startsWith(("set"))) { 125 Object p = getConstructorParameter(ps[0]); 126 if (p != null) { 127 m.invoke(o, p); 128 } 129 } 130 } 131 } catch (Exception ex) { 132 throw new IllegalArgumentException("Unable to configure cache", ex); 133 } 134 } 135 136 protected Cache<K,T> constructImplementationAndFillParameters(Class<?> cls) { 137 if (!Cache.class.isAssignableFrom(cls)) { 138 throw new IllegalArgumentException("Specified impl not a cache" + cls.getName()); 139 } 140 try { 141 Cache<K, T> _cache; 142 Constructor<?> ctr = findConstructor(cls); 143 if (ctr != null) { 144 Class<?>[] pt = ctr.getParameterTypes(); 145 Object[] _args = new Object[pt.length]; 146 for (int i = 0; i < _args.length; i++) { 147 _args[i] = getConstructorParameter(pt[i]); 148 } 149 _cache = (Cache<K, T>) ctr.newInstance(_args); 150 } else { 151 _cache = (Cache<K, T>) cls.newInstance(); 152 } 153 return _cache; 154 } catch (Exception e) { 155 throw new IllegalArgumentException("Not able to instantiate cache implementation", e); 156 } 157 } 158 159 public Cache<K, T> build() { 160 config = createConfiguration(); 161 if (config.getName() == null) { 162 config.setName(deriveNameFromStackTrace()); 163 } 164 Class<?> _implClass = BaseCache.TUNABLE.defaultImplementation; 165 if (config.getImplementation() != null) { 166 _implClass = config.getImplementation(); 167 } 168 Cache<K,T> _cache = constructImplementationAndFillParameters(_implClass); 169 CacheManagerImpl cm = null; 170 if (_cache instanceof BaseCache) { 171 cm = (CacheManagerImpl) CacheManager.getInstance(); 172 ((BaseCache) _cache).setCacheManager(cm); 173 } 174 configureViaSetters(_cache); 175 if (cm != null) { 176 cm.newCache(_cache); 177 } 178 if (_cache instanceof BaseCache) { 179 ((BaseCache) _cache).init(); 180 } 181 return _cache; 182 } 183 184}