1 5 package com.jofti.cache; 6 7 import java.util.HashMap ; 8 import java.util.Iterator ; 9 import java.util.LinkedHashMap ; 10 import java.util.Map ; 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 42 public abstract class BaseAdaptor implements IBaseAdaptor { 43 44 protected Object [] cacheLocks = new Object [31]; 46 47 int updates =0; 48 int queries =0; 49 protected boolean checkMutable = false; 51 52 protected String MUTABLE_VALUES = "mutable-values"; 53 54 protected InternalIndex index; 55 56 private final QueryUpdateLock queryUpdateLock = new QueryUpdateLock(); 58 59 private static Log log = LogFactory.getLog(BaseAdaptor.class); 60 61 { 63 for (int i = 0; i < 31; i++) { 64 cacheLocks[i] = new Object (); 65 } 66 } 67 68 71 public Object getCacheLock(Object key) { 72 int temp = (key.hashCode() % 31); 73 return cacheLocks[temp < 0 ? -temp : temp]; 74 } 75 80 83 public Map query(IndexQuery query) throws JoftiException { 84 85 Map 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 117 public Map getCacheValues(Map col, final IParsedQuery query, 118 final ClassIntrospector introspector) throws JoftiException { 119 120 121 final Map returnClasses = query.getResultFieldsMap(); 122 final CompositeComparator comp = query.getOrderingComparator(); 123 final int maxResults = query.getMaxResults(); 124 final int startEntry = query.getFirstResult(); 125 126 Map interim = null; 127 if (comp ==null || comp.getSize() ==0){ 128 interim =new HashMap (col.size() + 2, 1.00f); 129 }else{ 130 interim = new ValueTreeMap(comp); 131 } 132 133 final Map temp = interim; 135 136 137 138 OpenHashMap originalMap = (OpenHashMap) col; 140 141 142 originalMap.forEachPair(new ObjectProcedureAdapter() { 144 145 public boolean apply(Object key, Object value) { 146 147 if (value == null || returnClasses ==null || returnClasses.containsKey(value)) { 149 151 key = stripKey(key); 153 154 Object result = getCacheValue(key); 155 156 if (result == null) { 157 warnOutOfDate(key); 158 } else { 159 if (checkMutable) { 161 result = checkMutable(key, result); 162 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 ClassFieldMethods fieldSet = (ClassFieldMethods) returnClasses 178 .get(value); 179 180 Map tempMap = fieldSet != null ? fieldSet 181 .getFieldMap() : null; 182 183 if (tempMap != null && tempMap.size() > 0) { 184 186 Map resultMap = new LinkedHashMap (); 187 188 resultMap = introspector.getResultValuesFromObject(resultMap,result,tempMap); 189 190 if (resultMap.size()>0){ 192 Object [] res = new Object [resultMap.size()]; 193 Iterator it = resultMap.entrySet().iterator(); 194 for (int i = 0;i<resultMap.size();i++){ 195 Map.Entry entry = (Map.Entry )it.next(); 196 res[i]= entry.getValue(); 197 } 198 temp.put(key,res); 199 } 200 201 } else { 202 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 ("startResult cannot be less than 0:"+startEntry); 217 } 218 if (maxResults <0){ 219 throw new IllegalArgumentException ("maxResults cannot be less than 0:"+maxResults); 220 } 221 if (maxResults >0 || startEntry >0){ 223 return limitResults(temp, startEntry, maxResults); 224 } 225 226 return temp; 227 } 228 229 public void warnOutOfDate(Object 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 limitResults(Map 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 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 272 public void acquireUpdateLock() throws JoftiException { 273 try { 274 275 queryUpdateLock.updateLock().acquire(); 276 } catch (Exception e) { 277 throw new JoftiException(e); 278 } 279 280 } 281 282 285 public void releaseUpdateLock() { 286 287 queryUpdateLock.updateLock().release(); 288 289 } 290 291 294 public void acquireQueryLock() throws JoftiException { 295 try { 296 queryUpdateLock.queryLock().acquire(); 297 } catch (Exception e) { 298 throw new JoftiException(e); 299 } 300 } 301 302 305 public void releaseQueryLock() { 306 307 queryUpdateLock.queryLock().release(); 308 } 309 310 313 public Object decorateKey(Object key) { 314 if (key != null && !(key instanceof Comparable )) { 315 key = new NonComparableKeyWrapper(key); 316 } 317 return key; 318 } 319 320 323 public Object stripKey(Object key) { 324 if (key instanceof NonComparableKeyWrapper) { 325 key = ((NonComparableKeyWrapper) key).getKey(); 326 } 327 return key; 328 } 329 330 336 protected abstract Object getCacheValue(Object key); 337 338 345 protected Object checkMutable(Object key, Object result) { 346 try { 347 if (log.isDebugEnabled()) { 348 log.debug("Checking mutability "); 349 } 350 Map cacheObjectValues = index.getIntrospector().getAttributeValues( 352 result); 353 354 Map 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 365 } catch (JoftiException e) { 366 log.warn("Error checking mutability", e); 367 } 368 369 return null; 370 } 371 372 373 376 public abstract InternalIndex getIndex(); 377 } | Popular Tags |