001package org.apache.commons.jcs3.auxiliary.remote; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.rmi.registry.Registry; 023import java.util.ArrayList; 024import java.util.concurrent.ConcurrentHashMap; 025import java.util.concurrent.ConcurrentMap; 026 027import org.apache.commons.jcs3.auxiliary.AbstractAuxiliaryCacheFactory; 028import org.apache.commons.jcs3.auxiliary.AuxiliaryCache; 029import org.apache.commons.jcs3.auxiliary.AuxiliaryCacheAttributes; 030import org.apache.commons.jcs3.auxiliary.remote.behavior.IRemoteCacheAttributes; 031import org.apache.commons.jcs3.auxiliary.remote.server.behavior.RemoteType; 032import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager; 033import org.apache.commons.jcs3.engine.behavior.IElementSerializer; 034import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger; 035 036/** 037 * The RemoteCacheFactory creates remote caches for the cache hub. It returns a no wait facade which 038 * is a wrapper around a no wait. The no wait object is either an active connection to a remote 039 * cache or a balking zombie if the remote cache is not accessible. It should be transparent to the 040 * clients. 041 */ 042public class RemoteCacheFactory 043 extends AbstractAuxiliaryCacheFactory 044{ 045 /** Monitor thread */ 046 private RemoteCacheMonitor monitor; 047 048 /** Contains mappings of RemoteLocation instance to RemoteCacheManager instance. */ 049 private ConcurrentMap<RemoteLocation, RemoteCacheManager> managers; 050 051 /** 052 * For LOCAL clients we get a handle to all the failovers, but we do not register a listener 053 * with them. We create the RemoteCacheManager, but we do not get a cache. 054 * <p> 055 * The failover runner will get a cache from the manager. When the primary is restored it will 056 * tell the manager for the failover to deregister the listener. 057 * <p> 058 * @param iaca 059 * @param cacheMgr 060 * @param cacheEventLogger 061 * @param elementSerializer 062 * @return AuxiliaryCache 063 */ 064 @Override 065 public <K, V> AuxiliaryCache<K, V> createCache( 066 final AuxiliaryCacheAttributes iaca, final ICompositeCacheManager cacheMgr, 067 final ICacheEventLogger cacheEventLogger, final IElementSerializer elementSerializer ) 068 { 069 final RemoteCacheAttributes rca = (RemoteCacheAttributes) iaca; 070 071 final ArrayList<RemoteCacheNoWait<K,V>> noWaits = new ArrayList<>(); 072 073 switch (rca.getRemoteType()) 074 { 075 case LOCAL: 076 // a list to be turned into an array of failover server information 077 final ArrayList<RemoteLocation> failovers = new ArrayList<>(); 078 079 // not necessary if a failover list is defined 080 // REGISTER PRIMARY LISTENER 081 // if it is a primary 082 if ( rca.getRemoteLocation() != null ) 083 { 084 failovers.add( rca.getRemoteLocation() ); 085 final RemoteCacheManager rcm = getManager( rca, cacheMgr, cacheEventLogger, elementSerializer ); 086 noWaits.add(rcm.getCache(rca)); 087 } 088 089 // GET HANDLE BUT DON'T REGISTER A LISTENER FOR FAILOVERS 090 final String failoverList = rca.getFailoverServers(); 091 if (failoverList != null && !failoverList.isEmpty()) 092 { 093 final String[] failoverServers = failoverList.split("\\s*,\\s*"); 094 for (String server : failoverServers) 095 { 096 final RemoteLocation location = RemoteLocation.parseServerAndPort(server); 097 098 if (location != null) 099 { 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}