gt:         if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
context: /*******************************************************************************
   * Copyright (c) 2011, 2021 IBM Corporation and others.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package com.ibm.ws.sib.jfapchannel.impl.octracker;
  
  import java.net.InetSocketAddress;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  
  import com.ibm.ejs.ras.TraceNLS;
  import com.ibm.websphere.ras.Tr;
  import com.ibm.websphere.ras.TraceComponent;
  import com.ibm.websphere.sib.exception.SIErrorException;
  import com.ibm.websphere.sib.exception.SIResourceException;
  import com.ibm.ws.ffdc.FFDCFilter;
  import com.ibm.ws.sib.jfapchannel.Conversation;
  import com.ibm.ws.sib.jfapchannel.ConversationReceiveListener;
  import com.ibm.ws.sib.jfapchannel.ConversationUsageType;
  import com.ibm.ws.sib.jfapchannel.JFapChannelConstants;
  import com.ibm.ws.sib.jfapchannel.framework.Framework;
  import com.ibm.ws.sib.jfapchannel.framework.FrameworkException;
  import com.ibm.ws.sib.jfapchannel.framework.NetworkConnectionFactory;
  import com.ibm.ws.sib.jfapchannel.framework.NetworkTransportFactory;
  import com.ibm.ws.sib.jfapchannel.impl.Connection;
  import com.ibm.ws.sib.jfapchannel.impl.OutboundConnection;
  import com.ibm.ws.sib.utils.RuntimeInfo;
  import com.ibm.ws.sib.utils.ras.SibTr;
  
  /**
   * Keeps track of established outbound connections. The tracker class exists
   * to facilitate managing multiplexing multiple conversations over a smaller
   * set of connections.
   * <p>
   * The tracker is backed by the IdleConnectionPool class which acts as a repository
   * for connections not currently in use. When a new conversation is requested, we may
   * query this pool to see if it already contains a suitable connection. When we finish
   * using a connection it may be returned to the idle pool.
   * <p>
   * Despite the name, the connection tracker actually tracks groups of connection, rather
   * than dealing in individual connections. This is because, depending on the number of
   * conversations we want to multiplex over a connection, we may potentially need several
   * connections to the same remote host.
   * 
   * @see com.ibm.ws.sib.jfapchannel.impl.octracker.ConnectionDataGroup
   * @see com.ibm.ws.sib.jfapchannel.impl.octracker.IdleConnectionPool
   */
  public class OutboundConnectionTracker
  {
      private static final TraceComponent tc = SibTr.register(OutboundConnectionTracker.class, JFapChannelConstants.MSG_GROUP, JFapChannelConstants.MSG_BUNDLE);
  
      static
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
              SibTr.debug(tc,
                          "@(#) SIB/ws/code/sib.jfapchannel.client.common.impl/src/com/ibm/ws/sib/jfapchannel/impl/octracker/OutboundConnectionTracker.java, SIB.comms, WASX.SIB, uu1215.01 1.39");
      }
  
      private static final TraceNLS nls = TraceNLS.getTraceNLS(JFapChannelConstants.MSG_BUNDLE); // D226223
  
      // Number of (non-cloned) conversations that can share the same
      // the same underlying connection.
      private int conversationsPerConnection;
  
      // Maps end point descriptors to connection groups.  This is the main data-structure
      // backing the connection tracker.  It allows us to get a connection group from a
      // description of the machine we want to connect to.
      private final HashMap<EndPointDescriptor, ConnectionDataGroup> endPointToGroupMap =
                      new HashMap<EndPointDescriptor, ConnectionDataGroup>();
  
      // Reference to the JFap transport framework - used when establishing connections using the
      // overloaded form of "connect" which accepts a host, port and chain name.
      private Framework framework;
  
      private final BridgeServiceEndPointDescriptor bridgeServiceDescriptor = new BridgeServiceEndPointDescriptor(); // D259087
  
      private final LinkedList<OutboundConnection> closeList = new LinkedList<OutboundConnection>();
  
      /**
       * End point descriptor for CFEndPoint style of endpoints. This is
       * a representation of something we want to connect to.
       */
      private class CFEndPointDescriptor extends EndPointDescriptor
      {
          private final Object endPoint;
          private final Conversation.ConversationType convType;
  
          protected CFEndPointDescriptor(Object cfEndPoint, Conversation.ConversationType convType)
          {
              this.endPoint = cfEndPoint;
              this.convType = convType;
          }
  
          @Override
          public boolean equals(Object o)
          {
              // CFW CFEndPoints do not implement equals() * sigh *. As such we have to do it ourselves
              // but this cannot be done here as we are in framework agnostic land. We must therefore
              // delegate to the current framework which knows about the specific EP types and can
              // work out whether the EP's are equal
              boolean isEqual = false;
              if (o instanceof CFEndPointDescriptor)
              {
                  CFEndPointDescriptor cfDescriptor = (CFEndPointDescriptor) o;
                  isEqual = framework.areEndPointsEqual(cfDescriptor.endPoint, this.endPoint) &&
                            cfDescriptor.convType == this.convType;
  
              }
  
              return isEqual;
          }
  
          // Start D240362
          @Override
          public int hashCode()
          {
              return framework.getEndPointHashCode(this.endPoint) ^
                     this.convType.hashCode();
          }
  
          @Override
          public String toString()
          {
              return "CFEndPointDescriptor@" + Integer.toHexString(System.identityHashCode(this)) +
                     ": " + endPoint + " -> " + convType;
          }
          // End D240362
      }
  
      /**
       * End point descriptor for host/port style of endpoints. This
       * is a representation of something we want to connect to.
       */
      private static class HostPortEndPointDescriptor extends EndPointDescriptor
      {
          private final InetSocketAddress address;
          private final String chainName;
          private final Conversation.ConversationType convType;
  
          protected HostPortEndPointDescriptor(InetSocketAddress address,
                                               String chainName,
                                               Conversation.ConversationType convType)
          {
              this.address = address;
              this.chainName = chainName;
              this.convType = convType;
          }
  
          @Override
          public boolean equals(Object o)
          {
              boolean isEqual = false;
              if (o instanceof HostPortEndPointDescriptor)
              {
                  HostPortEndPointDescriptor hped = (HostPortEndPointDescriptor) o;
                  isEqual = (hped.address.equals(address)) &&
                            (hped.chainName.equals(chainName)) &&
                            (hped.convType == convType);
              }
              return isEqual;
          }
  
          @Override
          public int hashCode()
          {
              return address.hashCode() ^ chainName.hashCode() ^ convType.hashCode();
          }
  
          @Override
          public String toString()
          {
              return "HostPortEndPointDescriptor@" + Integer.toHexString(System.identityHashCode(this)) +
                     ": " + address + ":" + chainName + " -> " + convType;
          }
      }
  
      // begin F244595
      private static class BridgeServiceEndPointDescriptor extends EndPointDescriptor
      {}
  
      // end F244595
  
      /**
       * Creates a new instance of the outbound connection tracker.
       * 
       * @param channelFramework A reference to the channel framework.
       */
      public OutboundConnectionTracker(Framework channelFramework) // F196678.10
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(this, tc, "<init>", channelFramework);
  
          this.framework = channelFramework;
  
          // Determine how many conversations we should multiplex over the same
          // connection before starting a new connection.
          conversationsPerConnection = JFapChannelConstants.DEFAULT_CONVERSATIONS_PER_CONN; // D258248
          try
          {
              conversationsPerConnection =
                              Integer.parseInt(RuntimeInfo.getProperty("com.ibm.ws.sib.jfapchannel.CONVERSATIONS_PER_CONNECTION"));
          } catch (NumberFormatException nfe)
          {
              // No FFDC code needed
          }
          if (conversationsPerConnection < 1)
              conversationsPerConnection = 1;
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
              SibTr.debug(this, tc, "conversationsPerConnection=" + conversationsPerConnection);
  
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.exit(this, tc, "<init>");
      }
  
      /**
       * Gets a list of all the active conversations known about by the outbound connection tracker.
       * 
       * @return Returns a list
       */
      @SuppressWarnings("unchecked")
      public List getAllOutboundConversations()
      {
          if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled())
              SibTr.entry(this, tc, "getAllOutboundConversations");
  
          final List<Conversation> result = new ArrayList<Conversation>();
          final HashMap<EndPointDescriptor, ConnectionDataGroup> endPointToGroupMapClone;
  
          //Clone endPointToGroupMap to minimize amount of time we hold its monitor.
          synchronized (endPointToGroupMap)
          {
              endPointToGroupMapClone = (HashMap<EndPointDescriptor, ConnectionDataGroup>) endPointToGroupMap.clone();
          }
  
          for (final Iterator groupIterator = endPointToGroupMapClone.values().iterator(); groupIterator.hasNext();)
          {
              final ConnectionDataGroup group = (ConnectionDataGroup) groupIterator.next();
  
              //Don't need to get the monitor of ConnectionDataGroup in order to perform this action.
              final List connectionData = group.getConnections();
  
              for (final Iterator connectionDataIterator = connectionData.iterator(); connectionDataIterator.hasNext();)
              {
                  final ConnectionData thisConnectionData = (ConnectionData) connectionDataIterator.next();
                  final Connection connection = thisConnectionData.getConnection();
  
                  // Now get all the conversations on the link
                  final Conversation[] conversationArray = connection.getConversations();
                  for (Conversation conv : conversationArray)
                  {
                      if (conv != null)
                          result.add(conv);
                  }
              }
          }
  
  