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.rmi.UnmarshalException;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Set;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.jcs.auxiliary.AbstractAuxiliaryCache;
36  import org.apache.jcs.auxiliary.AuxiliaryCacheAttributes;
37  import org.apache.jcs.engine.CacheAdaptor;
38  import org.apache.jcs.engine.CacheEventQueueFactory;
39  import org.apache.jcs.engine.CacheStatus;
40  import org.apache.jcs.engine.behavior.ICacheElement;
41  import org.apache.jcs.engine.behavior.ICacheEventQueue;
42  import org.apache.jcs.engine.behavior.ICacheServiceNonLocal;
43  import org.apache.jcs.engine.stats.StatElement;
44  import org.apache.jcs.engine.stats.Stats;
45  import org.apache.jcs.engine.stats.behavior.IStatElement;
46  import org.apache.jcs.engine.stats.behavior.IStats;
47  
48  /**
49   * Used to queue up update requests to the underlying cache. These requests will be processed in
50   * their order of arrival via the cache event queue processor.
51   */
52  public class LateralCacheNoWait<K extends Serializable, V extends Serializable>
53      extends AbstractAuxiliaryCache<K, V>
54  {
55      /** Don't change */
56      private static final long serialVersionUID = -7251187566116178475L;
57  
58      /** The logger. */
59      private final static Log log = LogFactory.getLog( LateralCacheNoWait.class );
60  
61      /** The cache */
62      private final LateralCache<K, V> cache;
63  
64      /** The event queue */
65      private ICacheEventQueue<K, V> eventQueue;
66  
67      /** times get called */
68      private int getCount = 0;
69  
70      /** times remove called */
71      private int removeCount = 0;
72  
73      /** times put called */
74      private int putCount = 0;
75  
76      /**
77       * Constructs with the given lateral cache, and fires up an event queue for aysnchronous
78       * processing.
79       * <p>
80       * @param cache
81       */
82      public LateralCacheNoWait( LateralCache<K, V> cache )
83      {
84          this.cache = cache;
85  
86          if ( log.isDebugEnabled() )
87          {
88              log.debug( "Constructing LateralCacheNoWait, LateralCache = [" + cache + "]" );
89          }
90  
91          CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<K, V>();
92          this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor<K, V>( cache ), LateralCacheInfo.listenerId, cache
93              .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache
94              .getAuxiliaryCacheAttributes().getEventQueueType() );
95  
96          // need each no wait to handle each of its real updates and removes,
97          // since there may
98          // be more than one per cache? alternative is to have the cache
99          // perform updates using a different method that specifies the listener
100         // this.q = new CacheEventQueue(new CacheAdaptor(this),
101         // LateralCacheInfo.listenerId, cache.getCacheName());
102         if ( cache.getStatus() == CacheStatus.ERROR )
103         {
104             eventQueue.destroy();
105         }
106     }
107 
108     /**
109      * @param ce
110      * @throws IOException
111      */
112     public void update( ICacheElement<K, V> ce )
113         throws IOException
114     {
115         putCount++;
116         try
117         {
118             eventQueue.addPutEvent( ce );
119         }
120         catch ( IOException ex )
121         {
122             log.error( ex );
123             eventQueue.destroy();
124         }
125     }
126 
127     /**
128      * Synchronously reads from the lateral cache.
129      * <p>
130      * @param key
131      * @return ICacheElement<K, V> if found, else null
132      */
133     public ICacheElement<K, V> get( K key )
134     {
135         getCount++;
136         if ( this.getStatus() != CacheStatus.ERROR )
137         {
138             try
139             {
140                 return cache.get( key );
141             }
142             catch ( UnmarshalException ue )
143             {
144                 log.debug( "Retrying the get owing to UnmarshalException..." );
145                 try
146                 {
147                     return cache.get( key );
148                 }
149                 catch ( IOException ex )
150                 {
151                     log.error( "Failed in retrying the get for the second time." );
152                     eventQueue.destroy();
153                 }
154             }
155             catch ( IOException ex )
156             {
157                 eventQueue.destroy();
158             }
159         }
160         return null;
161     }
162 
163     /**
164      * Gets multiple items from the cache based on the given set of keys.
165      * <p>
166      * @param keys
167      * @return a map of K key to ICacheElement<K, V> element, or an empty map if there is no
168      *         data in cache for any of these keys
169      */
170     public Map<K, ICacheElement<K, V>> getMultiple(Set<K> keys)
171     {
172         Map<K, ICacheElement<K, V>> elements = new HashMap<K, ICacheElement<K, V>>();
173 
174         if ( keys != null && !keys.isEmpty() )
175         {
176             for (K key : keys)
177             {
178                 ICacheElement<K, V> element = get( key );
179 
180                 if ( element != null )
181                 {
182                     elements.put( key, element );
183                 }
184             }
185         }
186 
187         return elements;
188     }
189 
190     /**
191      * Synchronously reads from the lateral cache.
192      * <p>
193      * @param pattern
194      * @return ICacheElement<K, V> if found, else empty
195      */
196     public Map<K, ICacheElement<K, V>> getMatching(String pattern)
197     {
198         getCount++;
199         if ( this.getStatus() != CacheStatus.ERROR )
200         {
201             try
202             {
203                 return cache.getMatching( pattern );
204             }
205             catch ( UnmarshalException ue )
206             {
207                 log.debug( "Retrying the get owing to UnmarshalException." );
208                 try
209                 {
210                     return cache.getMatching( pattern );
211                 }
212                 catch ( IOException ex )
213                 {
214                     log.error( "Failed in retrying the get for the second time." );
215                     eventQueue.destroy();
216                 }
217             }
218             catch ( IOException ex )
219             {
220                 eventQueue.destroy();
221             }
222         }
223         return Collections.emptyMap();
224     }
225 
226     /**
227      * @param groupName
228      * @return Set
229      */
230     public Set<K> getGroupKeys(String groupName)
231     {
232         try
233         {
234             return cache.getGroupKeys( groupName );
235         }
236         catch ( IOException ex )
237         {
238             log.error( ex );
239             eventQueue.destroy();
240         }
241         return Collections.emptySet();
242     }
243     
244     /**
245      * @return Set
246      */
247     public Set<String> getGroupNames()
248     {
249         try
250         {
251             return cache.getGroupNames( );
252         }
253         catch ( IOException ex )
254         {
255             log.error( ex );
256             eventQueue.destroy();
257         }
258         return Collections.emptySet();
259     }
260 
261     /**
262      * Adds a remove request to the lateral cache.
263      * <p>
264      * @param key
265      * @return always false
266      */
267     public boolean remove( K key )
268     {
269         removeCount++;
270         try
271         {
272             eventQueue.addRemoveEvent( key );
273         }
274         catch ( IOException ex )
275         {
276             log.error( ex );
277             eventQueue.destroy();
278         }
279         return false;
280     }
281 
282     /** Adds a removeAll request to the lateral cache. */
283     public void removeAll()
284     {
285         try
286         {
287             eventQueue.addRemoveAllEvent();
288         }
289         catch ( IOException ex )
290         {
291             log.error( ex );
292             eventQueue.destroy();
293         }
294     }
295 
296     /** Adds a dispose request to the lateral cache. */
297     public void dispose()
298     {
299         try
300         {
301             eventQueue.addDisposeEvent();
302         }
303         catch ( IOException ex )
304         {
305             log.error( ex );
306             eventQueue.destroy();
307         }
308     }
309 
310     /**
311      * No lateral invocation.
312      * <p>
313      * @return The size value
314      */
315     public int getSize()
316     {
317         return cache.getSize();
318     }
319 
320     /**
321      * No lateral invocation.
322      * <p>
323      * @return The cacheType value
324      */
325     public CacheType getCacheType()
326     {
327         return cache.getCacheType();
328     }
329 
330     /**
331      * Returns the asyn cache status. An error status indicates either the lateral connection is not
332      * available, or the asyn queue has been unexpectedly destroyed. No lateral invocation.
333      * <p>
334      * @return The status value
335      */
336     public CacheStatus getStatus()
337     {
338         return eventQueue.isWorking() ? cache.getStatus() : CacheStatus.ERROR;
339     }
340 
341     /**
342      * Gets the cacheName attribute of the LateralCacheNoWait object
343      * <p>
344      * @return The cacheName value
345      */
346     public String getCacheName()
347     {
348         return cache.getCacheName();
349     }
350 
351     /**
352      * Replaces the lateral cache service handle with the given handle and reset the queue by
353      * starting up a new instance.
354      * <p>
355      * @param lateral
356      */
357     public void fixCache( ICacheServiceNonLocal<K, V> lateral )
358     {
359         cache.fixCache( lateral );
360         resetEventQ();
361     }
362 
363     /**
364      * Resets the event q by first destroying the existing one and starting up new one.
365      */
366     public void resetEventQ()
367     {
368         if ( eventQueue.isWorking() )
369         {
370             eventQueue.destroy();
371         }
372         CacheEventQueueFactory<K, V> fact = new CacheEventQueueFactory<K, V>();
373         this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor<K, V>( cache ), LateralCacheInfo.listenerId, cache
374             .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache
375             .getAuxiliaryCacheAttributes().getEventQueueType() );
376     }
377 
378     /**
379      * @return Returns the AuxiliaryCacheAttributes.
380      */
381     public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
382     {
383         return cache.getAuxiliaryCacheAttributes();
384     }
385 
386     /**
387      * getStats
388      * @return String
389      */
390     public String getStats()
391     {
392         return getStatistics().toString();
393     }
394 
395     /**
396      * this won't be called since we don't do ICache logging here.
397      * <p>
398      * @return String
399      */
400     @Override
401     public String getEventLoggingExtraInfo()
402     {
403         return "Lateral Cache No Wait";
404     }
405 
406     /**
407      * @return statistics about this communication
408      */
409     public IStats getStatistics()
410     {
411         IStats stats = new Stats();
412         stats.setTypeName( "Lateral Cache No Wait" );
413 
414         ArrayList<IStatElement> elems = new ArrayList<IStatElement>();
415 
416         // IStatElement se = null;
417         // no data gathered here
418 
419         // get the stats from the event queue too
420         // get as array, convert to list, add list to our outer list
421         IStats eqStats = this.eventQueue.getStatistics();
422 
423         IStatElement[] eqSEs = eqStats.getStatElements();
424         List<IStatElement> eqL = Arrays.asList( eqSEs );
425         elems.addAll( eqL );
426 
427         IStatElement se = null;
428 
429         se = new StatElement();
430         se.setName( "Get Count" );
431         se.setData( "" + this.getCount );
432         elems.add( se );
433 
434         se = new StatElement();
435         se.setName( "Remove Count" );
436         se.setData( "" + this.removeCount );
437         elems.add( se );
438 
439         se = new StatElement();
440         se.setName( "Put Count" );
441         se.setData( "" + this.putCount );
442         elems.add( se );
443 
444         se = new StatElement();
445         se.setName( "Attributes" );
446         se.setData( "" + cache.getAuxiliaryCacheAttributes() );
447         elems.add( se );
448 
449         // get an array and put them in the Stats object
450         IStatElement[] ses = elems.toArray( new StatElement[elems.size()] );
451         stats.setStatElements( ses );
452 
453         return stats;
454     }
455 
456     /**
457      * @return debugging info.
458      */
459     @Override
460     public String toString()
461     {
462         StringBuffer buf = new StringBuffer();
463         buf.append( " LateralCacheNoWait " );
464         buf.append( " Status = " + this.getStatus() );
465         buf.append( " cache = [" + cache.toString() + "]" );
466         return buf.toString();
467     }
468 }