/**
   * Builds a web map server with the given server url, version and getCapabilities response.
   *
   * @param serverURL The server base url.
   * @param security The server security.
   * @param version A string representation of the service version.
   * @param capabilities A getCapabilities response.
   */
  public WebMapClient(
      final URL serverURL,
      final ClientSecurity security,
      WMSVersion version,
      final AbstractWMSCapabilities capabilities) {
    super(create(WMSClientFactory.PARAMETERS, serverURL, security));

    this.capabilities = capabilities;

    // if version is null, call getCapabilities to found service version
    if (version == null) {
      if (LOGGER.isLoggable(Level.FINE)) {
        LOGGER.log(Level.FINE, "No version define : search it on getCapabilities");
      }
      try {
        if (capabilities != null) {
          this.capabilities = capabilities;
        } else {
          this.capabilities = getCapabilities();
        }

        // set version
        version = WMSVersion.getVersion(this.capabilities.getVersion());
      } catch (CapabilitiesException e) {
        LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
        version = WMSVersion.v130;
      }
    }
    Parameters.getOrCreate(WMSClientFactory.VERSION, parameters).setValue(version.getCode());
  }
  /**
   * Returns the {@linkplain AbstractWMSCapabilities capabilities} response for this request if the
   * server answers before the specified timeout, otherwise throws a {@link CapabilitiesException}.
   *
   * @param timeout Timeout in milliseconds
   * @return {@linkplain AbstractWMSCapabilities capabilities} response but never {@code null}.
   * @throws CapabilitiesException
   */
  public AbstractWMSCapabilities getCapabilities(final long timeout) throws CapabilitiesException {

    if (capabilities != null) {
      return capabilities;
    }

    final CapabilitiesException[] exception = new CapabilitiesException[1];

    // Thread to prevent infinite request on a server
    final Thread thread =
        new Thread() {
          @Override
          public void run() {
            final GetCapabilitiesRequest getCaps = createGetCapabilities();

            // Filling the request header map from the map of the layer's server
            final Map<String, String> headerMap = getRequestHeaderMap();
            getCaps.getHeaderMap().putAll(headerMap);

            try {
              System.out.println(getCaps.getURL());
              capabilities =
                  WMSBindingUtilities.unmarshall(getCaps.getResponseStream(), getVersion());
            } catch (Exception ex) {
              capabilities = null;
              try {
                exception[0] =
                    new CapabilitiesException(
                        "Wrong URL, the server doesn't answer : "
                            + createGetCapabilities().getURL().toString(),
                        ex);
              } catch (MalformedURLException ex1) {
                exception[0] =
                    new CapabilitiesException("Malformed URL, the server doesn't answer. ", ex);
              }
            }
          }
        };

    thread.start();
    final long start = System.currentTimeMillis();
    try {
      thread.join(timeout);
    } catch (InterruptedException ex) {
      throw new CapabilitiesException("The thread to obtain GetCapabilities doesn't answer.");
    }

    if (exception[0] != null) {
      throw exception[0];
    }

    if ((System.currentTimeMillis() - start) > timeout) {
      throw new CapabilitiesException("TimeOut error, the server takes too much time to answer.");
    }

    // force throw CapabilitiesException if the returned capabilities object is null
    if (capabilities == null) {
      throw new CapabilitiesException("The capabilities document is null.");
    }

    WMSVersion version = WMSVersion.getVersion(this.capabilities.getVersion());
    Parameters.getOrCreate(WMSClientFactory.VERSION, parameters).setValue(version.getCode());
    return capabilities;
  }