| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| |
| package org.apache.geode.cache.client.internal; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.CancelCriterion; |
| import org.apache.geode.cache.CacheClosedException; |
| import org.apache.geode.cache.client.PoolManager; |
| import org.apache.geode.distributed.DistributedMember; |
| import org.apache.geode.distributed.DistributedSystem; |
| import org.apache.geode.distributed.internal.ServerLocation; |
| import org.apache.geode.internal.cache.PoolStats; |
| import org.apache.geode.internal.cache.tier.InternalClientMembership; |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| |
| public class EndpointManagerImpl implements EndpointManager { |
| private static final Logger logger = LogService.getLogger(); |
| |
| private volatile Map<ServerLocation, Endpoint> endpointMap = Collections.emptyMap(); |
| private final Map<ServerLocation, ConnectionStats> statMap = new HashMap<>(); |
| private final DistributedSystem ds; |
| private final String poolName; |
| private final EndpointListenerBroadcaster listener = new EndpointListenerBroadcaster(); |
| protected final CancelCriterion cancelCriterion; |
| private final PoolStats poolStats; |
| |
| public EndpointManagerImpl(String poolName, DistributedSystem ds, CancelCriterion cancelCriterion, |
| PoolStats poolStats) { |
| this.ds = ds; |
| this.poolName = poolName; |
| this.cancelCriterion = cancelCriterion; |
| this.poolStats = poolStats; |
| listener.addListener(new EndpointListenerForBridgeMembership()); |
| } |
| |
| @Override |
| public Endpoint referenceEndpoint(ServerLocation server, DistributedMember memberId) { |
| Endpoint endpoint = endpointMap.get(server); |
| boolean addedEndpoint = false; |
| if (endpoint == null || endpoint.isClosed()) { |
| synchronized (this) { |
| endpoint = endpointMap.get(server); |
| if (endpoint == null || endpoint.isClosed()) { |
| ConnectionStats stats = getStats(server); |
| Map<ServerLocation, Endpoint> endpointMapTemp = new HashMap<>(endpointMap); |
| endpoint = new Endpoint(this, ds, server, stats, memberId); |
| listener.clearPdxRegistry(endpoint); |
| endpointMapTemp.put(server, endpoint); |
| endpointMap = Collections.unmodifiableMap(endpointMapTemp); |
| addedEndpoint = true; |
| poolStats.setServerCount(endpointMap.size()); |
| } |
| } |
| } |
| |
| endpoint.addReference(); |
| |
| if (addedEndpoint) { |
| listener.endpointNowInUse(endpoint); |
| } |
| |
| return endpoint; |
| } |
| |
| @Override |
| public void serverCrashed(Endpoint endpoint) { |
| removeEndpoint(endpoint, true); |
| } |
| |
| void endpointNotInUse(Endpoint endpoint) { |
| removeEndpoint(endpoint, false); |
| } |
| |
| /** Used by Endpoint only, when the reference count for this endpoint reaches 0 */ |
| private void removeEndpoint(Endpoint endpoint, boolean crashed) { |
| endpoint.close(); |
| boolean removedEndpoint = false; |
| synchronized (this) { |
| Map<ServerLocation, Endpoint> endpointMapTemp = new HashMap<>(endpointMap); |
| endpoint = endpointMapTemp.remove(endpoint.getLocation()); |
| if (endpoint != null) { |
| endpointMap = Collections.unmodifiableMap(endpointMapTemp); |
| removedEndpoint = true; |
| } |
| poolStats.setServerCount(endpointMap.size()); |
| } |
| if (removedEndpoint) { |
| PoolImpl pool = (PoolImpl) PoolManager.find(poolName); |
| if (pool != null && pool.getMultiuserAuthentication()) { |
| int size = 0; |
| ArrayList<ProxyCache> proxyCaches = pool.getProxyCacheList(); |
| synchronized (proxyCaches) { |
| for (ProxyCache proxyCache : proxyCaches) { |
| try { |
| Long userId = |
| proxyCache.getUserAttributes().getServerToId().remove(endpoint.getLocation()); |
| if (userId != null) { |
| ++size; |
| } |
| } catch (CacheClosedException cce) { |
| // If this call is triggered by a Cache.close(), then this can be |
| // expected. |
| } |
| } |
| if (logger.isDebugEnabled()) { |
| logger.debug( |
| "EndpointManagerImpl.removeEndpoint() Removed server {} from {} user's ProxyCache", |
| endpoint.getLocation(), size); |
| } |
| } |
| UserAttributes ua = UserAttributes.userAttributes.get(); |
| if (ua != null) { |
| Long userId = ua.getServerToId().remove(endpoint.getLocation()); |
| if (userId != null && logger.isDebugEnabled()) { |
| logger.debug( |
| "EndpointManagerImpl.removeEndpoint() Removed server {} from thread local variable", |
| endpoint.getLocation()); |
| } |
| } |
| } else if (pool != null && !pool.getMultiuserAuthentication()) { |
| endpoint.getLocation().setUserId(-1); |
| } |
| if (crashed) { |
| listener.endpointCrashed(endpoint); |
| } else { |
| listener.endpointNoLongerInUse(endpoint); |
| } |
| } |
| } |
| |
| |
| |
| @Override |
| public Map<ServerLocation, Endpoint> getEndpointMap() { |
| return endpointMap; |
| } |
| |
| @Override |
| public synchronized void close() { |
| for (ConnectionStats stats : statMap.values()) { |
| stats.close(); |
| } |
| |
| statMap.clear(); |
| endpointMap = Collections.emptyMap(); |
| listener.clear(); |
| } |
| |
| @Override |
| public void addListener(EndpointManager.EndpointListener listener) { |
| this.listener.addListener(listener); |
| } |
| |
| @Override |
| public void removeListener(EndpointManager.EndpointListener listener) { |
| this.listener.removeListener(listener); |
| } |
| |
| private synchronized ConnectionStats getStats(ServerLocation location) { |
| ConnectionStats stats = statMap.get(location); |
| if (stats == null) { |
| PoolImpl pool = (PoolImpl) PoolManager.find(poolName); |
| if (pool != null) { |
| if (pool.getGatewaySender() != null) { |
| String statName = pool.getGatewaySender().getId() + "-" + location.toString(); |
| stats = new ConnectionStats(ds, "GatewaySender", statName, this.poolStats); |
| } |
| } |
| if (stats == null) { |
| String statName = poolName + "-" + location.toString(); |
| stats = new ConnectionStats(ds, "Client", statName, poolStats); |
| } |
| statMap.put(location, stats); |
| } |
| |
| return stats; |
| } |
| |
| @Override |
| public synchronized Map<ServerLocation, ConnectionStats> getAllStats() { |
| return new HashMap<>(statMap); |
| } |
| |
| @Override |
| public int getConnectedServerCount() { |
| return getEndpointMap().size(); |
| } |
| |
| public static void loadEmergencyClasses() { |
| // do nothing |
| } |
| |
| protected static class EndpointListenerBroadcaster implements EndpointManager.EndpointListener { |
| |
| private volatile Set<EndpointListener> endpointListeners = Collections.emptySet(); |
| |
| public synchronized void addListener(EndpointManager.EndpointListener listener) { |
| HashSet<EndpointListener> tmpListeners = new HashSet<>(endpointListeners); |
| tmpListeners.add(listener); |
| endpointListeners = Collections.unmodifiableSet(tmpListeners); |
| } |
| |
| public synchronized void clear() { |
| endpointListeners = Collections.emptySet(); |
| } |
| |
| public void removeListener(EndpointManager.EndpointListener listener) { |
| HashSet<EndpointListener> tmpListeners = new HashSet<>(endpointListeners); |
| tmpListeners.remove(listener); |
| endpointListeners = Collections.unmodifiableSet(tmpListeners); |
| } |
| |
| @Override |
| public void endpointCrashed(Endpoint endpoint) { |
| for (EndpointListener listener : endpointListeners) { |
| listener.endpointCrashed(endpoint); |
| } |
| } |
| |
| @Override |
| public void endpointNoLongerInUse(Endpoint endpoint) { |
| for (EndpointListener listener : endpointListeners) { |
| listener.endpointNoLongerInUse(endpoint); |
| } |
| } |
| |
| @Override |
| public void endpointNowInUse(Endpoint endpoint) { |
| for (EndpointListener listener : endpointListeners) { |
| if (!(listener instanceof PdxRegistryRecoveryListener)) { |
| listener.endpointNowInUse(endpoint); |
| } |
| } |
| } |
| |
| void clearPdxRegistry(Endpoint endpoint) { |
| for (EndpointListener listener : endpointListeners) { |
| if (listener instanceof PdxRegistryRecoveryListener) { |
| listener.endpointNowInUse(endpoint); |
| } |
| } |
| } |
| |
| } |
| |
| |
| |
| public class EndpointListenerForBridgeMembership implements EndpointManager.EndpointListener { |
| |
| @Override |
| public void endpointCrashed(Endpoint endpoint) { |
| if (cancelCriterion.isCancelInProgress()) { |
| return; |
| } |
| InternalClientMembership.notifyServerCrashed(endpoint.getLocation()); |
| } |
| |
| @Override |
| public void endpointNoLongerInUse(Endpoint endpoint) { |
| if (cancelCriterion.isCancelInProgress()) { |
| return; |
| } |
| InternalClientMembership.notifyServerLeft(endpoint.getLocation()); |
| } |
| |
| @Override |
| public void endpointNowInUse(Endpoint endpoint) { |
| if (cancelCriterion.isCancelInProgress()) { |
| return; |
| } |
| InternalClientMembership.notifyServerJoined(endpoint.getLocation()); |
| } |
| } |
| |
| @Override |
| public String getPoolName() { |
| return poolName; |
| } |
| |
| } |