cdm/src/main/java/ucar/nc2/ft/FeatureDatasetFactoryManager.java
static public FeatureDataset open(FeatureType wantFeatureType, String location, ucar.nc2.util.CancelTask task, Formatter errlog) throws IOException {

    // special processing for thredds: datasets
    if (location.startsWith(DataFactory.SCHEME)) {
      DataFactory.Result result = new DataFactory().openFeatureDataset(wantFeatureType, location, task);
      errlog.format("%s", result.errLog);
      if (!featureTypeOk(wantFeatureType, result.featureType)) {
        errlog.format("wanted %s but dataset is of type %s%n", wantFeatureType, result.featureType);
        result.close();
        return null;
      }
      return result.featureDataset;

      // special processing for cdmrFeature: datasets
    } else if (location.startsWith(CdmrFeatureDataset.SCHEME)) {
      Optional<FeatureDataset> opt = CdmrFeatureDataset.factory(wantFeatureType, location);
      if (opt.isPresent()) return opt.get();
      errlog.format("%s", opt.getErrorMessage());
      return null;

      // special processing for collection: datasets
    } else if (location.startsWith(ucar.nc2.ft.point.collection.CompositeDatasetFactory.SCHEME)) {
      String spec = location.substring(CompositeDatasetFactory.SCHEME.length());
      MFileCollectionManager dcm = MFileCollectionManager.open(spec, spec, null, errlog); // LOOK we dont have a name
      return CompositeDatasetFactory.factory(location, wantFeatureType, dcm, errlog);
    }

    DatasetUrl durl = DatasetUrl.findDatasetUrl(location); // Cache ServiceType so we don't have to keep figuring it out
    if (durl.serviceType == null) { // skip GRIB check for anything not a plain ole file
      // check if its GRIB, may not have to go through NetcdfDataset
      Optional<FeatureDatasetCoverage> opt = CoverageDatasetFactory.openGrib(location);
      if (opt.isPresent()) { // its a GRIB file
        return opt.get();

      } else if (!opt.getErrorMessage().startsWith(CoverageDatasetFactory.NOT_GRIB_FILE) &&
              !opt.getErrorMessage().startsWith(CoverageDatasetFactory.NO_GRIB_CLASS)) {
        errlog.format("%s%n", opt.getErrorMessage()); // its a GRIB file with an error
        return null;
      }
    }

    // otherwise open as NetcdfDataset and run it through the FeatureDatasetFactories
    NetcdfDataset ncd = NetcdfDataset.acquireDataset(durl, true, task);
    FeatureDataset fd = wrap(wantFeatureType, ncd, task, errlog);
    if (fd == null)
      ncd.close();
    return fd;
  }
static public FeatureDataset open(FeatureType wantFeatureType, String location, ucar.nc2.util.CancelTask task, Formatter errlog) throws IOException {

    // special processing for thredds: datasets
    if (location.startsWith(DataFactory.SCHEME)) {
      DataFactory.Result result = new DataFactory().openFeatureDataset(wantFeatureType, location, task);
      errlog.format("%s", result.errLog);
      if (!featureTypeOk(wantFeatureType, result.featureType)) {
        errlog.format("wanted %s but dataset is of type %s%n", wantFeatureType, result.featureType);
        result.close();
        return null;
      }
      return result.featureDataset;

      // special processing for cdmrFeature: datasets
    } else if (location.startsWith(CdmrFeatureDataset.SCHEME)) {
      Optional<FeatureDataset> opt = CdmrFeatureDataset.factory(wantFeatureType, location);
      if (opt.isPresent()) return opt.get();
      errlog.format("%s", opt.getErrorMessage());
      return null;

      // special processing for collection: datasets
    } else if (location.startsWith(ucar.nc2.ft.point.collection.CompositeDatasetFactory.SCHEME)) {
      String spec = location.substring(CompositeDatasetFactory.SCHEME.length());
      MFileCollectionManager dcm = MFileCollectionManager.open(spec, spec, null, errlog); // LOOK we dont have a name
      return CompositeDatasetFactory.factory(location, wantFeatureType, dcm, errlog);
    }

    DatasetUrl durl = DatasetUrl.findDatasetUrl(location); // Cache ServiceType so we don't have to keep figuring it out
    if (durl.serviceType == null) { // skip GRIB check for anything not a plain ole file
      // check if its GRIB, may not have to go through NetcdfDataset
      Optional<FeatureDatasetCoverage> opt = CoverageDatasetFactory.openGrib(location);
      if (opt.isPresent()) { // its a GRIB file
        return opt.get();

      } else if (!opt.getErrorMessage().startsWith(CoverageDatasetFactory.NOT_GRIB_FILE) &&
              !opt.getErrorMessage().startsWith(CoverageDatasetFactory.NO_GRIB_CLASS)) {
        errlog.format("%s%n", opt.getErrorMessage()); // its a GRIB file with an error
        return null;
      }
    }

    // otherwise open as NetcdfDataset and run it through the FeatureDatasetFactories
    NetcdfDataset ncd = NetcdfDataset.acquireDataset(durl, true, task);
    FeatureDataset fd = wrap(wantFeatureType, ncd, task, errlog);
    if (fd == null)
      ncd.close();
    return fd;
  }
Open a dataset as a FeatureDataset.

@param wantFeatureType open this kind of FeatureDataset; may be null, which means search all factories.
If datatype is not null, only return correct FeatureDataset (eg PointFeatureDataset for DataType.POINT).
@param location        URL or file location of the dataset. This may be a
<ol>
<li>thredds catalog#dataset (with a thredds: prefix)
<li>cdmrFeature dataset (with a cdmrFeature: prefix)
<li>cdmremote dataset (with a cdmremote: prefix)
<li>collection dataset (with a collection: prefix)
<li>file location for a CDM dataset opened with NetcdfDataset.acquireDataset()
</ol>
@param task            user may cancel
@param errlog          place errors here, may not be null
@return a subclass of FeatureDataset, or null if no suitable factory was found, message in errlog
@throws java.io.IOException on io error