View Javadoc
1   package org.apache.commons.jcs.auxiliary.lateral;
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 org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCache;
23  import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
24  import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
25  import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheAttributes;
26  import org.apache.commons.jcs.auxiliary.lateral.behavior.ILateralCacheListener;
27  import org.apache.commons.jcs.engine.CacheStatus;
28  import org.apache.commons.jcs.engine.behavior.ICacheElement;
29  import org.apache.commons.jcs.engine.stats.StatElement;
30  import org.apache.commons.jcs.engine.stats.Stats;
31  import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
32  import org.apache.commons.jcs.engine.stats.behavior.IStats;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  import java.io.IOException;
37  import java.util.ArrayList;
38  import java.util.HashMap;
39  import java.util.HashSet;
40  import java.util.Map;
41  import java.util.Set;
42  
43  /**
44   * Used to provide access to multiple services under nowait protection. Composite factory should
45   * construct LateralCacheNoWaitFacade to give to the composite cache out of caches it constructs
46   * from the varies manager to lateral services. Perhaps the lateralcache factory should be able to
47   * do this.
48   */
49  public class LateralCacheNoWaitFacade<K, V>
50      extends AbstractAuxiliaryCache<K, V>
51  {
52      /** The logger */
53      private static final Log log = LogFactory.getLog( LateralCacheNoWaitFacade.class );
54  
55      /** The queuing facade to the client. */
56      public LateralCacheNoWait<K, V>[] noWaits;
57  
58      /** The region name */
59      private final String cacheName;
60  
61      /** A cache listener */
62      private ILateralCacheListener<K, V> listener;
63  
64      /** User configurable attributes. */
65      private final ILateralCacheAttributes lateralCacheAttributes;
66  
67      /** Disposed state of this facade */
68      private boolean disposed = false;
69  
70      /**
71       * Constructs with the given lateral cache, and fires events to any listeners.
72       * <p>
73       * @param noWaits
74       * @param cattr
75       */
76      public LateralCacheNoWaitFacade(ILateralCacheListener<K, V> listener, LateralCacheNoWait<K, V>[] noWaits, ILateralCacheAttributes cattr )
77      {
78          if ( log.isDebugEnabled() )
79          {
80              log.debug( "CONSTRUCTING NO WAIT FACADE" );
81          }
82          this.listener = listener;
83          this.noWaits = noWaits;
84          this.cacheName = cattr.getCacheName();
85          this.lateralCacheAttributes = cattr;
86      }
87  
88      /**
89       * Tells you if the no wait is in the list or not.
90       * <p>
91       * @param noWait
92       * @return true if the noWait is in the list.
93       */
94      public boolean containsNoWait( LateralCacheNoWait<K, V> noWait )
95      {
96          for ( int i = 0; i < noWaits.length; i++ )
97          {
98              // we know noWait isn't null
99              if ( noWait.equals( noWaits[i] ) )
100             {
101                 return true;
102             }
103         }
104         return false;
105     }
106 
107     /**
108      * Adds a no wait to the list if it isn't already in the list.
109      * <p>
110      * @param noWait
111      * @return true if it wasn't already contained
112      */
113     public synchronized boolean addNoWait( LateralCacheNoWait<K, V> noWait )
114     {
115         if ( noWait == null )
116         {
117             return false;
118         }
119 
120         if ( containsNoWait( noWait ) )
121         {
122             if ( log.isDebugEnabled() )
123             {
124                 log.debug( "No Wait already contained, [" + noWait + "]" );
125             }
126             return false;
127         }
128 
129         @SuppressWarnings("unchecked") // No generic arrays in java
130         LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length + 1];
131 
132         System.arraycopy( noWaits, 0, newArray, 0, noWaits.length );
133 
134         // set the last position to the new noWait
135         newArray[noWaits.length] = noWait;
136 
137         noWaits = newArray;
138 
139         return true;
140     }
141 
142     /**
143      * Removes a no wait from the list if it is already there.
144      * <p>
145      * @param noWait
146      * @return true if it was already in the array
147      */
148     public synchronized boolean removeNoWait( LateralCacheNoWait<K, V> noWait )
149     {
150         if ( noWait == null )
151         {
152             return false;
153         }
154 
155         int position = -1;
156         for ( int i = 0; i < noWaits.length; i++ )
157         {
158             // we know noWait isn't null
159             if ( noWait.equals( noWaits[i] ) )
160             {
161                 position = i;
162                 break;
163             }
164         }
165 
166         if ( position == -1 )
167         {
168             return false;
169         }
170 
171         @SuppressWarnings("unchecked") // No generic arrays in java
172         LateralCacheNoWait<K, V>[] newArray = new LateralCacheNoWait[noWaits.length - 1];
173 
174         System.arraycopy( noWaits, 0, newArray, 0, position );
175         if ( noWaits.length != position )
176         {
177             System.arraycopy( noWaits, position + 1, newArray, position, noWaits.length - position - 1 );
178         }
179         noWaits = newArray;
180 
181         return true;
182     }
183 
184     /**
185      * @param ce
186      * @throws IOException
187      */
188     @Override
189     public void update( ICacheElement<K, V> ce )
190         throws IOException
191     {
192         if ( log.isDebugEnabled() )
193         {
194             log.debug( "updating through lateral cache facade, noWaits.length = " + noWaits.length );
195         }
196         try
197         {
198             for ( int i = 0; i < noWaits.length; i++ )
199             {
200                 noWaits[i].update( ce );
201             }
202         }
203         catch ( Exception ex )
204         {
205             log.error( ex );
206         }
207     }
208 
209     /**
210      * Synchronously reads from the lateral cache.
211      * <p>
212      * @param key
213      * @return ICacheElement
214      */
215     @Override
216     public ICacheElement<K, V> get( K key )
217     {
218         for ( int i = 0; i < noWaits.length; i++ )
219         {
220             try
221             {
222                 ICacheElement<K, V> obj = noWaits[i].get( key );
223 
224                 if ( obj != null )
225                 {
226                     // TODO: return after first success
227                     // could do this simultaneously
228                     // serious blocking risk here
229                     return obj;
230                 }
231             }
232             catch ( Exception ex )
233             {
234                 log.error( "Failed to get", ex );
235             }
236         }
237         return null;
238     }
239 
240     /**
241      * Gets multiple items from the cache based on the given set of keys.
242      * <p>
243      * @param keys
244      * @return a map of K key to ICacheElement&lt;K, V&gt; element, or an empty map if there is no
245      *         data in cache for any of these keys
246      */
247     @Override
248     public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
249     {
250         Map<K, ICacheElement<K, V>> elements = new HashMap<K, ICacheElement<K, V>>();
251 
252         if ( keys != null && !keys.isEmpty() )
253         {
254             for (K key : keys)
255             {
256                 ICacheElement<K, V> element = get( key );
257 
258                 if ( element != null )
259                 {
260                     elements.put( key, element );
261                 }
262             }
263         }
264 
265         return elements;
266     }
267 
268     /**
269      * Synchronously reads from the lateral cache. Get a response from each! This will be slow.
270      * Merge them.
271      * <p>
272      * @param pattern
273      * @return ICacheElement
274      */
275     @Override
276     public Map<K, ICacheElement<K, V>> getMatching(String pattern)
277     {
278         Map<K, ICacheElement<K, V>> elements = new HashMap<K, ICacheElement<K, V>>();
279         for ( int i = 0; i < noWaits.length; i++ )
280         {
281             try
282             {
283                 elements.putAll( noWaits[i].getMatching( pattern ) );
284             }
285             catch ( Exception ex )
286             {
287                 log.error( "Failed to get", ex );
288             }
289         }
290         return elements;
291     }
292 
293     /**
294      * Return the keys in this cache.
295      * <p>
296      * @see org.apache.commons.jcs.auxiliary.AuxiliaryCache#getKeySet()
297      */
298     @Override
299     public Set<K> getKeySet() throws IOException
300     {
301         HashSet<K> allKeys = new HashSet<K>();
302         for ( int i = 0; i < noWaits.length; i++ )
303         {
304             AuxiliaryCache<K, V> aux = noWaits[i];
305             if ( aux != null )
306             {
307                 Set<K> keys = aux.getKeySet();
308                 if(keys != null)
309                 {
310                     allKeys.addAll( keys );
311                 }
312             }
313         }
314         return allKeys;
315     }
316 
317     /**
318      * Adds a remove request to the lateral cache.
319      * <p>
320      * @param key
321      * @return always false.
322      */
323     @Override
324     public boolean remove( K key )
325     {
326         try
327         {
328             for ( int i = 0; i < noWaits.length; i++ )
329             {
330                 noWaits[i].remove( key );
331             }
332         }
333         catch ( Exception ex )
334         {
335             log.error( ex );
336         }
337         return false;
338     }
339 
340     /**
341      * Adds a removeAll request to the lateral cache.
342      */
343     @Override
344     public void removeAll()
345     {
346         try
347         {
348             for ( int i = 0; i < noWaits.length; i++ )
349             {
350                 noWaits[i].removeAll();
351             }
352         }
353         catch ( Exception ex )
354         {
355             log.error( ex );
356         }
357     }
358 
359     /** Adds a dispose request to the lateral cache. */
360     @Override
361     public void dispose()
362     {
363         try
364         {
365             if ( listener != null )
366             {
367                 listener.dispose();
368                 listener = null;
369             }
370 
371             for ( int i = 0; i < noWaits.length; i++ )
372             {
373                 noWaits[i].dispose();
374             }
375         }
376         catch ( Exception ex )
377         {
378             log.error( ex );
379         }
380         finally
381         {
382             disposed = true;
383         }
384     }
385 
386     /**
387      * No lateral invocation.
388      * @return The size value
389      */
390     @Override
391     public int getSize()
392     {
393         return 0;
394         //cache.getSize();
395     }
396 
397     /**
398      * Gets the cacheType attribute of the LateralCacheNoWaitFacade object.
399      * <p>
400      * @return The cacheType value
401      */
402     @Override
403     public CacheType getCacheType()
404     {
405         return CacheType.LATERAL_CACHE;
406     }
407 
408     /**
409      * Gets the cacheName attribute of the LateralCacheNoWaitFacade object.
410      * <p>
411      * @return The cacheName value
412      */
413     @Override
414     public String getCacheName()
415     {
416         return "";
417         //cache.getCacheName();
418     }
419 
420     /**
421      * Gets the status attribute of the LateralCacheNoWaitFacade object
422      * @return The status value
423      */
424     @Override
425     public CacheStatus getStatus()
426     {
427         if (disposed)
428         {
429             return CacheStatus.DISPOSED;
430         }
431 
432         if (noWaits.length == 0 || listener != null)
433         {
434             return CacheStatus.ALIVE;
435         }
436 
437         CacheStatus[] statii = new CacheStatus[noWaits.length];
438         for (int i = 0; i < noWaits.length; i++)
439         {
440             statii[i] = noWaits[i].getStatus();
441         }
442         // It's alive if ANY of its nowaits is alive
443         for (int i = 0; i < noWaits.length; i++)
444         {
445             if (statii[i] == CacheStatus.ALIVE)
446             {
447                 return CacheStatus.ALIVE;
448             }
449         }
450         // It's alive if ANY of its nowaits is in error, but
451         // none are alive, then it's in error
452         for (int i = 0; i < noWaits.length; i++)
453         {
454             if (statii[i] == CacheStatus.ERROR)
455             {
456                 return CacheStatus.ERROR;
457             }
458         }
459 
460         // Otherwise, it's been disposed, since it's the only status left
461         return CacheStatus.DISPOSED;
462     }
463 
464     /**
465      * @return Returns the AuxiliaryCacheAttributes.
466      */
467     @Override
468     public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
469     {
470         return this.lateralCacheAttributes;
471     }
472 
473     /**
474      * @return "LateralCacheNoWaitFacade: " + cacheName;
475      */
476     @Override
477     public String toString()
478     {
479         return "LateralCacheNoWaitFacade: " + cacheName;
480     }
481 
482     /**
483      * this won't be called since we don't do ICache logging here.
484      * <p>
485      * @return String
486      */
487     @Override
488     public String getEventLoggingExtraInfo()
489     {
490         return "Lateral Cache No Wait";
491     }
492 
493     /**
494      * getStats
495      * @return String
496      */
497     @Override
498     public String getStats()
499     {
500         return getStatistics().toString();
501     }
502 
503     /**
504      * @return IStats
505      */
506     @Override
507     public IStats getStatistics()
508     {
509         IStats stats = new Stats();
510         stats.setTypeName( "Lateral Cache No Wait Facade" );
511 
512         ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
513 
514         if ( noWaits != null )
515         {
516             elems.add(new StatElement<Integer>( "Number of No Waits", Integer.valueOf(noWaits.length) ) );
517 
518             for ( LateralCacheNoWait<K, V> lcnw : noWaits )
519             {
520                 if ( lcnw != null )
521                 {
522                     // get the stats from the super too
523                     IStats sStats = lcnw.getStatistics();
524                     elems.addAll(sStats.getStatElements());
525                 }
526             }
527         }
528 
529         stats.setStatElements( elems );
530 
531         return stats;
532     }
533 }