View Javadoc
1   package org.apache.commons.jcs3.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.util.Collections;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheEventLogging;
28  import org.apache.commons.jcs3.auxiliary.lateral.behavior.ILateralCacheAttributes;
29  import org.apache.commons.jcs3.engine.CacheInfo;
30  import org.apache.commons.jcs3.engine.CacheStatus;
31  import org.apache.commons.jcs3.engine.ZombieCacheServiceNonLocal;
32  import org.apache.commons.jcs3.engine.behavior.ICacheElement;
33  import org.apache.commons.jcs3.engine.behavior.ICacheServiceNonLocal;
34  import org.apache.commons.jcs3.engine.behavior.IZombie;
35  import org.apache.commons.jcs3.engine.stats.Stats;
36  import org.apache.commons.jcs3.engine.stats.behavior.IStats;
37  import org.apache.commons.jcs3.log.Log;
38  import org.apache.commons.jcs3.log.LogManager;
39  
40  /**
41   * Lateral distributor. Returns null on get by default. Net search not implemented.
42   */
43  public class LateralCache<K, V>
44      extends AbstractAuxiliaryCacheEventLogging<K, V>
45  {
46      /** The logger. */
47      private static final Log log = LogManager.getLog( LateralCache.class );
48  
49      /** generalize this, use another interface */
50      private final ILateralCacheAttributes lateralCacheAttributes;
51  
52      /** The region name */
53      final String cacheName;
54  
55      /** either http, socket.udp, or socket.tcp can set in config */
56      private ICacheServiceNonLocal<K, V> lateralCacheService;
57  
58      /** Monitors the connection. */
59      private LateralCacheMonitor monitor;
60  
61      /**
62       * Constructor for the LateralCache object
63       * <p>
64       * @param cattr
65       * @param lateral
66       * @param monitor
67       */
68      public LateralCache( final ILateralCacheAttributes cattr, final ICacheServiceNonLocal<K, V> lateral, final LateralCacheMonitor monitor )
69      {
70          this.cacheName = cattr.getCacheName();
71          this.lateralCacheAttributes = cattr;
72          this.lateralCacheService = lateral;
73          this.monitor = monitor;
74      }
75  
76      /**
77       * Constructor for the LateralCache object
78       * <p>
79       * @param cattr
80       *
81       * @deprecated Causes NPE
82       */
83      @Deprecated
84      public LateralCache( final ILateralCacheAttributes cattr )
85      {
86          this(cattr, null, null);
87      }
88  
89      /**
90       * Update lateral.
91       * <p>
92       * @param ce
93       * @throws IOException
94       */
95      @Override
96      protected void processUpdate( final ICacheElement<K, V> ce )
97          throws IOException
98      {
99          try
100         {
101             if (ce != null)
102             {
103                 log.debug( "update: lateral = [{0}], CacheInfo.listenerId = {1}",
104                         lateralCacheService, CacheInfo.listenerId );
105                 lateralCacheService.update( ce, CacheInfo.listenerId );
106             }
107         }
108         catch ( final IOException ex )
109         {
110             handleException( ex, "Failed to put [" + ce.getKey() + "] to " + ce.getCacheName() + "@" + lateralCacheAttributes );
111         }
112     }
113 
114     /**
115      * The performance costs are too great. It is not recommended that you enable lateral gets.
116      * <p>
117      * @param key
118      * @return ICacheElement&lt;K, V&gt; or null
119      * @throws IOException
120      */
121     @Override
122     protected ICacheElement<K, V> processGet( final K key )
123         throws IOException
124     {
125         ICacheElement<K, V> obj = null;
126 
127         if ( !this.lateralCacheAttributes.getPutOnlyMode() )
128         {
129             try
130             {
131                 obj = lateralCacheService.get( cacheName, key );
132             }
133             catch ( final Exception e )
134             {
135                 log.error( e );
136                 handleException( e, "Failed to get [" + key + "] from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
137             }
138         }
139 
140         return obj;
141     }
142 
143     /**
144      * @param pattern
145      * @return A map of K key to ICacheElement&lt;K, V&gt; element, or an empty map if there is no
146      *         data in cache for any of these keys
147      * @throws IOException
148      */
149     @Override
150     protected Map<K, ICacheElement<K, V>> processGetMatching( final String pattern )
151         throws IOException
152     {
153         Map<K, ICacheElement<K, V>> map = Collections.emptyMap();
154 
155         if ( !this.lateralCacheAttributes.getPutOnlyMode() )
156         {
157             try
158             {
159                 return lateralCacheService.getMatching( cacheName, pattern );
160             }
161             catch ( final IOException e )
162             {
163                 log.error( e );
164                 handleException( e, "Failed to getMatching [" + pattern + "] from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
165             }
166         }
167 
168         return map;
169     }
170 
171     /**
172      * Return the keys in this cache.
173      * <p>
174      * @see org.apache.commons.jcs3.auxiliary.AuxiliaryCache#getKeySet()
175      */
176     @Override
177     public Set<K> getKeySet() throws IOException
178     {
179         try
180         {
181             return lateralCacheService.getKeySet( cacheName );
182         }
183         catch ( final IOException ex )
184         {
185             handleException( ex, "Failed to get key set from " + lateralCacheAttributes.getCacheName() + "@"
186                 + lateralCacheAttributes );
187         }
188         return Collections.emptySet();
189     }
190 
191     /**
192      * Synchronously remove from the remote cache; if failed, replace the remote handle with a
193      * zombie.
194      * <p>
195      * @param key
196      * @return false always
197      * @throws IOException
198      */
199     @Override
200     protected boolean processRemove( final K key )
201         throws IOException
202     {
203         log.debug( "removing key: {0}", key );
204 
205         try
206         {
207             lateralCacheService.remove( cacheName, key, CacheInfo.listenerId );
208         }
209         catch ( final IOException ex )
210         {
211             handleException( ex, "Failed to remove " + key + " from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
212         }
213         return false;
214     }
215 
216     /**
217      * Synchronously removeAll from the remote cache; if failed, replace the remote handle with a
218      * zombie.
219      * <p>
220      * @throws IOException
221      */
222     @Override
223     protected void processRemoveAll()
224         throws IOException
225     {
226         try
227         {
228             lateralCacheService.removeAll( cacheName, CacheInfo.listenerId );
229         }
230         catch ( final IOException ex )
231         {
232             handleException( ex, "Failed to remove all from " + lateralCacheAttributes.getCacheName() + "@" + lateralCacheAttributes );
233         }
234     }
235 
236     /**
237      * Synchronously dispose the cache. Not sure we want this.
238      * <p>
239      * @throws IOException
240      */
241     @Override
242     protected void processDispose()
243         throws IOException
244     {
245         log.debug( "Disposing of lateral cache" );
246 
247         try
248         {
249             lateralCacheService.dispose( this.lateralCacheAttributes.getCacheName() );
250             // Should remove connection
251         }
252         catch ( final IOException ex )
253         {
254             log.error( "Couldn't dispose", ex );
255             handleException( ex, "Failed to dispose " + lateralCacheAttributes.getCacheName() );
256         }
257     }
258 
259     /**
260      * Returns the cache status.
261      * <p>
262      * @return The status value
263      */
264     @Override
265     public CacheStatus getStatus()
266     {
267         return this.lateralCacheService instanceof IZombie ? CacheStatus.ERROR : CacheStatus.ALIVE;
268     }
269 
270     /**
271      * Returns the current cache size.
272      * <p>
273      * @return The size value
274      */
275     @Override
276     public int getSize()
277     {
278         return 0;
279     }
280 
281     /**
282      * Gets the cacheType attribute of the LateralCache object
283      * <p>
284      * @return The cacheType value
285      */
286     @Override
287     public CacheType getCacheType()
288     {
289         return CacheType.LATERAL_CACHE;
290     }
291 
292     /**
293      * Gets the cacheName attribute of the LateralCache object
294      * <p>
295      * @return The cacheName value
296      */
297     @Override
298     public String getCacheName()
299     {
300         return cacheName;
301     }
302 
303     /**
304      * Not yet sure what to do here.
305      * <p>
306      * @param ex
307      * @param msg
308      * @throws IOException
309      */
310     private void handleException( final Exception ex, final String msg )
311         throws IOException
312     {
313         log.error( "Disabling lateral cache due to error {0}", msg, ex );
314 
315         lateralCacheService = new ZombieCacheServiceNonLocal<>( lateralCacheAttributes.getZombieQueueMaxSize() );
316         // may want to flush if region specifies
317         // Notify the cache monitor about the error, and kick off the recovery
318         // process.
319         monitor.notifyError();
320 
321         // could stop the net search if it is built and try to reconnect?
322         if ( ex instanceof IOException )
323         {
324             throw (IOException) ex;
325         }
326         throw new IOException( ex.getMessage() );
327     }
328 
329     /**
330      * Replaces the current remote cache service handle with the given handle.
331      * <p>
332      * @param restoredLateral
333      */
334     public void fixCache( final ICacheServiceNonLocal<K, V> restoredLateral )
335     {
336         if ( this.lateralCacheService instanceof ZombieCacheServiceNonLocal )
337         {
338             final ZombieCacheServiceNonLocal<K, V> zombie = (ZombieCacheServiceNonLocal<K, V>) this.lateralCacheService;
339             this.lateralCacheService = restoredLateral;
340             try
341             {
342                 zombie.propagateEvents( restoredLateral );
343             }
344             catch ( final Exception e )
345             {
346                 try
347                 {
348                     handleException( e, "Problem propagating events from Zombie Queue to new Lateral Service." );
349                 }
350                 catch ( final IOException e1 )
351                 {
352                     // swallow, since this is just expected kick back.  Handle always throws
353                 }
354             }
355         }
356         else
357         {
358             this.lateralCacheService = restoredLateral;
359         }
360     }
361 
362     /**
363      * getStats
364      * <p>
365      * @return String
366      */
367     @Override
368     public String getStats()
369     {
370         return "";
371     }
372 
373     /**
374      * @return Returns the AuxiliaryCacheAttributes.
375      */
376     @Override
377     public ILateralCacheAttributes getAuxiliaryCacheAttributes()
378     {
379         return lateralCacheAttributes;
380     }
381 
382     /**
383      * @return debugging data.
384      */
385     @Override
386     public String toString()
387     {
388         final StringBuilder buf = new StringBuilder();
389         buf.append( "\n LateralCache " );
390         buf.append( "\n Cache Name [" + lateralCacheAttributes.getCacheName() + "]" );
391         buf.append( "\n cattr =  [" + lateralCacheAttributes + "]" );
392         return buf.toString();
393     }
394 
395     /**
396      * @return extra data.
397      */
398     @Override
399     public String getEventLoggingExtraInfo()
400     {
401         return null;
402     }
403 
404     /**
405      * The NoWait on top does not call out to here yet.
406      * <p>
407      * @return almost nothing
408      */
409     @Override
410     public IStats getStatistics()
411     {
412         final IStats stats = new Stats();
413         stats.setTypeName( "LateralCache" );
414         return stats;
415     }
416 }