1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.page.impl;
18
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.LinkedList;
22 import java.util.List;
23 import java.util.Properties;
24
25 import org.apache.jetspeed.om.folder.impl.FolderImpl;
26 import org.apache.jetspeed.page.PageManager;
27 import org.apache.jetspeed.page.document.impl.NodeImpl;
28 import org.apache.ojb.broker.Identity;
29 import org.apache.ojb.broker.PersistenceBroker;
30 import org.apache.ojb.broker.cache.ObjectCache;
31
32 /***
33 * DatabasePageManagerCache
34 *
35 * @author <a href="mailto:rwatler@apache.org">Randy Watler</a>
36 * @version $Id: $
37 */
38 public class DatabasePageManagerCache implements ObjectCache
39 {
40 private static HashMap cacheByOID;
41 private static LinkedList cacheLRUList;
42 private static HashMap cacheByPath;
43 private static int cacheSize;
44 private static int cacheExpiresSeconds;
45 private static boolean constraintsEnabled;
46 private static boolean permissionsEnabled;
47 private static PageManager pageManager;
48
49 /***
50 * cacheInit
51 *
52 * Initialize cache using page manager configuration.
53 *
54 * @param pageManager configured page manager
55 */
56 public synchronized static void cacheInit(DatabasePageManager dbPageManager)
57 {
58 if (pageManager == null)
59 {
60 cacheByOID = new HashMap();
61 cacheLRUList = new LinkedList();
62 cacheByPath = new HashMap();
63 cacheSize = dbPageManager.getCacheSize();
64 cacheExpiresSeconds = dbPageManager.getCacheExpiresSeconds();
65 constraintsEnabled = dbPageManager.getConstraintsEnabled();
66 permissionsEnabled = dbPageManager.getPermissionsEnabled();
67 pageManager = dbPageManager;
68 }
69 }
70
71 /***
72 * setPageManagerProxy
73 *
74 * @param proxy proxied page manager interface used to
75 * inject into Folder instances to provide
76 * transaction/interception
77 */
78 public synchronized static void setPageManagerProxy(PageManager proxy)
79 {
80
81
82 if (pageManager != proxy)
83 {
84 pageManager = proxy;
85 cacheClear();
86 }
87 }
88
89 /***
90 * cacheLookup
91 *
92 * Lookup node instances by unique path.
93 *
94 * @param path node unique path
95 * @return cached node
96 */
97 public synchronized static NodeImpl cacheLookup(String path)
98 {
99 if (path != null)
100 {
101
102 return (NodeImpl)cacheValidateEntry((Entry)cacheByPath.get(path));
103 }
104 return null;
105 }
106
107 /***
108 * cacheAdd
109 *
110 * Add object to cache and cache node instances by unique path;
111 * infuse nodes loaded by OJB with page manager configuration.
112 *
113 * @param oid object/node indentity
114 * @param obj object/node to cache
115 */
116 public synchronized static void cacheAdd(Identity oid, Object obj)
117 {
118 Entry entry = (Entry)cacheByOID.get(oid);
119 if (entry != null)
120 {
121
122 cacheLRUList.remove(entry);
123 cacheLRUList.addFirst(entry);
124
125 entry.touch();
126 }
127 else
128 {
129
130 entry = new Entry(obj, oid);
131 cacheByOID.put(oid, entry);
132 cacheLRUList.addFirst(entry);
133
134
135
136 if (obj instanceof NodeImpl)
137 {
138 NodeImpl node = (NodeImpl)obj;
139 node.setConstraintsEnabled(constraintsEnabled);
140 node.setPermissionsEnabled(permissionsEnabled);
141 cacheByPath.put(node.getPath(), entry);
142 if (obj instanceof FolderImpl)
143 {
144 ((FolderImpl)obj).setPageManager(pageManager);
145 }
146 }
147
148 while (cacheLRUList.size() > cacheSize)
149 {
150 cacheRemoveEntry((Entry)cacheLRUList.getLast(), true);
151 }
152 }
153 }
154
155 /***
156 * cacheClear
157 *
158 * Clear object and node caches.
159 */
160 public synchronized static void cacheClear()
161 {
162
163 Iterator removeIter = cacheLRUList.iterator();
164 while (removeIter.hasNext())
165 {
166 cacheRemoveEntry((Entry)removeIter.next(), false);
167 }
168
169 cacheByOID.clear();
170 cacheLRUList.clear();
171 cacheByPath.clear();
172 }
173
174 /***
175 * cacheLookup
176 *
177 * Lookup objects by identity.
178 *
179 * @param oid object identity
180 * @return cached object
181 */
182 public synchronized static Object cacheLookup(Identity oid)
183 {
184 if (oid != null)
185 {
186
187 return cacheValidateEntry((Entry)cacheByOID.get(oid));
188 }
189 return null;
190 }
191
192 /***
193 * cacheRemove
194 *
195 * Remove identified object from object and node caches.
196 *
197 * @param oid object identity
198 */
199 public synchronized static void cacheRemove(Identity oid)
200 {
201
202 cacheRemoveEntry((Entry)cacheByOID.get(oid), true);
203 }
204
205 /***
206 * cacheRemove
207 *
208 * Remove identified object from object and node caches.
209 *
210 * @param path object path
211 */
212 public synchronized static void cacheRemove(String path)
213 {
214
215 cacheRemoveEntry((Entry)cacheByPath.get(path), true);
216 }
217
218 /***
219 * cacheValidateEntry
220 *
221 * Validate specified entry from cache, returning cached
222 * object if valid.
223 *
224 * @param entry cache entry to validate
225 * @return validated object from cache
226 */
227 private synchronized static Object cacheValidateEntry(Entry entry)
228 {
229 if (entry != null)
230 {
231 if (!entry.isExpired())
232 {
233
234 cacheLRUList.remove(entry);
235 cacheLRUList.addFirst(entry);
236
237 entry.touch();
238 return entry.getObject();
239 }
240 else
241 {
242
243 cacheRemoveEntry(entry, true);
244 }
245 }
246 return null;
247 }
248
249 /***
250 * cacheRemoveEntry
251 *
252 * Remove specified entry from cache.
253 *
254 * @param entry cache entry to remove
255 * @param remove enable removal from cache
256 */
257 private synchronized static void cacheRemoveEntry(Entry entry, boolean remove)
258 {
259 if (entry != null)
260 {
261 Object removeObj = entry.getObject();
262 if (remove)
263 {
264
265
266 if (cacheLRUList.getLast() == entry)
267 {
268 cacheLRUList.removeLast();
269 }
270 else
271 {
272 int removeIndex = cacheLRUList.lastIndexOf(entry);
273 if (removeIndex > 0)
274 {
275 cacheLRUList.remove(removeIndex);
276 }
277 }
278
279 cacheByOID.remove(entry.getOID());
280 if (removeObj instanceof NodeImpl)
281 {
282 cacheByPath.remove(((NodeImpl)removeObj).getPath());
283 }
284 }
285
286 if (removeObj instanceof FolderImpl)
287 {
288 ((FolderImpl)removeObj).resetAll(false);
289 }
290 }
291 }
292
293 /***
294 * resetCachedSecurityConstraints
295 *
296 * Reset cached security constraints in all cached node objects.
297 */
298 public synchronized static void resetCachedSecurityConstraints()
299 {
300
301 Iterator resetIter = cacheLRUList.iterator();
302 while (resetIter.hasNext())
303 {
304 Object obj = ((Entry)resetIter.next()).getObject();
305 if (obj instanceof NodeImpl)
306 {
307 ((NodeImpl)obj).resetCachedSecurityConstraints();
308 }
309 }
310 }
311
312 /***
313 * Entry
314 *
315 * Cache entry class adding entry timestamp to track expiration
316 */
317 private static class Entry
318 {
319 public long timestamp;
320 public Object object;
321 public Identity oid;
322
323 public Entry(Object object, Identity oid)
324 {
325 touch();
326 this.object = object;
327 this.oid = oid;
328 }
329
330 public boolean isExpired()
331 {
332 if (DatabasePageManagerCache.cacheExpiresSeconds > 0)
333 {
334 long now = System.currentTimeMillis();
335 if (((now - timestamp) / 1000) < DatabasePageManagerCache.cacheExpiresSeconds)
336 {
337 timestamp = now;
338 return false;
339 }
340 return true;
341 }
342 return false;
343 }
344
345 public void touch()
346 {
347 if (DatabasePageManagerCache.cacheExpiresSeconds > 0)
348 {
349 timestamp = System.currentTimeMillis();
350 }
351 }
352
353 public Object getObject()
354 {
355 return object;
356 }
357
358 public Identity getOID()
359 {
360 return oid;
361 }
362 }
363
364 /***
365 * DatabasePageManagerCache
366 *
367 * Construct a cache instance using OJB compliant signatures.
368 *
369 * @param broker broker that is to own cache
370 * @param props attribute properties passed to cache
371 */
372 public DatabasePageManagerCache(PersistenceBroker broker, Properties props)
373 {
374 }
375
376
377
378
379 public void cache(Identity oid, Object obj)
380 {
381 cacheAdd(oid, obj);
382 }
383
384
385
386
387 public void clear()
388 {
389 cacheClear();
390 }
391
392
393
394
395 public Object lookup(Identity oid)
396 {
397 return cacheLookup(oid);
398 }
399
400
401
402
403 public void remove(Identity oid)
404 {
405 cacheRemove(oid);
406 }
407
408 public synchronized static void dump()
409 {
410 System.out.println("--------------------------1");
411 Iterator dumpIter = cacheLRUList.iterator();
412 while (dumpIter.hasNext())
413 {
414 Entry entry = (Entry)dumpIter.next();
415 Object entryObject = entry.getObject();
416 if (entryObject instanceof NodeImpl)
417 {
418 System.out.println("entry = " + ((NodeImpl)entryObject).getPath() + ", " + entry.getOID());
419 }
420 else
421 {
422 System.out.println("entry = <none>, " + entry.getOID());
423 }
424 }
425 System.out.println("--------------------------2");
426 }
427
428 protected static ThreadLocal transactionedOperations = new ThreadLocal();
429
430 public static List getTransactions()
431 {
432 List operations = (List)transactionedOperations.get();
433 if (operations == null)
434 {
435 operations = new LinkedList();
436 transactionedOperations.set(operations);
437 }
438
439 return operations;
440 }
441
442 /***
443 * @param principal
444 * The principal to set.
445 */
446 public static void addTransaction(TransactionedOperation operation)
447 {
448 List transactions = getTransactions();
449 transactions.add(operation);
450 }
451
452 public static void rollbackTransactions()
453 {
454 Iterator transactions = getTransactions().iterator();
455 while (transactions.hasNext())
456 {
457 TransactionedOperation operation = (TransactionedOperation)transactions.next();
458 cacheRemove(operation.getPath());
459 }
460 }
461 }