/**
   * Returns true if the server has the given tags. A server of either type {@code
   * ServerType.STANDALONE} or {@code ServerType.SHARD_ROUTER} is considered to have all tags, so
   * this method will always return true for instances of either of those types.
   *
   * @param desiredTags the tags
   * @return true if this server has the given tags
   */
  public boolean hasTags(final TagSet desiredTags) {
    if (!ok) {
      return false;
    }

    if (type == STANDALONE || type == SHARD_ROUTER) {
      return true;
    }

    return tagSet.containsAll(desiredTags);
  }
 /**
  * Returns a short, pretty description for this ServerDescription.
  *
  * @return a String containing the most pertinent information about this ServerDescription
  */
 public String getShortDescription() {
   return "{"
       + "address="
       + address
       + ", type="
       + type
       + (!tagSet.iterator().hasNext() ? "" : ", " + tagSet)
       + (state == CONNECTED
           ? (", roundTripTime=" + getRoundTripFormattedInMilliseconds() + " ms")
           : "")
       + ", state="
       + state
       + (exception == null ? "" : ", exception=" + translateExceptionToString())
       + '}';
 }
 @Override
 public int hashCode() {
   int result = address.hashCode();
   result = 31 * result + type.hashCode();
   result = 31 * result + (canonicalAddress != null ? canonicalAddress.hashCode() : 0);
   result = 31 * result + hosts.hashCode();
   result = 31 * result + passives.hashCode();
   result = 31 * result + arbiters.hashCode();
   result = 31 * result + (primary != null ? primary.hashCode() : 0);
   result = 31 * result + maxDocumentSize;
   result = 31 * result + tagSet.hashCode();
   result = 31 * result + (setName != null ? setName.hashCode() : 0);
   result = 31 * result + (electionId != null ? electionId.hashCode() : 0);
   result = 31 * result + (setVersion != null ? setVersion.hashCode() : 0);
   result = 31 * result + (ok ? 1 : 0);
   result = 31 * result + state.hashCode();
   result = 31 * result + version.hashCode();
   result = 31 * result + minWireVersion;
   result = 31 * result + maxWireVersion;
   result = 31 * result + (exception == null ? 0 : exception.getClass().hashCode());
   result = 31 * result + (exception == null ? 0 : exception.getMessage().hashCode());
   return result;
 }
  /**
   * Returns true if this instance is equals to @code{o}. Note that equality is defined to NOT
   * include the round trip time.
   *
   * @param o the object to compare to
   * @return true if this instance is equals to @code{o}
   */
  @Override
  public boolean equals(final Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    ServerDescription that = (ServerDescription) o;

    if (maxDocumentSize != that.maxDocumentSize) {
      return false;
    }
    if (ok != that.ok) {
      return false;
    }
    if (!address.equals(that.address)) {
      return false;
    }
    if (!arbiters.equals(that.arbiters)) {
      return false;
    }
    if (canonicalAddress != null
        ? !canonicalAddress.equals(that.canonicalAddress)
        : that.canonicalAddress != null) {
      return false;
    }
    if (!hosts.equals(that.hosts)) {
      return false;
    }
    if (!passives.equals(that.passives)) {
      return false;
    }
    if (primary != null ? !primary.equals(that.primary) : that.primary != null) {
      return false;
    }
    if (setName != null ? !setName.equals(that.setName) : that.setName != null) {
      return false;
    }
    if (state != that.state) {
      return false;
    }
    if (!tagSet.equals(that.tagSet)) {
      return false;
    }
    if (type != that.type) {
      return false;
    }
    if (!version.equals(that.version)) {
      return false;
    }
    if (minWireVersion != that.minWireVersion) {
      return false;
    }
    if (maxWireVersion != that.maxWireVersion) {
      return false;
    }
    if (electionId != null ? !electionId.equals(that.electionId) : that.electionId != null) {
      return false;
    }
    if (setVersion != null ? !setVersion.equals(that.setVersion) : that.setVersion != null) {
      return false;
    }

    // Compare class equality and message as exceptions rarely override equals
    Class<?> thisExceptionClass = exception != null ? exception.getClass() : null;
    Class<?> thatExceptionClass = that.exception != null ? that.exception.getClass() : null;
    if (thisExceptionClass != null
        ? !thisExceptionClass.equals(thatExceptionClass)
        : thatExceptionClass != null) {
      return false;
    }

    String thisExceptionMessage = exception != null ? exception.getMessage() : null;
    String thatExceptionMessage = that.exception != null ? that.exception.getMessage() : null;
    if (thisExceptionMessage != null
        ? !thisExceptionMessage.equals(thatExceptionMessage)
        : thatExceptionMessage != null) {
      return false;
    }

    return true;
  }