001package org.apache.commons.jcs.auxiliary.remote.http.server; 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 java.io.IOException; 023import java.io.Serializable; 024import java.util.Map; 025import java.util.Set; 026 027import org.apache.commons.jcs.engine.behavior.ICacheElement; 028import org.apache.commons.jcs.engine.behavior.ICacheServiceNonLocal; 029import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; 030import org.apache.commons.jcs.engine.control.CompositeCache; 031import org.apache.commons.jcs.engine.logging.CacheEvent; 032import org.apache.commons.jcs.engine.logging.behavior.ICacheEvent; 033import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; 034import org.apache.commons.logging.Log; 035import org.apache.commons.logging.LogFactory; 036 037/** 038 * This class contains common methods for remote cache services. Eventually I hope to extract out 039 * much of the RMI server to use this as well. I'm starting with the Http service. 040 */ 041public abstract class AbstractRemoteCacheService<K, V> 042 implements ICacheServiceNonLocal<K, V> 043{ 044 /** An optional event logger */ 045 private transient ICacheEventLogger cacheEventLogger; 046 047 /** The central hub */ 048 private ICompositeCacheManager cacheManager; 049 050 /** Name of the event log source. */ 051 private String eventLogSourceName = "AbstractRemoteCacheService"; 052 053 /** Number of puts into the cache. */ 054 private int puts = 0; 055 056 /** The interval at which we will log updates. */ 057 private final int logInterval = 100; 058 059 /** log instance */ 060 private static final Log log = LogFactory.getLog( AbstractRemoteCacheService.class ); 061 062 /** 063 * Creates the super with the needed items. 064 * <p> 065 * @param cacheManager 066 * @param cacheEventLogger 067 */ 068 public AbstractRemoteCacheService( ICompositeCacheManager cacheManager, ICacheEventLogger cacheEventLogger ) 069 { 070 this.cacheManager = cacheManager; 071 this.cacheEventLogger = cacheEventLogger; 072 } 073 074 /** 075 * @param item 076 * @throws IOException 077 */ 078 @Override 079 public void update( ICacheElement<K, V> item ) 080 throws IOException 081 { 082 update( item, 0 ); 083 } 084 085 /** 086 * The internal processing is wrapped in event logging calls. 087 * <p> 088 * @param item 089 * @param requesterId 090 * @throws IOException 091 */ 092 @Override 093 public void update( ICacheElement<K, V> item, long requesterId ) 094 throws IOException 095 { 096 ICacheEvent<ICacheElement<K, V>> cacheEvent = createICacheEvent( item, requesterId, ICacheEventLogger.UPDATE_EVENT ); 097 try 098 { 099 logUpdateInfo( item ); 100 101 processUpdate( item, requesterId ); 102 } 103 finally 104 { 105 logICacheEvent( cacheEvent ); 106 } 107 } 108 109 /** 110 * The internal processing is wrapped in event logging calls. 111 * <p> 112 * @param item 113 * @param requesterId 114 * @throws IOException 115 */ 116 abstract void processUpdate( ICacheElement<K, V> item, long requesterId ) 117 throws IOException; 118 119 /** 120 * Log some details. 121 * <p> 122 * @param item 123 */ 124 private void logUpdateInfo( ICacheElement<K, V> item ) 125 { 126 if ( log.isInfoEnabled() ) 127 { 128 // not thread safe, but it doesn't have to be accurate 129 puts++; 130 if ( puts % logInterval == 0 ) 131 { 132 log.info( "puts = " + puts ); 133 } 134 } 135 136 if ( log.isDebugEnabled() ) 137 { 138 log.debug( "In update, put [" + item.getKey() + "] in [" + item.getCacheName() + "]" ); 139 } 140 } 141 142 /** 143 * Returns a cache value from the specified remote cache; or null if the cache or key does not 144 * exist. 145 * <p> 146 * @param cacheName 147 * @param key 148 * @return ICacheElement 149 * @throws IOException 150 */ 151 @Override 152 public ICacheElement<K, V> get( String cacheName, K key ) 153 throws IOException 154 { 155 return this.get( cacheName, key, 0 ); 156 } 157 158 /** 159 * Returns a cache bean from the specified cache; or null if the key does not exist. 160 * <p> 161 * Adding the requestor id, allows the cache to determine the source of the get. 162 * <p> 163 * The internal processing is wrapped in event logging calls. 164 * <p> 165 * @param cacheName 166 * @param key 167 * @param requesterId 168 * @return ICacheElement 169 * @throws IOException 170 */ 171 @Override 172 public ICacheElement<K, V> get( String cacheName, K key, long requesterId ) 173 throws IOException 174 { 175 ICacheElement<K, V> element = null; 176 ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.GET_EVENT ); 177 try 178 { 179 element = processGet( cacheName, key, requesterId ); 180 } 181 finally 182 { 183 logICacheEvent( cacheEvent ); 184 } 185 return element; 186 } 187 188 /** 189 * Returns a cache bean from the specified cache; or null if the key does not exist. 190 * <p> 191 * Adding the requestor id, allows the cache to determine the source of the get. 192 * <p> 193 * @param cacheName 194 * @param key 195 * @param requesterId 196 * @return ICacheElement 197 * @throws IOException 198 */ 199 abstract ICacheElement<K, V> processGet( String cacheName, K key, long requesterId ) 200 throws IOException; 201 202 /** 203 * Gets all matching items. 204 * <p> 205 * @param cacheName 206 * @param pattern 207 * @return Map of keys and wrapped objects 208 * @throws IOException 209 */ 210 @Override 211 public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern ) 212 throws IOException 213 { 214 return getMatching( cacheName, pattern, 0 ); 215 } 216 217 /** 218 * Retrieves all matching keys. 219 * <p> 220 * @param cacheName 221 * @param pattern 222 * @param requesterId 223 * @return Map of keys and wrapped objects 224 * @throws IOException 225 */ 226 @Override 227 public Map<K, ICacheElement<K, V>> getMatching( String cacheName, String pattern, long requesterId ) 228 throws IOException 229 { 230 ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, pattern, requesterId, 231 ICacheEventLogger.GETMATCHING_EVENT ); 232 try 233 { 234 return processGetMatching( cacheName, pattern, requesterId ); 235 } 236 finally 237 { 238 logICacheEvent( cacheEvent ); 239 } 240 } 241 242 /** 243 * Retrieves all matching keys. 244 * <p> 245 * @param cacheName 246 * @param pattern 247 * @param requesterId 248 * @return Map of keys and wrapped objects 249 * @throws IOException 250 */ 251 abstract Map<K, ICacheElement<K, V>> processGetMatching( String cacheName, String pattern, long requesterId ) 252 throws IOException; 253 254 /** 255 * Gets multiple items from the cache based on the given set of keys. 256 * <p> 257 * @param cacheName 258 * @param keys 259 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no 260 * data in cache for any of these keys 261 * @throws IOException 262 */ 263 @Override 264 public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys ) 265 throws IOException 266 { 267 return this.getMultiple( cacheName, keys, 0 ); 268 } 269 270 /** 271 * Gets multiple items from the cache based on the given set of keys. 272 * <p> 273 * The internal processing is wrapped in event logging calls. 274 * <p> 275 * @param cacheName 276 * @param keys 277 * @param requesterId 278 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no 279 * data in cache for any of these keys 280 * @throws IOException 281 */ 282 @Override 283 public Map<K, ICacheElement<K, V>> getMultiple( String cacheName, Set<K> keys, long requesterId ) 284 throws IOException 285 { 286 ICacheEvent<Serializable> cacheEvent = createICacheEvent( cacheName, (Serializable) keys, requesterId, 287 ICacheEventLogger.GETMULTIPLE_EVENT ); 288 try 289 { 290 return processGetMultiple( cacheName, keys, requesterId ); 291 } 292 finally 293 { 294 logICacheEvent( cacheEvent ); 295 } 296 } 297 298 /** 299 * Gets multiple items from the cache based on the given set of keys. 300 * <p> 301 * @param cacheName 302 * @param keys 303 * @param requesterId 304 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no 305 * data in cache for any of these keys 306 * @throws IOException 307 */ 308 abstract Map<K, ICacheElement<K, V>> processGetMultiple( String cacheName, Set<K> keys, long requesterId ) 309 throws IOException; 310 311 /** 312 * Return the keys in this cache. 313 * <p> 314 * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet() 315 */ 316 @Override 317 public Set<K> getKeySet( String cacheName ) 318 { 319 return processGetKeySet( cacheName ); 320 } 321 322 /** 323 * Gets the set of keys of objects currently in the cache. 324 * <p> 325 * @param cacheName 326 * @return Set 327 */ 328 public Set<K> processGetKeySet( String cacheName ) 329 { 330 CompositeCache<K, V> cache = getCacheManager().getCache( cacheName ); 331 332 return cache.getKeySet(); 333 } 334 335 /** 336 * Removes the given key from the specified remote cache. Defaults the listener id to 0. 337 * <p> 338 * @param cacheName 339 * @param key 340 * @throws IOException 341 */ 342 @Override 343 public void remove( String cacheName, K key ) 344 throws IOException 345 { 346 remove( cacheName, key, 0 ); 347 } 348 349 /** 350 * Remove the key from the cache region and don't tell the source listener about it. 351 * <p> 352 * The internal processing is wrapped in event logging calls. 353 * <p> 354 * @param cacheName 355 * @param key 356 * @param requesterId 357 * @throws IOException 358 */ 359 @Override 360 public void remove( String cacheName, K key, long requesterId ) 361 throws IOException 362 { 363 ICacheEvent<K> cacheEvent = createICacheEvent( cacheName, key, requesterId, ICacheEventLogger.REMOVE_EVENT ); 364 try 365 { 366 processRemove( cacheName, key, requesterId ); 367 } 368 finally 369 { 370 logICacheEvent( cacheEvent ); 371 } 372 } 373 374 /** 375 * Remove the key from the cache region and don't tell the source listener about it. 376 * <p> 377 * @param cacheName 378 * @param key 379 * @param requesterId 380 * @throws IOException 381 */ 382 abstract void processRemove( String cacheName, K key, long requesterId ) 383 throws IOException; 384 385 /** 386 * Remove all keys from the specified remote cache. 387 * <p> 388 * @param cacheName 389 * @throws IOException 390 */ 391 @Override 392 public void removeAll( String cacheName ) 393 throws IOException 394 { 395 removeAll( cacheName, 0 ); 396 } 397 398 /** 399 * Remove all keys from the specified remote cache. 400 * <p> 401 * The internal processing is wrapped in event logging calls. 402 * <p> 403 * @param cacheName 404 * @param requesterId 405 * @throws IOException 406 */ 407 @Override 408 public void removeAll( String cacheName, long requesterId ) 409 throws IOException 410 { 411 ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "all", requesterId, ICacheEventLogger.REMOVEALL_EVENT ); 412 try 413 { 414 processRemoveAll( cacheName, requesterId ); 415 } 416 finally 417 { 418 logICacheEvent( cacheEvent ); 419 } 420 } 421 422 /** 423 * Remove all keys from the specified remote cache. 424 * <p> 425 * @param cacheName 426 * @param requesterId 427 * @throws IOException 428 */ 429 abstract void processRemoveAll( String cacheName, long requesterId ) 430 throws IOException; 431 432 /** 433 * Frees the specified remote cache. 434 * <p> 435 * @param cacheName 436 * @throws IOException 437 */ 438 @Override 439 public void dispose( String cacheName ) 440 throws IOException 441 { 442 dispose( cacheName, 0 ); 443 } 444 445 /** 446 * Frees the specified remote cache. 447 * <p> 448 * @param cacheName 449 * @param requesterId 450 * @throws IOException 451 */ 452 public void dispose( String cacheName, long requesterId ) 453 throws IOException 454 { 455 ICacheEvent<String> cacheEvent = createICacheEvent( cacheName, "none", requesterId, ICacheEventLogger.DISPOSE_EVENT ); 456 try 457 { 458 processDispose( cacheName, requesterId ); 459 } 460 finally 461 { 462 logICacheEvent( cacheEvent ); 463 } 464 } 465 466 /** 467 * @param cacheName 468 * @param requesterId 469 * @throws IOException 470 */ 471 abstract void processDispose( String cacheName, long requesterId ) 472 throws IOException; 473 474 /** 475 * Gets the stats attribute of the RemoteCacheServer object. 476 * <p> 477 * @return The stats value 478 * @throws IOException 479 */ 480 public String getStats() 481 throws IOException 482 { 483 return cacheManager.getStats(); 484 } 485 486 /** 487 * Logs an event if an event logger is configured. 488 * <p> 489 * @param item 490 * @param requesterId 491 * @param eventName 492 * @return ICacheEvent 493 */ 494 protected ICacheEvent<ICacheElement<K, V>> createICacheEvent( ICacheElement<K, V> item, long requesterId, String eventName ) 495 { 496 if ( cacheEventLogger == null ) 497 { 498 return new CacheEvent<ICacheElement<K, V>>(); 499 } 500 String ipAddress = getExtraInfoForRequesterId( requesterId ); 501 return cacheEventLogger.createICacheEvent( getEventLogSourceName(), item.getCacheName(), eventName, ipAddress, 502 item ); 503 } 504 505 /** 506 * Logs an event if an event logger is configured. 507 * <p> 508 * @param cacheName 509 * @param key 510 * @param requesterId 511 * @param eventName 512 * @return ICacheEvent 513 */ 514 protected <T> ICacheEvent<T> createICacheEvent( String cacheName, T key, long requesterId, String eventName ) 515 { 516 if ( cacheEventLogger == null ) 517 { 518 return new CacheEvent<T>(); 519 } 520 String ipAddress = getExtraInfoForRequesterId( requesterId ); 521 return cacheEventLogger.createICacheEvent( getEventLogSourceName(), cacheName, eventName, ipAddress, key ); 522 } 523 524 /** 525 * Logs an event if an event logger is configured. 526 * <p> 527 * @param source 528 * @param eventName 529 * @param optionalDetails 530 */ 531 protected void logApplicationEvent( String source, String eventName, String optionalDetails ) 532 { 533 if ( cacheEventLogger != null ) 534 { 535 cacheEventLogger.logApplicationEvent( source, eventName, optionalDetails ); 536 } 537 } 538 539 /** 540 * Logs an event if an event logger is configured. 541 * <p> 542 * @param cacheEvent 543 */ 544 protected <T> void logICacheEvent( ICacheEvent<T> cacheEvent ) 545 { 546 if ( cacheEventLogger != null ) 547 { 548 cacheEventLogger.logICacheEvent( cacheEvent ); 549 } 550 } 551 552 /** 553 * Ip address for the client, if one is stored. 554 * <p> 555 * Protected for testing. 556 * <p> 557 * @param requesterId 558 * @return String 559 */ 560 protected abstract String getExtraInfoForRequesterId( long requesterId ); 561 562 /** 563 * Allows it to be injected. 564 * <p> 565 * @param cacheEventLogger 566 */ 567 public void setCacheEventLogger( ICacheEventLogger cacheEventLogger ) 568 { 569 this.cacheEventLogger = cacheEventLogger; 570 } 571 572 /** 573 * @param cacheManager the cacheManager to set 574 */ 575 protected void setCacheManager( ICompositeCacheManager cacheManager ) 576 { 577 this.cacheManager = cacheManager; 578 } 579 580 /** 581 * @return the cacheManager 582 */ 583 protected ICompositeCacheManager getCacheManager() 584 { 585 return cacheManager; 586 } 587 588 /** 589 * @param eventLogSourceName the eventLogSourceName to set 590 */ 591 protected void setEventLogSourceName( String eventLogSourceName ) 592 { 593 this.eventLogSourceName = eventLogSourceName; 594 } 595 596 /** 597 * @return the eventLogSourceName 598 */ 599 protected String getEventLogSourceName() 600 { 601 return eventLogSourceName; 602 } 603}