View Javadoc

1   package org.apache.jcs.auxiliary.remote;
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.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.jcs.auxiliary.AuxiliaryCache;
33  import org.apache.jcs.auxiliary.AuxiliaryCacheAttributes;
34  import org.apache.jcs.engine.CacheConstants;
35  import org.apache.jcs.engine.behavior.ICacheElement;
36  import org.apache.jcs.engine.behavior.ICacheType;
37  import org.apache.jcs.engine.behavior.ICompositeCacheManager;
38  import org.apache.jcs.engine.stats.StatElement;
39  import org.apache.jcs.engine.stats.Stats;
40  import org.apache.jcs.engine.stats.behavior.IStatElement;
41  import org.apache.jcs.engine.stats.behavior.IStats;
42  
43  /***
44   * Used to provide access to multiple services under nowait protection. Factory should construct
45   * NoWaitFacade to give to the composite cache out of caches it constructs from the varies manager
46   * to lateral services.
47   * <p>
48   * Typically, we only connect to one remote server per facade.  We use a list of one RemoteCacheNoWait.
49   */
50  public class RemoteCacheNoWaitFacade
51      implements AuxiliaryCache
52  {
53      private static final long serialVersionUID = -4529970797620747110L;
54  
55      private final static Log log = LogFactory.getLog( RemoteCacheNoWaitFacade.class );
56  
57      /*** The connection to a remote server, or a zombie. */
58      public RemoteCacheNoWait[] noWaits;
59  
60      private String cacheName;
61  
62      /*** holds failover and cluster information */
63      protected RemoteCacheAttributes remoteCacheAttributes;
64  
65      private ICompositeCacheManager cacheMgr;
66  
67      /***
68       * Gets the remoteCacheAttributes attribute of the RemoteCacheNoWaitFacade object
69       * <p>
70       * @return The remoteCacheAttributes value
71       */
72      public RemoteCacheAttributes getRemoteCacheAttributes()
73      {
74          return remoteCacheAttributes;
75      }
76  
77      /***
78       * Sets the remoteCacheAttributes attribute of the RemoteCacheNoWaitFacade object.
79       * <p>
80       * @param rca The new remoteCacheAttributes value
81       */
82      public void setRemoteCacheAttributes( RemoteCacheAttributes rca )
83      {
84          this.remoteCacheAttributes = rca;
85      }
86  
87      /***
88       * Constructs with the given remote cache, and fires events to any listeners.
89       * <p>
90       * @param noWaits
91       * @param rca
92       * @param cacheMgr
93       */
94      public RemoteCacheNoWaitFacade( RemoteCacheNoWait[] noWaits, RemoteCacheAttributes rca,
95                                     ICompositeCacheManager cacheMgr )
96      {
97          if ( log.isDebugEnabled() )
98          {
99              log.debug( "CONSTRUCTING NO WAIT FACADE" );
100         }
101         this.noWaits = noWaits;
102         this.remoteCacheAttributes = rca;
103         this.cacheName = rca.getCacheName();
104         this.cacheMgr = cacheMgr;
105     }
106 
107     /***
108      * Put an element in the cache.
109      * <p>
110      * @param ce
111      * @throws IOException
112      */
113     public void update( ICacheElement ce )
114         throws IOException
115     {
116         if ( log.isDebugEnabled() )
117         {
118             log.debug( "updating through cache facade, noWaits.length = " + noWaits.length );
119         }
120         int i = 0;
121         try
122         {
123             for ( ; i < noWaits.length; i++ )
124             {
125                 noWaits[i].update( ce );
126                 // an initial move into a zombie will lock this to primary
127                 // recovery. will not discover other servers until primary
128                 // reconnect
129                 // and subsequent error
130             }
131         }
132         catch ( Exception ex )
133         {
134             log.error( ex );
135             // can handle failover here? Is it safe to try the others?
136             // check to see it the noWait is now a zombie
137             // if it is a zombie, then move to the next in the failover list
138             // will need to keep them in order or a count
139             failover( i );
140             // should start a failover thread
141             // should probably only failover if there is only one in the noWait
142             // list
143             // should start a background thread to set the original as the
144             // primary
145             // if we are in failover state
146         }
147     }
148 
149     /***
150      * Synchronously reads from the remote cache.
151      * <p>
152      * @param key
153      * @return Either an ICacheElement or null if it is not found.
154      */
155     public ICacheElement get( Serializable key )
156     {
157         for ( int i = 0; i < noWaits.length; i++ )
158         {
159             try
160             {
161                 Object obj = noWaits[i].get( key );
162                 if ( obj != null )
163                 {
164                     return (ICacheElement) obj;
165                 }
166             }
167             catch ( Exception ex )
168             {
169                 log.debug( "Failed to get." );
170             }
171             return null;
172         }
173         return null;
174     }
175 
176     /***
177      * Gets the set of keys of objects currently in the group.
178      * <p>
179      * @param group
180      * @return
181      * @throws IOException
182      */
183     public Set getGroupKeys( String group )
184         throws IOException
185     {
186         HashSet allKeys = new HashSet();
187         for ( int i = 0; i < noWaits.length; i++ )
188         {
189             AuxiliaryCache aux = noWaits[i];
190             if ( aux != null )
191             {
192                 allKeys.addAll( aux.getGroupKeys( group ) );
193             }
194         }
195         return allKeys;
196     }
197 
198     /***
199      * Adds a remove request to the remote cache.
200      * <p>
201      * @param key
202      * @return wether or not it was removed, right now it return false.
203      */
204     public boolean remove( Serializable key )
205     {
206         try
207         {
208             for ( int i = 0; i < noWaits.length; i++ )
209             {
210                 noWaits[i].remove( key );
211             }
212         }
213         catch ( Exception ex )
214         {
215             log.error( ex );
216         }
217         return false;
218     }
219 
220     /***
221      * Adds a removeAll request to the lateral cache.
222      */
223     public void removeAll()
224     {
225         try
226         {
227             for ( int i = 0; i < noWaits.length; i++ )
228             {
229                 noWaits[i].removeAll();
230             }
231         }
232         catch ( Exception ex )
233         {
234             log.error( ex );
235         }
236     }
237 
238     /*** Adds a dispose request to the lateral cache. */
239     public void dispose()
240     {
241         try
242         {
243             for ( int i = 0; i < noWaits.length; i++ )
244             {
245                 noWaits[i].dispose();
246             }
247         }
248         catch ( Exception ex )
249         {
250             log.error( "Problem in dispose.", ex );
251         }
252     }
253 
254     /***
255      * No lateral invocation.
256      * @return The size value
257      */
258     public int getSize()
259     {
260         return 0;
261         // cache.getSize();
262     }
263 
264     /***
265      * Gets the cacheType attribute of the RemoteCacheNoWaitFacade object.
266      * <p>
267      * @return The cacheType value
268      */
269     public int getCacheType()
270     {
271         return ICacheType.REMOTE_CACHE;
272     }
273 
274     /***
275      * Gets the cacheName attribute of the RemoteCacheNoWaitFacade object.
276      * <p>
277      * @return The cacheName value
278      */
279     public String getCacheName()
280     {
281         return remoteCacheAttributes.getCacheName();
282     }
283 
284     /***
285      * Gets the status attribute of the RemoteCacheNoWaitFacade object
286      * <p>
287      * Return ALIVE if any are alive.
288      * <p>
289      * @return The status value
290      */
291     public int getStatus()
292     {
293         for ( int i = 0; i < noWaits.length; i++ )
294         {
295             if ( noWaits[i].getStatus() == CacheConstants.STATUS_ALIVE )
296             {
297                 return CacheConstants.STATUS_ALIVE;
298             }
299         }
300         return 0;
301     }
302 
303     /***
304      * String form of some of the configuratin information for the remote cache.
305      * <p>
306      * @return Some info for logging.
307      */
308     public String toString()
309     {
310         return "RemoteCacheNoWaitFacade: " + cacheName + ", rca = " + remoteCacheAttributes;
311     }
312 
313     /***
314      * Begin the failover process if this is a local cache. Clustered remote caches do not failover.
315      * <p>
316      * @param i The no wait in error.
317      */
318     protected void failover( int i )
319     {
320         if ( log.isDebugEnabled() )
321         {
322             log.info( "in failover for " + i );
323         }
324 
325         if ( remoteCacheAttributes.getRemoteType() == RemoteCacheAttributes.LOCAL )
326         {
327             if ( noWaits[i].getStatus() == CacheConstants.STATUS_ERROR )
328             {
329                 // start failover, primary recovery process
330                 RemoteCacheFailoverRunner runner = new RemoteCacheFailoverRunner( this, cacheMgr );
331                 // If the returned monitor is null, it means it's already
332                 // started elsewhere.
333                 if ( runner != null )
334                 {
335                     runner.notifyError();
336                     Thread t = new Thread( runner );
337                     t.setDaemon( true );
338                     t.start();
339                 }
340             }
341             else
342             {
343                 if ( log.isInfoEnabled() )
344                 {
345                     log.info( "The noWait is not in error" );
346                 }
347             }
348         }
349     }
350 
351     /***
352      * @return Returns the AuxiliaryCacheAttributes.
353      */
354     public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
355     {
356         return this.remoteCacheAttributes;
357     }
358 
359     /***
360      * getStats
361      * @return String
362      */
363     public String getStats()
364     {
365         return getStatistics().toString();
366     }
367 
368     /*
369      * (non-Javadoc)
370      * @see org.apache.jcs.auxiliary.AuxiliaryCache#getStatistics()
371      */
372     public IStats getStatistics()
373     {
374         IStats stats = new Stats();
375         stats.setTypeName( "Remote Cache No Wait Facade" );
376 
377         ArrayList elems = new ArrayList();
378 
379         IStatElement se = null;
380 
381         if ( noWaits != null )
382         {
383             se = new StatElement();
384             se.setName( "Number of No Waits" );
385             se.setData( "" + noWaits.length );
386             elems.add( se );
387 
388             for ( int i = 0; i < noWaits.length; i++ )
389             {
390                 // get the stats from the super too
391                 // get as array, convert to list, add list to our outer list
392                 IStats sStats = noWaits[i].getStatistics();
393                 IStatElement[] sSEs = sStats.getStatElements();
394                 List sL = Arrays.asList( sSEs );
395                 elems.addAll( sL );
396             }
397         }
398 
399         // get an array and put them in the Stats object
400         IStatElement[] ses = (IStatElement[]) elems.toArray( new StatElement[0] );
401         stats.setStatElements( ses );
402 
403         return stats;
404     }
405 }