/**
   * 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;
  }