new utility for updated cached values in a multi-threaded environment.
[utils] / support / general / src / main / java / org / wamblee / cache / CachedObject.java
1 /*
2  * Copyright 2005-2010 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */ 
16 package org.wamblee.cache;
17
18 import org.apache.log4j.Logger;
19
20 import java.io.Serializable;
21
22 /**
23  * Represents a cached object. The object is either retrieved from the cache if
24  * the cache has it, or a call back is invoked to get the object (and put it in
25  * the cache).
26  * 
27  * @author Erik Brakkee
28  * 
29  */
30 public class CachedObject<KeyType extends Serializable, ValueType extends Serializable> {
31     private static final Logger LOGGER = Logger.getLogger(CachedObject.class);
32
33     /**
34      * Cache to use.
35      */
36     private Cache<KeyType, ValueType> cache;
37
38     /**
39      * Key of the object in the cache.
40      */
41     private KeyType objectKey;
42
43     /**
44      * Computation used to obtain the object if it is not found in the cache.
45      */
46     private Computation<KeyType, ValueType> computation;
47
48     /**
49      * Constructs the cached object.
50      * 
51      * @param aCache
52      *            Cache to use.
53      * @param aObjectKey
54      *            Key of the object in the cache.
55      * @param aComputation
56      *            Computation to get the object in case the object is not in the
57      *            cache.
58      */
59     public CachedObject(Cache<KeyType, ValueType> aCache, KeyType aObjectKey,
60         Computation<KeyType, ValueType> aComputation) {
61         cache = aCache;
62         objectKey = aObjectKey;
63         computation = aComputation;
64     }
65
66     /**
67      * Gets the object. Since the object is cached, different calls to this
68      * method may return different objects.
69      * 
70      * @return Object.
71      */
72     public ValueType get() {
73         ValueType object = (ValueType) cache.get(objectKey); // the used
74         // cache is
75         // thread safe.
76
77         if (object == null) {
78             // synchronize the computation to make sure that the object is only
79             // computed
80             // once when multiple concurrent threads detect that the entry must
81             // be
82             // recomputed.
83             synchronized (this) {
84                 object = (ValueType) cache.get(objectKey);
85
86                 if (object == null) {
87                     // No other thread did a recomputation so we must do this
88                     // now.
89                     LOGGER.debug("Refreshing cache for '" + objectKey + "'");
90                     object = computation.getObject(objectKey);
91                     cache.put(objectKey, object);
92                 }
93             }
94         }
95
96         return object;
97     }
98
99     /**
100      * Invalidates the cache for the object so that it is recomputed the next
101      * time it is requested.
102      */
103     public void invalidate() {
104         cache.remove(objectKey);
105     }
106
107     /**
108      * Gets the cache.
109      * 
110      * @return Cache.
111      */
112     public Cache getCache() {
113         return cache;
114     }
115
116     /**
117      * Callback invoked to compute an object if it was not found in the cache.
118      * 
119      * @param <T>
120      *            Type of the object
121      */
122     public static interface Computation<Key extends Serializable, Value extends Serializable> {
123         /**
124          * Gets the object. Called when the object is not in the cache.
125          * 
126          * @param aObjectKey
127          *            Id of the object in the cache.
128          * 
129          * @return Object, must be non-null.
130          */
131         Value getObject(Key aObjectKey);
132     }
133 }