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.AuxiliaryCache; 024import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; 025import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes; 026import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheListener; 027import org.apache.commons.jcs.engine.CacheStatus; 028import org.apache.commons.jcs.engine.behavior.ICacheElement; 029import org.apache.commons.jcs.engine.stats.StatElement; 030import org.apache.commons.jcs.engine.stats.Stats; 031import org.apache.commons.jcs.engine.stats.behavior.IStatElement; 032import org.apache.commons.jcs.engine.stats.behavior.IStats; 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035 036import java.io.IOException; 037import java.util.ArrayList; 038import java.util.HashMap; 039import java.util.HashSet; 040import java.util.Map; 041import java.util.Set; 042 043/** 044 * Used to provide access to multiple services under nowait protection. Composite factory should 045 * construct LateralCacheNoWaitFacade to give to the composite cache out of caches it constructs 046 * from the varies manager to lateral services. Perhaps the lateralcache factory should be able to 047 * do this. 048 */ 049public class LateralCacheNoWaitFacade<K, V> 050 extends AbstractAuxiliaryCache<K, V> 051{ 052 /** The logger */ 053 private static final Log log = LogFactory.getLog( LateralCacheNoWaitFacade.class ); 054 055 /** The queuing facade to the client. */ 056 public LateralCacheNoWait<K, V>[] noWaits; 057 058 /** The region name */ 059 private final String cacheName; 060 061 /** A cache listener */ 062 private ILateralCacheListener<K, V> listener; 063 064 /** User configurable attributes. */ 065 private final ILateralCacheAttributes lateralCacheAttributes; 066 067 /** Disposed state of this facade */ 068 private boolean disposed = false; 069 070 /** 071 * Constructs with the given lateral cache, and fires events to any listeners. 072 * <p> 073 * @param noWaits 074 * @param cattr 075 */ 076 public LateralCacheNoWaitFacade(ILateralCacheListener<K, V> listener, LateralCacheNoWait<K, V>[] noWaits, ILateralCacheAttributes cattr ) 077 { 078 if ( log.isDebugEnabled() ) 079 { 080 log.debug( "CONSTRUCTING NO WAIT FACADE" ); 081 } 082 this.listener = listener; 083 this.noWaits = noWaits; 084 this.cacheName = cattr.getCacheName(); 085 this.lateralCacheAttributes = cattr; 086 } 087 088 /** 089 * Tells you if the no wait is in the list or not. 090 * <p> 091 * @param noWait 092 * @return true if the noWait is in the list. 093 */ 094 public boolean containsNoWait( LateralCacheNoWait<K, V> noWait ) 095 { 096 for ( int i = 0; i < noWaits.length; i++ ) 097 { 098 // we know noWait isn't null 099 if ( noWait.equals( noWaits[i] ) ) 100 { 101 return true; 102 } 103 } 104 return false; 105 } 106 107 /** 108 * Adds a no wait to the list if it isn't already in the list. 109 * <p> 110 * @param noWait 111 * @return true if it wasn't already contained 112 */ 113 public synchronized boolean addNoWait( LateralCacheNoWait<K, V> noWait ) 114 { 115 if ( noWait == null ) 116 { 117 return false; 118 } 119 120 if ( containsNoWait( noWait ) ) 121 { 122 if ( log.isDebugEnabled() ) 123 { 124 log.debug( "No Wait already contained, [" + noWait + "]" ); 125 } 126 return false; 127 } 128 129 @SuppressWarnings("unchecked") // No generic arrays in java 130 LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length + 1]; 131 132 System.arraycopy( noWaits, 0, newArray, 0, noWaits.length ); 133 134 // set the last position to the new noWait 135 newArray[noWaits.length] = noWait; 136 137 noWaits = newArray; 138 139 return true; 140 } 141 142 /** 143 * Removes a no wait from the list if it is already there. 144 * <p> 145 * @param noWait 146 * @return true if it was already in the array 147 */ 148 public synchronized boolean removeNoWait( LateralCacheNoWait<K, V> noWait ) 149 { 150 if ( noWait == null ) 151 { 152 return false; 153 } 154 155 int position = -1; 156 for ( int i = 0; i < noWaits.length; i++ ) 157 { 158 // we know noWait isn't null 159 if ( noWait.equals( noWaits[i] ) ) 160 { 161 position = i; 162 break; 163 } 164 } 165 166 if ( position == -1 ) 167 { 168 return false; 169 } 170 171 @SuppressWarnings("unchecked") // No generic arrays in java 172 LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length - 1]; 173 174 System.arraycopy( noWaits, 0, newArray, 0, position ); 175 if ( noWaits.length != position ) 176 { 177 System.arraycopy( noWaits, position + 1, newArray, position, noWaits.length - position - 1 ); 178 } 179 noWaits = newArray; 180 181 return true; 182 } 183 184 /** 185 * @param ce 186 * @throws IOException 187 */ 188 @Override 189 public void update( ICacheElement<K, V> ce ) 190 throws IOException 191 { 192 if ( log.isDebugEnabled() ) 193 { 194 log.debug( "updating through lateral cache facade, noWaits.length = " + noWaits.length ); 195 } 196 try 197 { 198 for ( int i = 0; i < noWaits.length; i++ ) 199 { 200 noWaits[i].update( ce ); 201 } 202 } 203 catch ( Exception ex ) 204 { 205 log.error( ex ); 206 } 207 } 208 209 /** 210 * Synchronously reads from the lateral cache. 211 * <p> 212 * @param key 213 * @return ICacheElement 214 */ 215 @Override 216 public ICacheElement<K, V> get( K key ) 217 { 218 for ( int i = 0; i < noWaits.length; i++ ) 219 { 220 try 221 { 222 ICacheElement<K, V> obj = noWaits[i].get( key ); 223 224 if ( obj != null ) 225 { 226 // TODO: return after first success 227 // could do this simultaneously 228 // serious blocking risk here 229 return obj; 230 } 231 } 232 catch ( Exception ex ) 233 { 234 log.error( "Failed to get", ex ); 235 } 236 } 237 return null; 238 } 239 240 /** 241 * Gets multiple items from the cache based on the given set of keys. 242 * <p> 243 * @param keys 244 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no 245 * data in cache for any of these keys 246 */ 247 @Override 248 public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys) 249 { 250 Map<K, ICacheElement<K, V>> elements = new HashMap<K, ICacheElement<K, V>>(); 251 252 if ( keys != null && !keys.isEmpty() ) 253 { 254 for (K key : keys) 255 { 256 ICacheElement<K, V> element = get( key ); 257 258 if ( element != null ) 259 { 260 elements.put( key, element ); 261 } 262 } 263 } 264 265 return elements; 266 } 267 268 /** 269 * Synchronously reads from the lateral cache. Get a response from each! This will be slow. 270 * Merge them. 271 * <p> 272 * @param pattern 273 * @return ICacheElement 274 */ 275 @Override 276 public Map<K, ICacheElement<K, V>> getMatching(String pattern) 277 { 278 Map<K, ICacheElement<K, V>> elements = new HashMap<K, ICacheElement<K, V>>(); 279 for ( int i = 0; i < noWaits.length; i++ ) 280 { 281 try 282 { 283 elements.putAll( noWaits[i].getMatching( pattern ) ); 284 } 285 catch ( Exception ex ) 286 { 287 log.error( "Failed to get", ex ); 288 } 289 } 290 return elements; 291 } 292 293 /** 294 * Return the keys in this cache. 295 * <p> 296 * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() 297 */ 298 @Override 299 public Set<K> getKeySet() throws IOException 300 { 301 HashSet<K> allKeys = new HashSet<K>(); 302 for ( int i = 0; i < noWaits.length; i++ ) 303 { 304 AuxiliaryCache<K, V> aux = noWaits[i]; 305 if ( aux != null ) 306 { 307 Set<K> keys = aux.getKeySet(); 308 if(keys != null) 309 { 310 allKeys.addAll( keys ); 311 } 312 } 313 } 314 return allKeys; 315 } 316 317 /** 318 * Adds a remove request to the lateral cache. 319 * <p> 320 * @param key 321 * @return always false. 322 */ 323 @Override 324 public boolean remove( K key ) 325 { 326 try 327 { 328 for ( int i = 0; i < noWaits.length; i++ ) 329 { 330 noWaits[i].remove( key ); 331 } 332 } 333 catch ( Exception ex ) 334 { 335 log.error( ex ); 336 } 337 return false; 338 } 339 340 /** 341 * Adds a removeAll request to the lateral cache. 342 */ 343 @Override 344 public void removeAll() 345 { 346 try 347 { 348 for ( int i = 0; i < noWaits.length; i++ ) 349 { 350 noWaits[i].removeAll(); 351 } 352 } 353 catch ( Exception ex ) 354 { 355 log.error( ex ); 356 } 357 } 358 359 /** Adds a dispose request to the lateral cache. */ 360 @Override 361 public void dispose() 362 { 363 try 364 { 365 if ( listener != null ) 366 { 367 listener.dispose(); 368 listener = null; 369 } 370 371 for ( int i = 0; i < noWaits.length; i++ ) 372 { 373 noWaits[i].dispose(); 374 } 375 } 376 catch ( Exception ex ) 377 { 378 log.error( ex ); 379 } 380 finally 381 { 382 disposed = true; 383 } 384 } 385 386 /** 387 * No lateral invocation. 388 * @return The size value 389 */ 390 @Override 391 public int getSize() 392 { 393 return 0; 394 //cache.getSize(); 395 } 396 397 /** 398 * Gets the cacheType attribute of the LateralCacheNoWaitFacade object. 399 * <p> 400 * @return The cacheType value 401 */ 402 @Override 403 public CacheType getCacheType() 404 { 405 return CacheType.LATERAL_CACHE; 406 } 407 408 /** 409 * Gets the cacheName attribute of the LateralCacheNoWaitFacade object. 410 * <p> 411 * @return The cacheName value 412 */ 413 @Override 414 public String getCacheName() 415 { 416 return ""; 417 //cache.getCacheName(); 418 } 419 420 /** 421 * Gets the status attribute of the LateralCacheNoWaitFacade object 422 * @return The status value 423 */ 424 @Override 425 public CacheStatus getStatus() 426 { 427 if (disposed) 428 { 429 return CacheStatus.DISPOSED; 430 } 431 432 if (noWaits.length == 0 || listener != null) 433 { 434 return CacheStatus.ALIVE; 435 } 436 437 CacheStatus[] statii = new CacheStatus[noWaits.length]; 438 for (int i = 0; i < noWaits.length; i++) 439 { 440 statii[i] = noWaits[i].getStatus(); 441 } 442 // It's alive if ANY of its nowaits is alive 443 for (int i = 0; i < noWaits.length; i++) 444 { 445 if (statii[i] == CacheStatus.ALIVE) 446 { 447 return CacheStatus.ALIVE; 448 } 449 } 450 // It's alive if ANY of its nowaits is in error, but 451 // none are alive, then it's in error 452 for (int i = 0; i < noWaits.length; i++) 453 { 454 if (statii[i] == CacheStatus.ERROR) 455 { 456 return CacheStatus.ERROR; 457 } 458 } 459 460 // Otherwise, it's been disposed, since it's the only status left 461 return CacheStatus.DISPOSED; 462 } 463 464 /** 465 * @return Returns the AuxiliaryCacheAttributes. 466 */ 467 @Override 468 public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes() 469 { 470 return this.lateralCacheAttributes; 471 } 472 473 /** 474 * @return "LateralCacheNoWaitFacade: " + cacheName; 475 */ 476 @Override 477 public String toString() 478 { 479 return "LateralCacheNoWaitFacade: " + cacheName; 480 } 481 482 /** 483 * this won't be called since we don't do ICache logging here. 484 * <p> 485 * @return String 486 */ 487 @Override 488 public String getEventLoggingExtraInfo() 489 { 490 return "Lateral Cache No Wait"; 491 } 492 493 /** 494 * getStats 495 * @return String 496 */ 497 @Override 498 public String getStats() 499 { 500 return getStatistics().toString(); 501 } 502 503 /** 504 * @return IStats 505 */ 506 @Override 507 public IStats getStatistics() 508 { 509 IStats stats = new Stats(); 510 stats.setTypeName( "Lateral Cache No Wait Facade" ); 511 512 ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>(); 513 514 if ( noWaits != null ) 515 { 516 elems.add(new StatElement<Integer>( "Number of No Waits", Integer.valueOf(noWaits.length) ) ); 517 518 for ( LateralCacheNoWait<K, V> lcnw : noWaits ) 519 { 520 if ( lcnw != null ) 521 { 522 // get the stats from the super too 523 IStats sStats = lcnw.getStatistics(); 524 elems.addAll(sStats.getStatElements()); 525 } 526 } 527 } 528 529 stats.setStatElements( elems ); 530 531 return stats; 532 } 533}