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 || Integer.class == type) {
153 metaCache.setValue(name, Integer.valueOf(value));
154 } else if (long.class == type || Long.class == type) {
155 metaCache.setValue(name, Long.valueOf(value));
156 } else if (short.class == type || Short.class == type) {
157 metaCache.setValue(name, Short.valueOf(value));
158 } else if (byte.class == type || Byte.class == type) {
159 metaCache.setValue(name, Byte.valueOf(value));
160 } else if (float.class == type || Float.class == type) {
161 metaCache.setValue(name, Float.valueOf(value));
162 } else if (boolean.class == type || Boolean.class == type) {
163 metaCache.setValue(name, Boolean.valueOf(value));
164 } else if (double.class == type || Double.class == type) {
165 metaCache.setValue(name, Double.valueOf(value));
166 } else {
167 throw new CacheException("Unsupported property type for cache: '" + name + "' of type " + type);
168 }
169 }
170 }
171 }
172 if (InitializingObject.class.isAssignableFrom(cache.getClass())) {
173 try {
174 ((InitializingObject) cache).initialize();
175 } catch (Exception e) {
176 throw new CacheException(
177 "Failed cache initialization for '" + cache.getId() + "' on '" + cache.getClass().getName() + "'", e);
178 }
179 }
180 }
181
182 private Cache newBaseCacheInstance(Class<? extends Cache> cacheClass, String id) {
183 Constructor<? extends Cache> cacheConstructor = getBaseCacheConstructor(cacheClass);
184 try {
185 return cacheConstructor.newInstance(id);
186 } catch (Exception e) {
187 throw new CacheException("Could not instantiate cache implementation (" + cacheClass + "). Cause: " + e, e);
188 }
189 }
190
191 private Constructor<? extends Cache> getBaseCacheConstructor(Class<? extends Cache> cacheClass) {
192 try {
193 return cacheClass.getConstructor(String.class);
194 } catch (Exception e) {
195 throw new CacheException("Invalid base cache implementation (" + cacheClass + "). "
196 + "Base cache implementations must have a constructor that takes a String id as a parameter. Cause: " + e,
197 e);
198 }
199 }
200
201 private Cache newCacheDecoratorInstance(Class<? extends Cache> cacheClass, Cache base) {
202 Constructor<? extends Cache> cacheConstructor = getCacheDecoratorConstructor(cacheClass);
203 try {
204 return cacheConstructor.newInstance(base);
205 } catch (Exception e) {
206 throw new CacheException("Could not instantiate cache decorator (" + cacheClass + "). Cause: " + e, e);
207 }
208 }
209
210 private Constructor<? extends Cache> getCacheDecoratorConstructor(Class<? extends Cache> cacheClass) {
211 try {
212 return cacheClass.getConstructor(Cache.class);
213 } catch (Exception e) {
214 throw new CacheException("Invalid cache decorator (" + cacheClass + "). "
215 + "Cache decorators must have a constructor that takes a Cache instance as a parameter. Cause: " + e, e);
216 }
217 }
218 }