public void checkPermission(
      ExtractorLayerRequest request, String secureHost, String username, String roles)
      throws IOException {
    URL capabilitiesURL = request.capabilitiesURL("WFS", "1.0.0");

    final HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
    httpClientBuilder.setUserAgent(this.userAgent);

    HttpClientContext localContext = HttpClientContext.create();
    final HttpHost httpHost =
        new HttpHost(
            capabilitiesURL.getHost(), capabilitiesURL.getPort(), capabilitiesURL.getProtocol());

    HttpGet get = new HttpGet(capabilitiesURL.toExternalForm());
    if (username != null
        && (secureHost.equalsIgnoreCase(request._url.getHost())
            || "127.0.0.1".equalsIgnoreCase(request._url.getHost())
            || "localhost".equalsIgnoreCase(request._url.getHost()))) {
      LOG.debug(
          "WfsExtractor.checkPermission - Secured Server: adding username header and role headers to request for checkPermission");

      addImpersonateUserHeaders(username, roles, get);

      enablePreemptiveBasicAuth(
          capabilitiesURL,
          httpClientBuilder,
          localContext,
          httpHost,
          _adminUsername,
          _adminPassword);
    } else {
      // use a user agent that does *not* trigger basic auth on remote server
      httpClientBuilder.setUserAgent("Apache-HttpClient");
      LOG.debug("WfsExtractor.checkPermission - Non Secured Server");
    }

    final CloseableHttpClient httpclient = httpClientBuilder.build();
    String capabilities =
        FileUtils.asString(
            httpclient.execute(httpHost, get, localContext).getEntity().getContent());
    Pattern regex =
        Pattern.compile(
            "(?m)<FeatureType[^>]*>(\\\\n|\\s)*<Name>\\s*(\\w*:)?"
                + Pattern.quote(request._layerName)
                + "\\s*</Name>");
    boolean permitted = regex.matcher(capabilities).find();

    if (!permitted) {
      throw new SecurityException(
          "User does not have sufficient privileges to access the Layer: "
              + request._layerName
              + ". \n\nCapabilities:  "
              + capabilities);
    }
  }
  /**
   * Extract the data as defined in the request object.
   *
   * @return the directory that contains the extracted file
   */
  public File extract(ExtractorLayerRequest request)
      throws IOException, TransformException, FactoryException {
    if (request._owsType != OWSType.WFS) {
      throw new IllegalArgumentException(request._owsType + "must be WFS for the WfsExtractor");
    }

    Map<String, Serializable> params = new HashMap<String, Serializable>();
    params.put(WFSDataStoreFactory.URL.key, request.capabilitiesURL("WFS", "1.0.0"));
    params.put(WFSDataStoreFactory.LENIENT.key, true);
    params.put(WFSDataStoreFactory.PROTOCOL.key, true);
    params.put(WFSDataStoreFactory.TIMEOUT.key, Integer.valueOf(60000));
    params.put(WFSDataStoreFactory.MAXFEATURES.key, Integer.valueOf(0));

    // HACK  I want unrestricted access to layers.
    // Security check takes place in ExtractorThread
    if (_secureHost.equalsIgnoreCase(request._url.getHost())
        || "127.0.0.1".equalsIgnoreCase(request._url.getHost())
        || "localhost".equalsIgnoreCase(request._url.getHost())) {
      LOG.debug(
          "WfsExtractor.extract - Secured Server: Adding extractionUserName to connection params");
      if (_adminUsername != null) params.put(WFSDataStoreFactory.USERNAME.key, _adminUsername);
      if (_adminPassword != null) params.put(WFSDataStoreFactory.PASSWORD.key, _adminPassword);
    } else {
      LOG.debug("WfsExtractor.extract - Non Secured Server");
    }

    DataStore sourceDs = DataStoreFinder.getDataStore(params);
    // WFS-ng: we need to convert the schema name

    String typeName = request.getWFSName();
    SimpleFeatureType sourceSchema = null;
    // prefixed typeName
    if (typeName.contains(":")) {
      typeName = typeName.replaceFirst(":", "_");
      sourceSchema = sourceDs.getSchema(typeName);
    }
    // Not prefixed one (mapserver ?)
    else {
      // Recreating the datastore forcing wfs 1.1.0, so that (presuming
      // the remote server is actually powered by MapServer), we would
      // have a typename prefixed with the same convention as before.
      params.put(WFSDataStoreFactory.URL.key, request.capabilitiesURL("WFS", "1.1.0"));
      // params.put(WFSDataStoreFactory.WFS_STRATEGY.key, "mapserver");
      sourceDs = DataStoreFinder.getDataStore(params);
      String[] typeNames = sourceDs.getTypeNames();
      for (String s : typeNames) {
        if (s.contains(typeName)) {
          typeName = s;
          sourceSchema = sourceDs.getSchema(s);
          // replace the expected typename in the request
          break;
        }
      }
      if (sourceSchema == null) {
        throw new IOException("Unable to find the remote layer " + typeName);
      }
    }

    Query query = createQuery(request, sourceSchema);
    SimpleFeatureCollection features = sourceDs.getFeatureSource(typeName).getFeatures(query);

    ProgressListener progressListener =
        new NullProgressListener() {
          @Override
          public void exceptionOccurred(Throwable exception) {
            throw new RuntimeException(exception);
          }
        };
    File basedir = request.createContainingDir(_basedir);

    basedir.mkdirs();

    FeatureWriterStrategy featuresWriter;
    BBoxWriter bboxWriter;
    LOG.debug("Number of features returned : " + features.size());
    if ("shp".equalsIgnoreCase(request._format)) {
      featuresWriter = new ShpFeatureWriter(progressListener, sourceSchema, basedir, features);
      bboxWriter =
          new BBoxWriter(
              request._bbox,
              basedir,
              OGRFeatureWriter.FileFormat.shp,
              request._projection,
              progressListener);
    } else if ("mif".equalsIgnoreCase(request._format)) {
      // featuresWriter = new MifFeatureWriter(progressListener, sourceSchema, basedir, features);
      featuresWriter =
          new OGRFeatureWriter(
              progressListener, sourceSchema, basedir, OGRFeatureWriter.FileFormat.mif, features);
      bboxWriter =
          new BBoxWriter(
              request._bbox,
              basedir,
              OGRFeatureWriter.FileFormat.mif,
              request._projection,
              progressListener);
    } else if ("tab".equalsIgnoreCase(request._format)) {
      featuresWriter =
          new OGRFeatureWriter(
              progressListener, sourceSchema, basedir, OGRFeatureWriter.FileFormat.tab, features);
      bboxWriter =
          new BBoxWriter(
              request._bbox,
              basedir,
              OGRFeatureWriter.FileFormat.tab,
              request._projection,
              progressListener);
    } else if ("kml".equalsIgnoreCase(request._format)) {
      featuresWriter =
          new OGRFeatureWriter(
              progressListener, sourceSchema, basedir, OGRFeatureWriter.FileFormat.kml, features);
      bboxWriter =
          new BBoxWriter(
              request._bbox,
              basedir,
              OGRFeatureWriter.FileFormat.kml,
              request._projection,
              progressListener);
    } else {
      throw new IllegalArgumentException(request._format + " is not a recognized vector format");
    }
    // generates the feature files and bbox file
    featuresWriter.generateFiles();

    bboxWriter.generateFiles();

    return basedir;
  }