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