View Javadoc

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