public synchronized void logUnavailableHost(URL url) {
    if (this.offlineMode) return;

    if (url == null) {
      String message = Logging.getMessage("nullValue.URLIsNull");
      Logging.error(message);
      throw new IllegalArgumentException(message);
    }

    String hostName = url.getHost();
    HostInfo hi = this.hostMap.get(hostName);
    if (hi != null) {
      if (!hi.isUnavailable()) {
        hi.logCount.incrementAndGet();
        if (hi.isUnavailable()) // host just became unavailable
        this.firePropertyChange(NetworkStatus.HOST_UNAVAILABLE, null, url);
      }
      hi.lastLogTime.set(System.currentTimeMillis());
    } else {
      hi = new HostInfo(this.attemptLimit.get(), this.tryAgainInterval.get());
      hi.logCount.set(1);
      if (hi.isUnavailable()) // the attempt limit may be as low as 1, so handle that case here
      this.firePropertyChange(NetworkStatus.HOST_UNAVAILABLE, null, url);
      this.hostMap.put(hostName, hi);
    }

    this.lastUnavailableLogTime.set(System.currentTimeMillis());
  }
  public void setTryAgainInterval(long interval) {
    if (interval < 0) {
      String message = Logging.getMessage("NetworkStatus.InvalidTryAgainInterval");
      Logging.error(message);
      throw new IllegalArgumentException(message);
    }

    this.tryAgainInterval.set(interval);
  }
  public void setAttemptLimit(int limit) {
    if (limit < 1) {
      String message = Logging.getMessage("NetworkStatus.InvalidAttemptLimit");
      Logging.error(message);
      throw new IllegalArgumentException(message);
    }

    this.attemptLimit.set(limit);
  }
  // TODO: Consider implementing this method using Android's ConnectivityManager
  public synchronized boolean isNetworkUnavailable(long checkInterval) {
    if (this.offlineMode) return true;

    // If there's been success since failure, network assumed to be reachable.
    if (this.lastAvailableLogTime.get() > this.lastUnavailableLogTime.get()) {
      this.lastNetworkUnavailableResult.set(false);
      return this.lastNetworkUnavailableResult.get();
    }

    long now = System.currentTimeMillis();

    // If there's been success recently, network assumed to be reachable.
    if (!this.lastNetworkUnavailableResult.get()
        && now - this.lastAvailableLogTime.get() < checkInterval) {
      return this.lastNetworkUnavailableResult.get();
    }

    // If query comes too soon after an earlier one that addressed the network, return the earlier
    // result.
    if (now - this.lastNetworkCheckTime.get() < checkInterval) {
      return this.lastNetworkUnavailableResult.get();
    }

    this.lastNetworkCheckTime.set(now);

    if (!this.isWorldWindServerUnavailable()) {
      this.lastNetworkUnavailableResult.set(false); // network not unreachable
      return this.lastNetworkUnavailableResult.get();
    }

    for (String testHost : networkTestSites) {
      if (isHostReachable(testHost)) {
        {
          this.lastNetworkUnavailableResult.set(false); // network not unreachable
          return this.lastNetworkUnavailableResult.get();
        }
      }
    }

    if (now - this.lastNetworkStatusReportTime.get() > NETWORK_STATUS_REPORT_INTERVAL) {
      this.lastNetworkStatusReportTime.set(now);
      String message = Logging.getMessage("NetworkStatus.NetworkUnreachable");
      Logging.info(message);
    }

    this.lastNetworkUnavailableResult.set(
        true); // if no successful contact then network is unreachable
    return this.lastNetworkUnavailableResult.get();
  }
  public synchronized void logAvailableHost(URL url) {
    if (this.offlineMode) return;

    if (url == null) {
      String message = Logging.getMessage("nullValue.URLIsNull");
      Logging.error(message);
      throw new IllegalArgumentException(message);
    }

    String hostName = url.getHost();
    HostInfo hi = this.hostMap.get(hostName);
    if (hi != null) {
      this.hostMap.remove(hostName); // host is available again
      firePropertyChange(NetworkStatus.HOST_AVAILABLE, null, url);
    }

    this.lastAvailableLogTime.set(System.currentTimeMillis());
  }
  public boolean isHostUnavailable(URL url) {
    if (this.offlineMode) return true;

    if (url == null) {
      String message = Logging.getMessage("nullValue.URLIsNull");
      Logging.error(message);
      throw new IllegalArgumentException(message);
    }

    String hostName = url.getHost();
    HostInfo hi = this.hostMap.get(hostName);
    if (hi == null) return false;

    if (hi.isTimeToTryAgain()) {
      hi.logCount.set(0); // info removed from table in logAvailableHost
      return false;
    }

    return hi.isUnavailable();
  }
  /**
   * Determine if a host is reachable by attempting to resolve the host name, and then attempting to
   * open a connection.
   *
   * @param hostName Name of the host to connect to.
   * @return {@code true} if a the host is reachable, {@code false} if the host name cannot be
   *     resolved, or if opening a connection to the host fails.
   */
  protected static boolean isHostReachable(String hostName) {
    try {
      // Assume host is unreachable if we can't get its dns entry without getting an exception
      //noinspection ResultOfMethodCallIgnored
      InetAddress.getByName(hostName);
    } catch (UnknownHostException e) {
      String message = Logging.getMessage("NetworkStatus.UnreachableTestHost", hostName);
      Logging.verbose(message);
      return false;
    } catch (Exception e) {
      String message = Logging.getMessage("NetworkStatus.ExceptionTestingHost", hostName);
      Logging.verbose(message);
      return false;
    }

    // Was able to get internet address, but host still might not be reachable because the address
    // might have been
    // cached earlier when it was available. So need to try something else.

    URLConnection connection = null;
    try {
      URL url = new URL("http://" + hostName);
      Proxy proxy = WWIO.configureProxy();
      if (proxy != null) connection = url.openConnection(proxy);
      else connection = url.openConnection();

      connection.setConnectTimeout(2000);
      connection.setReadTimeout(2000);
      String ct = connection.getContentType();
      if (ct != null) return true;
    } catch (IOException e) {
      String message = Logging.getMessage("NetworkStatus.ExceptionTestingHost", hostName);
      Logging.info(message);
    } finally {
      if (connection instanceof HttpURLConnection) ((HttpURLConnection) connection).disconnect();
    }

    return false;
  }