KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jofti > cache > BaseAdaptor


1 /*
2  * Created on 05-May-2005
3  *
4  */

5 package com.jofti.cache;
6
7 import java.util.HashMap JavaDoc;
8 import java.util.Iterator JavaDoc;
9 import java.util.LinkedHashMap JavaDoc;
10 import java.util.Map JavaDoc;
11 import java.util.Map.Entry;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15
16 import com.jofti.api.IndexQuery;
17 import com.jofti.core.INameSpaceAware;
18 import com.jofti.core.IParsedQuery;
19 import com.jofti.core.InternalIndex;
20 import com.jofti.core.QueryId;
21 import com.jofti.core.QueryType;
22 import com.jofti.exception.JoftiException;
23 import com.jofti.introspect.ClassIntrospector;
24 import com.jofti.parser.ClassFieldMethods;
25 import com.jofti.parser.ParserManager;
26 import com.jofti.util.CompositeComparator;
27 import com.jofti.util.ObjectProcedureAdapter;
28 import com.jofti.util.OpenHashMap;
29 import com.jofti.util.ValueTreeMap;
30
31 /**
32
33  *
34  * The base class for the adapters. The locking is used to allow a reasonable amount of concurrency in the
35  * cache. There are 31 locks that are obtained as a mod 31 of the Object's hashcode. The premise is that a lock can be obtained on methods that modify or access the cache. The objective is to prevent
36  * concurrent modification for identical keys . However, it is also desirable to allow concurrent usage of the
37  * cache and the index as both should be multi-threaded. Although that is reliant on the implementation.<p>
38  
39  * @author Steve Woodcock<br>
40  *
41  */

42 public abstract class BaseAdaptor implements IBaseAdaptor {
43
44     // array of locks
45
protected Object JavaDoc[] cacheLocks = new Object JavaDoc[31];
46
47     int updates =0;
48     int queries =0;
49     // is check mutable enabled?
50
protected boolean checkMutable = false;
51
52     protected String JavaDoc MUTABLE_VALUES = "mutable-values";
53     
54     protected InternalIndex index;
55
56     // lock that provides two groups of exclusive readers
57
private final QueryUpdateLock queryUpdateLock = new QueryUpdateLock();
58
59     private static Log log = LogFactory.getLog(BaseAdaptor.class);
60
61     // initialise the object locks
62
{
63         for (int i = 0; i < 31; i++) {
64             cacheLocks[i] = new Object JavaDoc();
65         }
66     }
67
68     /* (non-Javadoc)
69      * @see com.jofti.cache.IBaseAdaptor#getCacheLock(java.lang.Object)
70      */

71     public Object JavaDoc getCacheLock(Object JavaDoc key) {
72         int temp = (key.hashCode() % 31);
73         return cacheLocks[temp < 0 ? -temp : temp];
74     }
75     /*
76      * (non-Javadoc)
77      *
78      * @see com.jofti.api.IndexCache#query(com.jofti.api.IndexQuery)
79      */

80     /* (non-Javadoc)
81      * @see com.jofti.cache.IBaseAdaptor#query(com.jofti.api.IndexQuery)
82      */

83     public Map JavaDoc query(IndexQuery query) throws JoftiException {
84         
85         Map JavaDoc temp = null;
86         
87         query = processQuery(query, index.getParserManager());
88         
89         
90         acquireQueryLock();
91         try {
92         
93         temp=index.query(query);
94         } finally {
95             releaseQueryLock();
96         }
97         return getCacheValues(temp, (IParsedQuery)query,index.getIntrospector());
98         
99         
100
101     }
102     public IndexQuery processQuery(IndexQuery query, ParserManager manager) throws JoftiException {
103         QueryType type = ((QueryId)query).getQueryType();
104          if ( type!= QueryType.PARSED_QUERY) {
105                query = (IndexQuery) manager.parseQuery( query);
106          }
107       
108            if (((INameSpaceAware) query).getNameSpace() != null) {
109                throw new JoftiException(
110                        "namespace not allowed in non name-space cache query");
111            }
112         return query;
113     }
114     /* (non-Javadoc)
115      * @see com.jofti.cache.IBaseAdaptor#getCacheValues(java.util.Map, com.jofti.core.IParsedQuery, com.jofti.introspect.ClassIntrospector)
116      */

117     public Map JavaDoc getCacheValues(Map JavaDoc col, final IParsedQuery query,
118             final ClassIntrospector introspector) throws JoftiException {
119
120         
121         final Map JavaDoc returnClasses = query.getResultFieldsMap();
122         final CompositeComparator comp = query.getOrderingComparator();
123         final int maxResults = query.getMaxResults();
124         final int startEntry = query.getFirstResult();
125         
126         Map JavaDoc interim = null;
127         if (comp ==null || comp.getSize() ==0){
128             interim =new HashMap JavaDoc(col.size() + 2, 1.00f);
129         }else{
130             interim = new ValueTreeMap(comp);
131         }
132         
133         // return map
134
final Map JavaDoc temp = interim;
135         
136         
137
138         // the results should always be an OpenHashMap
139
OpenHashMap originalMap = (OpenHashMap) col;
140
141         
142         // populate the return Map
143
originalMap.forEachPair(new ObjectProcedureAdapter() {
144             
145             public boolean apply(Object JavaDoc key, Object JavaDoc value) {
146                 
147                 //this will be an alias or null or it is not in the return set and we can ignore it
148
if (value == null || returnClasses ==null || returnClasses.containsKey(value)) {
149                     // see if we have the class in the return map
150

151                     // strip the key of wrapper if it is noncomparable
152
key = stripKey(key);
153
154                     Object JavaDoc result = getCacheValue(key);
155
156                     if (result == null) {
157                         warnOutOfDate(key);
158                     } else {
159                         // get the methods to be operated on the value
160
if (checkMutable) {
161                             result = checkMutable(key, result);
162                             // mutability check failed
163
if (result == null) {
164                                 if (log.isDebugEnabled()) {
165                                     log
166                                             .debug("Object under key:"
167                                                     + key
168                                                     + " has changed in cache since it was indexed");
169                                 }
170                                 return true;
171                             }
172                         }
173                         
174                         
175                         if (returnClasses != null) {
176                             // we need to get the value from result if we are using fields
177
ClassFieldMethods fieldSet = (ClassFieldMethods) returnClasses
178                                     .get(value);
179
180                             Map JavaDoc tempMap = fieldSet != null ? fieldSet
181                                     .getFieldMap() : null;
182
183                             if (tempMap != null && tempMap.size() > 0) {
184                                 // get the fields and apply the values to them
185

186                                     Map JavaDoc resultMap = new LinkedHashMap JavaDoc();
187                 
188                                     resultMap = introspector.getResultValuesFromObject(resultMap,result,tempMap);
189                                     
190                                     // no values means no mapping in results
191
if (resultMap.size()>0){
192                                         Object JavaDoc[] res = new Object JavaDoc[resultMap.size()];
193                                         Iterator JavaDoc it = resultMap.entrySet().iterator();
194                                         for (int i = 0;i<resultMap.size();i++){
195                                             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)it.next();
196                                             res[i]= entry.getValue();
197                                         }
198                                         temp.put(key,res);
199                                     }
200                                     
201                             } else {
202                                 // there are no fields just return the value
203
temp.put(key, result);
204                             }
205                         } else {
206                             temp.put(key, result);
207                         }
208                     }
209
210                 }
211                 return true;
212             }
213         });
214
215         if (startEntry <0){
216             throw new IllegalArgumentException JavaDoc("startResult cannot be less than 0:"+startEntry);
217         }
218         if (maxResults <0){
219             throw new IllegalArgumentException JavaDoc("maxResults cannot be less than 0:"+maxResults);
220         }
221         // now limit result size
222
if (maxResults >0 || startEntry >0){
223             return limitResults(temp, startEntry, maxResults);
224         }
225                 
226         return temp;
227     }
228     
229     public void warnOutOfDate(Object JavaDoc key){
230         if (log.isWarnEnabled()) {
231             log
232                     .warn("Index and cache have become out of date for key "
233                             + key);
234         }
235     }
236
237     public Map JavaDoc limitResults(Map JavaDoc temp, int startResult, int maxResults){
238         
239         if (maxResults ==0){
240             maxResults = temp.size();
241         }
242         
243         if (temp.size() <= (maxResults - startResult)){
244             return temp;
245         }
246         
247         if (temp instanceof ValueTreeMap) {
248             return ((ValueTreeMap)temp).getSubMap(startResult, maxResults);
249             
250         }else{
251
252         Iterator JavaDoc it = temp.entrySet().iterator();
253         
254         
255         int count =0;
256             while (it.hasNext()){
257                 it.next();
258                 if (count < startResult || count >= maxResults +startResult){
259                     it.remove();
260                 }
261                 count++;
262             }
263             return temp;
264         }
265         
266         
267         
268     }
269     /* (non-Javadoc)
270      * @see com.jofti.cache.IBaseAdaptor#acquireUpdateLock()
271      */

272     public void acquireUpdateLock() throws JoftiException {
273         try {
274
275             queryUpdateLock.updateLock().acquire();
276         } catch (Exception JavaDoc e) {
277             throw new JoftiException(e);
278         }
279
280     }
281
282     /* (non-Javadoc)
283      * @see com.jofti.cache.IBaseAdaptor#releaseUpdateLock()
284      */

285     public void releaseUpdateLock() {
286
287         queryUpdateLock.updateLock().release();
288     
289     }
290
291     /* (non-Javadoc)
292      * @see com.jofti.cache.IBaseAdaptor#acquireQueryLock()
293      */

294     public void acquireQueryLock() throws JoftiException {
295         try {
296             queryUpdateLock.queryLock().acquire();
297             } catch (Exception JavaDoc e) {
298             throw new JoftiException(e);
299         }
300     }
301
302     /* (non-Javadoc)
303      * @see com.jofti.cache.IBaseAdaptor#releaseQueryLock()
304      */

305     public void releaseQueryLock() {
306
307         queryUpdateLock.queryLock().release();
308     }
309
310     /* (non-Javadoc)
311      * @see com.jofti.cache.IBaseAdaptor#decorateKey(java.lang.Object)
312      */

313     public Object JavaDoc decorateKey(Object JavaDoc key) {
314         if (key != null && !(key instanceof Comparable JavaDoc)) {
315             key = new NonComparableKeyWrapper(key);
316         }
317         return key;
318     }
319
320     /* (non-Javadoc)
321      * @see com.jofti.cache.IBaseAdaptor#stripKey(java.lang.Object)
322      */

323     public Object JavaDoc stripKey(Object JavaDoc key) {
324         if (key instanceof NonComparableKeyWrapper) {
325             key = ((NonComparableKeyWrapper) key).getKey();
326         }
327         return key;
328     }
329
330     /**
331      * Returns the value from the Cache for the key. Each adpter is responsible for the specific implementation of this, as
332      * the Cache retrieval mechanism will probably be different for each Cache.
333      * @param key
334      * @return
335      */

336     protected abstract Object JavaDoc getCacheValue(Object JavaDoc key);
337
338     /**
339      * Checks the multability of a Cache value retrieved from the Cache instance in the adapter. Each
340      * adapter is responsible for providing the implementation.
341      * @param key
342      * @param result
343      * @return The value from the Cache or Null if the value has changed after it was indexed
344      */

345     protected Object JavaDoc checkMutable(Object JavaDoc key, Object JavaDoc result) {
346         try {
347             if (log.isDebugEnabled()) {
348                 log.debug("Checking mutability ");
349             }
350             // first parse the object - again
351
Map JavaDoc cacheObjectValues = index.getIntrospector().getAttributeValues(
352                     result);
353
354             Map JavaDoc indexObjectValues = index.getAttributesByKey(decorateKey(key));
355             if (cacheObjectValues.equals(indexObjectValues)) {
356                 return result;
357             } else {
358                 if (log.isDebugEnabled()) {
359                     log.debug("Object under Key " + key
360                             + " - attributes changed without re-insert");
361                 }
362             }
363             // then get the values for the key
364

365         } catch (JoftiException e) {
366             log.warn("Error checking mutability", e);
367         }
368
369         return null;
370     }
371     
372
373     /* (non-Javadoc)
374      * @see com.jofti.cache.IBaseAdaptor#getIndex()
375      */

376     public abstract InternalIndex getIndex();
377 }
Popular Tags