001package org.apache.commons.jcs3.auxiliary.remote; 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.util.ArrayList; 024import java.util.Collections; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029import java.util.stream.Collectors; 030 031import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache; 032import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes; 033import org.apache.commons.jcs3.engine.CacheStatus; 034import org.apache.commons.jcs3.engine.behavior.ICacheElement; 035import org.apache.commons.jcs3.engine.behavior.IElementSerializer; 036import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger; 037import org.apache.commons.jcs3.engine.stats.StatElement; 038import org.apache.commons.jcs3.engine.stats.Stats; 039import org.apache.commons.jcs3.engine.stats.behavior.IStatElement; 040import org.apache.commons.jcs3.engine.stats.behavior.IStats; 041import org.apache.commons.jcs3.log.Log; 042import org.apache.commons.jcs3.log.LogManager; 043 044/** An abstract base for the No Wait Facade. Different implementations will failover differently. */ 045public abstract class AbstractRemoteCacheNoWaitFacade<K, V> 046 extends AbstractAuxiliaryCache<K, V> 047{ 048 /** log instance */ 049 private static final Log log = LogManager.getLog( AbstractRemoteCacheNoWaitFacade.class ); 050 051 /** The connection to a remote server, or a zombie. */ 052 protected List<RemoteCacheNoWait<K, V>> noWaits; 053 054 /** holds failover and cluster information */ 055 private final IRemoteCacheAttributes remoteCacheAttributes; 056 057 /** 058 * Constructs with the given remote cache, and fires events to any listeners. 059 * <p> 060 * @param noWaits 061 * @param rca 062 * @param cacheEventLogger 063 * @param elementSerializer 064 */ 065 public AbstractRemoteCacheNoWaitFacade( final List<RemoteCacheNoWait<K,V>> noWaits, final IRemoteCacheAttributes rca, 066 final ICacheEventLogger cacheEventLogger, final IElementSerializer elementSerializer ) 067 { 068 log.debug( "CONSTRUCTING NO WAIT FACADE" ); 069 this.remoteCacheAttributes = rca; 070 setCacheEventLogger( cacheEventLogger ); 071 setElementSerializer( elementSerializer ); 072 this.noWaits = new ArrayList<>(noWaits); 073 for (final RemoteCacheNoWait<K,V> nw : this.noWaits) 074 { 075 // FIXME: This cast is very brave. Remove this. 076 ((RemoteCache<K, V>)nw.getRemoteCache()).setFacade(this); 077 } 078 } 079 080 /** 081 * Put an element in the cache. 082 * <p> 083 * @param ce 084 * @throws IOException 085 */ 086 @Override 087 public void update( final ICacheElement<K, V> ce ) 088 throws IOException 089 { 090 log.debug("updating through cache facade, noWaits.length = {0}", noWaits::size); 091 092 for (final RemoteCacheNoWait<K, V> nw : noWaits) 093 { 094 nw.update( ce ); 095 } 096 } 097 098 /** 099 * Synchronously reads from the remote cache. 100 * <p> 101 * @param key 102 * @return Either an ICacheElement<K, V> or null if it is not found. 103 */ 104 @Override 105 public ICacheElement<K, V> get( final K key ) throws IOException 106 { 107 for (final RemoteCacheNoWait<K, V> nw : noWaits) 108 { 109 return nw.get(key); 110 } 111 112 return null; 113 } 114 115 /** 116 * Synchronously read from the remote cache. 117 * <p> 118 * @param pattern 119 * @return map 120 * @throws IOException 121 */ 122 @Override 123 public Map<K, ICacheElement<K, V>> getMatching( final String pattern ) 124 throws IOException 125 { 126 for (final RemoteCacheNoWait<K, V> nw : noWaits) 127 { 128 return nw.getMatching( pattern ); 129 } 130 131 return Collections.emptyMap(); 132 } 133 134 /** 135 * Gets multiple items from the cache based on the given set of keys. 136 * <p> 137 * @param keys 138 * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no 139 * data in cache for any of these keys 140 */ 141 @Override 142 public Map<K, ICacheElement<K, V>> getMultiple( final Set<K> keys ) throws IOException 143 { 144 if ( keys != null && !keys.isEmpty() ) 145 { 146 for (final RemoteCacheNoWait<K, V> nw : noWaits) 147 { 148 return nw.getMultiple( keys ); 149 } 150 } 151 152 return Collections.emptyMap(); 153 } 154 155 /** 156 * Return the keys in this cache. 157 * <p> 158 * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet() 159 */ 160 @Override 161 public Set<K> getKeySet() throws IOException 162 { 163 final HashSet<K> allKeys = new HashSet<>(); 164 for (final RemoteCacheNoWait<K, V> nw : noWaits) 165 { 166 final Set<K> keys = nw.getKeySet(); 167 if(keys != null) 168 { 169 allKeys.addAll( keys ); 170 } 171 } 172 173 return allKeys; 174 } 175 176 /** 177 * Adds a remove request to the remote cache. 178 * <p> 179 * @param key 180 * @return whether or not it was removed, right now it return false. 181 */ 182 @Override 183 public boolean remove( final K key ) throws IOException 184 { 185 for (final RemoteCacheNoWait<K, V> nw : noWaits) 186 { 187 nw.remove( key ); 188 } 189 190 return false; 191 } 192 193 /** 194 * Adds a removeAll request to the remote cache. 195 */ 196 @Override 197 public void removeAll() throws IOException 198 { 199 for (final RemoteCacheNoWait<K, V> nw : noWaits) 200 { 201 nw.removeAll(); 202 } 203 } 204 205 /** Adds a dispose request to the remote cache. */ 206 @Override 207 public void dispose() 208 { 209 noWaits.forEach(RemoteCacheNoWait::dispose); 210 } 211 212 /** 213 * No remote invocation. 214 * <p> 215 * @return The size value 216 */ 217 @Override 218 public int getSize() 219 { 220 return 0; 221 // cache.getSize(); 222 } 223 224 /** 225 * Gets the cacheType attribute of the RemoteCacheNoWaitFacade object. 226 * <p> 227 * @return The cacheType value 228 */ 229 @Override 230 public CacheType getCacheType() 231 { 232 return CacheType.REMOTE_CACHE; 233 } 234 235 /** 236 * Gets the cacheName attribute of the RemoteCacheNoWaitFacade object. 237 * <p> 238 * @return The cacheName value 239 */ 240 @Override 241 public String getCacheName() 242 { 243 return remoteCacheAttributes.getCacheName(); 244 } 245 246 /** 247 * Gets the status attribute of the RemoteCacheNoWaitFacade object 248 * <p> 249 * Return ALIVE if any are alive. 250 * <p> 251 * @return The status value 252 */ 253 @Override 254 public CacheStatus getStatus() 255 { 256 return noWaits.stream() 257 .map(nw -> nw.getStatus()) 258 .filter(status -> status == CacheStatus.ALIVE) 259 .findFirst() 260 .orElse(CacheStatus.DISPOSED); 261 } 262 263 /** 264 * String form of some of the configuration information for the remote cache. 265 * <p> 266 * @return Some info for logging. 267 */ 268 @Override 269 public String toString() 270 { 271 return "RemoteCacheNoWaitFacade: " + remoteCacheAttributes.getCacheName() + 272 ", rca = " + remoteCacheAttributes; 273 } 274 275 /** 276 * Begin the failover process if this is a local cache. Clustered remote caches do not failover. 277 * <p> 278 * @param rcnw The no wait in error. 279 */ 280 protected abstract void failover( RemoteCacheNoWait<K, V> rcnw ); 281 282 /** 283 * Get the primary server from the list of failovers 284 * 285 * @return a no wait 286 */ 287 public RemoteCacheNoWait<K, V> getPrimaryServer() 288 { 289 return noWaits.get(0); 290 } 291 292 /** 293 * restore the primary server in the list of failovers 294 * 295 */ 296 public void restorePrimaryServer(final RemoteCacheNoWait<K, V> rcnw) 297 { 298 noWaits.clear(); 299 noWaits.add(rcnw); 300 } 301 302 /** 303 * @return Returns the AuxiliaryCacheAttributes. 304 */ 305 @Override 306 public IRemoteCacheAttributes getAuxiliaryCacheAttributes() 307 { 308 return this.remoteCacheAttributes; 309 } 310 311 /** 312 * getStats 313 * @return String 314 */ 315 @Override 316 public String getStats() 317 { 318 return getStatistics().toString(); 319 } 320 321 /** 322 * @return statistics about the cache region 323 */ 324 @Override 325 public IStats getStatistics() 326 { 327 final IStats stats = new Stats(); 328 stats.setTypeName( "Remote Cache No Wait Facade" ); 329 330 final ArrayList<IStatElement<?>> elems = new ArrayList<>(); 331 332 if ( noWaits != null ) 333 { 334 elems.add(new StatElement<>( "Number of No Waits", Integer.valueOf(noWaits.size()) ) ); 335 336 // get the stats from the super too 337 elems.addAll(noWaits.stream() 338 .flatMap(rcnw -> rcnw.getStatistics().getStatElements().stream()) 339 .collect(Collectors.toList())); 340 } 341 342 stats.setStatElements( elems ); 343 344 return stats; 345 } 346 347 /** 348 * This typically returns end point info . 349 * <p> 350 * @return the name 351 */ 352 @Override 353 public String getEventLoggingExtraInfo() 354 { 355 return "Remote Cache No Wait Facade"; 356 } 357}