/**
  * Check whether the content type returned by the server is acceptable to the endpoint and data
  * provider
  */
 protected boolean isValidContentType(String contentType, Endpoint endpoint) {
   if (endpoint != null && endpoint.getContentTypes().size() > 0) {
     ContentType parsed = parseContentType(contentType);
     for (ContentType valid : endpoint.getContentTypes()) {
       if (valid.matches(parsed) || valid.matchesWildcard(parsed)) {
         return true;
       }
     }
     return false;
   } else {
     // TODO: should probably be removed, since it is not used
     for (String type : listMimeTypes()) {
       if (type.split(";")[0].equalsIgnoreCase(contentType)) return true;
     }
     return false;
   }
 }
    @Override
    public List<String> handleResponse(HttpResponse response)
        throws ClientProtocolException, IOException {
      ArrayList<String> requestUrls = new ArrayList<String>();

      if (response.getStatusLine().getStatusCode() >= 200
          && response.getStatusLine().getStatusCode() < 400) {
        final HttpEntity entity = response.getEntity();
        if (entity == null)
          throw new IOException("no content returned by Linked Data resource " + resource);

        if (!isValidContentType(entity.getContentType().getValue().split(";")[0], endpoint)) {
          // FIXME: here was get.abort()
          throw new IOException(
              "invalid content returned by Linked Data resource "
                  + resource
                  + ": "
                  + entity.getContentType().getValue());
        }

        this.httpStatus = response.getStatusLine().getStatusCode();

        if (entity != null) {
          String parseContentType = "application/rdf+xml";
          if (endpoint != null && "SPARQL".equals(endpoint.getType())) {
            parseContentType = "application/sparql-results+xml";
          } else if (entity.getContentType() != null) {
            parseContentType = entity.getContentType().getValue().split(";")[0];
          }

          InputStream in = entity.getContent();
          try {

            List<String> urls = parseResponse(resource, requestUrl, triples, in, parseContentType);
            requestUrls.addAll(urls);

            if (expiresDate == null) {
              Header expires = response.getFirstHeader("Expires");
              if (expires != null) {
                try {
                  expiresDate = DateUtils.parseDate(expires.getValue());
                } catch (DateParseException e) {
                  log.debug("error parsing Expires: header");
                }
              }
            }

          } catch (DataRetrievalException e) {
            // FIXME: get.abort();
            throw new IOException(e);
          } finally {
            in.close();
          }
        }
        EntityUtils.consume(entity);
      } else if (response.getStatusLine().getStatusCode() == 500
          || response.getStatusLine().getStatusCode() == 503
          || response.getStatusLine().getStatusCode() == 504) {
        this.httpStatus = response.getStatusLine().getStatusCode();

        Header retry = response.getFirstHeader("Retry-After");
        if (retry != null) {
          try {
            int duration = Integer.parseInt(retry.getValue());
            expiresDate = new Date(System.currentTimeMillis() + duration * 1000);
          } catch (NumberFormatException ex) {
            log.debug("error parsing Retry-After: header");
          }
        } else {
          expiresDate = new Date(System.currentTimeMillis() + RETRY_AFTER * 1000);
        }

      } else {
        log.error("the HTTP request failed (status: {})", response.getStatusLine());
        throw new ClientProtocolException(
            "the HTTP request failed (status: " + response.getStatusLine() + ")");
      }

      return requestUrls;
    }
  /**
   * Retrieve the data for a resource using the given http client and endpoint definition. The
   * service is supposed to manage the connection handling itself. See {@link AbstractHttpProvider}
   * for a generic implementation of this method.
   *
   * @param resource the resource to be retrieved
   * @param endpoint the endpoint definition
   * @return a completely specified client response, including expiry information and the set of
   *     triples
   */
  @Override
  public ClientResponse retrieveResource(String resource, LDClientService client, Endpoint endpoint)
      throws DataRetrievalException {

    try {

      String contentType;
      if (endpoint != null && endpoint.getContentTypes().size() > 0) {
        contentType =
            CollectionUtils.fold(
                endpoint.getContentTypes(),
                new CollectionUtils.StringSerializer<ContentType>() {
                  @Override
                  public String serialize(ContentType contentType) {
                    return contentType.toString("q");
                  }
                },
                ",");
      } else {
        contentType = CollectionUtils.fold(Arrays.asList(listMimeTypes()), ",");
      }

      long defaultExpires = client.getClientConfiguration().getDefaultExpiry();
      if (endpoint != null && endpoint.getDefaultExpiry() != null) {
        defaultExpires = endpoint.getDefaultExpiry();
      }

      final ResponseHandler handler = new ResponseHandler(resource, endpoint);

      // a queue for queuing the request URLs needed to build the query response
      Queue<String> requestUrls = new LinkedList<String>();
      requestUrls.addAll(buildRequestUrl(resource, endpoint));

      Set<String> visited = new HashSet<String>();

      String requestUrl = requestUrls.poll();
      while (requestUrl != null) {

        if (!visited.contains(requestUrl)) {
          HttpGet get = new HttpGet(requestUrl);
          try {
            get.setHeader("Accept", contentType);
            get.setHeader("Accept-Language", "*"); // PoolParty compatibility

            log.info(
                "retrieving resource data for {} from '{}' endpoint, request URI is <{}>",
                new Object[] {resource, getName(), get.getURI().toASCIIString()});

            handler.requestUrl = requestUrl;
            List<String> additionalRequestUrls = client.getClient().execute(get, handler);
            requestUrls.addAll(additionalRequestUrls);

            visited.add(requestUrl);
          } finally {
            get.releaseConnection();
          }
        }

        requestUrl = requestUrls.poll();
      }

      Date expiresDate = handler.expiresDate;
      if (expiresDate == null) {
        expiresDate = new Date(System.currentTimeMillis() + defaultExpires * 1000);
      }

      long min_expires =
          System.currentTimeMillis() + client.getClientConfiguration().getMinimumExpiry() * 1000;
      if (expiresDate.getTime() < min_expires) {
        log.info(
            "expiry time returned by request lower than minimum expiration time; using minimum time instead");
        expiresDate = new Date(min_expires);
      }

      if (log.isInfoEnabled()) {
        RepositoryConnection con = handler.triples.getConnection();
        log.info(
            "retrieved {} triples for resource {}; expiry date: {}",
            new Object[] {con.size(), resource, expiresDate});
        con.close();
      }

      ClientResponse result = new ClientResponse(handler.httpStatus, handler.triples);
      result.setExpires(expiresDate);
      return result;
    } catch (RepositoryException e) {
      log.error("error while initialising Sesame repository; classpath problem?", e);
      throw new DataRetrievalException(
          "error while initialising Sesame repository; classpath problem?", e);
    } catch (ClientProtocolException e) {
      log.error(
          "HTTP client error while trying to retrieve resource {}: {}", resource, e.getMessage());
      throw new DataRetrievalException(
          "I/O error while trying to retrieve resource " + resource, e);
    } catch (IOException e) {
      log.error("I/O error while trying to retrieve resource {}: {}", resource, e.getMessage());
      throw new DataRetrievalException(
          "I/O error while trying to retrieve resource " + resource, e);
    } catch (RuntimeException ex) {
      log.error(
          "Unknown error while trying to retrieve resource {}: {}", resource, ex.getMessage());
      throw new DataRetrievalException(
          "Unknown error while trying to retrieve resource " + resource, ex);
    }
  }