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