In order for the TDS to serve data through any of the subsetting protocols like OPenDAP, WCS or the NetCDF Subsetting Service (NCSS), it must be able to read the data into the Common Data Model. When the data is contained in a file, this is done with an I/O Service Provider (IOSP). When the dataset depends on request parameters that are passed to the TDS by the client, then a more general interface is needed, since the IOSP does not have access to the HttpServletRequest object.

Create DatasetSource Implementation Class

Your class must implement the thredds.servlet.DatasetSource interface:

public interface DatasetSource {

  public boolean isMine( HttpServletRequest req);

  public NetcdfFile getNetcdfFile( HttpServletRequest req, HttpServletResponse res) throws IOException;

The implementor of DatasetSource must quickly determine if it can service the request by returning true or false from the isMine method. If true, then it must be able to return a NetcdfFile from the getNetcdfFile(). Any caching or performance optimizations must be handled by the DatasetSource implementor. It is usually important for performance reasons to cache the NetcdfFile object for subsequent access, since clients typically access a NetcdfFile several or many times, not just once.

If the getNetcdfFile method encounters an error processing the request, it should set the return code on the HttpResponse and return null. For example:

 response.sendError(HttpServletResponse.SC_NOT_FOUND, message);

By returning null, the calling routine assumes that you have sent the response yourself, and will terminate processing without further action.


public class DatasetSourceExample implements thredds.servlet.DatasetSource {
  static final String prefix =  "/special/";
  static final int prefixLen =  prefix.length();

  public boolean isMine(HttpServletRequest req) {
    String path = req.getPathInfo();
    return path.startsWith(prefix);

  public NetcdfFile getNetcdfFile(HttpServletRequest req, HttpServletResponse res) throws IOException {
    String path = req.getPathInfo().substring(prefixLen);
    DataRootHandler.DataRootMatch match = DataRootHandler.getInstance().findDataRootMatch(path);
    if (match == null) {
      res.sendError(HttpServletResponse.SC_NOT_FOUND, path);
      return null;

    int pos = match.remaining.lastIndexOf('.');
    String filename = match.remaining.substring(0, pos);
    File file = new File(match.dirLocation+filename);
    if (!file.exists()) {
      res.sendError(HttpServletResponse.SC_NOT_FOUND, match.dirLocation+filename);
      return null;

    NetcdfFile ncfile = NetcdfDataset.openFile(file.getPath(), null);
    ncfile.addAttribute(null, new Attribute("Special", req.getRequestURI()));
    return ncfile;

Loading Your Class At Runtime

You must place your DatasetSource class into the ${tomcat_home}/webapps/thredds/WEB-INF/lib or ${tomcat_home}/webapps/thredds/WEB-INF/classes directory.

Then tell the TDS to load it by adding a line to the ${tds.content.root.path}/thredds/threddsConfig.xml file, for example:


Adding To The THREDDS Configuration Catalog

In the above example, DatasetSourceExample will claim any request whose path starts with */special/*. In the THREDDS Configuration Catalog, you will add datasets which have that path.

A simple example:

<service name="thisDODS" serviceType="OpenDAP" base="/thredds/dodsC/" />
<dataset name="Test ExampleDataSource" ID="testDataset" serviceName="thisDODS" urlPath="special/my/" />

The dataset will have a URL of http://server:port/thredds/dodsC/special/my/ Its path will be /special/my/, so DatasetSourceExample will claim it, and will be required to return a NetcdfFile object.

The value that you put into urlPath will be used by TDS clients. You can use anything you want, as long as your DatasetSource recognizes the path and correctly returns the corresponding NetcdfFile.