View Javadoc
1   package org.apache.commons.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.rmi.registry.Registry;
23  import java.util.ArrayList;
24  import java.util.StringTokenizer;
25  import java.util.concurrent.ConcurrentHashMap;
26  import java.util.concurrent.ConcurrentMap;
27  import java.util.concurrent.locks.Lock;
28  import java.util.concurrent.locks.ReentrantLock;
29  
30  import org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory;
31  import org.apache.commons.jcs.auxiliary.AuxiliaryCache;
32  import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
33  import org.apache.commons.jcs.auxiliary.remote.behavior.IRemoteCacheAttributes;
34  import org.apache.commons.jcs.auxiliary.remote.server.behavior.RemoteType;
35  import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
36  import org.apache.commons.jcs.engine.behavior.IElementSerializer;
37  import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
38  
39  /**
40   * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which
41   * is a wrapper around a no wait. The no wait object is either an active connection to a remote
42   * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the
43   * clients.
44   */
45  public class RemoteCacheFactory
46      extends AbstractAuxiliaryCacheFactory
47  {
48      /** Monitor thread */
49      private RemoteCacheMonitor monitor;
50  
51      /** Contains mappings of RemoteLocation instance to RemoteCacheManager instance. */
52      private ConcurrentMap<RemoteLocation, RemoteCacheManager> managers;
53  
54      /** Lock for initialization of manager instances */
55      private Lock managerLock;
56  
57      /**
58       * For LOCAL clients we get a handle to all the failovers, but we do not register a listener
59       * with them. We create the RemoteCacheManager, but we do not get a cache.
60       * <p>
61       * The failover runner will get a cache from the manager. When the primary is restored it will
62       * tell the manager for the failover to deregister the listener.
63       * <p>
64       * @param iaca
65       * @param cacheMgr
66       * @param cacheEventLogger
67       * @param elementSerializer
68       * @return AuxiliaryCache
69       */
70      @Override
71      public <K, V> AuxiliaryCache<K, V> createCache(
72              AuxiliaryCacheAttributes iaca, ICompositeCacheManager cacheMgr,
73             ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
74      {
75          RemoteCacheAttributes rca = (RemoteCacheAttributes) iaca;
76  
77          ArrayList<RemoteCacheNoWait<K,V>> noWaits = new ArrayList<RemoteCacheNoWait<K,V>>();
78  
79          switch (rca.getRemoteType())
80          {
81              case LOCAL:
82                  // a list to be turned into an array of failover server information
83                  ArrayList<RemoteLocation> failovers = new ArrayList<RemoteLocation>();
84  
85                  // not necessary if a failover list is defined
86                  // REGISTER PRIMARY LISTENER
87                  // if it is a primary
88                  boolean primaryDefined = false;
89                  if ( rca.getRemoteLocation() != null )
90                  {
91                      primaryDefined = true;
92  
93                      failovers.add( rca.getRemoteLocation() );
94                      RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
95                      RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
96                      noWaits.add( ic );
97                  }
98  
99                  // GET HANDLE BUT DONT REGISTER A LISTENER FOR FAILOVERS
100                 String failoverList = rca.getFailoverServers();
101                 if ( failoverList != null )
102                 {
103                     StringTokenizer fit = new StringTokenizer( failoverList, "," );
104                     int fCnt = 0;
105                     while ( fit.hasMoreTokens() )
106                     {
107                         fCnt++;
108 
109                         String server = fit.nextToken();
110                         RemoteLocation location = RemoteLocation.parseServerAndPort(server);
111 
112                         if (location != null)
113                         {
114                             failovers.add( location );
115                             rca.setRemoteLocation(location);
116                             RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
117 
118                             // add a listener if there are none, need to tell rca what
119                             // number it is at
120                             if ( ( !primaryDefined && fCnt == 1 ) || noWaits.size() <= 0 )
121                             {
122                                 RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
123                                 noWaits.add( ic );
124                             }
125                         }
126                     }
127                     // end while
128                 }
129                 // end if failoverList != null
130 
131                 rca.setFailovers( failovers );
132                 break;
133 
134             case CLUSTER:
135                 // REGISTER LISTENERS FOR EACH SYSTEM CLUSTERED CACHEs
136                 StringTokenizer it = new StringTokenizer( rca.getClusterServers(), "," );
137                 while ( it.hasMoreElements() )
138                 {
139                     String server = (String) it.nextElement();
140                     RemoteLocation location = RemoteLocation.parseServerAndPort(server);
141 
142                     if (location != null)
143                     {
144                         rca.setRemoteLocation(location);
145                         RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer );
146                         rca.setRemoteType( RemoteType.CLUSTER );
147                         RemoteCacheNoWait<K,V> ic = rcm.getCache( rca );
148                         noWaits.add( ic );
149                     }
150                 }
151                 break;
152         }
153 
154         RemoteCacheNoWaitFacade<K, V> rcnwf =
155             new RemoteCacheNoWaitFacade<K, V>(noWaits, rca, cacheEventLogger, elementSerializer, this );
156 
157         return rcnwf;
158     }
159 
160     // end createCache
161 
162     /**
163      * Returns an instance of RemoteCacheManager for the given connection parameters.
164      * <p>
165      * Host and Port uniquely identify a manager instance.
166      * <p>
167      * @param cattr
168      *
169      * @return The instance value or null if no such manager exists
170      */
171     public RemoteCacheManager getManager( IRemoteCacheAttributes cattr )
172     {
173         if ( cattr.getRemoteLocation() == null )
174         {
175             cattr.setRemoteLocation("", Registry.REGISTRY_PORT);
176         }
177 
178         RemoteLocation loc = cattr.getRemoteLocation();
179         RemoteCacheManager ins = managers.get( loc );
180 
181         return ins;
182     }
183 
184     /**
185      * Returns an instance of RemoteCacheManager for the given connection parameters.
186      * <p>
187      * Host and Port uniquely identify a manager instance.
188      * <p>
189      * If the connection cannot be established, zombie objects will be used for future recovery
190      * purposes.
191      * <p>
192      * @param cattr
193      * @param cacheMgr
194      * @param cacheEventLogger
195      * @param elementSerializer
196      * @return The instance value, never null
197      */
198     public RemoteCacheManager getManager( IRemoteCacheAttributes cattr, ICompositeCacheManager cacheMgr,
199                                                   ICacheEventLogger cacheEventLogger,
200                                                   IElementSerializer elementSerializer )
201     {
202         RemoteCacheManager ins = getManager( cattr );
203 
204         if ( ins == null )
205         {
206             managerLock.lock();
207 
208             try
209             {
210                 ins = managers.get( cattr.getRemoteLocation() );
211 
212                 if (ins == null)
213                 {
214                     ins = new RemoteCacheManager( cattr, cacheMgr, monitor, cacheEventLogger, elementSerializer);
215                     managers.put( cattr.getRemoteLocation(), ins );
216                     monitor.addManager(ins);
217                 }
218             }
219             finally
220             {
221                 managerLock.unlock();
222             }
223         }
224 
225         return ins;
226     }
227 
228 	/**
229 	 * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#initialize()
230 	 */
231 	@Override
232 	public void initialize()
233 	{
234 		super.initialize();
235 
236 		managers = new ConcurrentHashMap<RemoteLocation, RemoteCacheManager>();
237 		managerLock = new ReentrantLock();
238 
239         monitor = new RemoteCacheMonitor();
240         monitor.setDaemon(true);
241 	}
242 
243 	/**
244 	 * @see org.apache.commons.jcs.auxiliary.AbstractAuxiliaryCacheFactory#dispose()
245 	 */
246 	@Override
247 	public void dispose()
248 	{
249 		for (RemoteCacheManager manager : managers.values())
250 		{
251 			manager.release();
252 		}
253 
254 		managers.clear();
255 
256         if (monitor != null)
257         {
258             monitor.notifyShutdown();
259             try
260             {
261                 monitor.join(5000);
262             }
263             catch (InterruptedException e)
264             {
265                 // swallow
266             }
267             monitor = null;
268         }
269 
270 		super.dispose();
271 	}
272 }