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.auxiliary.lateral.behavior.ILateralCacheService;
38  import org.apache.jcs.engine.CacheAdaptor;
39  import org.apache.jcs.engine.CacheConstants;
40  import org.apache.jcs.engine.CacheEventQueueFactory;
41  import org.apache.jcs.engine.behavior.ICacheElement;
42  import org.apache.jcs.engine.behavior.ICacheEventQueue;
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
53      extends AbstractAuxiliaryCache
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 cache;
63  
64      /** The event queue */
65      private ICacheEventQueue 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 cache )
83      {
84          this.cache = cache;
85  
86          if ( log.isDebugEnabled() )
87          {
88              log.debug( "Constructing LateralCacheNoWait, LateralCache = [" + cache + "]" );
89          }
90  
91          CacheEventQueueFactory fact = new CacheEventQueueFactory();
92          this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor( 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 spcifies the listener
100         // this.q = new CacheEventQueue(new CacheAdaptor(this),
101         // LateralCacheInfo.listenerId, cache.getCacheName());
102         if ( cache.getStatus() == CacheConstants.STATUS_ERROR )
103         {
104             eventQueue.destroy();
105         }
106     }
107 
108     /**
109      * @param ce
110      * @throws IOException
111      */
112     public void update( ICacheElement 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 if found, else null
132      */
133     public ICacheElement get( Serializable key )
134     {
135         getCount++;
136         if ( this.getStatus() != CacheConstants.STATUS_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 Serializable key to ICacheElement element, or an empty map if there is no
168      *         data in cache for any of these keys
169      */
170     public Map<Serializable, ICacheElement> getMultiple(Set<Serializable> keys)
171     {
172         Map<Serializable, ICacheElement> elements = new HashMap<Serializable, ICacheElement>();
173 
174         if ( keys != null && !keys.isEmpty() )
175         {
176             for (Serializable key : keys)
177             {
178                 ICacheElement 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 if found, else empty
195      */
196     public Map<Serializable, ICacheElement> getMatching(String pattern)
197     {
198         getCount++;
199         if ( this.getStatus() != CacheConstants.STATUS_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<Serializable> 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      * Adds a remove request to the lateral cache.
246      * <p>
247      * @param key
248      * @return always false
249      */
250     public boolean remove( Serializable key )
251     {
252         removeCount++;
253         try
254         {
255             eventQueue.addRemoveEvent( key );
256         }
257         catch ( IOException ex )
258         {
259             log.error( ex );
260             eventQueue.destroy();
261         }
262         return false;
263     }
264 
265     /** Adds a removeAll request to the lateral cache. */
266     public void removeAll()
267     {
268         try
269         {
270             eventQueue.addRemoveAllEvent();
271         }
272         catch ( IOException ex )
273         {
274             log.error( ex );
275             eventQueue.destroy();
276         }
277     }
278 
279     /** Adds a dispose request to the lateral cache. */
280     public void dispose()
281     {
282         try
283         {
284             eventQueue.addDisposeEvent();
285         }
286         catch ( IOException ex )
287         {
288             log.error( ex );
289             eventQueue.destroy();
290         }
291     }
292 
293     /**
294      * No lateral invocation.
295      * <p>
296      * @return The size value
297      */
298     public int getSize()
299     {
300         return cache.getSize();
301     }
302 
303     /**
304      * No lateral invocation.
305      * <p>
306      * @return The cacheType value
307      */
308     public int getCacheType()
309     {
310         return cache.getCacheType();
311     }
312 
313     /**
314      * Returns the asyn cache status. An error status indicates either the lateral connection is not
315      * available, or the asyn queue has been unexpectedly destroyed. No lateral invokation.
316      * <p>
317      * @return The status value
318      */
319     public int getStatus()
320     {
321         return eventQueue.isWorking() ? cache.getStatus() : CacheConstants.STATUS_ERROR;
322     }
323 
324     /**
325      * Gets the cacheName attribute of the LateralCacheNoWait object
326      * <p>
327      * @return The cacheName value
328      */
329     public String getCacheName()
330     {
331         return cache.getCacheName();
332     }
333 
334     /**
335      * Replaces the lateral cache service handle with the given handle and reset the queue by
336      * starting up a new instance.
337      * <p>
338      * @param lateral
339      */
340     public void fixCache( ILateralCacheService lateral )
341     {
342         cache.fixCache( lateral );
343         resetEventQ();
344     }
345 
346     /**
347      * Resets the event q by first destroying the existing one and starting up new one.
348      */
349     public void resetEventQ()
350     {
351         if ( eventQueue.isWorking() )
352         {
353             eventQueue.destroy();
354         }
355         CacheEventQueueFactory fact = new CacheEventQueueFactory();
356         this.eventQueue = fact.createCacheEventQueue( new CacheAdaptor( cache ), LateralCacheInfo.listenerId, cache
357             .getCacheName(), cache.getAuxiliaryCacheAttributes().getEventQueuePoolName(), cache
358             .getAuxiliaryCacheAttributes().getEventQueueType() );
359     }
360 
361     /**
362      * @return Returns the AuxiliaryCacheAttributes.
363      */
364     public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
365     {
366         return cache.getAuxiliaryCacheAttributes();
367     }
368 
369     /**
370      * getStats
371      * @return String
372      */
373     public String getStats()
374     {
375         return getStatistics().toString();
376     }
377 
378     /**
379      * this won't be called since we don't do ICache logging here.
380      * <p>
381      * @return String
382      */
383     @Override
384     public String getEventLoggingExtraInfo()
385     {
386         return "Lateral Cache No Wait";
387     }
388 
389     /**
390      * @return statistics about this communication
391      */
392     public IStats getStatistics()
393     {
394         IStats stats = new Stats();
395         stats.setTypeName( "Lateral Cache No Wait" );
396 
397         ArrayList<IStatElement> elems = new ArrayList<IStatElement>();
398 
399         // IStatElement se = null;
400         // no data gathered here
401 
402         // get the stats from the event queue too
403         // get as array, convert to list, add list to our outer list
404         IStats eqStats = this.eventQueue.getStatistics();
405 
406         IStatElement[] eqSEs = eqStats.getStatElements();
407         List<IStatElement> eqL = Arrays.asList( eqSEs );
408         elems.addAll( eqL );
409 
410         IStatElement se = null;
411 
412         se = new StatElement();
413         se.setName( "Get Count" );
414         se.setData( "" + this.getCount );
415         elems.add( se );
416 
417         se = new StatElement();
418         se.setName( "Remove Count" );
419         se.setData( "" + this.removeCount );
420         elems.add( se );
421 
422         se = new StatElement();
423         se.setName( "Put Count" );
424         se.setData( "" + this.putCount );
425         elems.add( se );
426 
427         se = new StatElement();
428         se.setName( "Attributes" );
429         se.setData( "" + cache.getAuxiliaryCacheAttributes() );
430         elems.add( se );
431 
432         // get an array and put them in the Stats object
433         IStatElement[] ses = elems.toArray( new StatElement[elems.size()] );
434         stats.setStatElements( ses );
435 
436         return stats;
437     }
438 
439     /**
440      * @return debugging info.
441      */
442     @Override
443     public String toString()
444     {
445         StringBuffer buf = new StringBuffer();
446         buf.append( " LateralCacheNoWait " );
447         buf.append( " Status = " + this.getStatus() );
448         buf.append( " cache = [" + cache.toString() + "]" );
449         return buf.toString();
450     }
451 }