This project has retired. For details please refer to its
Attic page.
CacheImpl xref
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.runtime.cache;
20
21 import java.io.IOException;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.io.Serializable;
25 import java.lang.ref.SoftReference;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.Map;
29 import java.util.concurrent.locks.ReentrantReadWriteLock;
30
31 import org.apache.chemistry.opencmis.client.api.CmisObject;
32 import org.apache.chemistry.opencmis.client.api.Session;
33 import org.apache.chemistry.opencmis.commons.PropertyIds;
34 import org.apache.chemistry.opencmis.commons.SessionParameter;
35
36
37
38
39
40 public class CacheImpl implements Cache {
41
42 private static final long serialVersionUID = 1L;
43
44 private static final float HASHTABLE_LOAD_FACTOR = 0.75f;
45
46 private int cacheSize;
47 private int cacheTtl;
48 private int pathToIdSize;
49 private int pathToIdTtl;
50
51 private LinkedHashMap<String, CacheItem<Map<String, CmisObject>>> objectMap;
52 private LinkedHashMap<String, CacheItem<String>> pathToIdMap;
53
54 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
55
56
57
58
59 public CacheImpl() {
60 }
61
62 public void initialize(Session session, Map<String, String> parameters) {
63 lock.writeLock().lock();
64 try {
65
66 try {
67 cacheSize = Integer.valueOf(parameters.get(SessionParameter.CACHE_SIZE_OBJECTS));
68 if (cacheSize < 0) {
69 cacheSize = 0;
70 }
71 } catch (Exception e) {
72 cacheSize = 1000;
73 }
74
75
76 try {
77 cacheTtl = Integer.valueOf(parameters.get(SessionParameter.CACHE_TTL_OBJECTS));
78 if (cacheTtl < 0) {
79 cacheTtl = 2 * 60 * 60 * 1000;
80 }
81 } catch (Exception e) {
82 cacheTtl = 2 * 60 * 60 * 1000;
83 }
84
85
86 try {
87 pathToIdSize = Integer.valueOf(parameters.get(SessionParameter.CACHE_SIZE_PATHTOID));
88 if (pathToIdSize < 0) {
89 pathToIdSize = 0;
90 }
91 } catch (Exception e) {
92 pathToIdSize = 1000;
93 }
94
95
96 try {
97 pathToIdTtl = Integer.valueOf(parameters.get(SessionParameter.CACHE_TTL_PATHTOID));
98 if (pathToIdTtl < 0) {
99 pathToIdTtl = 30 * 60 * 1000;
100 }
101 } catch (Exception e) {
102 pathToIdTtl = 30 * 60 * 1000;
103 }
104
105 initializeInternals();
106 } finally {
107 lock.writeLock().unlock();
108 }
109 }
110
111
112
113
114 private void initializeInternals() {
115 lock.writeLock().lock();
116 try {
117
118 int cacheHashTableCapacity = (int) Math.ceil(cacheSize / HASHTABLE_LOAD_FACTOR) + 1;
119
120 final int cs = cacheSize;
121
122 objectMap = new LinkedHashMap<String, CacheItem<Map<String, CmisObject>>>(cacheHashTableCapacity,
123 HASHTABLE_LOAD_FACTOR) {
124
125 private static final long serialVersionUID = 1L;
126
127 @Override
128 protected boolean removeEldestEntry(Map.Entry<String, CacheItem<Map<String, CmisObject>>> eldest) {
129 return size() > cs;
130 }
131 };
132
133
134 int pathtoidHashTableCapacity = (int) Math.ceil(pathToIdSize / HASHTABLE_LOAD_FACTOR) + 1;
135
136 final int ptis = pathToIdSize;
137
138 pathToIdMap = new LinkedHashMap<String, CacheItem<String>>(pathtoidHashTableCapacity, HASHTABLE_LOAD_FACTOR) {
139
140 private static final long serialVersionUID = 1L;
141
142 @Override
143 protected boolean removeEldestEntry(Map.Entry<String, CacheItem<String>> eldest) {
144 return size() > ptis;
145 }
146 };
147 } finally {
148 lock.writeLock().unlock();
149 }
150 }
151
152 public void clear() {
153 initializeInternals();
154 }
155
156 public boolean containsId(String objectId, String cacheKey) {
157 lock.writeLock().lock();
158 try {
159 if (!objectMap.containsKey(objectId)) {
160 return false;
161 }
162
163 CacheItem<Map<String, CmisObject>> item = objectMap.get(objectId);
164 if (item.isExpired()) {
165 objectMap.remove(objectId);
166 return false;
167 }
168
169 return true;
170 } finally {
171 lock.writeLock().unlock();
172 }
173 }
174
175 public boolean containsPath(String path, String cacheKey) {
176 lock.writeLock().lock();
177 try {
178 if (!pathToIdMap.containsKey(path)) {
179 return false;
180 }
181
182 CacheItem<String> item = pathToIdMap.get(path);
183 if (item.isExpired() || !containsId(item.getItem(), cacheKey)) {
184 pathToIdMap.remove(path);
185 return false;
186 }
187
188 return true;
189 } finally {
190 lock.writeLock().unlock();
191 }
192 }
193
194 public CmisObject getById(String objectId, String cacheKey) {
195 lock.writeLock().lock();
196 try {
197 if (!containsId(objectId, cacheKey)) {
198 return null;
199 }
200
201 Map<String, CmisObject> item = objectMap.get(objectId).getItem();
202 return (item == null ? null : item.get(cacheKey));
203 } finally {
204 lock.writeLock().unlock();
205 }
206 }
207
208 public CmisObject getByPath(String path, String cacheKey) {
209 lock.writeLock().lock();
210 try {
211 if (!containsPath(path, cacheKey)) {
212 return null;
213 }
214
215 CacheItem<String> item = pathToIdMap.get(path);
216 return getById(item.getItem(), cacheKey);
217 } finally {
218 lock.writeLock().unlock();
219 }
220 }
221
222 public void put(CmisObject object, String cacheKey) {
223
224 if ((object == null) || (cacheKey == null)) {
225 return;
226 }
227
228
229 if (object.getId() == null) {
230 return;
231 }
232
233 lock.writeLock().lock();
234 try {
235
236 CacheItem<Map<String, CmisObject>> cacheKeyMap = objectMap.get(object.getId());
237 if (cacheKeyMap == null) {
238 cacheKeyMap = new CacheItem<Map<String, CmisObject>>(new HashMap<String, CmisObject>(), cacheTtl);
239 objectMap.put(object.getId(), cacheKeyMap);
240 }
241
242
243 Map<String, CmisObject> m = cacheKeyMap.getItem();
244 if (m != null) {
245 m.put(cacheKey, object);
246 }
247
248
249 String path = object.getPropertyValue(PropertyIds.PATH);
250 if (path != null) {
251 pathToIdMap.put(path, new CacheItem<String>(object.getId(), pathToIdTtl));
252 }
253 } finally {
254 lock.writeLock().unlock();
255 }
256 }
257
258 public void putPath(String path, CmisObject object, String cacheKey) {
259 if (path == null) {
260 return;
261 }
262
263 lock.writeLock().lock();
264 try {
265 put(object, cacheKey);
266
267 if ((object != null) && (object.getId() != null) && (cacheKey != null)) {
268 pathToIdMap.put(path, new CacheItem<String>(object.getId(), pathToIdTtl));
269 }
270 } finally {
271 lock.writeLock().unlock();
272 }
273 }
274
275 public void remove(String objectId) {
276 if(objectId == null) {
277 return;
278 }
279
280 lock.writeLock().lock();
281 try {
282 objectMap.remove(objectId);
283 } finally {
284 lock.writeLock().unlock();
285 }
286 }
287
288 public int getCacheSize() {
289 return this.cacheSize;
290 }
291
292
293
294 private static class CacheItem<T> implements Serializable {
295
296 private static final long serialVersionUID = 1L;
297
298 private SoftReference<T> item;
299 private long timestamp;
300 private int ttl;
301
302 public CacheItem(T item, int ttl) {
303 this.item = new SoftReference<T>(item);
304 timestamp = System.currentTimeMillis();
305 this.ttl = ttl;
306 }
307
308 public synchronized boolean isExpired() {
309 if ((item == null) || (item.get() == null)) {
310 return true;
311 }
312
313 return (timestamp + ttl < System.currentTimeMillis());
314 }
315
316 public synchronized T getItem() {
317 if (isExpired()) {
318 item = null;
319 return null;
320 }
321
322 return item.get();
323 }
324
325 private void writeObject(ObjectOutputStream out) throws IOException {
326 out.writeObject(isExpired() ? null : item.get());
327 out.writeLong(timestamp);
328 out.writeInt(ttl);
329 }
330
331 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
332 @SuppressWarnings("unchecked")
333 T object = (T) in.readObject();
334 timestamp = in.readLong();
335 ttl = in.readInt();
336
337 if ((object != null) && (timestamp + ttl >= System.currentTimeMillis())) {
338 this.item = new SoftReference<T>(object);
339 }
340 }
341 }
342 }