View Javadoc
1   package org.apache.commons.jcs.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  
30  import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache;
31  import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
32  import org.apache.commons.jcs.engine.CacheStatus;
33  import org.apache.commons.jcs.engine.behavior.ICache;
34  import org.apache.commons.jcs.engine.behavior.ICacheElement;
35  import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
36  import org.apache.commons.jcs.engine.behavior.IElementSerializer;
37  import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
38  import org.apache.commons.jcs.engine.stats.StatElement;
39  import org.apache.commons.jcs.engine.stats.Stats;
40  import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
41  import org.apache.commons.jcs.engine.stats.behavior.IStats;
42  import org.apache.commons.logging.Log;
43  import org.apache.commons.logging.LogFactory;
44  
45  /** An abstract base for the No Wait Facade.  Different implementations will failover differently. */
46  public abstract class AbstractRemoteCacheNoWaitFacade<K, V>
47      extends AbstractAuxiliaryCache<K, V>
48  {
49      /** log instance */
50      private static final Log log = LogFactory.getLog( AbstractRemoteCacheNoWaitFacade.class );
51  
52      /** The connection to a remote server, or a zombie. */
53      protected List<RemoteCacheNoWait<K, V>> noWaits;
54  
55      /** holds failover and cluster information */
56      private IRemoteCacheAttributes remoteCacheAttributes;
57  
58      /**
59       * Constructs with the given remote cache, and fires events to any listeners.
60       * <p>
61       * @param noWaits
62       * @param rca
63       * @param cacheEventLogger
64       * @param elementSerializer
65       */
66      public AbstractRemoteCacheNoWaitFacade( List<RemoteCacheNoWait<K,V>> noWaits, IRemoteCacheAttributes rca,
67                                      ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
68      {
69          if ( log.isDebugEnabled() )
70          {
71              log.debug( "CONSTRUCTING NO WAIT FACADE" );
72          }
73          this.remoteCacheAttributes = rca;
74          setCacheEventLogger( cacheEventLogger );
75          setElementSerializer( elementSerializer );
76          this.noWaits = new ArrayList<RemoteCacheNoWait<K,V>>(noWaits);
77          for (RemoteCacheNoWait<K,V> nw : this.noWaits)
78          {
79              // FIXME: This cast is very brave. Remove this.
80              ((RemoteCache<K, V>)nw.getRemoteCache()).setFacade(this);
81          }
82      }
83  
84      /**
85       * Constructs with the given remote cache, and fires events to any listeners.
86       * <p>
87       * @param noWaits
88       * @param rca
89       * @param cacheMgr
90       * @param cacheEventLogger
91       * @param elementSerializer
92       * @deprecated Unused parameter cacheMgr scheduled for removal
93       */
94      @Deprecated
95      public AbstractRemoteCacheNoWaitFacade( List<ICache<K, V>> noWaits, RemoteCacheAttributes rca,
96                                      ICompositeCacheManager cacheMgr, ICacheEventLogger cacheEventLogger,
97                                      IElementSerializer elementSerializer )
98      {
99          if ( log.isDebugEnabled() )
100         {
101             log.debug( "CONSTRUCTING NO WAIT FACADE" );
102         }
103         this.remoteCacheAttributes = rca;
104         setCacheEventLogger( cacheEventLogger );
105         setElementSerializer( elementSerializer );
106         this.noWaits = new ArrayList<RemoteCacheNoWait<K,V>>();
107         for (ICache<K, V> nw : noWaits)
108         {
109             RemoteCacheNoWait<K,V> rcnw = (RemoteCacheNoWait<K,V>)nw;
110             ((RemoteCache<K, V>)rcnw.getRemoteCache()).setFacade(this);
111             this.noWaits.add(rcnw);
112         }
113     }
114 
115     /**
116      * Put an element in the cache.
117      * <p>
118      * @param ce
119      * @throws IOException
120      */
121     @Override
122     public void update( ICacheElement<K, V> ce )
123         throws IOException
124     {
125         if ( log.isDebugEnabled() )
126         {
127             log.debug( "updating through cache facade, noWaits.length = " + noWaits.size() );
128         }
129 
130         for (RemoteCacheNoWait<K, V> nw : noWaits)
131         {
132             try
133             {
134                 nw.update( ce );
135                 // an initial move into a zombie will lock this to primary
136                 // recovery. will not discover other servers until primary
137                 // reconnect
138                 // and subsequent error
139             }
140             catch ( IOException ex )
141             {
142                 String message = "Problem updating no wait. Will initiate failover if the noWait is in error.";
143                 log.error( message, ex );
144 
145                 if ( getCacheEventLogger() != null )
146                 {
147                     getCacheEventLogger().logError( "RemoteCacheNoWaitFacade",
148                                                     ICacheEventLogger.UPDATE_EVENT,
149                                                     message + ":" + ex.getMessage() + " REGION: " + ce.getCacheName()
150                                                         + " ELEMENT: " + ce );
151                 }
152 
153                 // can handle failover here? Is it safe to try the others?
154                 // check to see it the noWait is now a zombie
155                 // if it is a zombie, then move to the next in the failover list
156                 // will need to keep them in order or a count
157                 failover( nw );
158                 // should start a failover thread
159                 // should probably only failover if there is only one in the noWait
160                 // list
161                 // Should start a background thread to restore the original primary if we are in failover state.
162             }
163         }
164     }
165 
166     /**
167      * Synchronously reads from the remote cache.
168      * <p>
169      * @param key
170      * @return Either an ICacheElement&lt;K, V&gt; or null if it is not found.
171      */
172     @Override
173     public ICacheElement<K, V> get( K key )
174     {
175         for (RemoteCacheNoWait<K, V> nw : noWaits)
176         {
177             try
178             {
179                 ICacheElement<K, V> obj = nw.get( key );
180                 if ( obj != null )
181                 {
182                     return obj;
183                 }
184             }
185             catch ( IOException ex )
186             {
187                 log.debug( "Failed to get." );
188                 return null;
189             }
190         }
191         return null;
192     }
193 
194     /**
195      * Synchronously read from the remote cache.
196      * <p>
197      * @param pattern
198      * @return map
199      * @throws IOException
200      */
201     @Override
202     public Map<K, ICacheElement<K, V>> getMatching( String pattern )
203         throws IOException
204     {
205         for (RemoteCacheNoWait<K, V> nw : noWaits)
206         {
207             try
208             {
209                 return nw.getMatching( pattern );
210             }
211             catch ( IOException ex )
212             {
213                 log.debug( "Failed to getMatching." );
214             }
215         }
216         return Collections.emptyMap();
217     }
218 
219     /**
220      * Gets multiple items from the cache based on the given set of keys.
221      * <p>
222      * @param keys
223      * @return a map of K key to ICacheElement&lt;K, V&gt; element, or an empty map if there is no
224      *         data in cache for any of these keys
225      */
226     @Override
227     public Map<K, ICacheElement<K, V>> getMultiple( Set<K> keys )
228     {
229         if ( keys != null && !keys.isEmpty() )
230         {
231             for (RemoteCacheNoWait<K, V> nw : noWaits)
232             {
233                 try
234                 {
235                     return nw.getMultiple( keys );
236                 }
237                 catch ( IOException ex )
238                 {
239                     log.debug( "Failed to get." );
240                 }
241             }
242         }
243 
244         return Collections.emptyMap();
245     }
246 
247     /**
248      * Return the keys in this cache.
249      * <p>
250      * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
251      */
252     @Override
253     public Set<K> getKeySet() throws IOException
254     {
255         HashSet<K> allKeys = new HashSet<K>();
256         for (RemoteCacheNoWait<K, V> nw : noWaits)
257         {
258             if ( nw != null )
259             {
260                 Set<K> keys = nw.getKeySet();
261                 if(keys != null)
262                 {
263                     allKeys.addAll( keys );
264                 }
265             }
266         }
267         return allKeys;
268     }
269 
270     /**
271      * Adds a remove request to the remote cache.
272      * <p>
273      * @param key
274      * @return whether or not it was removed, right now it return false.
275      */
276     @Override
277     public boolean remove( K key )
278     {
279         try
280         {
281             for (RemoteCacheNoWait<K, V> nw : noWaits)
282             {
283                 nw.remove( key );
284             }
285         }
286         catch ( IOException ex )
287         {
288             log.error( ex );
289         }
290         return false;
291     }
292 
293     /**
294      * Adds a removeAll request to the remote cache.
295      */
296     @Override
297     public void removeAll()
298     {
299         try
300         {
301             for (RemoteCacheNoWait<K, V> nw : noWaits)
302             {
303                 nw.removeAll();
304             }
305         }
306         catch ( IOException ex )
307         {
308             log.error( ex );
309         }
310     }
311 
312     /** Adds a dispose request to the remote cache. */
313     @Override
314     public void dispose()
315     {
316         for (RemoteCacheNoWait<K, V> nw : noWaits)
317         {
318             nw.dispose();
319         }
320     }
321 
322     /**
323      * No remote invocation.
324      * <p>
325      * @return The size value
326      */
327     @Override
328     public int getSize()
329     {
330         return 0;
331         // cache.getSize();
332     }
333 
334     /**
335      * Gets the cacheType attribute of the RemoteCacheNoWaitFacade object.
336      * <p>
337      * @return The cacheType value
338      */
339     @Override
340     public CacheType getCacheType()
341     {
342         return CacheType.REMOTE_CACHE;
343     }
344 
345     /**
346      * Gets the cacheName attribute of the RemoteCacheNoWaitFacade object.
347      * <p>
348      * @return The cacheName value
349      */
350     @Override
351     public String getCacheName()
352     {
353         return remoteCacheAttributes.getCacheName();
354     }
355 
356     /**
357      * Gets the status attribute of the RemoteCacheNoWaitFacade object
358      * <p>
359      * Return ALIVE if any are alive.
360      * <p>
361      * @return The status value
362      */
363     @Override
364     public CacheStatus getStatus()
365     {
366         for (RemoteCacheNoWait<K, V> nw : noWaits)
367         {
368             if ( nw.getStatus() == CacheStatus.ALIVE )
369             {
370                 return CacheStatus.ALIVE;
371             }
372         }
373 
374         return CacheStatus.DISPOSED;
375     }
376 
377     /**
378      * String form of some of the configuration information for the remote cache.
379      * <p>
380      * @return Some info for logging.
381      */
382     @Override
383     public String toString()
384     {
385         return "RemoteCacheNoWaitFacade: " + remoteCacheAttributes.getCacheName() + ", rca = " + remoteCacheAttributes;
386     }
387 
388     /**
389      * Begin the failover process if this is a local cache. Clustered remote caches do not failover.
390      * <p>
391      * @param rcnw The no wait in error.
392      */
393     protected abstract void failover( RemoteCacheNoWait<K, V> rcnw );
394 
395     /**
396      * Get the primary server from the list of failovers
397      *
398      * @return a no wait
399      */
400     public RemoteCacheNoWait<K, V> getPrimaryServer()
401     {
402         return noWaits.get(0);
403     }
404 
405     /**
406      * restore the primary server in the list of failovers
407      *
408      */
409     public void restorePrimaryServer(RemoteCacheNoWait<K, V> rcnw)
410     {
411         noWaits.clear();
412         noWaits.add(rcnw);
413     }
414 
415     /**
416      * @return Returns the AuxiliaryCacheAttributes.
417      */
418     @Override
419     public IRemoteCacheAttributes getAuxiliaryCacheAttributes()
420     {
421         return this.remoteCacheAttributes;
422     }
423 
424     /**
425      * getStats
426      * @return String
427      */
428     @Override
429     public String getStats()
430     {
431         return getStatistics().toString();
432     }
433 
434     /**
435      * @return statistics about the cache region
436      */
437     @Override
438     public IStats getStatistics()
439     {
440         IStats stats = new Stats();
441         stats.setTypeName( "Remote Cache No Wait Facade" );
442 
443         ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
444 
445         if ( noWaits != null )
446         {
447             elems.add(new StatElement<Integer>( "Number of No Waits", Integer.valueOf(noWaits.size()) ) );
448 
449             for ( RemoteCacheNoWait<K, V> rcnw : noWaits )
450             {
451                 // get the stats from the super too
452                 IStats sStats = rcnw.getStatistics();
453                 elems.addAll(sStats.getStatElements());
454             }
455         }
456 
457         stats.setStatElements( elems );
458 
459         return stats;
460     }
461 
462     /**
463      * This typically returns end point info .
464      * <p>
465      * @return the name
466      */
467     @Override
468     public String getEventLoggingExtraInfo()
469     {
470         return "Remote Cache No Wait Facade";
471     }
472 }