docs: protected SSLContext getSSLContextForLink(VirtualConnection vc,
                                                String host, String port, String endPoint, Boolean isZWebContainerChain,
                                                SSLConnectionLink link) throws ChannelException {
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "host=" + host + " port=" + port + " endPoint=" + endPoint);
          }
  
          // Set up the parameters needed to call into the JSSEHelper to extract official SSL Props.
          String direction = (getConfig().isInbound()) ? Constants.DIRECTION_INBOUND : Constants.DIRECTION_OUTBOUND;
          final Map<String, Object> connectionInfo = new HashMap<String, Object>();
          connectionInfo.put(Constants.CONNECTION_INFO_DIRECTION, direction);
          connectionInfo.put(Constants.CONNECTION_INFO_REMOTE_HOST, host);
          connectionInfo.put(Constants.CONNECTION_INFO_REMOTE_PORT, port);
          connectionInfo.put(Constants.CONNECTION_INFO_ENDPOINT_NAME, endPoint);
  
          // PK40641 - handle channel props that do not need JSSEHelper
          Properties props = null;
          boolean useJSSEHelper = (null != this.alias);
          if (!useJSSEHelper) {
              // 436920 - check for ssl properties put programmatically on the thread.
              // Calling into JSSEHelper.getProperties() does this same action
              try {
                  props = AccessController.doPrivileged(new PrivilegedExceptionAction<Properties>() {
                      @Override
                      public Properties run() throws Exception {
                          return jsseHelper.getSSLPropertiesOnThread();
                      }
                  });
              } catch (Exception e) {
                  // no ffdc required
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Caught exception looking for on-thread props; e=" + e);
                  }
              }
              if (null == props || 0 == props.size()) {
                  // if alias is null, then if keystore and truststore are found then
                  // simply use the existing config properties. If either one is
                  // missing, call into the jssehelper for the default repertoire (null alias)
                  props = null;
                  useJSSEHelper = !getConfig().getProperties().containsKey(Constants.SSLPROP_KEY_STORE)
                                  || !getConfig().getProperties().containsKey(Constants.SSLPROP_TRUST_STORE);
              } else {
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Found on-thread ssl properties");
                  }
              }
          }
          if (useJSSEHelper) {
              try {
                  // Extract the official SSL props based on config information.
                  final String aliasFinal = this.alias;
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Querying security service for alias=[" + aliasFinal + "]");
                  }
                  props = AccessController.doPrivileged(new PrivilegedExceptionAction<Properties>() {
  
                      @Override
                      public Properties run() throws Exception {
                          return jsseHelper.getProperties(aliasFinal, connectionInfo, null);
                      }
                  });
              } catch (
  
              Exception e) {
                  // no FFDC required
                  if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                      Tr.debug(tc, "Exception getting SSL properties from alias: " + this.alias);
                  }
                  throw new ChannelException(e);
              }
          }
  
          // at this point, we have a set of properties to use, which might be
          // repertoire based or on-thread config... merge the channel props into
          // them without overwriting any
          if (null != props) {
              Enumeration<?> names = getConfig().getProperties().propertyNames();
              String key = null;
              String value = null;
              while (names.hasMoreElements()) {
                  key = (String) names.nextElement();
                  value = getConfig().getStringProperty(key);
                  if (null != value && !props.containsKey(key)) {
                      props.put(key, value);
                  }
              }
          } else {
              // otherwise we just use the channel config
              props = getConfig().getProperties();
          }
  
          // "SSSL" is a zOS repertoire type that is not supported by SSLChannel
          // We only support "JSSE"
          String sslType = (String) props.get(Constants.SSLPROP_SSLTYPE);
          if (null != sslType) {
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "SSLConfig type: " + sslType);
              }
              if (sslType.equals("SSSL")) {
                  throw new ChannelException("Invalid SSLConfig type: " + sslType);
              }
          }
  
          // if debug is enabled, print out the properties we're going to use
          if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
              Tr.debug(tc, "SSL configuration <null value means non-string>:");
              Enumeration<?> names = props.propertyNames();
              while (names.hasMoreElements()) {
                  String key = (String) names.nextElement();
                  String value = props.getProperty(key);
                  if (-1 == key.toLowerCase().indexOf("password")) {
                      Tr.debug(tc, "\t" + key + " = " + value);
                  } else {
                      // for nicer debug... print 1 * per character in the password
                      StringBuilder output = new StringBuilder(4 + key.length() + value.length());
                      output.append("\t").append(key).append(" = ");
                      for (int i = 0; i < value.length(); i++) {
                          output.append("*");
                      }
                      Tr.debug(tc, output.toString());
                  }
              }
          }
  
          SSLContext context = null;
          try {
              SSLConfig config = new SSLConfig(props);
              context = this.jsseProvider.getSSLContext(connectionInfo, config);
              SSLLinkConfig linkConfig = new SSLLinkConfig(props);
              if (null == link) {
                  // discrimination path
                  vc.getStateMap().put(SSLConnectionLink.LINKCONFIG, linkConfig);
              } else {
                  link.setLinkConfig(linkConfig);
              }
          } catch (Exception e) {
              // no FFDC required
              if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
                  Tr.debug(tc, "Exception getting SSLContext from properties.", new Object[] { e });
              }
              throw new ChannelException(e);
          }
          return context;
      }