Coverage report

  %line %branch
org.apache.jcs.engine.control.CompositeCache
64% 
87% 

 1  
 package org.apache.jcs.engine.control;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.IOException;
 23  
 import java.io.Serializable;
 24  
 import java.util.ArrayList;
 25  
 import java.util.HashSet;
 26  
 import java.util.Iterator;
 27  
 import java.util.Map;
 28  
 import java.util.Set;
 29  
 
 30  
 import org.apache.commons.logging.Log;
 31  
 import org.apache.commons.logging.LogFactory;
 32  
 import org.apache.jcs.access.exception.CacheException;
 33  
 import org.apache.jcs.access.exception.ObjectNotFoundException;
 34  
 import org.apache.jcs.auxiliary.AuxiliaryCache;
 35  
 import org.apache.jcs.engine.CacheConstants;
 36  
 import org.apache.jcs.engine.CacheElement;
 37  
 import org.apache.jcs.engine.behavior.ICache;
 38  
 import org.apache.jcs.engine.behavior.ICacheElement;
 39  
 import org.apache.jcs.engine.behavior.ICacheType;
 40  
 import org.apache.jcs.engine.behavior.ICompositeCacheAttributes;
 41  
 import org.apache.jcs.engine.behavior.IElementAttributes;
 42  
 import org.apache.jcs.engine.control.event.ElementEvent;
 43  
 import org.apache.jcs.engine.control.event.ElementEventQueue;
 44  
 import org.apache.jcs.engine.control.event.behavior.IElementEvent;
 45  
 import org.apache.jcs.engine.control.event.behavior.IElementEventConstants;
 46  
 import org.apache.jcs.engine.control.event.behavior.IElementEventHandler;
 47  
 import org.apache.jcs.engine.control.event.behavior.IElementEventQueue;
 48  
 import org.apache.jcs.engine.control.group.GroupId;
 49  
 import org.apache.jcs.engine.memory.MemoryCache;
 50  
 import org.apache.jcs.engine.memory.lru.LRUMemoryCache;
 51  
 import org.apache.jcs.engine.stats.CacheStats;
 52  
 import org.apache.jcs.engine.stats.StatElement;
 53  
 import org.apache.jcs.engine.stats.Stats;
 54  
 import org.apache.jcs.engine.stats.behavior.ICacheStats;
 55  
 import org.apache.jcs.engine.stats.behavior.IStatElement;
 56  
 import org.apache.jcs.engine.stats.behavior.IStats;
 57  
 
 58  
 /**
 59  
  * This is the primary hub for a single cache/region. It controls the flow of items through the
 60  
  * cache. The auxiliary and memory caches are plugged in here.
 61  
  * <p>
 62  
  * This is the core of a JCS region. Hence, this simple class is the core of JCS.
 63  
  */
 64  6
 public class CompositeCache
 65  
     implements ICache, Serializable
 66  
 {
 67  
     private static final long serialVersionUID = -2838097410378294960L;
 68  
 
 69  424
     private final static Log log = LogFactory.getLog( CompositeCache.class );
 70  
 
 71  
     /**
 72  
      * EventQueue for handling element events. 1 should be enough for all the regions. Else should
 73  
      * create as needed per region.
 74  
      */
 75  215
     public static IElementEventQueue elementEventQ = new ElementEventQueue( "AllRegionQueue" );
 76  
 
 77  
     // Auxiliary caches.
 78  675
     private AuxiliaryCache[] auxCaches = new AuxiliaryCache[0];
 79  
 
 80  675
     private boolean alive = true;
 81  
 
 82  
     // this is in the cacheAttr, shouldn't be used, remove
 83  
     final String cacheName;
 84  
 
 85  
     /** Region Elemental Attributes, default. */
 86  
     private IElementAttributes attr;
 87  
 
 88  
     /** Cache Attributes, for hub and memory auxiliary. */
 89  
     private ICompositeCacheAttributes cacheAttr;
 90  
 
 91  
     // Statistics
 92  
     private int updateCount;
 93  
 
 94  
     private int removeCount;
 95  
 
 96  
     /** Memory cache hit count */
 97  
     private int hitCountRam;
 98  
 
 99  
     /** Auxiliary cache hit count (number of times found in ANY auxiliary) */
 100  
     private int hitCountAux;
 101  
 
 102  
     /** Auxiliary hit counts broken down by auxiliary. */
 103  
     private int[] auxHitCountByIndex;
 104  
 
 105  
     /** Count of misses where element was not found. */
 106  675
     private int missCountNotFound = 0;
 107  
 
 108  
     /** Count of misses where element was expired. */
 109  675
     private int missCountExpired = 0;
 110  
 
 111  
     /**
 112  
      * The cache hub can only have one memory cache. This could be made more flexible in the future,
 113  
      * but they are tied closely together. More than one doesn't make much sense.
 114  
      */
 115  
     private MemoryCache memCache;
 116  
 
 117  
     /**
 118  
      * Constructor for the Cache object
 119  
      * <p>
 120  
      * @param cacheName The name of the region
 121  
      * @param cattr The cache attribute
 122  
      * @param attr The default element attributes
 123  
      */
 124  14
     public CompositeCache( String cacheName, ICompositeCacheAttributes cattr, IElementAttributes attr )
 125  661
     {
 126  675
         this.cacheName = cacheName;
 127  675
         this.attr = attr;
 128  675
         this.cacheAttr = cattr;
 129  
 
 130  675
         createMemoryCache( cattr );
 131  
 
 132  675
         if ( log.isInfoEnabled() )
 133  
         {
 134  675
             log.info( "Constructed cache with name [" + cacheName + "] and cache attributes " + cattr );
 135  
         }
 136  675
     }
 137  
 
 138  
     /**
 139  
      * This sets the list of auxiliary caches for this region.
 140  
      * <p>
 141  
      * @param auxCaches
 142  
      */
 143  
     public void setAuxCaches( AuxiliaryCache[] auxCaches )
 144  
     {
 145  660
         this.auxCaches = auxCaches;
 146  
 
 147  660
         if ( auxCaches != null )
 148  
         {
 149  660
             this.auxHitCountByIndex = new int[auxCaches.length];
 150  
         }
 151  660
     }
 152  
 
 153  
     /**
 154  
      * Standard update method.
 155  
      * <p>
 156  
      * @param ce
 157  
      * @exception IOException
 158  
      */
 159  
     public synchronized void update( ICacheElement ce )
 160  
         throws IOException
 161  
     {
 162  1686262
         update( ce, false );
 163  1686114
     }
 164  
 
 165  
     /**
 166  
      * Standard update method.
 167  
      * <p>
 168  
      * @param ce
 169  
      * @exception IOException
 170  
      */
 171  
     public synchronized void localUpdate( ICacheElement ce )
 172  
         throws IOException
 173  
     {
 174  84
         update( ce, true );
 175  84
     }
 176  
 
 177  
     /**
 178  
      * Put an item into the cache. If it is localOnly, then do no notify remote or lateral
 179  
      * auxiliaries.
 180  
      * <p>
 181  
      * @param cacheElement the ICacheElement
 182  
      * @param localOnly Whether the operation should be restricted to local auxiliaries.
 183  
      * @exception IOException
 184  
      */
 185  
     protected synchronized void update( ICacheElement cacheElement, boolean localOnly )
 186  
         throws IOException
 187  
     {
 188  
         // not thread safe, but just for debugging and testing.
 189  1686410
         updateCount++;
 190  
 
 191  1686154
         if ( cacheElement.getKey() instanceof String
 192  72505
             && cacheElement.getKey().toString().endsWith( CacheConstants.NAME_COMPONENT_DELIMITER ) )
 193  
         {
 194  0
             throw new IllegalArgumentException( "key must not end with " + CacheConstants.NAME_COMPONENT_DELIMITER
 195  
                 + " for a put operation" );
 196  
         }
 197  1686495
         else if ( cacheElement.getKey() instanceof GroupId )
 198  
         {
 199  0
             throw new IllegalArgumentException( "key cannot be a GroupId " + " for a put operation" );
 200  
         }
 201  
 
 202  1686262
         if ( log.isDebugEnabled() )
 203  
         {
 204  0
             log.debug( "Updating memory cache" );
 205  
         }
 206  
 
 207  1686472
         memCache.update( cacheElement );
 208  
 
 209  1686329
         updateAuxiliaries( cacheElement, localOnly );
 210  1686380
     }
 211  
 
 212  
     /**
 213  
      * This method is responsible for updating the auxiliaries if they are present. If it is local
 214  
      * only, any lateral and remote auxiliaries will not be updated.
 215  
      * <p>
 216  
      * Before updating an auxiliary it checks to see if the element attributes permit the operation.
 217  
      * <p>
 218  
      * Disk auxiliaries are only updated if the disk cache is not merely used as a swap. If the disk
 219  
      * cache is merely a swap, then items will only go to disk when they overflow from memory.
 220  
      * <p>
 221  
      * This is called by update( cacheElement, localOnly ) after it updates the memory cache.
 222  
      * <p>
 223  
      * This is protected to make it testable.
 224  
      * <p>
 225  
      * @param cacheElement
 226  
      * @param localOnly
 227  
      * @throws IOException
 228  
      */
 229  
     protected void updateAuxiliaries( ICacheElement cacheElement, boolean localOnly )
 230  
         throws IOException
 231  
     {
 232  
         // UPDATE AUXILLIARY CACHES
 233  
         // There are 3 types of auxiliary caches: remote, lateral, and disk
 234  
         // more can be added if future auxiliary caches don't fit the model
 235  
         // You could run a database cache as either a remote or a local disk.
 236  
         // The types would describe the purpose.
 237  
 
 238  1686530
         if ( log.isDebugEnabled() )
 239  
         {
 240  0
             if ( auxCaches.length > 0 )
 241  
             {
 242  0
                 log.debug( "Updating auxilliary caches" );
 243  0
             }
 244  
             else
 245  
             {
 246  0
                 log.debug( "No auxilliary cache to update" );
 247  
             }
 248  
         }
 249  
 
 250  2651560
         for ( int i = 0; i < auxCaches.length; i++ )
 251  
         {
 252  965482
             ICache aux = auxCaches[i];
 253  
 
 254  241
             if ( log.isDebugEnabled() )
 255  
             {
 256  0
                 log.debug( "Auxilliary cache type: " + aux.getCacheType() );
 257  
             }
 258  
 
 259  965568
             if ( aux == null )
 260  
             {
 261  0
                 continue;
 262  
             }
 263  
 
 264  
             // SEND TO REMOTE STORE
 265  965494
             if ( aux.getCacheType() == ICache.REMOTE_CACHE )
 266  
             {
 267  70
                 if ( log.isDebugEnabled() )
 268  
                 {
 269  0
                     log.debug( "ce.getElementAttributes().getIsRemote() = "
 270  
                         + cacheElement.getElementAttributes().getIsRemote() );
 271  
                 }
 272  
 
 273  70
                 if ( cacheElement.getElementAttributes().getIsRemote() && !localOnly )
 274  
                 {
 275  
                     try
 276  
                     {
 277  
                         // need to make sure the group cache understands that
 278  
                         // the key is a group attribute on update
 279  70
                         aux.update( cacheElement );
 280  70
                         if ( log.isDebugEnabled() )
 281  
                         {
 282  0
                             log.debug( "Updated remote store for " + cacheElement.getKey() + cacheElement );
 283  
                         }
 284  
                     }
 285  0
                     catch ( IOException ex )
 286  
                     {
 287  0
                         log.error( "Failure in updateExclude", ex );
 288  70
                     }
 289  0
                 }
 290  
                 // SEND LATERALLY
 291  
             }
 292  965490
             else if ( aux.getCacheType() == ICache.LATERAL_CACHE )
 293  
             {
 294  
                 // lateral can't do the checking since it is dependent on the
 295  
                 // cache region restrictions
 296  46
                 if ( log.isDebugEnabled() )
 297  
                 {
 298  0
                     log.debug( "lateralcache in aux list: cattr " + cacheAttr.getUseLateral() );
 299  
                 }
 300  46
                 if ( cacheAttr.getUseLateral() && cacheElement.getElementAttributes().getIsLateral() && !localOnly )
 301  
                 {
 302  
                     // later if we want a multicast, possibly delete abnormal
 303  
                     // broadcaster
 304  
                     // DISTRIBUTE LATERALLY
 305  
                     // Currently always multicast even if the value is
 306  
                     // unchanged,
 307  
                     // just to cause the cache item to move to the front.
 308  39
                     aux.update( cacheElement );
 309  39
                     if ( log.isDebugEnabled() )
 310  
                     {
 311  0
                         log.debug( "updated lateral cache for " + cacheElement.getKey() );
 312  0
                     }
 313  
                 }
 314  
             }
 315  
             // update disk if the usage pattern permits
 316  965398
             else if ( aux.getCacheType() == ICache.DISK_CACHE )
 317  
             {
 318  965354
                 if ( log.isDebugEnabled() )
 319  
                 {
 320  0
                     log.debug( "diskcache in aux list: cattr " + cacheAttr.getUseDisk() );
 321  
                 }
 322  965360
                 if ( cacheAttr.getUseDisk()
 323  
                     && ( cacheAttr.getDiskUsagePattern() == ICompositeCacheAttributes.DISK_USAGE_PATTERN_UPDATE )
 324  
                     && cacheElement.getElementAttributes().getIsSpool() )
 325  
                 {
 326  21
                     aux.update( cacheElement );
 327  21
                     if ( log.isDebugEnabled() )
 328  
                     {
 329  0
                         log.debug( "updated disk cache for " + cacheElement.getKey() );
 330  
                     }
 331  
                 }
 332  
             }
 333  
         }
 334  1686438
     }
 335  
 
 336  
     /**
 337  
      * Writes the specified element to any disk auxilliaries. Might want to rename this "overflow"
 338  
      * incase the hub wants to do something else.
 339  
      * <p>
 340  
      * If JCS is not configured to use the disk as a swap, that is if the the
 341  
      * CompositeCacheAttribute diskUsagePattern is not SWAP_ONLY, then the item will not be spooled.
 342  
      * <p>
 343  
      * @param ce The CacheElement
 344  
      */
 345  
     public void spoolToDisk( ICacheElement ce )
 346  
     {
 347  
         // if the item is not spoolable, return
 348  1601793
         if ( !ce.getElementAttributes().getIsSpool() )
 349  
         {
 350  
             // there is an event defined for this.
 351  280014
             handleElementEvent( ce, IElementEventConstants.ELEMENT_EVENT_SPOOLED_NOT_ALLOWED );
 352  280014
             return;
 353  
         }
 354  
 
 355  1321904
         boolean diskAvailable = false;
 356  
 
 357  
         // SPOOL TO DISK.
 358  2107506
         for ( int i = 0; i < auxCaches.length; i++ )
 359  
         {
 360  785843
             ICache aux = auxCaches[i];
 361  
 
 362  785757
             if ( aux != null && aux.getCacheType() == ICache.DISK_CACHE )
 363  
             {
 364  785815
                 diskAvailable = true;
 365  
 
 366  785778
                 if ( cacheAttr.getDiskUsagePattern() == ICompositeCacheAttributes.DISK_USAGE_PATTERN_SWAP )
 367  
                 {
 368  
                     // write the last items to disk.2
 369  
                     try
 370  
                     {
 371  785825
                         handleElementEvent( ce, IElementEventConstants.ELEMENT_EVENT_SPOOLED_DISK_AVAILABLE );
 372  
 
 373  785758
                         aux.update( ce );
 374  
                     }
 375  0
                     catch ( IOException ex )
 376  
                     {
 377  
                         // impossible case.
 378  0
                         log.error( "Problem spooling item to disk cache.", ex );
 379  0
                         throw new IllegalStateException( ex.getMessage() );
 380  
                     }
 381  0
                     catch ( Exception oee )
 382  
                     {
 383  
                         // swallow
 384  785835
                     }
 385  785822
                     if ( log.isDebugEnabled() )
 386  
                     {
 387  0
                         log.debug( "spoolToDisk done for: " + ce.getKey() + " on disk cache[" + i + "]" );
 388  0
                     }
 389  
                 }
 390  
                 else
 391  
                 {
 392  7
                     if ( log.isDebugEnabled() )
 393  
                     {
 394  0
                         log.debug( "DiskCache avaialbe, but JCS is not configured to use the DiskCache as a swap." );
 395  
                     }
 396  
                 }
 397  
             }
 398  
         }
 399  
 
 400  1321922
         if ( !diskAvailable )
 401  
         {
 402  
             try
 403  
             {
 404  536071
                 handleElementEvent( ce, IElementEventConstants.ELEMENT_EVENT_SPOOLED_DISK_NOT_AVAILABLE );
 405  
             }
 406  0
             catch ( Exception e )
 407  
             {
 408  0
                 log.error( "Trouble handling the ELEMENT_EVENT_SPOOLED_DISK_NOT_AVAILABLE  element event", e );
 409  486563
             }
 410  
         }
 411  1321839
     }
 412  
 
 413  
     /**
 414  
      * Gets an item from the cache.
 415  
      * <p>
 416  
      * @param key
 417  
      * @return
 418  
      * @throws IOException
 419  
      * @see org.apache.jcs.engine.behavior.ICache#get(java.io.Serializable)
 420  
      */
 421  
     public ICacheElement get( Serializable key )
 422  
     {
 423  1573102
         return get( key, false );
 424  
     }
 425  
 
 426  
     /**
 427  
      * Do not try to go remote or laterally for this get.
 428  
      * <p>
 429  
      * @param key
 430  
      * @return ICacheElement
 431  
      */
 432  
     public ICacheElement localGet( Serializable key )
 433  
     {
 434  1412
         return get( key, true );
 435  
     }
 436  
 
 437  
     /**
 438  
      * Look in memory, then disk, remote, or laterally for this item. The order is dependent on the
 439  
      * order in the cache.ccf file.
 440  
      * <p>
 441  
      * Do not try to go remote or laterally for this get if it is localOnly. Otherwise try to go
 442  
      * remote or lateral if such an auxiliary is configured for this region.
 443  
      * <p>
 444  
      * @param key
 445  
      * @param localOnly
 446  
      * @return ICacheElement
 447  
      */
 448  
     protected ICacheElement get( Serializable key, boolean localOnly )
 449  
     {
 450  1574662
         ICacheElement element = null;
 451  
 
 452  1574759
         boolean found = false;
 453  
 
 454  1574759
         if ( log.isDebugEnabled() )
 455  
         {
 456  0
             log.debug( "get: key = " + key + ", localOnly = " + localOnly );
 457  
         }
 458  
 
 459  
         try
 460  
         {
 461  
             // First look in memory cache
 462  1574739
             element = memCache.get( key );
 463  
 
 464  1574812
             if ( element != null )
 465  
             {
 466  
                 // Found in memory cache
 467  344627
                 if ( isExpired( element ) )
 468  
                 {
 469  0
                     if ( log.isDebugEnabled() )
 470  
                     {
 471  0
                         log.debug( cacheName + " - Memory cache hit, but element expired" );
 472  
                     }
 473  
 
 474  0
                     missCountExpired++;
 475  
 
 476  0
                     remove( key );
 477  
 
 478  0
                     element = null;
 479  0
                 }
 480  
                 else
 481  
                 {
 482  344626
                     if ( log.isDebugEnabled() )
 483  
                     {
 484  0
                         log.debug( cacheName + " - Memory cache hit" );
 485  
                     }
 486  
 
 487  
                     // Update counters
 488  344610
                     hitCountRam++;
 489  
                 }
 490  
 
 491  344629
                 found = true;
 492  322128
             }
 493  
             else
 494  
             {
 495  
                 // Item not found in memory. If local invocation look in aux
 496  
                 // caches, even if not local look in disk auxiliaries
 497  
 
 498  1694842
                 for ( int i = 0; i < auxCaches.length; i++ )
 499  
                 {
 500  874284
                     AuxiliaryCache aux = auxCaches[i];
 501  
 
 502  874278
                     if ( aux != null )
 503  
                     {
 504  874235
                         long cacheType = aux.getCacheType();
 505  
 
 506  874277
                         if ( !localOnly || cacheType == AuxiliaryCache.DISK_CACHE )
 507  
                         {
 508  872869
                             if ( log.isDebugEnabled() )
 509  
                             {
 510  0
                                 log.debug( "Attempting to get from aux [" + aux.getCacheName() + "] which is of type: "
 511  
                                     + cacheType );
 512  
                             }
 513  
 
 514  
                             try
 515  
                             {
 516  872844
                                 element = aux.get( key );
 517  
                             }
 518  0
                             catch ( IOException ex )
 519  
                             {
 520  0
                                 log.error( "Error getting from aux", ex );
 521  872675
                             }
 522  
                         }
 523  
 
 524  874209
                         if ( log.isDebugEnabled() )
 525  
                         {
 526  0
                             log.debug( "Got CacheElement: " + element );
 527  
                         }
 528  
 
 529  874129
                         if ( element != null )
 530  
                         {
 531  
                             // Item found in one of the auxiliary caches.
 532  
 
 533  408459
                             if ( isExpired( element ) )
 534  
                             {
 535  1206
                                 if ( log.isDebugEnabled() )
 536  
                                 {
 537  0
                                     log.debug( cacheName + " - Aux cache[" + i + "] hit, but element expired." );
 538  
                                 }
 539  
 
 540  1206
                                 missCountExpired++;
 541  
 
 542  
                                 // This will tell the remotes to remove the item
 543  
                                 // based on the element's expiration policy. The elements attributes
 544  
                                 // associated with the item when it created govern its behavior
 545  
                                 // everywhere.
 546  1206
                                 remove( key );
 547  
 
 548  1206
                                 element = null;
 549  1206
                             }
 550  
                             else
 551  
                             {
 552  407210
                                 if ( log.isDebugEnabled() )
 553  
                                 {
 554  0
                                     log.debug( cacheName + " - Aux cache[" + i + "] hit" );
 555  
                                 }
 556  
 
 557  
                                 // Update counters
 558  
 
 559  407261
                                 hitCountAux++;
 560  407281
                                 auxHitCountByIndex[i]++;
 561  
 
 562  
                                 // Spool the item back into memory
 563  
                                 // only spool if the mem cache size is greater
 564  
                                 // than 0, else the item will immediately get put
 565  
                                 // into purgatory
 566  407288
                                 if ( memCache.getCacheAttributes().getMaxObjects() > 0 )
 567  
                                 {
 568  362559
                                     memCache.update( element );
 569  362581
                                 }
 570  
                                 else
 571  
                                 {
 572  44635
                                     if ( log.isDebugEnabled() )
 573  
                                     {
 574  0
                                         log.debug( "Skipping memory update since no items are allowed in memory" );
 575  
                                     }
 576  
                                 }
 577  
                             }
 578  
 
 579  408462
                             found = true;
 580  
 
 581  407899
                             break;
 582  
                         }
 583  
                     }
 584  
                 }
 585  
             }
 586  
         }
 587  0
         catch ( Exception e )
 588  
         {
 589  0
             log.error( "Problem encountered getting element.", e );
 590  1507300
         }
 591  
 
 592  1574649
         if ( !found )
 593  
         {
 594  821920
             missCountNotFound++;
 595  
 
 596  821896
             if ( log.isDebugEnabled() )
 597  
             {
 598  0
                 log.debug( cacheName + " - Miss" );
 599  
             }
 600  
         }
 601  
 
 602  1574267
         return element;
 603  
     }
 604  
 
 605  
     /**
 606  
      * Determine if the element has exceeded its max life.
 607  
      * <p>
 608  
      * @param element
 609  
      * @return true if the element is expired, else false.
 610  
      */
 611  
     private boolean isExpired( ICacheElement element )
 612  
     {
 613  
         try
 614  
         {
 615  753056
             IElementAttributes attributes = element.getElementAttributes();
 616  
 
 617  753023
             if ( !attributes.getIsEternal() )
 618  
             {
 619  24220
                 long now = System.currentTimeMillis();
 620  
 
 621  
                 // Remove if maxLifeSeconds exceeded
 622  
 
 623  24220
                 long maxLifeSeconds = attributes.getMaxLifeSeconds();
 624  24220
                 long createTime = attributes.getCreateTime();
 625  
 
 626  24220
                 if ( maxLclass="keyword">ifeSeconds != -1 && ( now - createTime ) > ( maxLclass="keyword">ifeSeconds * 1000 ) )
 627  
                 {
 628  1206
                     if ( log.isDebugEnabled() )
 629  
                     {
 630  0
                         log.debug( "Exceeded maxLife: " + element.getKey() );
 631  
                     }
 632  
 
 633  1206
                     return true;
 634  
                 }
 635  23014
                 long idleTime = attributes.getIdleTime();
 636  23014
                 long lastAccessTime = attributes.getLastAccessTime();
 637  
 
 638  
                 // Remove if maxIdleTime exceeded
 639  
                 // If you have a 0 size memory cache, then the last access will
 640  
                 // not get updated.
 641  
                 // you will need to set the idle time to -1.
 642  
 
 643  23014
                 if ( ( idleTime != -1 ) && ( now - lastAccessTime ) > ( idleTime * 1000 ) )
 644  
                 {
 645  0
                     if ( log.isDebugEnabled() )
 646  
                     {
 647  0
                         log.info( "Exceeded maxIdle: " + element.getKey() );
 648  
                     }
 649  
 
 650  0
                     return true;
 651  
                 }
 652  
             }
 653  
         }
 654  0
         catch ( Exception e )
 655  
         {
 656  0
             log.error( "Error determining expiration period, expiring", e );
 657  
 
 658  0
             return true;
 659  729202
         }
 660  
 
 661  751798
         return false;
 662  
     }
 663  
 
 664  
     /**
 665  
      * Gets the set of keys of objects currently in the group.
 666  
      * <p>
 667  
      * @param group
 668  
      * @return A Set of keys, or null.
 669  
      */
 670  
     public Set getGroupKeys( String group )
 671  
     {
 672  0
         HashSet allKeys = new HashSet();
 673  0
         allKeys.addAll( memCache.getGroupKeys( group ) );
 674  0
         for ( int i = 0; i < auxCaches.length; i++ )
 675  
         {
 676  0
             AuxiliaryCache aux = auxCaches[i];
 677  0
             if ( aux != null )
 678  
             {
 679  
                 try
 680  
                 {
 681  0
                     allKeys.addAll( aux.getGroupKeys( group ) );
 682  
                 }
 683  0
                 catch ( IOException e )
 684  
                 {
 685  
                     // ignore
 686  0
                 }
 687  
             }
 688  
         }
 689  0
         return allKeys;
 690  
     }
 691  
 
 692  
     /**
 693  
      * Removes an item from the cache.
 694  
      * <p>
 695  
      * @param key
 696  
      * @return
 697  
      * @throws IOException
 698  
      * @see org.apache.jcs.engine.behavior.ICache#remove(java.io.Serializable)
 699  
      */
 700  
     public boolean remove( Serializable key )
 701  
     {
 702  427729
         return remove( key, false );
 703  
     }
 704  
 
 705  
     /**
 706  
      * Do not propogate removeall laterally or remotely.
 707  
      * <p>
 708  
      * @param key
 709  
      * @return true if the item was already in the cache.
 710  
      */
 711  
     public boolean localRemove( Serializable key )
 712  
     {
 713  1413
         return remove( key, true );
 714  
     }
 715  
 
 716  
     /**
 717  
      * fromRemote: If a remove call was made on a cache with both, then the remote should have been
 718  
      * called. If it wasn't then the remote is down. we'll assume it is down for all. If it did come
 719  
      * from the remote then the cache is remotely configured and lateral removal is unncessary. If
 720  
      * it came laterally then lateral removal is unnecessary. Does this assume that there is only
 721  
      * one lateral and remote for the cache? Not really, the intial removal should take care of the
 722  
      * problem if the source cache was similiarly configured. Otherwise the remote cache, if it had
 723  
      * no laterals, would remove all the elements from remotely configured caches, but if those
 724  
      * caches had some other wierd laterals that were not remotely configured, only laterally
 725  
      * propagated then they would go out of synch. The same could happen for multiple remotes. If
 726  
      * this looks necessary we will need to build in an identifier to specify the source of a
 727  
      * removal.
 728  
      * <p>
 729  
      * @param key
 730  
      * @param localOnly
 731  
      * @return true if the item was in the cache, else false
 732  
      */
 733  
     protected synchronized boolean remove( Serializable key, class="keyword">boolean localOnly )
 734  
     {
 735  
         // not thread safe, but just for debugging and testing.
 736  429180
         removeCount++;
 737  
 
 738  429068
         boolean removed = false;
 739  
 
 740  
         try
 741  
         {
 742  429181
             removed = memCache.remove( key );
 743  
         }
 744  0
         catch ( IOException e )
 745  
         {
 746  0
             log.error( e );
 747  427028
         }
 748  
 
 749  
         // Removes from all auxiliary caches.
 750  842208
         for ( int i = 0; i < auxCaches.length; i++ )
 751  
         {
 752  412963
             ICache aux = auxCaches[i];
 753  
 
 754  413064
             if ( aux == null )
 755  
             {
 756  0
                 continue;
 757  
             }
 758  
 
 759  412848
             int cacheType = aux.getCacheType();
 760  
 
 761  
             // for now let laterals call remote remove but not vice versa
 762  
 
 763  413055
             if ( localOnly && ( cacheType == REMOTE_CACHE || cacheType == LATERAL_CACHE ) )
 764  
             {
 765  1406
                 continue;
 766  
             }
 767  
             try
 768  
             {
 769  411433
                 if ( log.isDebugEnabled() )
 770  
                 {
 771  0
                     log.debug( "Removing " + key + " from cacheType" + cacheType );
 772  
                 }
 773  
 
 774  411635
                 boolean b = aux.remove( key );
 775  
 
 776  
                 // Don't take the remote removal into account.
 777  411402
                 if ( !removed && cacheType != REMOTE_CACHE )
 778  
                 {
 779  405184
                     removed = b;
 780  
                 }
 781  
             }
 782  0
             catch ( IOException ex )
 783  
             {
 784  0
                 log.error( "Failure removing from aux", ex );
 785  411546
             }
 786  
         }
 787  429059
         return removed;
 788  
     }
 789  
 
 790  
     /**
 791  
      * Clears the region. This command will be sent to all auxiliaries. Some auxiliaries, such as
 792  
      * the JDBC disk cache, can be configured to not honor removeAll requests.
 793  
      * <p>
 794  
      * @see org.apache.jcs.engine.behavior.ICache#removeAll()
 795  
      */
 796  
     public void removeAll()
 797  
         throws IOException
 798  
     {
 799  104
         removeAll( false );
 800  104
     }
 801  
 
 802  
     /**
 803  
      * Will not pass the remove message remotely.
 804  
      * <p>
 805  
      * @throws IOException
 806  
      */
 807  
     public void localRemoveAll()
 808  
         throws IOException
 809  
     {
 810  0
         removeAll( true );
 811  0
     }
 812  
 
 813  
     /**
 814  
      * Removes all cached items.
 815  
      * <p>
 816  
      * @param localOnly must pass in false to get remote and lateral aux's updated. This prevents
 817  
      *            looping.
 818  
      * @throws IOException
 819  
      */
 820  
     protected synchronized void removeAll( boolean localOnly )
 821  
         throws IOException
 822  
     {
 823  
         try
 824  
         {
 825  104
             memCache.removeAll();
 826  
 
 827  104
             if ( log.isDebugEnabled() )
 828  
             {
 829  0
                 log.debug( "Removed All keys from the memory cache." );
 830  
             }
 831  
         }
 832  0
         catch ( IOException ex )
 833  
         {
 834  0
             log.error( "Trouble updating memory cache.", ex );
 835  103
         }
 836  
 
 837  
         // Removes from all auxiliary disk caches.
 838  160
         for ( int i = 0; i < auxCaches.length; i++ )
 839  
         {
 840  56
             ICache aux = auxCaches[i];
 841  
 
 842  56
             int cacheType = aux.getCacheType();
 843  
 
 844  56
             if ( aux != null && ( cacheType == ICache.DISK_CACHE || !localOnly ) )
 845  
             {
 846  
                 try
 847  
                 {
 848  56
                     if ( log.isDebugEnabled() )
 849  
                     {
 850  0
                         log.debug( "Removing All keys from cacheType" + cacheType );
 851  
                     }
 852  
 
 853  56
                     aux.removeAll();
 854  
                 }
 855  0
                 catch ( IOException ex )
 856  
                 {
 857  0
                     log.error( "Failure removing all from aux", ex );
 858  56
                 }
 859  
             }
 860  
         }
 861  104
         return;
 862  
     }
 863  
 
 864  
     /**
 865  
      * Flushes all cache items from memory to auxilliary caches and close the auxilliary caches.
 866  
      */
 867  
     public void dispose()
 868  
     {
 869  14
         dispose( false );
 870  14
     }
 871  
 
 872  
     /**
 873  
      * Invoked only by CacheManager. This method disposes of the auxiliaries one by one. For the disk cache, the items in memory
 874  
      * are freed, meaning that they will be sent through the overflow chanel to disk.  After the
 875  
      * auxiliaries are disposed, the memory cache is dispposed.
 876  
      * <p>
 877  
      * @param fromRemote
 878  
      */
 879  
     public synchronized void dispose( boolean fromRemote )
 880  
     {
 881  14
         if ( log.isInfoEnabled() )
 882  
         {
 883  14
             log.info( "In DISPOSE, [" + this.cacheName + "] fromRemote [" + fromRemote + "] \n" + this.getStats() );
 884  
         }
 885  
 
 886  
         // If already disposed, return immediately
 887  14
         if ( !alive )
 888  
         {
 889  0
             return;
 890  
         }
 891  14
         alive = false;
 892  
 
 893  
         // Dispose of each auxilliary cache, Remote auxilliaries will be
 894  
         // skipped if 'fromRemote' is true.
 895  
 
 896  28
         for ( int i = 0; i < auxCaches.length; i++ )
 897  
         {
 898  
             try
 899  
             {
 900  14
                 ICache aux = auxCaches[i];
 901  
 
 902  
                 // Skip this auxilliary if:
 903  
                 // - The auxilliary is null
 904  
                 // - The auxilliary is not alive
 905  
                 // - The auxilliary is remote and the invocation was remote
 906  
 
 907  14
                 if ( aux == null || aux.getStatus() != CacheConstants.STATUS_ALIVE
 908  
                     || ( fromRemote && aux.getCacheType() == REMOTE_CACHE ) )
 909  
                 {
 910  0
                     if ( log.isInfoEnabled() )
 911  
                     {
 912  0
                         log.info( "In DISPOSE, [" + this.cacheName + "] SKIPPING auxiliary [" + aux + "] fromRemote ["
 913  
                             + fromRemote + "]" );
 914  
                     }
 915  0
                     continue;
 916  
                 }
 917  
 
 918  14
                 if ( log.isInfoEnabled() )
 919  
                 {
 920  14
                     log.info( "In DISPOSE, [" + this.cacheName + "] auxiliary [" + aux + "]" );
 921  
                 }
 922  
 
 923  
                 // IT USED TO BE THE CASE THAT (If the auxilliary is not a lateral, or the cache
 924  
                 // attributes
 925  
                 // have 'getUseLateral' set, all the elements currently in
 926  
                 // memory are written to the lateral before disposing)
 927  
                 // I changed this. It was excessive. Only the disk cache needs the items, since only
 928  
                 // the disk cache
 929  
                 // is in a situation to not get items on a put.
 930  
 
 931  14
                 if ( aux.getCacheType() == ICacheType.DISK_CACHE )
 932  
                 {
 933  7
                     int numToFree = memCache.getSize();
 934  7
                     memCache.freeElements( numToFree );
 935  
 
 936  7
                     if ( log.isInfoEnabled() )
 937  
                     {
 938  7
                         log.info( "In DISPOSE, [" + this.cacheName + "] put " + numToFree + " into auxiliary " + aux );
 939  
                     }
 940  
                 }
 941  
 
 942  
                 // Dispose of the auxiliary
 943  14
                 aux.dispose();
 944  
             }
 945  0
             catch ( IOException ex )
 946  
             {
 947  0
                 log.error( "Failure disposing of aux.", ex );
 948  14
             }
 949  
         }
 950  
 
 951  14
         if ( log.isInfoEnabled() )
 952  
         {
 953  14
             log.info( "In DISPOSE, [" + this.cacheName + "] disposing of memory cache." );
 954  
         }
 955  
         try
 956  
         {
 957  14
             memCache.dispose();
 958  
         }
 959  0
         catch ( IOException ex )
 960  
         {
 961  0
             log.error( "Failure disposing of memCache", ex );
 962  14
         }
 963  14
     }
 964  
 
 965  
     /**
 966  
      * Calling save cause the entire contents of the memory cache to be flushed to all auxiliaries.
 967  
      * Though this put is extremely fast, this could bog the cache and should be avoided. The
 968  
      * dispose method should call a version of this. Good for testing.
 969  
      */
 970  
     public void save()
 971  
     {
 972  0
         if ( !alive )
 973  
         {
 974  0
             return;
 975  
         }
 976  0
         synchronized ( this )
 977  
         {
 978  0
             if ( !alive )
 979  
             {
 980  0
                 return;
 981  
             }
 982  0
             alive = false;
 983  
 
 984  0
             for ( int i = 0; i < auxCaches.length; i++ )
 985  
             {
 986  
                 try
 987  
                 {
 988  0
                     ICache aux = auxCaches[i];
 989  
 
 990  0
                     if ( aux.getStatus() == CacheConstants.STATUS_ALIVE )
 991  
                     {
 992  
 
 993  0
                         Iterator itr = memCache.getIterator();
 994  
 
 995  0
                         while ( itr.hasNext() )
 996  
                         {
 997  0
                             Map.Entry entry = (Map.Entry) itr.next();
 998  
 
 999  0
                             ICacheElement ce = (ICacheElement) entry.getValue();
 1000  
 
 1001  0
                             aux.update( ce );
 1002  0
                         }
 1003  
                     }
 1004  
                 }
 1005  0
                 catch ( IOException ex )
 1006  
                 {
 1007  0
                     log.error( "Failure saving aux caches.", ex );
 1008  0
                 }
 1009  
             }
 1010  0
         }
 1011  0
         if ( log.isDebugEnabled() )
 1012  
         {
 1013  0
             log.debug( "Called save for [" + cacheName + "]" );
 1014  
         }
 1015  0
     }
 1016  
 
 1017  
     /**
 1018  
      * Gets the size attribute of the Cache object. This return the number of elements, not the byte
 1019  
      * size.
 1020  
      * <p>
 1021  
      * @return The size value
 1022  
      */
 1023  
     public int getSize()
 1024  
     {
 1025  0
         return memCache.getSize();
 1026  
     }
 1027  
 
 1028  
     /**
 1029  
      * Gets the cacheType attribute of the Cache object.
 1030  
      * <p>
 1031  
      * @return The cacheType value
 1032  
      */
 1033  
     public int getCacheType()
 1034  
     {
 1035  0
         return CACHE_HUB;
 1036  
     }
 1037  
 
 1038  
     /**
 1039  
      * Gets the status attribute of the Cache object.
 1040  
      * <p>
 1041  
      * @return The status value
 1042  
      */
 1043  
     public int getStatus()
 1044  
     {
 1045  16
         return alive ? CacheConstants.STATUS_ALIVE : CacheConstants.STATUS_DISPOSED;
 1046  
     }
 1047  
 
 1048  
     /**
 1049  
      * Gets stats for debugging.
 1050  
      * <p>
 1051  
      * @return String
 1052  
      */
 1053  
     public String getStats()
 1054  
     {
 1055  55719
         return getStatistics().toString();
 1056  
     }
 1057  
 
 1058  
     /**
 1059  
      * This returns data gathered for this region and all the auxiliaries it currently uses.
 1060  
      * <p>
 1061  
      * @return Statistics and Info on the Region.
 1062  
      */
 1063  
     public ICacheStats getStatistics()
 1064  
     {
 1065  55776
         ICacheStats stats = new CacheStats();
 1066  55780
         stats.setRegionName( this.getCacheName() );
 1067  
 
 1068  
         // store the composite cache stats first
 1069  55808
         IStatElement[] elems = new StatElement[2];
 1070  55792
         elems[0] = new StatElement();
 1071  55778
         elems[0].setName( "HitCountRam" );
 1072  55795
         elems[0].setData( "" + getHitCountRam() );
 1073  
 
 1074  55804
         elems[1] = new StatElement();
 1075  55809
         elems[1].setName( "HitCountAux" );
 1076  55782
         elems[1].setData( "" + getHitCountAux() );
 1077  
 
 1078  
         // store these local stats
 1079  55792
         stats.setStatElements( elems );
 1080  
 
 1081  
         // memory + aux, memory is not considered an auxiliary internally
 1082  55807
         int total = auxCaches.length + 1;
 1083  55792
         IStats[] auxStats = new Stats[total];
 1084  
 
 1085  55797
         auxStats[0] = getMemoryCache().getStatistics();
 1086  
 
 1087  111386
         for ( int i = 0; i < auxCaches.length; i++ )
 1088  
         {
 1089  55703
             AuxiliaryCache aux = auxCaches[i];
 1090  55704
             auxStats[i + 1] = aux.getStatistics();
 1091  
         }
 1092  
 
 1093  
         // sore the auxiliary stats
 1094  55807
         stats.setAuxiliaryCacheStats( auxStats );
 1095  
 
 1096  55807
         return stats;
 1097  
     }
 1098  
 
 1099  
     /**
 1100  
      * Gets the cacheName attribute of the Cache object. This is also known as the region name.
 1101  
      * <p>
 1102  
      * @return The cacheName value
 1103  
      */
 1104  
     public String getCacheName()
 1105  
     {
 1106  1751434
         return cacheName;
 1107  
     }
 1108  
 
 1109  
     /**
 1110  
      * Gets the default element attribute of the Cache object This returna a copy. It does not
 1111  
      * return a reference to the attributes.
 1112  
      * <p>
 1113  
      * @return The attributes value
 1114  
      */
 1115  
     public IElementAttributes getElementAttributes()
 1116  
     {
 1117  1690867
         if ( attr != null )
 1118  
         {
 1119  1690685
             return attr.copy();
 1120  
         }
 1121  0
         return null;
 1122  
     }
 1123  
 
 1124  
     /**
 1125  
      * Sets the default element attribute of the Cache object.
 1126  
      * <p>
 1127  
      * @param attr
 1128  
      */
 1129  
     public void setElementAttributes( IElementAttributes attr )
 1130  
     {
 1131  29
         this.attr = attr;
 1132  29
     }
 1133  
 
 1134  
     /**
 1135  
      * Gets the ICompositeCacheAttributes attribute of the Cache object.
 1136  
      * <p>
 1137  
      * @return The ICompositeCacheAttributes value
 1138  
      */
 1139  
     public ICompositeCacheAttributes getCacheAttributes()
 1140  
     {
 1141  802
         return this.cacheAttr;
 1142  
     }
 1143  
 
 1144  
     /**
 1145  
      * Sets the ICompositeCacheAttributes attribute of the Cache object.
 1146  
      * <p>
 1147  
      * @param cattr The new ICompositeCacheAttributes value
 1148  
      */
 1149  
     public void setCacheAttributes( ICompositeCacheAttributes cattr )
 1150  
     {
 1151  0
         this.cacheAttr = cattr;
 1152  
         // need a better way to do this, what if it is in error
 1153  0
         this.memCache.initialize( class="keyword">this );
 1154  0
     }
 1155  
 
 1156  
     /**
 1157  
      * Gets the elementAttributes attribute of the Cache object.
 1158  
      * <p>
 1159  
      * @param key
 1160  
      * @return The elementAttributes value
 1161  
      * @exception CacheException
 1162  
      * @exception IOException
 1163  
      */
 1164  
     public IElementAttributes getElementAttributes( Serializable key )
 1165  
         throws CacheException, IOException
 1166  
     {
 1167  0
         CacheElement ce = (CacheElement) get( key );
 1168  0
         if ( ce == null )
 1169  
         {
 1170  0
             throw new ObjectNotFoundException( "key " + key + " is not found" );
 1171  
         }
 1172  0
         return ce.getElementAttributes();
 1173  
     }
 1174  
 
 1175  
     /**
 1176  
      * Create the MemoryCache based on the config parameters. TODO: consider making this an
 1177  
      * auxiliary, despite its close tie to the CacheHub. TODO: might want to create a memory cache
 1178  
      * config file separate from that of the hub -- ICompositeCacheAttributes
 1179  
      * <p>
 1180  
      * @param cattr
 1181  
      */
 1182  
     private void createMemoryCache( ICompositeCacheAttributes cattr )
 1183  
     {
 1184  675
         if ( memCache == null )
 1185  
         {
 1186  
             try
 1187  
             {
 1188  675
                 Class c = Class.forName( cattr.getMemoryCacheName() );
 1189  675
                 memCache = (MemoryCache) c.newInstance();
 1190  675
                 memCache.initialize( this );
 1191  
             }
 1192  0
             catch ( Exception e )
 1193  
             {
 1194  0
                 log.warn( "Failed to init mem cache, using: LRUMemoryCache", e );
 1195  
 
 1196  0
                 this.memCache = new LRUMemoryCache();
 1197  0
                 this.memCache.initialize( class="keyword">this );
 1198  661
             }
 1199  0
         }
 1200  
         else
 1201  
         {
 1202  0
             log.warn( "Refusing to create memory cache -- already exists." );
 1203  
         }
 1204  675
     }
 1205  
 
 1206  
     /**
 1207  
      * Access to the memory cache for instrumentation.
 1208  
      * <p>
 1209  
      * @return the MemoryCache implementation
 1210  
      */
 1211  
     public MemoryCache getMemoryCache()
 1212  
     {
 1213  55874
         return memCache;
 1214  
     }
 1215  
 
 1216  
     /**
 1217  
      * Number of times a requested item was found in the memory cache.
 1218  
      * <p>
 1219  
      * @return number of hits in memory
 1220  
      */
 1221  
     public int getHitCountRam()
 1222  
     {
 1223  55781
         return hitCountRam;
 1224  
     }
 1225  
 
 1226  
     /**
 1227  
      * Number of times a requested item was found in and auxiliary cache.
 1228  
      * @return number of auxiliary hits.
 1229  
      */
 1230  
     public int getHitCountAux()
 1231  
     {
 1232  55796
         return hitCountAux;
 1233  
     }
 1234  
 
 1235  
     /**
 1236  
      * Number of times a requested element was not found.
 1237  
      * @return number of misses.
 1238  
      */
 1239  
     public int getMissCountNotFound()
 1240  
     {
 1241  0
         return missCountNotFound;
 1242  
     }
 1243  
 
 1244  
     /**
 1245  
      * Number of times a requested element was found but was expired.
 1246  
      * @return number of found but expired gets.
 1247  
      */
 1248  
     public int getMissCountExpired()
 1249  
     {
 1250  0
         return missCountExpired;
 1251  
     }
 1252  
 
 1253  
     /**
 1254  
      * If there are event handlers for the item, then create an event and queue it up.
 1255  
      * <p>
 1256  
      * This does not call handle directly; instead the handler and the event are put into a queue.
 1257  
      * This prevents the event handling from blocking normal cache operations.
 1258  
      * @param ce
 1259  
      * @param eventType
 1260  
      */
 1261  
     private void handleElementEvent( ICacheElement ce, int eventType )
 1262  
     {
 1263  
         // handle event, might move to a new method
 1264  1601748
         ArrayList eventHandlers = ce.getElementAttributes().getElementEventHandlers();
 1265  1601840
         if ( eventHandlers != null )
 1266  
         {
 1267  560028
             if ( log.isDebugEnabled() )
 1268  
             {
 1269  0
                 log.debug( "Element Handlers are registered.  Create event type " + eventType );
 1270  
             }
 1271  560028
             IElementEvent event = new ElementEvent( ce, eventType );
 1272  560028
             Iterator hIt = eventHandlers.iterator();
 1273  1260063
             while ( hIt.hasNext() )
 1274  
             {
 1275  700035
                 IElementEventHandler hand = (IElementEventHandler) hIt.next();
 1276  
                 try
 1277  
                 {
 1278  700035
                     addElementEvent( hand, event );
 1279  
                 }
 1280  0
                 catch ( Exception e )
 1281  
                 {
 1282  0
                     log.error( "Trouble adding element event to queue", e );
 1283  700035
                 }
 1284  700035
             }
 1285  
         }
 1286  1601936
     }
 1287  
 
 1288  
     /**
 1289  
      * Adds an ElementEvent to be handled to the queue.
 1290  
      * @param hand The IElementEventHandler
 1291  
      * @param event The IElementEventHandler IElementEvent event
 1292  
      * @exception IOException Description of the Exception
 1293  
      */
 1294  
     public void addElementEvent( IElementEventHandler hand, IElementEvent event )
 1295  
         throws IOException
 1296  
     {
 1297  700035
         if ( log.isDebugEnabled() )
 1298  
         {
 1299  0
             log.debug( "Adding event to Element Event Queue" );
 1300  
         }
 1301  700035
         elementEventQ.addElementEvent( hand, event );
 1302  700035
     }
 1303  
 
 1304  
     /**
 1305  
      * @param updateCount The updateCount to set.
 1306  
      */
 1307  
     public void setUpdateCount( int updateCount )
 1308  
     {
 1309  0
         this.updateCount = updateCount;
 1310  0
     }
 1311  
 
 1312  
     /**
 1313  
      * @return Returns the updateCount.
 1314  
      */
 1315  
     public int getUpdateCount()
 1316  
     {
 1317  0
         return updateCount;
 1318  
     }
 1319  
 
 1320  
     /**
 1321  
      * @param removeCount The removeCount to set.
 1322  
      */
 1323  
     public void setRemoveCount( int removeCount )
 1324  
     {
 1325  0
         this.removeCount = removeCount;
 1326  0
     }
 1327  
 
 1328  
     /**
 1329  
      * @return Returns the removeCount.
 1330  
      */
 1331  
     public int getRemoveCount()
 1332  
     {
 1333  0
         return removeCount;
 1334  
     }
 1335  
 
 1336  
     /**
 1337  
      * This returns the stats.
 1338  
      * <p>
 1339  
      * (non-Javadoc)
 1340  
      * @see java.lang.Object#toString()
 1341  
      */
 1342  
     public String toString()
 1343  
     {
 1344  0
         return getStats();
 1345  
     }
 1346  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.