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