1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.chemistry.opencmis.client.bindings.cache.impl;
20
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.concurrent.locks.ReentrantReadWriteLock;
26
27 import org.apache.chemistry.opencmis.client.bindings.cache.Cache;
28 import org.apache.chemistry.opencmis.client.bindings.cache.CacheLevel;
29 import org.apache.chemistry.opencmis.commons.impl.ClassLoaderUtil;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33
34
35
36 public class CacheImpl implements Cache {
37
38 private static final Logger LOG = LoggerFactory.getLogger(CacheImpl.class);
39
40 private static final long serialVersionUID = 1L;
41
42 private List<Class<?>> levels;
43 private List<Map<String, String>> levelParameters;
44
45 private final String name;
46
47 private CacheLevel root;
48
49 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
50
51
52
53
54 public CacheImpl() {
55 this.name = "Cache";
56 }
57
58
59
60
61 public CacheImpl(String name) {
62 this.name = name;
63 }
64
65 @Override
66 public void initialize(String[] cacheLevelConfig) {
67 if (levels != null) {
68 throw new IllegalStateException("Cache already initialize!");
69 }
70
71 if (cacheLevelConfig == null || cacheLevelConfig.length == 0) {
72 throw new IllegalArgumentException("Cache config must not be empty!");
73 }
74
75 lock.writeLock().lock();
76 try {
77 levels = new ArrayList<Class<?>>(cacheLevelConfig.length);
78 levelParameters = new ArrayList<Map<String, String>>();
79
80
81 for (String config : cacheLevelConfig) {
82 int x = config.indexOf(' ');
83 if (x == -1) {
84 addLevel(config, null);
85 } else {
86 addLevel(config.substring(0, x), config.substring(x + 1));
87 }
88 }
89
90
91 root = createCacheLevel(0);
92 } finally {
93 lock.writeLock().unlock();
94 }
95 }
96
97 private void addLevel(String className, String parameters) {
98
99 Class<?> clazz;
100 try {
101 clazz = ClassLoaderUtil.loadClass(className, this.getClass().getClassLoader());
102 } catch (ClassNotFoundException e) {
103 throw new IllegalArgumentException("Class '" + className + "' not found!", e);
104 }
105
106
107 if (!CacheLevel.class.isAssignableFrom(clazz)) {
108 throw new IllegalArgumentException("Class '" + className + "' does not implement the CacheLevel interface!");
109 }
110
111 levels.add(clazz);
112
113
114 if (parameters == null) {
115 levelParameters.add(null);
116 } else {
117 Map<String, String> parameterMap = new HashMap<String, String>();
118 levelParameters.add(parameterMap);
119
120 for (String pair : parameters.split(",")) {
121 String[] keyValue = pair.split("=");
122 if (keyValue.length == 1) {
123 parameterMap.put(keyValue[0], "");
124 } else {
125 parameterMap.put(keyValue[0], keyValue[1]);
126 }
127 }
128 }
129 }
130
131 @Override
132 public Object get(String... keys) {
133
134 if (keys == null) {
135 return null;
136 }
137
138
139 if (levels.size() != keys.length) {
140 throw new IllegalArgumentException("Wrong number of keys!");
141 }
142
143 Object result = null;
144
145 lock.readLock().lock();
146 try {
147 CacheLevel cacheLevel = root;
148
149
150 for (int i = 0; i < keys.length - 1; i++) {
151 Object level = cacheLevel.get(keys[i]);
152
153
154 if (level == null) {
155 return null;
156 }
157
158
159 cacheLevel = (CacheLevel) level;
160 }
161
162
163 result = cacheLevel.get(keys[keys.length - 1]);
164 } finally {
165 lock.readLock().unlock();
166 }
167
168 return result;
169 }
170
171 @Override
172 public void put(Object value, String... keys) {
173
174 if (keys == null) {
175 return;
176 }
177
178
179 if (levels.size() != keys.length) {
180 throw new IllegalArgumentException("Wrong number of keys!");
181 }
182
183 lock.writeLock().lock();
184 try {
185 CacheLevel cacheLevel = root;
186
187
188 for (int i = 0; i < keys.length - 1; i++) {
189 Object level = cacheLevel.get(keys[i]);
190
191
192 if (level == null) {
193 level = createCacheLevel(i + 1);
194 cacheLevel.put(level, keys[i]);
195 }
196
197
198 cacheLevel = (CacheLevel) level;
199 }
200
201 cacheLevel.put(value, keys[keys.length - 1]);
202
203 if (LOG.isTraceEnabled()) {
204 LOG.trace("{}: put [{}] = {}", name, getFormattedKeys(keys), value);
205 }
206 } finally {
207 lock.writeLock().unlock();
208 }
209 }
210
211 @Override
212 public void remove(String... keys) {
213 if (keys == null) {
214 return;
215 }
216
217 lock.writeLock().lock();
218 try {
219 CacheLevel cacheLevel = root;
220
221
222 for (int i = 0; i < keys.length - 1; i++) {
223 Object level = cacheLevel.get(keys[i]);
224
225
226 if (level == null) {
227 return;
228 }
229
230
231 cacheLevel = (CacheLevel) level;
232 }
233
234 cacheLevel.remove(keys[keys.length - 1]);
235
236 if (LOG.isTraceEnabled()) {
237 LOG.trace("{}: removed [{}]", name, getFormattedKeys(keys));
238 }
239 } finally {
240 lock.writeLock().unlock();
241 }
242 }
243
244 @Override
245 public void removeAll() {
246 lock.writeLock().lock();
247 try {
248 root = createCacheLevel(0);
249
250 if (LOG.isTraceEnabled()) {
251 LOG.trace("{}: removed all", name);
252 }
253 } finally {
254 lock.writeLock().unlock();
255 }
256 }
257
258 @Override
259 public int check(String... keys) {
260 if (keys == null) {
261 return -1;
262 }
263
264 lock.readLock().lock();
265 try {
266 CacheLevel cacheLevel = root;
267
268
269 for (int i = 0; i < keys.length - 1; i++) {
270 Object level = cacheLevel.get(keys[i]);
271
272
273 if (level == null) {
274 return i;
275 }
276
277
278 cacheLevel = (CacheLevel) level;
279 }
280 } finally {
281 lock.readLock().unlock();
282 }
283
284 return keys.length;
285 }
286
287 @Override
288 public void writeLock() {
289 lock.writeLock().lock();
290 }
291
292 @Override
293 public void writeUnlock() {
294 lock.writeLock().unlock();
295 }
296
297
298
299
300
301
302 private CacheLevel createCacheLevel(int level) {
303 if (level < 0 || level >= levels.size()) {
304 throw new IllegalArgumentException("Cache level doesn't fit the configuration!");
305 }
306
307
308 Class<?> clazz = levels.get(level);
309 CacheLevel cacheLevel = null;
310 try {
311 cacheLevel = (CacheLevel) clazz.newInstance();
312 } catch (Exception e) {
313 throw new IllegalArgumentException("Cache level problem?!", e);
314 }
315
316
317 cacheLevel.initialize(levelParameters.get(level));
318
319 return cacheLevel;
320 }
321
322 @Override
323 public String toString() {
324 return root == null ? "(no cache root)" : root.toString();
325 }
326
327
328
329 private static String getFormattedKeys(String[] keys) {
330 assert keys != null;
331
332 StringBuilder sb = new StringBuilder(32);
333 for (String k : keys) {
334 if (sb.length() > 0) {
335 sb.append(", ");
336 }
337 sb.append(k);
338 }
339
340 return sb.toString();
341 }
342 }