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