View Javadoc

1   package org.apache.jcs.auxiliary.lateral.socket.tcp;
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.HashMap;
24  import java.util.Map;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.jcs.auxiliary.AuxiliaryCache;
29  import org.apache.jcs.auxiliary.lateral.LateralCache;
30  import org.apache.jcs.auxiliary.lateral.LateralCacheAbstractManager;
31  import org.apache.jcs.auxiliary.lateral.LateralCacheAttributes;
32  import org.apache.jcs.auxiliary.lateral.LateralCacheMonitor;
33  import org.apache.jcs.auxiliary.lateral.LateralCacheNoWait;
34  import org.apache.jcs.auxiliary.lateral.LateralCacheWatchRepairable;
35  import org.apache.jcs.auxiliary.lateral.ZombieLateralCacheService;
36  import org.apache.jcs.auxiliary.lateral.ZombieLateralCacheWatch;
37  import org.apache.jcs.auxiliary.lateral.behavior.ILateralCacheListener;
38  import org.apache.jcs.auxiliary.lateral.behavior.ILateralCacheManager;
39  import org.apache.jcs.auxiliary.lateral.behavior.ILateralCacheService;
40  import org.apache.jcs.auxiliary.lateral.socket.tcp.behavior.ITCPLateralCacheAttributes;
41  import org.apache.jcs.engine.behavior.ICompositeCacheManager;
42  
43  /***
44   * Creates lateral caches. Lateral caches are primarily used for removing non
45   * laterally configured caches. Non laterally configured cache regions should
46   * still be able to participate in removal. But if there is a non laterally
47   * configured cache hub, then lateral removals may be necessary. For flat
48   * webserver production environments, without a strong machine at the app server
49   * level, distribution and search may need to occur at the lateral cache level.
50   * This is currently not implemented in the lateral cache.
51   * <p>
52   *
53   * @TODO: - need freeCache, release, getStats - need to find an interface
54   *        acceptable for all - cache managers or a manager within a type
55   */
56  public class LateralTCPCacheManager
57      extends LateralCacheAbstractManager
58  {
59      private static final long serialVersionUID = -9213011856644392480L;
60  
61      private final static Log log = LogFactory.getLog( LateralTCPCacheManager.class );
62  
63      private static LateralCacheMonitor monitor;
64  
65      /*** Address to instance map.  */
66      protected static Map instances = new HashMap();
67  
68      /*** ITCPLateralCacheAttributes  */
69      protected ITCPLateralCacheAttributes lca;
70  
71      private int clients;
72  
73      /***
74       * Handle to the lateral cache service; or a zombie handle if failed to
75       * connect.
76       */
77      private ILateralCacheService lateralService;
78  
79      /***
80       * Wrapper of the lateral cache watch service; or wrapper of a zombie
81       * service if failed to connect.
82       */
83      private LateralCacheWatchRepairable lateralWatch;
84  
85      /*** This is set in the constructor.  */
86      private ICompositeCacheManager cacheMgr;
87  
88      /***
89       * Returns an instance of the LateralCacheManager.
90       * <p>
91       * @param lca
92       * @param cacheMgr
93       *            this allows the auxiliary to be passed a cache manager.
94       * @return
95       */
96      public static LateralTCPCacheManager getInstance( ITCPLateralCacheAttributes lca, ICompositeCacheManager cacheMgr )
97      {
98          LateralTCPCacheManager ins = (LateralTCPCacheManager) instances.get( lca.toString() );
99          synchronized ( instances )
100         {
101             if ( ins == null )
102             {
103                 log.info( "Instance for [" + lca.toString() + "] is null, creating" );
104 
105                 ins = (LateralTCPCacheManager) instances.get( lca.toString() );
106                 if ( ins == null )
107                 {
108                     ins = new LateralTCPCacheManager( lca, cacheMgr );
109                     instances.put( lca.toString(), ins );
110                 }
111             }
112             createMonitor( ins );
113         }
114         ins.clients++;
115 
116         return ins;
117     }
118 
119     /***
120      * The monitor needs reference to one instance, actually just a type.
121      * <p>
122      * TODO refactor this.
123      * <p>
124      * @param instance
125      */
126     private static synchronized void createMonitor( ILateralCacheManager instance )
127     {
128         // only want one monitor per lateral type
129         // Fires up the monitoring daemon.
130         if ( monitor == null )
131         {
132             monitor = new LateralCacheMonitor( instance );
133             // Should never be null
134             if ( monitor != null )
135             {
136                 Thread t = new Thread( monitor );
137                 t.setDaemon( true );
138                 t.start();
139             }
140         }
141     }
142 
143     /***
144      * Constructor for the LateralCacheManager object.
145      * <p>
146      * @param lcaA
147      * @param cacheMgr
148      */
149     private LateralTCPCacheManager( ITCPLateralCacheAttributes lcaA, ICompositeCacheManager cacheMgr )
150     {
151         this.lca = lcaA;
152 
153         this.cacheMgr = cacheMgr;
154 
155         if ( log.isDebugEnabled() )
156         {
157             log.debug( "Creating lateral cache service, lca = " + this.lca );
158         }
159 
160         // Create the service
161         try
162         {
163             if ( log.isInfoEnabled() )
164             {
165                 log.info( "Creating TCP service, lca = " + this.lca );
166             }
167             this.lateralService = new LateralTCPService( this.lca );
168 
169             if ( this.lateralService == null )
170             {
171                 log.error( "No service created, must zombie" );
172                 throw new Exception( "No service created for lateral cache." );
173             }
174 
175             this.lateralWatch = new LateralCacheWatchRepairable();
176             this.lateralWatch.setCacheWatch( new ZombieLateralCacheWatch() );
177         }
178         catch ( Exception ex )
179         {
180             // Failed to connect to the lateral server.
181             // Configure this LateralCacheManager instance to use the
182             // "zombie" services.
183             log.error( "Failure, lateral instance will use zombie service", ex );
184 
185             this.lateralService = new ZombieLateralCacheService();
186             this.lateralWatch = new LateralCacheWatchRepairable();
187             this.lateralWatch.setCacheWatch( new ZombieLateralCacheWatch() );
188 
189             // Notify the cache monitor about the error, and kick off
190             // the recovery process.
191             createMonitor( this );
192             monitor.notifyError();
193         }
194     }
195 
196     /***
197      * Adds the lateral cache listener to the underlying cache-watch service.
198      * <p>
199      * @param cacheName
200      *            The feature to be added to the LateralCacheListener attribute
201      * @param listener
202      *            The feature to be added to the LateralCacheListener attribute
203      * @exception IOException
204      */
205     public void addLateralCacheListener( String cacheName, ILateralCacheListener listener )
206         throws IOException
207     {
208         synchronized ( this.caches )
209         {
210             this.lateralWatch.addCacheListener( cacheName, listener );
211         }
212     }
213 
214     /***
215      * Called to access a precreated region or construct one with defaults.
216      * Since all aux cache access goes through the manager, this will never be
217      * called.
218      * <p>
219      * After getting the manager instance for a server, the factory gets a cache
220      * for the region name it is constructing.
221      * <p>
222      * There should be one manager per server and one cache per region per
223      * manager.
224      * <p>
225      * @return AuxiliaryCache
226      * @param cacheName
227      */
228     public AuxiliaryCache getCache( String cacheName )
229     {
230         LateralCacheNoWait lateralNoWait = null;
231         synchronized ( this.caches )
232         {
233             lateralNoWait = (LateralCacheNoWait) this.caches.get( cacheName );
234             if ( lateralNoWait == null )
235             {
236                 LateralCacheAttributes attr = (LateralCacheAttributes) lca.copy();
237                 attr.setCacheName( cacheName );
238 
239                 LateralCache cache = new LateralCache( attr, this.lateralService, monitor );
240                 if ( log.isDebugEnabled() )
241                 {
242                     log.debug( "Created cache for noWait, cache [" + cache + "]" );
243                 }
244                 lateralNoWait = new LateralCacheNoWait( cache );
245                 this.caches.put( cacheName, lateralNoWait );
246 
247                 if ( log.isInfoEnabled() )
248                 {
249                     log.info( "Created LateralCacheNoWait for [" + this.lca + "] LateralCacheNoWait = ["
250                         + lateralNoWait + "]" );
251                 }
252             }
253         }
254 
255         // don't create a listener if we are not receiving.
256         if ( lca.isReceive() )
257         {
258             try
259             {
260                 addLateralCacheListener( cacheName, LateralTCPListener.getInstance( this.lca, cacheMgr ) );
261             }
262             catch ( IOException ioe )
263             {
264                 log.error( "Problem creating lateral listener", ioe );
265             }
266             catch ( Exception e )
267             {
268                 log.error( "Problem creating lateral listener", e );
269             }
270         }
271         else
272         {
273             if ( log.isDebugEnabled() )
274             {
275                 log.debug( "Not creating a listener since we are not receiving." );
276             }
277         }
278         // TODO: need listener repair
279 
280         return lateralNoWait;
281     }
282 
283     /*
284      * (non-Javadoc)
285      *
286      * @see org.apache.jcs.auxiliary.lateral.LateralCacheAbstractManager#getInstances()
287      */
288     public Map getInstances()
289     {
290         return instances;
291     }
292 
293     /*
294      * (non-Javadoc)
295      *
296      * @see org.apache.jcs.auxiliary.lateral.behavior.ILateralCacheManager#fixService()
297      */
298     public Object fixService()
299         throws IOException
300     {
301         Object service = null;
302         try
303         {
304             service = new LateralTCPService( lca );
305         }
306         catch ( Exception ex )
307         {
308             log.error( "Can't fix " + ex.getMessage() );
309             throw new IOException( "Can't fix " + ex.getMessage() );
310         }
311         return service;
312     }
313 }