001package org.apache.commons.jcs.auxiliary.lateral; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache; 023import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; 024import org.apache.commons.jcs.engine.CacheAdaptor; 025import org.apache.commons.jcs.engine.CacheEventQueueFactory; 026import org.apache.commons.jcs.engine.CacheInfo; 027import org.apache.commons.jcs.engine.CacheStatus; 028import org.apache.commons.jcs.engine.behavior.ICacheElement; 029import org.apache.commons.jcs.engine.behavior.ICacheEventQueue; 030import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; 031import org.apache.commons.jcs.engine.stats.StatElement; 032import org.apache.commons.jcs.engine.stats.Stats; 033import org.apache.commons.jcs.engine.stats.behavior.IStatElement; 034import org.apache.commons.jcs.engine.stats.behavior.IStats; 035import org.apache.commons.logging.Log; 036import org.apache.commons.logging.LogFactory; 037 038import java.io.IOException; 039import java.rmi.UnmarshalException; 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.HashMap; 043import java.util.Map; 044import java.util.Set; 045 046/** 047 * Used to queue up update requests to the underlying cache. These requests will be processed in 048 * their order of arrival via the cache event queue processor. 049 */ 050public class LateralCacheNoWait<K, V> 051 extends AbstractAuxiliaryCache<K, V> 052{ 053 /** The logger. */ 054 private static final Log log = LogFactory.getLog( LateralCacheNoWait.class ); 055 056 /** The cache */ 057 private final LateralCache<K, V> cache; 058 059 /** The event queue */ 060 private ICacheEventQueue<K, V> eventQueue; 061 062 /** times get called */ 063 private int getCount = 0; 064 065 /** times remove called */ 066 private int removeCount = 0; 067 068 /** times put called */ 069 private int putCount = 0; 070 071 /** 072 * Constructs with the given lateral cache, and fires up an event queue for asynchronous 073 * processing. 074 * <p> 075 * @param cache 076 */ 077 public LateralCacheNoWait( LateralCache<K, V> cache ) 078 { 079 this.cache = cache; 080 081 if ( log.isDebugEnabled() ) 082 { 083 log.debug( "Constructing LateralCacheNoWait, LateralCache = [" + cache + "]" ); 084 } 085 086 CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<K, V>(); 087 this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor<K, V>( cache ), CacheInfo.listenerId, cache 088 .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache 089 .getAuxiliaryCacheAttributes().getEventQueueType() ); 090 091 // need each no wait to handle each of its real updates and removes, 092 // since there may 093 // be more than one per cache? alternative is to have the cache 094 // perform updates using a different method that specifies the listener 095 // this.q = new CacheEventQueue(new CacheAdaptor(this), 096 // LateralCacheInfo.listenerId, cache.getCacheName()); 097 if ( cache.getStatus() == CacheStatus.ERROR ) 098 { 099 eventQueue.destroy(); 100 } 101 } 102 103 /** 104 * @param ce 105 * @throws IOException 106 */ 107 @Override 108 public void update( ICacheElement<K, V> ce ) 109 throws IOException 110 { 111 putCount++; 112 try 113 { 114 eventQueue.addPutEvent( ce ); 115 } 116 catch ( IOException ex ) 117 { 118 log.error( ex ); 119 eventQueue.destroy(); 120 } 121 } 122 123 /** 124 * Synchronously reads from the lateral cache. 125 * <p> 126 * @param key 127 * @return ICacheElement<K, V> if found, else null 128 */ 129 @Override 130 public ICacheElement<K, V> get( K key ) 131 { 132 getCount++; 133 if ( this.getStatus() != CacheStatus.ERROR ) 134 { 135 try 136 { 137 return cache.get( key ); 138 } 139 catch ( UnmarshalException ue ) 140 { 141 log.debug( "Retrying the get owing to UnmarshalException..." ); 142 try 143 { 144 return cache.get( key ); 145 } 146 catch ( IOException ex ) 147 { 148 log.error( "Failed in retrying the get for the second time." ); 149 eventQueue.destroy(); 150 } 151 } 152 catch ( IOException ex ) 153 { 154 eventQueue.destroy(); 155 } 156 } 157 return null; 158 } 159 160 /** 161 * Gets multiple items from the cache based on the given set of keys. 162 * <p> 163 * @param keys 164 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no 165 * data in cache for any of these keys 166 */ 167 @Override 168 public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys) 169 { 170 Map<K, ICacheElement<K, V>> elements = new HashMap<K, ICacheElement<K, V>>(); 171 172 if ( keys != null && !keys.isEmpty() ) 173 { 174 for (K key : keys) 175 { 176 ICacheElement<K, V> element = get( key ); 177 178 if ( element != null ) 179 { 180 elements.put( key, element ); 181 } 182 } 183 } 184 185 return elements; 186 } 187 188 /** 189 * Synchronously reads from the lateral cache. 190 * <p> 191 * @param pattern 192 * @return ICacheElement<K, V> if found, else empty 193 */ 194 @Override 195 public Map<K, ICacheElement<K, V>> getMatching(String pattern) 196 { 197 getCount++; 198 if ( this.getStatus() != CacheStatus.ERROR ) 199 { 200 try 201 { 202 return cache.getMatching( pattern ); 203 } 204 catch ( UnmarshalException ue ) 205 { 206 log.debug( "Retrying the get owing to UnmarshalException." ); 207 try 208 { 209 return cache.getMatching( pattern ); 210 } 211 catch ( IOException ex ) 212 { 213 log.error( "Failed in retrying the get for the second time." ); 214 eventQueue.destroy(); 215 } 216 } 217 catch ( IOException ex ) 218 { 219 eventQueue.destroy(); 220 } 221 } 222 return Collections.emptyMap(); 223 } 224 225 /** 226 * Return the keys in this cache. 227 * <p> 228 * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() 229 */ 230 @Override 231 public Set<K> getKeySet() throws IOException 232 { 233 try 234 { 235 return cache.getKeySet(); 236 } 237 catch ( IOException ex ) 238 { 239 log.error( ex ); 240 eventQueue.destroy(); 241 } 242 return Collections.emptySet(); 243 } 244 245 /** 246 * Adds a remove request to the lateral cache. 247 * <p> 248 * @param key 249 * @return always false 250 */ 251 @Override 252 public boolean remove( K key ) 253 { 254 removeCount++; 255 try 256 { 257 eventQueue.addRemoveEvent( key ); 258 } 259 catch ( IOException ex ) 260 { 261 log.error( ex ); 262 eventQueue.destroy(); 263 } 264 return false; 265 } 266 267 /** Adds a removeAll request to the lateral cache. */ 268 @Override 269 public void removeAll() 270 { 271 try 272 { 273 eventQueue.addRemoveAllEvent(); 274 } 275 catch ( IOException ex ) 276 { 277 log.error( ex ); 278 eventQueue.destroy(); 279 } 280 } 281 282 /** Adds a dispose request to the lateral cache. */ 283 @Override 284 public void dispose() 285 { 286 try 287 { 288 eventQueue.addDisposeEvent(); 289 } 290 catch ( IOException ex ) 291 { 292 log.error( ex ); 293 eventQueue.destroy(); 294 } 295 } 296 297 /** 298 * No lateral invocation. 299 * <p> 300 * @return The size value 301 */ 302 @Override 303 public int getSize() 304 { 305 return cache.getSize(); 306 } 307 308 /** 309 * No lateral invocation. 310 * <p> 311 * @return The cacheType value 312 */ 313 @Override 314 public CacheType getCacheType() 315 { 316 return cache.getCacheType(); 317 } 318 319 /** 320 * Returns the asyn cache status. An error status indicates either the lateral connection is not 321 * available, or the asyn queue has been unexpectedly destroyed. No lateral invocation. 322 * <p> 323 * @return The status value 324 */ 325 @Override 326 public CacheStatus getStatus() 327 { 328 return eventQueue.isWorking() ? cache.getStatus() : CacheStatus.ERROR; 329 } 330 331 /** 332 * Gets the cacheName attribute of the LateralCacheNoWait object 333 * <p> 334 * @return The cacheName value 335 */ 336 @Override 337 public String getCacheName() 338 { 339 return cache.getCacheName(); 340 } 341 342 /** 343 * Replaces the lateral cache service handle with the given handle and reset the queue by 344 * starting up a new instance. 345 * <p> 346 * @param lateral 347 */ 348 public void fixCache( ICacheServiceNonLocal<K, V> lateral ) 349 { 350 cache.fixCache( lateral ); 351 resetEventQ(); 352 } 353 354 /** 355 * Resets the event q by first destroying the existing one and starting up new one. 356 */ 357 public void resetEventQ() 358 { 359 if ( eventQueue.isWorking() ) 360 { 361 eventQueue.destroy(); 362 } 363 CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<K, V>(); 364 this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor<K, V>( cache ), CacheInfo.listenerId, cache 365 .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache 366 .getAuxiliaryCacheAttributes().getEventQueueType() ); 367 } 368 369 /** 370 * @return Returns the AuxiliaryCacheAttributes. 371 */ 372 @Override 373 public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() 374 { 375 return cache.getAuxiliaryCacheAttributes(); 376 } 377 378 /** 379 * getStats 380 * @return String 381 */ 382 @Override 383 public String getStats() 384 { 385 return getStatistics().toString(); 386 } 387 388 /** 389 * this won't be called since we don't do ICache logging here. 390 * <p> 391 * @return String 392 */ 393 @Override 394 public String getEventLoggingExtraInfo() 395 { 396 return "Lateral Cache No Wait"; 397 } 398 399 /** 400 * @return statistics about this communication 401 */ 402 @Override 403 public IStats getStatistics() 404 { 405 IStats stats = new Stats(); 406 stats.setTypeName( "Lateral Cache No Wait" ); 407 408 ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>(); 409 410 // get the stats from the event queue too 411 IStats eqStats = this.eventQueue.getStatistics(); 412 elems.addAll(eqStats.getStatElements()); 413 414 elems.add(new StatElement<Integer>( "Get Count", Integer.valueOf(this.getCount) ) ); 415 elems.add(new StatElement<Integer>( "Remove Count", Integer.valueOf(this.removeCount) ) ); 416 elems.add(new StatElement<Integer>( "Put Count", Integer.valueOf(this.putCount) ) ); 417 elems.add(new StatElement<AuxiliaryCacheAttributes>( "Attributes", cache.getAuxiliaryCacheAttributes() ) ); 418 419 stats.setStatElements( elems ); 420 421 return stats; 422 } 423 424 /** 425 * @return debugging info. 426 */ 427 @Override 428 public String toString() 429 { 430 StringBuilder buf = new StringBuilder(); 431 buf.append( " LateralCacheNoWait " ); 432 buf.append( " Status = " + this.getStatus() ); 433 buf.append( " cache = [" + cache.toString() + "]" ); 434 return buf.toString(); 435 } 436}