1
2
3
4
5
6
7
8
9 package ca.uhn.cache.internal.impl;
10
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.Date;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Set;
18
19 import net.sf.hibernate.Hibernate;
20
21 import org.apache.commons.collections.CollectionUtils;
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.springframework.beans.factory.InitializingBean;
25 import org.springframework.orm.hibernate.support.HibernateDaoSupport;
26
27 import ca.uhn.cache.CacheReasonEnum;
28 import ca.uhn.cache.IQuery;
29 import ca.uhn.cache.VolatilityEnum;
30 import ca.uhn.cache.internal.IChunk;
31 import ca.uhn.cache.internal.IChunkIterator;
32 import ca.uhn.cache.internal.IChunkPurger;
33 import ca.uhn.cache.internal.IChunkStore;
34 import ca.uhn.cache.internal.IStaleChunkRule;
35 import ca.uhn.cache.internal.hibernate.impl.ChunkField;
36 import ca.uhn.cache.internal.util.TimestampUtils;
37 import ca.uhn.cache.internal.util.UTC;
38
39 /***
40 * Hibernate-based implementation of <code>IChunkStore</code>
41 *
42 * @author <a href="mailto:alexei.guevara@uhn.on.ca">Alexei Guevara</a>
43 * @version $Revision: 1.1 $ updated on $Date: 2005/01/24 22:54:04 $ by $Author: bryan_tripp $
44 */
45 public class HibernateChunkStore extends HibernateDaoSupport implements IChunkStore, IChunkPurger, InitializingBean {
46
47 private static Log ourLog = LogFactory.getLog(HibernateChunkStore.class);
48
49 private final IStaleChunkRule myStaleChunkRule;
50
51 /***
52 * Constructor.
53 *
54 * @param theStaleChunkRule The rule to decide when the chunks will become stale.
55 */
56 public HibernateChunkStore( IStaleChunkRule theStaleChunkRule )
57 {
58 myStaleChunkRule = theStaleChunkRule;
59 }
60
61 /***
62 * @param theQuery The specified query.
63 * @return The value to which this <code>IChunkStore</code> maps the specified query, or
64 * <tt>null</tt> if the <code>IChunkStore</code> contains no mapping for the query.
65 */
66 public IChunk get( IQuery theQuery )
67 {
68 assert theQuery != null;
69 assert !theQuery.isEmpty();
70
71 IChunk retVal = null;
72
73 List foundChunkList = null;
74
75
76 foundChunkList = getHibernateTemplate().find(
77 "FROM " +ChunkField.class.getName()+ " WHERE queryHash=?",
78 new Integer( theQuery.hashCode() ),
79 Hibernate.INTEGER );
80
81 if (!foundChunkList.isEmpty()){
82 ChunkField foundChunk = (ChunkField)foundChunkList.get(0);
83
84 if (foundChunk != null){
85 retVal = foundChunk.toChunk();
86 }
87 }
88
89 return retVal;
90 }
91
92
93 /***
94 * Places a <code>IChunk</code> corresponding to the specified <code>IQuery</code>
95 * in this <code>IChunkStore</code>. If the <code>IChunkStore</code> previously contained
96 * a mapping for this query, the value is replaced by a new <code>IChunk</code> with the new volatility
97 * and reasons.
98 *
99 * @param theQuery Query with which the chunk is to be associated.
100 * @param theVolatility The volatility that will decide the length of stay in the cache. If there
101 * is a mapping for this query currently in the cache, this will replace the old value.
102 * @param theReasons The reasons that this chunk was cached. If there is a mapping for this query
103 * currently in the cache, this will be appended to the old value.
104 *
105 * @return Previous value associated with specified query, or <tt>null</tt>
106 * if there was no mapping for the query.
107 */
108 public IChunk put( IQuery theQuery, VolatilityEnum theVolatility, CacheReasonEnum[] theReasons )
109 {
110 assert theQuery != null;
111 assert !theQuery.isEmpty();
112 assert theVolatility != null;
113 assert theReasons != null;
114 assert theReasons.length > 0;
115
116 IChunk retVal = null;
117 Set cacheReasons = new HashSet();
118
119
120 retVal = get(theQuery);
121
122 if (retVal != null){
123 CacheReasonEnum[] oldReasons = retVal.getReasons();
124 Collection newReasons = CollectionUtils.union(Arrays.asList(oldReasons), Arrays.asList(theReasons));
125
126 Iterator iter = newReasons.iterator();
127 while(iter.hasNext()){
128 CacheReasonEnum next = (CacheReasonEnum)iter.next();
129 cacheReasons.add( next );
130 }
131
132 ChunkField newVal = new ChunkField();
133 newVal.setHibernateId(retVal.getId());
134
135 newVal.setVolatility(theVolatility);
136 newVal.setLastUpdateTime( TimestampUtils.dateToTimestamp( UTC.currentTime() ) );
137 newVal.setCacheTime( TimestampUtils.dateToTimestamp( retVal.getCacheTime() ) );
138 newVal.setLastAccessTime( TimestampUtils.dateToTimestamp( UTC.currentTime() ) );
139 newVal.setReasons( cacheReasons );
140 newVal.setQueryHash( theQuery.hashCode() );
141
142 getHibernateTemplate().update(newVal);
143 }
144 else{
145 ChunkField newVal = new ChunkField();
146
147 for (int i = 0; i < theReasons.length; i++){
148 cacheReasons.add( theReasons[ i ] );
149 }
150
151 newVal.setVolatility(theVolatility);
152 newVal.setLastUpdateTime(TimestampUtils.dateToTimestamp( UTC.currentTime() ));
153 newVal.setCacheTime(TimestampUtils.dateToTimestamp( UTC.currentTime() ));
154 newVal.setLastAccessTime(TimestampUtils.dateToTimestamp( UTC.currentTime() ));
155 newVal.setReasons(cacheReasons);
156 newVal.setQueryHash(theQuery.hashCode());
157
158
159 long maxAgeInMillis = getStaleChunkRule().getMaxAge( newVal.toChunk() );
160 Date expiryDate = UTC.fromCurrentTime( maxAgeInMillis );
161 newVal.setExpiryTime( TimestampUtils.dateToTimestamp( expiryDate ) );
162
163 getHibernateTemplate().save(newVal);
164 }
165
166 return retVal;
167 }
168
169 /***
170 * Removes the mapping for this query from this <code>IChunkStore</code> if it is present
171 *
172 * @param theQuery Query whose mapping is to be removed from the <code>IChunkStore</code>.
173 *
174 * @return Previous value associated with specified query, or <tt>null</tt>
175 * if there was no mapping for the query.
176 */
177 public IChunk remove( IQuery theQuery )
178 {
179 assert theQuery != null;
180 assert !theQuery.isEmpty();
181
182 IChunk retVal = get(theQuery);
183
184 if (retVal != null){
185 getHibernateTemplate().delete(
186 "FROM " +ChunkField.class.getName()+ " WHERE queryHash=?",
187 new Integer( theQuery.hashCode() ),
188 Hibernate.INTEGER );
189 }
190
191 return retVal;
192 }
193
194 /***
195 * {@inheritDoc}
196 */
197 public IChunkIterator getUnusedChunks( long theVoguenessThreshold ) {
198
199 throw new UnsupportedOperationException( "Not implemented" );
200 }
201
202 /***
203 * {@inheritDoc}
204 */
205 public IChunkIterator getStaleChunks() {
206 ChunkIterator retVal = new ChunkIterator();
207
208 List staleChunkList =
209 getHibernateTemplate().find(
210 "FROM " +ChunkField.class.getName()+ " WHERE expiryTime <= ?",
211 TimestampUtils.dateToTimestamp( UTC.currentTime() ),
212 Hibernate.TIMESTAMP );
213
214 for (Iterator iter = staleChunkList.iterator(); iter.hasNext();) {
215 ChunkField chunk = (ChunkField) iter.next();
216 retVal.add( chunk.toChunk() );
217 }
218
219 retVal.finished();
220
221 return retVal;
222
223 }
224
225 /***
226 * {@inheritDoc}
227 */
228 public long getLowestVogueness() {
229
230 throw new UnsupportedOperationException( "Not implemented" );
231 }
232
233 /***
234 * {@inheritDoc}
235 */
236 public int getNumCachedItems() {
237
238 throw new UnsupportedOperationException( "Not implemented" );
239 }
240
241 /***
242 * {@inheritDoc}
243 */
244 public IStaleChunkRule getStaleChunkRule() {
245 return myStaleChunkRule;
246 }
247
248 }