1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.mapping;
17
18 import java.lang.reflect.Constructor;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Properties;
23
24 import org.apache.ibatis.builder.InitializingObject;
25 import org.apache.ibatis.cache.Cache;
26 import org.apache.ibatis.cache.CacheException;
27 import org.apache.ibatis.cache.decorators.BlockingCache;
28 import org.apache.ibatis.cache.decorators.LoggingCache;
29 import org.apache.ibatis.cache.decorators.LruCache;
30 import org.apache.ibatis.cache.decorators.ScheduledCache;
31 import org.apache.ibatis.cache.decorators.SerializedCache;
32 import org.apache.ibatis.cache.decorators.SynchronizedCache;
33 import org.apache.ibatis.cache.impl.PerpetualCache;
34 import org.apache.ibatis.reflection.MetaObject;
35 import org.apache.ibatis.reflection.SystemMetaObject;
36
37
38
39
40 public class CacheBuilder {
41 private final String id;
42 private Class<? extends Cache> implementation;
43 private final List<Class<? extends Cache>> decorators;
44 private Integer size;
45 private Long clearInterval;
46 private boolean readWrite;
47 private Properties properties;
48 private boolean blocking;
49
50 public CacheBuilder(String id) {
51 this.id = id;
52 this.decorators = new ArrayList<>();
53 }
54
55 public CacheBuilder implementation(Class<? extends Cache> implementation) {
56 this.implementation = implementation;
57 return this;
58 }
59
60 public CacheBuilder addDecorator(Class<? extends Cache> decorator) {
61 if (decorator != null) {
62 this.decorators.add(decorator);
63 }
64 return this;
65 }
66
67 public CacheBuilder size(Integer size) {
68 this.size = size;
69 return this;
70 }
71
72 public CacheBuilder clearInterval(Long clearInterval) {
73 this.clearInterval = clearInterval;
74 return this;
75 }
76
77 public CacheBuilder readWrite(boolean readWrite) {
78 this.readWrite = readWrite;
79 return this;
80 }
81
82 public CacheBuilder blocking(boolean blocking) {
83 this.blocking = blocking;
84 return this;
85 }
86
87 public CacheBuilder properties(Properties properties) {
88 this.properties = properties;
89 return this;
90 }
91
92 public Cache build() {
93 setDefaultImplementations();
94 Cache cache = newBaseCacheInstance(implementation, id);
95 setCacheProperties(cache);
96
97 if (PerpetualCache.class.equals(cache.getClass())) {
98 for (Class<? extends Cache> decorator : decorators) {
99 cache = newCacheDecoratorInstance(decorator, cache);
100 setCacheProperties(cache);
101 }
102 cache = setStandardDecorators(cache);
103 } else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
104 cache = new LoggingCache(cache);
105 }
106 return cache;
107 }
108
109 private void setDefaultImplementations() {
110 if (implementation == null) {
111 implementation = PerpetualCache.class;
112 if (decorators.isEmpty()) {
113 decorators.add(LruCache.class);
114 }
115 }
116 }
117
118 private Cache setStandardDecorators(Cache cache) {
119 try {
120 MetaObject metaCache = SystemMetaObject.forObject(cache);
121 if (size != null && metaCache.hasSetter("size")) {
122 metaCache.setValue("size", size);
123 }
124 if (clearInterval != null) {
125 cache = new ScheduledCache(cache);
126 ((ScheduledCache) cache).setClearInterval(clearInterval);
127 }
128 if (readWrite) {
129 cache = new SerializedCache(cache);
130 }
131 cache = new LoggingCache(cache);
132 cache = new SynchronizedCache(cache);
133 if (blocking) {
134 cache = new BlockingCache(cache);
135 }
136 return cache;
137 } catch (Exception e) {
138 throw new CacheException("Error building standard cache decorators. Cause: " + e, e);
139 }
140 }
141
142 private void setCacheProperties(Cache cache) {
143 if (properties != null) {
144 MetaObject metaCache = SystemMetaObject.forObject(cache);
145 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
146 String name = (String) entry.getKey();
147 String value = (String) entry.getValue();
148 if (metaCache.hasSetter(name)) {
149 Class<?> type = metaCache.getSetterType(name);
150 if (String.class == type) {
151 metaCache.setValue(name, value);
152 } else if (int.class == type
153 || Integer.class == type) {
154 metaCache.setValue(name, Integer.valueOf(value));
155 } else if (long.class == type
156 || Long.class == type) {
157 metaCache.setValue(name, Long.valueOf(value));
158 } else if (short.class == type
159 || Short.class == type) {
160 metaCache.setValue(name, Short.valueOf(value));
161 } else if (byte.class == type
162 || Byte.class == type) {
163 metaCache.setValue(name, Byte.valueOf(value));
164 } else if (float.class == type
165 || Float.class == type) {
166 metaCache.setValue(name, Float.valueOf(value));
167 } else if (boolean.class == type
168 || Boolean.class == type) {
169 metaCache.setValue(name, Boolean.valueOf(value));
170 } else if (double.class == type
171 || Double.class == type) {
172 metaCache.setValue(name, Double.valueOf(value));
173 } else {
174 throw new CacheException("Unsupported property type for cache: '" + name + "' of type " + type);
175 }
176 }
177 }
178 }
179 if (InitializingObject.class.isAssignableFrom(cache.getClass())) {
180 try {
181 ((InitializingObject) cache).initialize();
182 } catch (Exception e) {
183 throw new CacheException("Failed cache initialization for '"
184 + cache.getId() + "' on '" + cache.getClass().getName() + "'", e);
185 }
186 }
187 }
188
189 private Cache newBaseCacheInstance(Class<? extends Cache> cacheClass, String id) {
190 Constructor<? extends Cache> cacheConstructor = getBaseCacheConstructor(cacheClass);
191 try {
192 return cacheConstructor.newInstance(id);
193 } catch (Exception e) {
194 throw new CacheException("Could not instantiate cache implementation (" + cacheClass + "). Cause: " + e, e);
195 }
196 }
197
198 private Constructor<? extends Cache> getBaseCacheConstructor(Class<? extends Cache> cacheClass) {
199 try {
200 return cacheClass.getConstructor(String.class);
201 } catch (Exception e) {
202 throw new CacheException("Invalid base cache implementation (" + cacheClass + "). "
203 + "Base cache implementations must have a constructor that takes a String id as a parameter. Cause: " + e, e);
204 }
205 }
206
207 private Cache newCacheDecoratorInstance(Class<? extends Cache> cacheClass, Cache base) {
208 Constructor<? extends Cache> cacheConstructor = getCacheDecoratorConstructor(cacheClass);
209 try {
210 return cacheConstructor.newInstance(base);
211 } catch (Exception e) {
212 throw new CacheException("Could not instantiate cache decorator (" + cacheClass + "). Cause: " + e, e);
213 }
214 }
215
216 private Constructor<? extends Cache> getCacheDecoratorConstructor(Class<? extends Cache> cacheClass) {
217 try {
218 return cacheClass.getConstructor(Cache.class);
219 } catch (Exception e) {
220 throw new CacheException("Invalid cache decorator (" + cacheClass + "). "
221 + "Cache decorators must have a constructor that takes a Cache instance as a parameter. Cause: " + e, e);
222 }
223 }
224 }