All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.geode.cache.client.internal.PoolImpl Maven / Gradle / Ivy

Go to download

Apache Geode provides a database-like consistency model, reliable transaction processing and a shared-nothing architecture to maintain very low latency performance with high concurrency processing

There is a newer version: 1.15.1
Show newest version
/*
 * 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 org.apache.geode.CancelCriterion;
import org.apache.geode.CancelException;
import org.apache.geode.StatisticsFactory;
import org.apache.geode.SystemFailure;
import org.apache.geode.cache.*;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.ServerConnectivityException;
import org.apache.geode.cache.client.SubscriptionNotEnabledException;
import org.apache.geode.cache.client.internal.pooling.ConnectionManager;
import org.apache.geode.cache.client.internal.pooling.ConnectionManagerImpl;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.internal.DefaultQueryService;
import org.apache.geode.cache.wan.GatewaySender;
import org.apache.geode.distributed.PoolCancelledException;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.ServerLocation;
import org.apache.geode.internal.statistics.DummyStatisticsFactory;
import org.apache.geode.internal.ScheduledThreadPoolExecutorWithKeepAlive;
import org.apache.geode.internal.admin.ClientStatsManager;
import org.apache.geode.internal.cache.*;
import org.apache.geode.internal.cache.tier.sockets.AcceptorImpl;
import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID;
import org.apache.geode.internal.i18n.LocalizedStrings;
import org.apache.geode.internal.logging.InternalLogWriter;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.internal.logging.log4j.LocalizedMessage;
import org.apache.logging.log4j.Logger;

import java.net.InetSocketAddress;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Manages the client side of client to server connections and client queues.
 * 
 * @since GemFire 5.7
 */
public class PoolImpl implements InternalPool {
  public static final String ON_DISCONNECT_CLEAR_PDXTYPEIDS =
      DistributionConfig.GEMFIRE_PREFIX + "ON_DISCONNECT_CLEAR_PDXTYPEIDS";

  private static final Logger logger = LogService.getLogger();

  public static final int HANDSHAKE_TIMEOUT =
      Long.getLong(DistributionConfig.GEMFIRE_PREFIX + "PoolImpl.HANDSHAKE_TIMEOUT",
          AcceptorImpl.DEFAULT_HANDSHAKE_TIMEOUT_MS).intValue();
  public static final long SHUTDOWN_TIMEOUT = Long
      .getLong(DistributionConfig.GEMFIRE_PREFIX + "PoolImpl.SHUTDOWN_TIMEOUT", 30000).longValue();
  public static final int BACKGROUND_TASK_POOL_SIZE = Integer
      .getInteger(DistributionConfig.GEMFIRE_PREFIX + "PoolImpl.BACKGROUND_TASK_POOL_SIZE", 20)
      .intValue();
  public static final int BACKGROUND_TASK_POOL_KEEP_ALIVE =
      Integer
          .getInteger(
              DistributionConfig.GEMFIRE_PREFIX + "PoolImpl.BACKGROUND_TASK_POOL_KEEP_ALIVE", 1000)
          .intValue();
  // For durable client tests only. Connection Sources read this flag
  // and return an empty list of servers.
  public volatile static boolean TEST_DURABLE_IS_NET_DOWN = false;

  private final String name;
  private final int freeConnectionTimeout;
  private final int loadConditioningInterval;
  private final int socketBufferSize;
  private final boolean threadLocalConnections;
  private final int readTimeout;
  private final boolean subscriptionEnabled;
  private final boolean prSingleHopEnabled;
  private final int subscriptionRedundancyLevel;
  private final int subscriptionMessageTrackingTimeout;
  private final int subscriptionAckInterval;
  private final String serverGroup;
  private final List locators;
  private final List servers;
  private final boolean startDisabled;
  private final boolean usedByGateway;
  private final int maxConnections;
  private final int minConnections;
  private final int retryAttempts;
  private final long idleTimeout;
  private final long pingInterval;
  private final int statisticInterval;
  private final boolean multiuserSecureModeEnabled;

  private final ConnectionSource source;
  private final ConnectionManager manager;
  private QueueManager queueManager;
  protected final EndpointManager endpointManager;
  private final PoolManagerImpl pm;
  protected final InternalLogWriter securityLogWriter;
  protected volatile boolean destroyed;
  private final PoolStats stats;
  private ScheduledExecutorService backgroundProcessor;
  private final OpExecutorImpl executor;
  private final RegisterInterestTracker riTracker = new RegisterInterestTracker();
  private final InternalDistributedSystem dsys;

  private final ClientProxyMembershipID proxyId;
  protected final CancelCriterion cancelCriterion;
  private final ConnectionFactoryImpl connectionFactory;

  private final ArrayList proxyCacheList;

  private final GatewaySender gatewaySender;

  private boolean keepAlive = false;
  private static Object simpleLock = new Object();

  public static final int PRIMARY_QUEUE_NOT_AVAILABLE = -2;
  public static final int PRIMARY_QUEUE_TIMED_OUT = -1;
  private AtomicInteger primaryQueueSize = new AtomicInteger(PRIMARY_QUEUE_NOT_AVAILABLE);

  public static PoolImpl create(PoolManagerImpl pm, String name, Pool attributes) {
    PoolImpl pool = new PoolImpl(pm, name, attributes);
    pool.finishCreate(pm);
    return pool;
  }

  public boolean isUsedByGateway() {
    return usedByGateway;
  }

  /**
   * @since GemFire 5.7
   */
  protected void finishCreate(PoolManagerImpl pm) {
    pm.register(this);
    try {
      start();
    } catch (RuntimeException e) {
      try {
        destroy(false);
      } catch (RuntimeException e2) {
        // do nothing
      }
      throw e;
    }
  }

  protected PoolImpl(PoolManagerImpl pm, String name, Pool attributes) {
    this.pm = pm;
    this.name = name;
    this.freeConnectionTimeout = attributes.getFreeConnectionTimeout();
    this.loadConditioningInterval = attributes.getLoadConditioningInterval();
    this.socketBufferSize = attributes.getSocketBufferSize();
    this.threadLocalConnections = attributes.getThreadLocalConnections();
    this.readTimeout = attributes.getReadTimeout();
    this.minConnections = attributes.getMinConnections();
    this.maxConnections = attributes.getMaxConnections();
    this.retryAttempts = attributes.getRetryAttempts();
    this.idleTimeout = attributes.getIdleTimeout();
    this.pingInterval = attributes.getPingInterval();
    this.statisticInterval = attributes.getStatisticInterval();
    this.subscriptionEnabled = attributes.getSubscriptionEnabled();
    this.prSingleHopEnabled = attributes.getPRSingleHopEnabled();
    this.subscriptionRedundancyLevel = attributes.getSubscriptionRedundancy();
    this.subscriptionMessageTrackingTimeout = attributes.getSubscriptionMessageTrackingTimeout();
    this.subscriptionAckInterval = attributes.getSubscriptionAckInterval();
    this.serverGroup = attributes.getServerGroup();
    this.multiuserSecureModeEnabled = attributes.getMultiuserAuthentication();
    this.locators = attributes.getLocators();
    this.servers = attributes.getServers();
    this.startDisabled =
        ((PoolFactoryImpl.PoolAttributes) attributes).startDisabled || !pm.isNormal();
    this.usedByGateway = ((PoolFactoryImpl.PoolAttributes) attributes).isGateway();
    this.gatewaySender = ((PoolFactoryImpl.PoolAttributes) attributes).getGatewaySender();
    // if (this.subscriptionEnabled && this.multiuserSecureModeEnabled) {
    // throw new IllegalStateException(
    // "subscription-enabled and multiuser-authentication both cannot be true.");
    // }
    InternalDistributedSystem ds = InternalDistributedSystem.getAnyInstance();
    if (ds == null) {
      throw new IllegalStateException(
          LocalizedStrings.PoolImpl_DISTRIBUTED_SYSTEM_MUST_BE_CREATED_BEFORE_CREATING_POOL
              .toLocalizedString());
    }
    this.securityLogWriter = ds.getSecurityInternalLogWriter();
    if (!ds.getConfig().getStatisticSamplingEnabled() && this.statisticInterval > 0) {
      logger.info(LocalizedMessage.create(
          LocalizedStrings.PoolImpl_STATISTIC_SAMPLING_MUST_BE_ENABLED_FOR_SAMPLING_RATE_OF_0_TO_TAKE_AFFECT,
          this.statisticInterval));
    }
    this.dsys = ds;
    this.cancelCriterion = new Stopper();
    if (Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "SPECIAL_DURABLE")) {
      ClientProxyMembershipID.setPoolName(name);
      this.proxyId = ClientProxyMembershipID.getNewProxyMembership(ds);
      ClientProxyMembershipID.setPoolName(null);
    } else {
      this.proxyId = ClientProxyMembershipID.getNewProxyMembership(ds);
    }
    StatisticsFactory statFactory = null;
    if (this.gatewaySender != null) {
      statFactory = new DummyStatisticsFactory();
    } else {
      statFactory = ds;
    }
    this.stats = this.startDisabled ? null
        : new PoolStats(statFactory,
            getName() + "->" + (serverGroup == null || serverGroup.equals("") ? "[any servers]"
                : "[" + getServerGroup() + "]"));

    source = getSourceImpl(((PoolFactoryImpl.PoolAttributes) attributes).locatorCallback);
    endpointManager = new EndpointManagerImpl(name, ds, this.cancelCriterion, this.stats);
    connectionFactory = new ConnectionFactoryImpl(source, endpointManager, ds, socketBufferSize,
        HANDSHAKE_TIMEOUT, readTimeout, proxyId, this.cancelCriterion, usedByGateway, gatewaySender,
        pingInterval, multiuserSecureModeEnabled, this);
    if (subscriptionEnabled) {
      queueManager = new QueueManagerImpl(this, endpointManager, source, connectionFactory,
          subscriptionRedundancyLevel, pingInterval, securityLogWriter, proxyId);
    }

    manager = new ConnectionManagerImpl(name, connectionFactory, endpointManager, maxConnections,
        minConnections, idleTimeout, loadConditioningInterval, securityLogWriter, pingInterval,
        cancelCriterion, getStats());
    // Fix for 43468 - make sure we check the cache cancel criterion if we get
    // an exception, by passing in the poolOrCache stopper
    executor = new OpExecutorImpl(manager, queueManager, endpointManager, riTracker, retryAttempts,
        freeConnectionTimeout, threadLocalConnections, new PoolOrCacheStopper(), this);
    if (this.multiuserSecureModeEnabled) {
      this.proxyCacheList = new ArrayList();
    } else {
      this.proxyCacheList = null;
    }
  }

  /**
   * Return true if the given Pool is compatible with these attributes. Currently this does what
   * equals would but in the future we might decide to weaken the compatibility contract.
   * 
   * @since GemFire 6.5
   */
  public boolean isCompatible(Pool p) {
    if (p == null)
      return false;
    return getFreeConnectionTimeout() == p.getFreeConnectionTimeout()
        && getLoadConditioningInterval() == p.getLoadConditioningInterval()
        && getSocketBufferSize() == p.getSocketBufferSize()
        && getMinConnections() == p.getMinConnections()
        && getMaxConnections() == p.getMaxConnections() && getIdleTimeout() == p.getIdleTimeout()
        && getPingInterval() == p.getPingInterval()
        && getStatisticInterval() == p.getStatisticInterval()
        && getRetryAttempts() == p.getRetryAttempts()
        && getThreadLocalConnections() == p.getThreadLocalConnections()
        && getReadTimeout() == p.getReadTimeout()
        && getSubscriptionEnabled() == p.getSubscriptionEnabled()
        && getPRSingleHopEnabled() == p.getPRSingleHopEnabled()
        && getSubscriptionRedundancy() == p.getSubscriptionRedundancy()
        && getSubscriptionMessageTrackingTimeout() == p.getSubscriptionMessageTrackingTimeout()
        && getSubscriptionAckInterval() == p.getSubscriptionAckInterval()
        && getServerGroup().equals(p.getServerGroup())
        && getMultiuserAuthentication() == p.getMultiuserAuthentication()
        && getLocators().equals(p.getLocators()) && getServers().equals(p.getServers());
  }

  private void start() {
    if (this.startDisabled)
      return;

    final boolean isDebugEnabled = logger.isDebugEnabled();
    if (isDebugEnabled) {
      List locators = getLocators();
      if (!locators.isEmpty()) {
        logger.debug("PoolImpl - starting pool with locators: {}", locators);
      } else {
        logger.debug("PoolImpl -starting pool with servers: {}", getServers());
      }
    }

    final String timerName = "poolTimer-" + getName() + "-";
    backgroundProcessor = new ScheduledThreadPoolExecutorWithKeepAlive(BACKGROUND_TASK_POOL_SIZE,
        BACKGROUND_TASK_POOL_KEEP_ALIVE, TimeUnit.MILLISECONDS, new ThreadFactory() {
          AtomicInteger threadNum = new AtomicInteger();

          public Thread newThread(final Runnable r) {
            Thread result = new Thread(r, timerName + threadNum.incrementAndGet());
            result.setDaemon(true);
            return result;
          }
        });
    ((ScheduledThreadPoolExecutorWithKeepAlive) backgroundProcessor)
        .setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
    ((ScheduledThreadPoolExecutorWithKeepAlive) backgroundProcessor)
        .setExecuteExistingDelayedTasksAfterShutdownPolicy(false);

    source.start(this);
    connectionFactory.start(backgroundProcessor);
    endpointManager.addListener(new InstantiatorRecoveryListener(backgroundProcessor, this));
    endpointManager.addListener(new DataSerializerRecoveryListener(backgroundProcessor, this));
    if (Boolean.getBoolean(ON_DISCONNECT_CLEAR_PDXTYPEIDS)) {
      endpointManager.addListener(new PdxRegistryRecoveryListener(this));
    }
    endpointManager.addListener(new LiveServerPinger(this));

    manager.start(backgroundProcessor);
    if (queueManager != null) {
      if (isDebugEnabled) {
        logger.debug("starting queueManager");
      }
      queueManager.start(backgroundProcessor);
    }
    if (isDebugEnabled) {
      logger.debug("scheduling pings every {} milliseconds", pingInterval);
    }


    if (this.statisticInterval > 0 && this.dsys.getConfig().getStatisticSamplingEnabled()) {
      backgroundProcessor.scheduleWithFixedDelay(new PublishClientStatsTask(), statisticInterval,
          statisticInterval, TimeUnit.MILLISECONDS);
    }
    // LOG: changed from config to info
    logger.info(LocalizedMessage.create(
        LocalizedStrings.PoolImpl_POOL_0_STARTED_WITH_MULTIUSER_SECURE_MODE_ENABLED_1,
        new Object[] {this.name, this.multiuserSecureModeEnabled}));
  }

  /**
   * Returns the cancellation criterion for this proxy
   * 
   * @return the cancellation criterion
   */
  public CancelCriterion getCancelCriterion() {
    return this.cancelCriterion;
  }

  public void releaseThreadLocalConnection() {
    executor.releaseThreadLocalConnection();
  }

  public void setupServerAffinity(boolean allowFailover) {
    executor.setupServerAffinity(allowFailover);
  }

  public void releaseServerAffinity() {
    executor.releaseServerAffinity();
  }

  /*
   * (non-Javadoc)
   * 
   * @see org.apache.geode.cache.Pool#getName()
   */
  public String getName() {
    return this.name;
  }

  public int getFreeConnectionTimeout() {
    return this.freeConnectionTimeout;
  }

  public int getLoadConditioningInterval() {
    return this.loadConditioningInterval;
  }

  public int getMaxConnections() {
    return maxConnections;
  }

  public int getMinConnections() {
    return minConnections;
  }

  public int getRetryAttempts() {
    return retryAttempts;
  }

  public long getIdleTimeout() {
    return idleTimeout;
  }

  public long getPingInterval() {
    return pingInterval;
  }

  public int getStatisticInterval() {
    return this.statisticInterval;
  }

  public int getSocketBufferSize() {
    return this.socketBufferSize;
  }

  public boolean getThreadLocalConnections() {
    return this.threadLocalConnections;
  }

  public int getReadTimeout() {
    return this.readTimeout;
  }

  public boolean getSubscriptionEnabled() {
    return this.subscriptionEnabled;
  }

  public boolean getPRSingleHopEnabled() {
    return this.prSingleHopEnabled;
  }

  public int getSubscriptionRedundancy() {
    return this.subscriptionRedundancyLevel;
  }

  public int getSubscriptionMessageTrackingTimeout() {
    return this.subscriptionMessageTrackingTimeout;
  }

  public int getSubscriptionAckInterval() {
    return subscriptionAckInterval;
  }

  public String getServerGroup() {
    return this.serverGroup;
  }

  public boolean getMultiuserAuthentication() {
    return this.multiuserSecureModeEnabled;
  }

  public List getLocators() {
    return this.locators;
  }

  public List getServers() {
    return this.servers;
  }

  public GatewaySender getGatewaySender() {
    return gatewaySender;
  }

  public InternalLogWriter getSecurityInternalLogWriter() {
    return this.securityLogWriter;
  }

  public void destroy() {
    destroy(false);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder(100);
    sb.append(this.getClass().getSimpleName()).append('@').append(System.identityHashCode(this))
        .append(" name=").append(getName());
    return sb.toString();
  }

  public void destroy(boolean keepAlive) {
    int cnt = getAttachCount();
    this.keepAlive = keepAlive;
    boolean SPECIAL_DURABLE =
        Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "SPECIAL_DURABLE");
    if (cnt > 0) {
      // special case to allow closing durable client pool under the keep alive flag
      // closing regions prior to closing pool can cause them to unregister interest
      if (SPECIAL_DURABLE) {
        synchronized (simpleLock) {
          try {
            if (!CacheFactory.getAnyInstance().isClosed()
                && this.getPoolOrCacheCancelInProgress() == null) {
              Set> regions = CacheFactory.getInstance(dsys).rootRegions();
              for (Region roots : regions) {
                Set> subregions = roots.subregions(true);
                for (Region subroots : subregions) {
                  if (!subroots.isDestroyed() && subroots.getAttributes().getPoolName() != null
                      && subroots.getAttributes().getPoolName().equals(this.name)) {
                    if (logger.isDebugEnabled()) {
                      logger.debug(
                          "PoolImpl.destroy[ Region connected count:{} Region subroot closing:{} Pool Name:{} ]",
                          cnt, subroots.getName(), this.name);
                    }
                    subroots.close();
                  }
                }

                if (!roots.isDestroyed() && roots.getAttributes().getPoolName() != null
                    && roots.getAttributes().getPoolName().equals(this.name)) {
                  if (logger.isDebugEnabled()) {
                    logger.debug(
                        "PoolImpl.destroy[ Region connected count:{} Region root closing:{} Pool Name:{} ]",
                        cnt, roots.getName(), this.name);
                  }
                  roots.close();
                }
              }
            }
          } catch (CacheClosedException ccex) {
            if (logger.isDebugEnabled()) {
              logger.debug(ccex.getMessage(), ccex);
            }
          } catch (Exception ex) {
            if (logger.isDebugEnabled()) {
              logger.debug(ex.getMessage(), ex);
            }
          }
        }
      } // end special case

      cnt = getAttachCount();
      if (cnt > 0) {
        throw new IllegalStateException(
            LocalizedStrings.PoolImpl_POOL_COULD_NOT_BE_DESTROYED_BECAUSE_IT_IS_STILL_IN_USE_BY_0_REGIONS
                .toLocalizedString(Integer.valueOf(cnt)));
      }
    }
    if (this.pm.unregister(this)) {
      basicDestroy(keepAlive);
    }
  }

  /**
   * Destroys this pool but does not unregister it. This is used by the PoolManagerImpl when it
   * wants to close all its pools.
   */
  public synchronized void basicDestroy(boolean keepAlive) {
    if (!isDestroyed()) {
      this.destroyed = true;
      this.keepAlive = keepAlive;
      // LOG: changed from config to info
      logger.info(
          LocalizedMessage.create(LocalizedStrings.PoolImpl_DESTROYING_CONNECTION_POOL_0, name));

      try {
        if (backgroundProcessor != null) {
          backgroundProcessor.shutdown();
          if (!backgroundProcessor.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS)) {
            logger.warn(LocalizedMessage.create(
                LocalizedStrings.PoolImpl_TIMEOUT_WAITING_FOR_BACKGROUND_TASKS_TO_COMPLETE));
          }
        }
      } catch (RuntimeException e) {
        logger.error(LocalizedMessage.create(
            LocalizedStrings.PoolImpl_ERROR_ENCOUNTERED_WHILE_STOPPING_BACKGROUNDPROCESSOR), e);
      } catch (InterruptedException e) {
        logger.error(LocalizedMessage
            .create(LocalizedStrings.PoolImpl_INTERRUPTED_WHILE_STOPPING_BACKGROUNDPROCESSOR), e);
      }

      try {
        if (this.source != null) {
          this.source.stop();
        }
      } catch (RuntimeException e) {
        logger.error(LocalizedMessage.create(
            LocalizedStrings.PoolImpl_ERROR_ENCOUNTERED_WHILE_STOPPING_CONNECTION_SOURCE), e);
      }

      try {
        if (this.queueManager != null) {
          queueManager.close(keepAlive);
        }
      } catch (RuntimeException e) {
        logger.error(
            LocalizedMessage.create(
                LocalizedStrings.PoolImpl_ERROR_ENCOUNTERED_WHILE_STOPPING_SUBSCRIPTION_MANAGER),
            e);
      }

      try {
        if (this.manager != null) {
          manager.close(keepAlive);
        }
      } catch (RuntimeException e) {
        logger.error(LocalizedMessage.create(
            LocalizedStrings.PoolImpl_ERROR_ENCOUNTERED_WHILE_STOPPING_CONNECTION_MANAGER), e);
      }

      try {
        endpointManager.close();
      } catch (RuntimeException e) {
        logger.error(LocalizedMessage.create(
            LocalizedStrings.PoolImpl_ERROR_ENCOUNTERED_WHILE_STOPPING_ENDPOINT_MANAGER), e);
      }

      try {
        if (this.stats != null) {
          this.stats.close();
        }
      } catch (RuntimeException e) {
        logger.error(
            LocalizedMessage.create(LocalizedStrings.PoolImpl_ERROR_WHILE_CLOSING_STATISTICS), e);
      }
    }
  }

  public boolean isDestroyed() {
    return destroyed;
  }


  private ConnectionSource getSourceImpl(LocatorDiscoveryCallback locatorDiscoveryCallback) {
    List locators = getLocators();
    if (locators.isEmpty()) {
      return new ExplicitConnectionSourceImpl(getServers());
    } else {
      AutoConnectionSourceImpl source =
          new AutoConnectionSourceImpl(locators, getServerGroup(), HANDSHAKE_TIMEOUT);
      if (locatorDiscoveryCallback != null) {
        source.setLocatorDiscoveryCallback(locatorDiscoveryCallback);
      }
      return source;
    }
  }

  /**
   * Used internally by xml parsing code.
   */
  public void sameAs(Object obj) {
    if (!(obj instanceof PoolImpl)) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl__0_IS_NOT_THE_SAME_AS_1_BECAUSE_IT_SHOULD_HAVE_BEEN_A_POOLIMPL
              .toLocalizedString(new Object[] {this, obj}));
    }
    PoolImpl other = (PoolImpl) obj;
    if (!getName().equals(other.getName())) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_ARE_DIFFERENT.toLocalizedString("names"));
    }
    if (getFreeConnectionTimeout() != other.getFreeConnectionTimeout()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("connectionTimeout"));
    }
    if (getLoadConditioningInterval() != other.getLoadConditioningInterval()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("connectionLifetime"));
    }
    if (getSocketBufferSize() != other.getSocketBufferSize()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("socketBufferSize"));
    }
    if (getThreadLocalConnections() != other.getThreadLocalConnections()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("threadLocalConnections"));
    }
    if (getReadTimeout() != other.getReadTimeout()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("readTimeout"));
    }
    if (getMinConnections() != other.getMinConnections()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("MinConnections"));
    }
    if (getMaxConnections() != other.getMaxConnections()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("MaxConnections"));
    }
    if (getRetryAttempts() != other.getRetryAttempts()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("RetryAttempts"));
    }
    if (getIdleTimeout() != other.getIdleTimeout()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("IdleTimeout"));
    }
    if (getPingInterval() != other.getPingInterval()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("PingInterval"));
    }
    if (getStatisticInterval() != other.getStatisticInterval()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("StatisticInterval"));
    }
    if (getSubscriptionAckInterval() != other.getSubscriptionAckInterval()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("subscriptionAckInterval"));
    }
    if (getSubscriptionEnabled() != other.getSubscriptionEnabled()) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("subscriptionEnabled"));
    }
    if (getSubscriptionMessageTrackingTimeout() != other.getSubscriptionMessageTrackingTimeout()) {
      throw new RuntimeException(LocalizedStrings.PoolImpl_0_IS_DIFFERENT
          .toLocalizedString("subscriptionMessageTrackingTimeout"));
    }
    if (getSubscriptionRedundancy() != other.getSubscriptionRedundancy()) {
      throw new RuntimeException(LocalizedStrings.PoolImpl_0_IS_DIFFERENT
          .toLocalizedString("subscriptionRedundancyLevel"));
    }
    if (!getServerGroup().equals(other.getServerGroup())) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_IS_DIFFERENT.toLocalizedString("serverGroup"));
    }
    if (!getLocators().equals(other.getLocators())) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_ARE_DIFFERENT.toLocalizedString("locators"));
    }
    if (!getServers().equals(other.getServers())) {
      throw new RuntimeException(
          LocalizedStrings.PoolImpl_0_ARE_DIFFERENT.toLocalizedString("servers"));
    }
    // ignore startDisabled
  }

  public PoolStats getStats() {
    return this.stats;
  }


  /**
   * Execute the given op on the servers that this pool connects to. This method is responsible for
   * retrying the op if an attempt fails. It will only execute it once and on one server.
   * 
   * @param op the operation to execute
   * @return the result of execution if any; null if not
   * @since GemFire 5.7
   */
  public Object execute(Op op) {
    // if(multiuser)
    // get a server from threadlocal cache else throw cacheWriterException
    // executeOn(ServerLocation server, Op op, boolean accessed,boolean onlyUseExistingCnx)

    // Retries are ignored here. FIX IT - FIXED.
    // But this may lead to a user getting authenticated on all servers, even if
    // a single server could have serviced all its requests.
    authenticateIfRequired(op);
    return executor.execute(op);
  }

  /**
   * Execute the given op on the servers that this pool connects to. This method is responsible for
   * retrying the op if an attempt fails. It will only execute it once and on one server.
   * 
   * @param op the operation to execute
   * @param retries how many times to retry the operation
   * @return the result of execution if any; null if not
   * @since GemFire 5.7
   */
  public Object execute(Op op, int retries) {
    authenticateIfRequired(op);
    return executor.execute(op, retries);
  }

  /**
   * Execute the given op on the given server.
   * 
   * @param server the server to do the execution on
   * @param op the operation to execute
   * @return the result of execution if any; null if not
   */
  public Object executeOn(ServerLocation server, Op op) {
    authenticateIfRequired(server, op);
    return executor.executeOn(server, op);
  }

  /**
   * Execute the given op on the given server.
   * 
   * @param server the server to do the execution on
   * @param op the operation to execute
   * @param accessed true if the connection is accessed by this execute
   * @return the result of execution if any; null if not
   */
  public Object executeOn(ServerLocation server, Op op, boolean accessed,
      boolean onlyUseExistingCnx) {
    authenticateIfRequired(server, op);
    return executor.executeOn(server, op, accessed, onlyUseExistingCnx);
  }

  /**
   * Execute the given op on the given connection.
   * 
   * @param con the connection to do the execution on
   * @param op the operation to execute
   * @return the result of execution if any; null if not
   */
  public Object executeOn(Connection con, Op op) {
    authenticateIfRequired(con.getServer(), op);
    return executor.executeOn(con, op);
  }

  public Object executeOn(Connection con, Op op, boolean timeoutFatal) {
    return executor.executeOn(con, op, timeoutFatal);
  }

  /**
   * Execute the given op on all the servers that have server-to-client queues for this pool
   * 
   * @param op the operation to execute
   * @return the result of execution if any; null if not
   * @since GemFire 5.7
   */
  public Object executeOnQueuesAndReturnPrimaryResult(Op op) {
    authenticateOnAllServers(op);
    return executor.executeOnQueuesAndReturnPrimaryResult(op);
  }

  public void executeOnAllQueueServers(Op op)
      throws NoSubscriptionServersAvailableException, SubscriptionNotEnabledException {
    authenticateOnAllServers(op);
    executor.executeOnAllQueueServers(op);
  }

  /**
   * Execute the given op on the current primary server.
   * 
   * @param op the operation to execute
   * @return the result of execution if any; null if not
   */
  public Object executeOnPrimary(Op op) {
    return executor.executeOnPrimary(op);
  }

  public Map getEndpointMap() {
    return endpointManager.getEndpointMap();
  }

  public ScheduledExecutorService getBackgroundProcessor() {
    return backgroundProcessor;
  }

  public RegisterInterestTracker getRITracker() {
    return this.riTracker;
  }

  /**
   * Test hook that returns the number of servers we currently have connections to.
   */
  public int getConnectedServerCount() {
    return this.endpointManager.getConnectedServerCount();
  }

  /**
   * Test hook. Verify if this EventId is already present in the map or not. If it is already
   * present then return true.
   *
   * @param eventId the EventId of the incoming event
   * @return true if it is already present
   * @since GemFire 5.1
   */
  public boolean verifyIfDuplicate(EventID eventId) {
    return ((QueueStateImpl) this.queueManager.getState()).verifyIfDuplicate(eventId);
  }

  public boolean verifyIfDuplicate(EventID eventId, boolean addToMap) {
    return ((QueueStateImpl) this.queueManager.getState()).verifyIfDuplicate(eventId);
  }

  /**
   * Borrows a connection from the pool.. Used by gateway and tests. Any connection that is acquired
   * using this method must be returned using returnConnection, even if it is destroyed.
   * 
   */
  public Connection acquireConnection() {
    return manager.borrowConnection(45000L);
  }

  /**
   * Hook to return connections that were acquired using acquireConnection.
   * 
   * @param conn
   */
  public void returnConnection(Connection conn) {
    manager.returnConnection(conn);
  }

  /**
   * Test hook that acquires and returns a connection from the pool with a given ServerLocation.
   */
  public Connection acquireConnection(ServerLocation loc) {
    return manager.borrowConnection(loc, 15000L, false);
  }

  /**
   * Test hook that returns an unnmodifiable list of the current blacklisted servers
   */
  public Set getBlacklistedServers() {
    return connectionFactory.getBlackList().getBadServers();
  }

  /**
   * Test hook to handle an exception that happened on the given connection
   */
  public void processException(Throwable e, Connection con) {
    executor.handleException(e, con, 0, false);
  }

  /**
   * Test hook that returns the ThreadIdToSequenceIdMap
   */
  public Map getThreadIdToSequenceIdMap() {
    if (this.queueManager == null)
      return Collections.EMPTY_MAP;
    if (this.queueManager.getState() == null)
      return Collections.EMPTY_MAP;
    return this.queueManager.getState().getThreadIdToSequenceIdMap();
  }

  /**
   * Test hook that returns true if we have a primary and its updater thread is alive.
   */
  public boolean isPrimaryUpdaterAlive() {
    return ((QueueManagerImpl) this.queueManager).isPrimaryUpdaterAlive();
  }

  /**
   * Test hook used to simulate a kill of the primaryEndpoint
   */
  public void killPrimaryEndpoint() // throws ServerException
  {
    boolean ok = false;
    if (this.queueManager != null) {
      QueueManager.QueueConnections cons = this.queueManager.getAllConnections();
      Connection con = cons.getPrimary();
      if (con != null) {
        final String msg = "killing primary endpoint";
        logger.info("{}", msg);
        Exception e = new Exception(msg);
        try {
          processException(e, con);
        } catch (ServerConnectivityException expected) {
        } finally {
          logger.info("{}", msg);
        }
        // do some validation here that we are no longer connected to "sl"
        ok = true;
      }
    }
    if (!ok) {
      throw new IllegalStateException("primaryEndpoint was null");
    }
  }

  // Pool that are declared in a cache.xml will set this property to true.
  private boolean declaredInXML;

  public void setDeclaredInXML(boolean v) {
    this.declaredInXML = v;
  }

  public boolean getDeclaredInXML() {
    return this.declaredInXML;
  }

  // used by unit tests to confirm if readyForEvents has been called on a pool
  private boolean readyForEventsCalled;

  public boolean getReadyForEventsCalled() {
    return this.readyForEventsCalled;
  }

  public void readyForEvents(InternalDistributedSystem system) {
    if (!isDurableClient() || queueManager == null) {
      return;
    }
    this.readyForEventsCalled = true;
    queueManager.readyForEvents(system);

  }

  public boolean isDurableClient() {
    boolean isDurable = false;
    InternalDistributedSystem system = InternalDistributedSystem.getAnyInstance();
    DistributionConfig config = system.getConfig();
    String durableClientId = config.getDurableClientId();
    isDurable = durableClientId != null && durableClientId.length() > 0;
    return isDurable;
  }

  /**
   * Test hook that returns a string consisting of the host name and port of the primary server.
   * Null is returned if we have no primary.
   */
  public String getPrimaryName() {
    String result = null;
    ServerLocation sl = getPrimary();
    if (sl != null) {
      result = sl.getHostName() + sl.getPort();
    }
    return result;
  }

  /**
   * Test hook that returns an int which the port of the primary server. -1 is returned if we have
   * no primary.
   */
  public int getPrimaryPort() {
    int result = -1;
    ServerLocation sl = getPrimary();
    if (sl != null) {
      result = sl.getPort();
    }
    return result;
  }

  /**
   * Test hook that returns a string consisting of the host name and port of the primary server.
   * Null is returned if we have no primary.
   */
  public ServerLocation getPrimary() {
    ServerLocation result = null;
    if (this.queueManager != null) {
      QueueManager.QueueConnections cons = this.queueManager.getAllConnections();
      Connection con = cons.getPrimary();
      result = con.getServer();
    }
    return result;
  }

  /**
   * Test hook to get a connection to the primary server.
   */
  public Connection getPrimaryConnection() {
    if (this.queueManager != null) {
      QueueManager.QueueConnections cons = this.queueManager.getAllConnections();
      return cons.getPrimary();
    }
    return null;
  }

  /**
   * Test hook that returns a list of strings. Each string consists of the host name and port of a
   * redundant server. An empty list is returned if we have no redundant servers.
   */
  public List getRedundantNames() {
    List result = Collections.EMPTY_LIST;
    if (this.queueManager != null) {
      QueueManager.QueueConnections cons = this.queueManager.getAllConnections();
      List backupCons = cons.getBackups();
      if (backupCons.size() > 0) {
        result = new ArrayList(backupCons.size());
        Iterator it = backupCons.iterator();
        while (it.hasNext()) {
          Connection con = it.next();
          ServerLocation sl = con.getServer();
          result.add(sl.getHostName() + sl.getPort());
        }
      }
    }
    return result;
  }

  /**
   * Test hook that returns a list of ServerLocation instances. Each ServerLocation describes a
   * redundant server. An empty list is returned if we have no redundant servers.
   */
  public List getRedundants() {
    List result = Collections.EMPTY_LIST;
    if (this.queueManager != null) {
      QueueManager.QueueConnections cons = this.queueManager.getAllConnections();
      List backupCons = cons.getBackups();
      if (backupCons.size() > 0) {
        result = new ArrayList(backupCons.size());
        Iterator it = backupCons.iterator();
        while (it.hasNext()) {
          Connection con = it.next();
          result.add(con.getServer());
        }
      }
    }
    return result;
  }

  /**
   * Test hook to find out current number of connections this pool has.
   */
  public int getConnectionCount() {
    return manager.getConnectionCount();
  }

  /**
   * Atomic counter used to keep track of services using this pool.
   * 
   * @since GemFire 5.7
   */
  private final AtomicInteger attachCount = new AtomicInteger();
  public static volatile boolean IS_INSTANTIATOR_CALLBACK = false;

  /**
   * Returns number of services currently using/attached to this pool.
   * 

* Made public so it can be used by tests * * @since GemFire 5.7 */ public int getAttachCount() { return this.attachCount.get(); } /** * This needs to be called when a service (like a Region or CQService) starts using a pool. * * @since GemFire 5.7 */ public void attach() { this.attachCount.getAndIncrement(); } /** * This needs to be called when a service (like a Region or CQService) stops using a pool. * * @since GemFire 5.7 */ public void detach() { this.attachCount.getAndDecrement(); } /** * Get the connection held by this thread if we're using thread local connections * * This is a a hook for hydra code to pass thread local connections between threads. * * @return the connection from the thread local, or null if there is no thread local connection. */ public Connection getThreadLocalConnection() { return executor.getThreadLocalConnection(); } /** * Returns a list of ServerLocation instances; one for each server we are currently connected to. */ public List getCurrentServers() { ArrayList result = new ArrayList(); Map endpointMap = endpointManager.getEndpointMap(); result.addAll(endpointMap.keySet()); return result; } /** * Test hook that returns a list of server names (host+port); one for each server we are currently * connected to. */ public List getCurrentServerNames() { List servers = getCurrentServers(); ArrayList result = new ArrayList(servers.size()); Iterator it = servers.iterator(); while (it.hasNext()) { ServerLocation sl = (ServerLocation) it.next(); String name = sl.getHostName() + sl.getPort(); result.add(name); } return result; } public EndpointManager getEndpointManager() { return endpointManager; } /** * Fetch the connection source for this pool * * @return the source */ public ConnectionSource getConnectionSource() { return source; } private static void setTEST_DURABLE_IS_NET_DOWN(boolean v) { TEST_DURABLE_IS_NET_DOWN = v; } /** * test hook */ public void endpointsNetDownForDUnitTest() { logger.debug("PoolImpl - endpointsNetDownForDUnitTest"); setTEST_DURABLE_IS_NET_DOWN(true); try { java.lang.Thread.sleep(this.pingInterval * 2); } catch (java.lang.InterruptedException ex) { // do nothing. } Map endpoints = endpointManager.getEndpointMap(); for (Iterator itr = endpoints.values().iterator(); itr.hasNext();) { Endpoint endpoint = (Endpoint) itr.next(); logger.debug("PoolImpl Simulating crash of endpoint {}", endpoint); endpointManager.serverCrashed(endpoint); } } /** * test hook */ public void endpointsNetUpForDUnitTest() { setTEST_DURABLE_IS_NET_DOWN(false); try { java.lang.Thread.sleep(this.pingInterval * 2); } catch (java.lang.InterruptedException ex) { // do nothing. } } /** * test hook */ public int getInvalidateCount() { return ((QueueStateImpl) this.queueManager.getState()).getInvalidateCount(); } /** * Set the connection held by this thread if we're using thread local connections * * This is a a hook for hydra code to pass thread local connections between threads. */ public void setThreadLocalConnection(Connection conn) { executor.setThreadLocalConnection(conn); } public ServerLocation getServerAffinityLocation() { return executor.getServerAffinityLocation(); } public void setServerAffinityLocation(ServerLocation serverLocation) { executor.setServerAffinityLocation(serverLocation); } public ServerLocation getNextOpServerLocation() { return executor.getNextOpServerLocation(); } /** * Test hook for getting the client proxy membership id from this proxy. */ public ClientProxyMembershipID getProxyID() { return proxyId; } public void emergencyClose() { destroyed = true; manager.emergencyClose(); queueManager.emergencyClose(); } ///////////////////// start test hooks /////////////////////// /** * A debug flag used for testing used in ClientServerObserver */ public static volatile boolean AFTER_PRIMARY_IDENTIFICATION_FROM_BACKUP_CALLBACK_FLAG = false; /** * A debug flag used for testing used in ClientServerObserver */ public static volatile boolean BEFORE_REGISTER_CALLBACK_FLAG = false; /** * A debug flag used for testing used in ClientServerObserver */ public static volatile boolean BEFORE_RECOVER_INTEREST_CALLBACK_FLAG = false; /** * A debug flag used for testing used in ClientServerObserver */ public static volatile boolean AFTER_REGISTER_CALLBACK_FLAG = false; /** * A debug flag used for testing used in ClientServerObserver */ public static volatile boolean BEFORE_PRIMARY_IDENTIFICATION_FROM_BACKUP_CALLBACK_FLAG = false; /** * A debug flag used for testing used in ClientServerObserver */ public static volatile boolean BEFORE_SENDING_CLIENT_ACK_CALLBACK_FLAG = false; /** * A debug flag used for testing used in ClientServerObserver */ public static volatile boolean AFTER_QUEUE_DESTROY_MESSAGE_FLAG = false; /** * Test hook flag to notify observer(s) that a primary is recovered either from a backup or from a * new connection. */ public static volatile boolean AFTER_PRIMARY_RECOVERED_CALLBACK_FLAG = false; public static abstract class PoolTask implements Runnable { public final void run() { try { run2(); } catch (VirtualMachineError e) { SystemFailure.initiateFailure(e); throw e; } catch (CancelException e) { // throw e; if (logger.isDebugEnabled()) { logger.debug("Pool task <{}> cancelled", this, logger.isTraceEnabled() ? e : null); } } catch (Throwable t) { logger.error(LocalizedMessage .create(LocalizedStrings.PoolImpl_UNEXPECTED_ERROR_IN_POOL_TASK_0, this), t); } } public abstract void run2(); } ///////////////////// end test hooks /////////////////////// protected class PublishClientStatsTask extends PoolTask { @Override public void run2() { ClientStatsManager.publishClientStats(PoolImpl.this); } } /** * A cancel criterion that checks both the pool and the cache for canceled status. */ protected class PoolOrCacheStopper extends CancelCriterion { @Override public String cancelInProgress() { return getPoolOrCacheCancelInProgress(); } @Override public RuntimeException generateCancelledException(Throwable e) { return generatePoolOrCacheCancelledException(e); } } /** * A cancel criterion that checks only if this pool has been closed. This is necessary because * there are some things that we want to allow even after the cache has started closing. */ protected class Stopper extends CancelCriterion { @Override public String cancelInProgress() { if (destroyed) { return "Pool " + PoolImpl.this + " is shut down"; } else { return null; } } @Override public RuntimeException generateCancelledException(Throwable t) { String reason = cancelInProgress(); if (reason == null) { return null; } return new PoolCancelledException(reason, t); } } public static void loadEmergencyClasses() { QueueManagerImpl.loadEmergencyClasses(); ConnectionManagerImpl.loadEmergencyClasses(); EndpointManagerImpl.loadEmergencyClasses(); } /** * Returns the QueryService, that can be used to execute Query functions on the servers associated * with this pool. * * @return the QueryService */ public QueryService getQueryService() { Cache cache = CacheFactory.getInstance(InternalDistributedSystem.getAnyInstance()); DefaultQueryService queryService = new DefaultQueryService((InternalCache) cache); queryService.setPool(this); return queryService; } public RegionService createAuthenticatedCacheView(Properties properties) { if (!this.multiuserSecureModeEnabled) { throw new UnsupportedOperationException( "Operation not supported when multiuser-authentication is false."); } if (properties == null || properties.isEmpty()) { throw new IllegalArgumentException("Security properties cannot be empty."); } Cache cache = CacheFactory.getInstance(InternalDistributedSystem.getAnyInstance()); Properties props = new Properties(); for (Entry entry : properties.entrySet()) { props.setProperty((String) entry.getKey(), (String) entry.getValue()); } ProxyCache proxy = new ProxyCache(props, (GemFireCacheImpl) cache, this); synchronized (this.proxyCacheList) { this.proxyCacheList.add(proxy); } return proxy; } private volatile CancelCriterion cacheCriterion = null; private RuntimeException generatePoolOrCacheCancelledException(Throwable e) { RuntimeException re = getCancelCriterion().generateCancelledException(e); if (re != null) { return re; } Cache cache = GemFireCacheImpl.getInstance(); if (cache == null) { if (cacheCriterion != null) { return cacheCriterion.generateCancelledException(e); } } else { if (cacheCriterion == null) { cacheCriterion = cache.getCancelCriterion(); } else if (cacheCriterion != cache.getCancelCriterion()) { /* * If the cache instance has somehow changed, we need to get a reference to the new * criterion. This is pretty unlikely because the cache closes all the pools when it shuts * down, but I wanted to be safe. */ cacheCriterion = cache.getCancelCriterion(); } return cacheCriterion.generateCancelledException(e); } return null; } public String getPoolOrCacheCancelInProgress() { String reason = null; try { reason = getCancelCriterion().cancelInProgress(); if (reason != null) { return reason; } Cache cache = GemFireCacheImpl.getInstance(); if (cache == null) { if (cacheCriterion != null) { return cacheCriterion.cancelInProgress(); } return null; } else { if (cacheCriterion == null) { cacheCriterion = cache.getCancelCriterion(); } else if (cacheCriterion != cache.getCancelCriterion()) { /* * If the cache instance has somehow changed, we need to get a reference to the new * criterion. This is pretty unlikely because the cache closes all the pools when it shuts * down, but I wanted to be safe. */ cacheCriterion = cache.getCancelCriterion(); } return cacheCriterion.cancelInProgress(); } } catch (CancelException cce) { if (cce.getMessage() != null) { return cce.getMessage(); } else { return "cache is closed"; } } } public boolean getKeepAlive() { GemFireCacheImpl cache = GemFireCacheImpl.getInstance(); if (cache == null) { return keepAlive; } return cache.keepDurableSubscriptionsAlive(); } public ArrayList getProxyCacheList() { return this.proxyCacheList; } private void authenticateIfRequired(Op op) { authenticateIfRequired(null, op); } /** * Assert thread-local var is not null, if it has multiuser-authentication set to true. * * If serverLocation is non-null, check if the the user is authenticated on that server. If not, * authenticate it and return. * * @param serverLocation * @param op */ private void authenticateIfRequired(ServerLocation serverLocation, Op op) { if (this.multiuserSecureModeEnabled && op instanceof AbstractOp && ((AbstractOp) op).needsUserId()) { UserAttributes userAttributes = UserAttributes.userAttributes.get(); if (userAttributes == null) { throw new UnsupportedOperationException( LocalizedStrings.MultiUserSecurityEnabled_USE_POOL_API.toLocalizedString()); } if (serverLocation != null) { if (!userAttributes.getServerToId().containsKey(serverLocation)) { Long userId = (Long) AuthenticateUserOp.executeOn(serverLocation, this, userAttributes.getCredentials()); if (userId != null) { userAttributes.setServerToId(serverLocation, userId); } } } } } private void authenticateOnAllServers(Op op) { if (this.multiuserSecureModeEnabled && ((AbstractOp) op).needsUserId()) { UserAttributes userAttributes = UserAttributes.userAttributes.get(); if (userAttributes != null) { ConcurrentHashMap map = userAttributes.getServerToId(); if (this.queueManager == null) { throw new SubscriptionNotEnabledException(); } Connection primary = this.queueManager.getAllConnectionsNoWait().getPrimary(); if (primary != null && !map.containsKey(primary.getServer())) { Long userId = (Long) AuthenticateUserOp.executeOn(primary.getServer(), this, userAttributes.getCredentials()); if (userId != null) { map.put(primary.getServer(), userId); } } List backups = this.queueManager.getAllConnectionsNoWait().getBackups(); for (int i = 0; i < backups.size(); i++) { Connection conn = backups.get(i); if (!map.containsKey(conn.getServer())) { Long userId = (Long) AuthenticateUserOp.executeOn(conn.getServer(), this, userAttributes.getCredentials()); if (userId != null) { map.put(conn.getServer(), userId); } } } } else { throw new UnsupportedOperationException( LocalizedStrings.MultiUserSecurityEnabled_USE_POOL_API.toLocalizedString()); } } } public void setPendingEventCount(int count) { this.primaryQueueSize.set(count); } public int getPendingEventCount() { if (!isDurableClient() || this.queueManager == null) { throw new IllegalStateException( LocalizedStrings.PoolManagerImpl_ONLY_DURABLE_CLIENTS_SHOULD_CALL_GETPENDINGEVENTCOUNT .toLocalizedString()); } if (this.readyForEventsCalled) { throw new IllegalStateException( LocalizedStrings.PoolManagerImpl_GETPENDINGEVENTCOUNT_SHOULD_BE_CALLED_BEFORE_INVOKING_READYFOREVENTS .toLocalizedString()); } return this.primaryQueueSize.get(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy