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

com.gemstone.gemfire.cache.client.internal.ConnectionFactoryImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed 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. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.cache.client.internal;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;

import com.gemstone.gemfire.CancelCriterion;
import com.gemstone.gemfire.cache.GatewayConfigurationException;
import com.gemstone.gemfire.cache.client.ServerRefusedConnectionException;
import com.gemstone.gemfire.cache.client.internal.ServerBlackList.FailureTracker;
import com.gemstone.gemfire.cache.wan.GatewaySender;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.distributed.PoolCancelledException;
import com.gemstone.gemfire.distributed.internal.ServerLocation;
import com.gemstone.gemfire.i18n.LogWriterI18n;
import com.gemstone.gemfire.internal.cache.PoolManagerImpl;
import com.gemstone.gemfire.internal.cache.tier.Acceptor;
import com.gemstone.gemfire.internal.cache.tier.sockets.CacheClientUpdater;
import com.gemstone.gemfire.internal.cache.tier.sockets.ClientProxyMembershipID;
import com.gemstone.gemfire.internal.cache.tier.sockets.HandShake;
import com.gemstone.gemfire.internal.cache.wan.GatewaySenderConfigurationException;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.security.GemFireSecurityException;

/**
 * Creates connections, using a connection source to determine
 * which server to connect to.
 * @author dsmith
 * @since 5.7
 * 
 */
public class ConnectionFactoryImpl implements ConnectionFactory {
  
  //TODO  - the handshake holds state. It seems like the code depends 
  //on all of the handshake operations happening in a single thread. I don't think we
  //want that, need to refactor.
  private final HandShake handshake;
  private final int socketBufferSize;
  private final int handShakeTimeout;
  private final LogWriterI18n logger;
  private final boolean usedByGateway;
  private final ServerBlackList blackList;
  private final CancelCriterion cancelCriterion;
  private ConnectionSource source;
  private int readTimeout;
  private DistributedSystem ds;
  private EndpointManager endpointManager;
  private GatewaySender gatewaySender;
  
  /**
   * Test hook for client version support
   * @since 5.7
   */
  
  public static boolean testFailedConnectionToServer = false;
    
  public ConnectionFactoryImpl(ConnectionSource source,
      EndpointManager endpointManager, DistributedSystem sys,
      int socketBufferSize, int handShakeTimeout, int readTimeout,
      LogWriterI18n logger, ClientProxyMembershipID proxyId,
      CancelCriterion cancelCriterion, boolean usedByGateway,GatewaySender sender,
      long pingInterval, boolean multiuserSecureMode) {
    this.handshake = new HandShake(proxyId, sys);
    this.handshake.setClientReadTimeout(readTimeout);
    this.source = source;
    this.endpointManager = endpointManager;
    this.ds = sys;
    this.socketBufferSize = socketBufferSize;
    this.handShakeTimeout = handShakeTimeout;
    this.handshake.setMultiuserSecureMode(multiuserSecureMode);
    this.readTimeout = readTimeout;
    this.logger = logger;
    this.usedByGateway = usedByGateway;
    this.gatewaySender = sender;
    this.blackList = new ServerBlackList(logger, pingInterval);
    this.cancelCriterion = cancelCriterion;
  }
  
  public void start(ScheduledExecutorService background) {
    blackList.start(background);
  }

  private byte getCommMode(boolean forQueue) {
    if (this.usedByGateway || (this.gatewaySender != null)) {
      return Acceptor.GATEWAY_TO_GATEWAY;
    } else if(forQueue) {
      return Acceptor.CLIENT_TO_SERVER_FOR_QUEUE;
    } else {
      return Acceptor.CLIENT_TO_SERVER;
    }
  }
  
  public ServerBlackList getBlackList() { 
    return blackList;
  }
  
  public Connection createClientToServerConnection(ServerLocation location, boolean forQueue)  throws GemFireSecurityException {
    ConnectionImpl connection = new ConnectionImpl(logger, this.ds, this.cancelCriterion);
    FailureTracker failureTracker = blackList.getFailureTracker(location);
    
    boolean initialized = false;
    
    try {
      //ds.getLogWriter().warning("CREATING CLIENT SERVER:"+location,new Exception());
      HandShake connHandShake = new HandShake(handshake);
      connection.connect(endpointManager, location, connHandShake,
                         socketBufferSize, handShakeTimeout, readTimeout, getCommMode(forQueue), this.gatewaySender);
      failureTracker.reset();
      connection.setHandShake(connHandShake);
      authenticateIfRequired(connection);
      initialized = true;
    } catch(GemFireSecurityException e) {
      //propagate this up, don't retry
      throw e;
    } catch(GatewayConfigurationException e) {
    //propagate this up, don't retry
      throw e;
    } catch(ServerRefusedConnectionException src) {
      //propagate this up, don't retry      	
      logger.warning(LocalizedStrings.AutoConnectionSourceImpl_COULD_NOT_CREATE_A_NEW_CONNECTION_TO_SERVER_0, src.getMessage());
      testFailedConnectionToServer = true;
      throw src;
    } catch (Exception e) {
      if(logger.fineEnabled()) {
        if (e.getMessage() != null &&
            e.getMessage().equals("Connection refused")) { // this is the most common case, so don't print an exception
          logger.fine("Unable to connect to " + location + ": connection refused");
        } else {
          logger.fine("Error attempting to connect to " + location + ": ", e);
        }
      }
      testFailedConnectionToServer = true;
    } finally {
      if(!initialized) {
        connection.destroy();
        failureTracker.addFailure();
        connection = null;
      }
    }
    
    return connection;
  }

  private void authenticateIfRequired(Connection conn) {
    PoolImpl pool = (PoolImpl)PoolManagerImpl.getPMI().find(
        this.endpointManager.getPoolName());
    if (pool == null) {
      throw new PoolCancelledException(
          LocalizedStrings.ConnectionFactoryImpl_POOL_0_IS_NOT_AVAILABLE
              .toString(new Object[] { this.endpointManager.getPoolName() }));
    }
    if (!pool.isUsedByGateway() && !pool.getMultiuserAuthentication()) {
      if (conn.getServer().getRequiresCredentials()) {
        if (conn.getServer().getUserId() == -1) {
          Long uniqueID = (Long)AuthenticateUserOp.executeOn(conn, pool);
          conn.getServer().setUserId(uniqueID);
          if (logger.fineEnabled()) {
            logger.fine("CFI.authenticateIfRequired() Completed authentication on " + conn);
          }
        }
      }
    }
  }

  public ServerLocation findBestServer(ServerLocation currentServer, Set excludedServers) {
    if (currentServer != null && source.isBalanced()) {
      return currentServer;
    }
    final Set origExcludedServers = excludedServers;
    excludedServers = new HashSet(excludedServers);
    Set blackListedServers = blackList.getBadServers();  
    excludedServers.addAll(blackListedServers);
    ServerLocation server = source.findReplacementServer(currentServer, excludedServers);
    if (server == null) {
      // Nothing worked! Let's try without the blacklist.
      if (excludedServers.size() > origExcludedServers.size()) {
        // We had some guys black listed so lets give this another whirl.
        server = source.findReplacementServer(currentServer, origExcludedServers);
      }
    }
    if (server == null) {
      logger.fine("Source was unable to findForReplacement any servers");
    }
    return server;
  }
  
  public Connection createClientToServerConnection(Set excludedServers) throws GemFireSecurityException {
    final Set origExcludedServers = excludedServers;
    excludedServers = new HashSet(excludedServers);
    Set blackListedServers = blackList.getBadServers();  
    excludedServers.addAll(blackListedServers);
    Connection conn = null;
//    long startTime = System.currentTimeMillis();
    RuntimeException fatalException = null;
    boolean tryBlackList = true;
    
    do {
      ServerLocation server = source.findServer(excludedServers);
      if(server == null) {
        
        if(tryBlackList) {
          // Nothing worked! Let's try without the blacklist.
          tryBlackList = false;
          int size = excludedServers.size();
          excludedServers.removeAll(blackListedServers);
          // make sure we didn't remove any of the ones that the caller set not to use
          excludedServers.addAll(origExcludedServers);
          if(excludedServers.size()




© 2015 - 2024 Weber Informatics LLC | Privacy Policy