View Javadoc
1   package org.apache.commons.jcs3.auxiliary.remote;
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.util.ArrayList;
24  import java.util.Collections;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.stream.Collectors;
30  
31  import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCache;
32  import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes;
33  import org.apache.commons.jcs3.engine.CacheStatus;
34  import org.apache.commons.jcs3.engine.behavior.ICacheElement;
35  import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
36  import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
37  import org.apache.commons.jcs3.engine.stats.StatElement;
38  import org.apache.commons.jcs3.engine.stats.Stats;
39  import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
40  import org.apache.commons.jcs3.engine.stats.behavior.IStats;
41  import org.apache.commons.jcs3.log.Log;
42  import org.apache.commons.jcs3.log.LogManager;
43  
44  /** An abstract base for the No Wait Facade.  Different implementations will failover differently. */
45  public abstract class AbstractRemoteCacheNoWaitFacade<K, V>
46      extends AbstractAuxiliaryCache<K, V>
47  {
48      /** log instance */
49      private static final Log log = LogManager.getLog( AbstractRemoteCacheNoWaitFacade.class );
50  
51      /** The connection to a remote server, or a zombie. */
52      protected List<RemoteCacheNoWait<K, V>> noWaits;
53  
54      /** holds failover and cluster information */
55      private final IRemoteCacheAttributes remoteCacheAttributes;
56  
57      /**
58       * Constructs with the given remote cache, and fires events to any listeners.
59       * <p>
60       * @param noWaits
61       * @param rca
62       * @param cacheEventLogger
63       * @param elementSerializer
64       */
65      public AbstractRemoteCacheNoWaitFacade( final List<RemoteCacheNoWait<K,V>> noWaits, final IRemoteCacheAttributes rca,
66                                      final ICacheEventLogger cacheEventLogger, final IElementSerializer elementSerializer )
67      {
68          log.debug( "CONSTRUCTING NO WAIT FACADE" );
69          this.remoteCacheAttributes = rca;
70          setCacheEventLogger( cacheEventLogger );
71          setElementSerializer( elementSerializer );
72          this.noWaits = new ArrayList<>(noWaits);
73          for (final RemoteCacheNoWait<K,V> nw : this.noWaits)
74          {
75              // FIXME: This cast is very brave. Remove this.
76              ((RemoteCache<K, V>)nw.getRemoteCache()).setFacade(this);
77          }
78      }
79  
80      /**
81       * Put an element in the cache.
82       * <p>
83       * @param ce
84       * @throws IOException
85       */
86      @Override
87      public void update( final ICacheElement<K, V> ce )
88          throws IOException
89      {
90          log.debug("updating through cache facade, noWaits.length = {0}", noWaits::size);
91  
92          for (final RemoteCacheNoWait<K, V> nw : noWaits)
93          {
94              nw.update( ce );
95          }
96      }
97  
98      /**
99       * Synchronously reads from the remote cache.
100      * <p>
101      * @param key
102      * @return Either an ICacheElement&lt;K, V&gt; 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&lt;K, V&gt; 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 }