Currently, the TDS automatically adds, when appropriate, the following standard viewer links at the bottom of a datasets HTML web page:

  • a Godiva3 web-based WMS client link to any dataset that has a WMS service.
  • a Jupyter Notebook viewer which provides the boilerplate python code to access remote data for a direct-access dataset.

Example

Viewers

The TDS also supports two ways to configure other custom viewer links.

Dataset viewer links can be added to dataset HTML pages using viewer property elements. To add a dataset viewer link to a specific dataset, add a property element that has a name starting with viewer. When the TDS generates a dataset HTML page, it looks for all viewer property elements and uses the value of each property element to generate a viewer link. The value of the viewer property element must be a string containing a URL and, optionally, a name, description, and ViewerType separated by commas.

Note that the parameters passed to the viewer property element are interpreted by order, so if you wish to include a ViewerType but no description or name, you will need to place empty strings as fillers.

The options for ViewerType are as follows:

  • Application
  • Browser
  • Jupyter Notebook
  • Unknown If no ViewerType or an unrecognized type is provided, the type will default to Unknown.

An HTML link is built using the viewer property element.

Example

<dataset name="Test Single Dataset" ID="testDataset" serviceName="odap" urlPath="test/testData.nc" dataType="Grid">
  <property name="viewer" value="https://www.unidata.ucar.edu/staff/caron/,MyViewer,A viewer for my data,Application"/>
  <property name="viewer2" value="https://www.unidata.ucar.edu/,,,Browser"/>
</dataset>

which looks like this on the TDS page:

Added Viewers

When a viewer property element is contained in an inherited metadata element, it will apply to all the descendants of the containing dataset.

Example

The following will result in viewer links for all children datasets:

<dataset name="Test inherited viewer" ID="tiv">
  <metadata inherited="true">
    <serviceName>all</serviceName>
    <property name="viewer" value="https://www.unidata.ucar.edu/staff/caron/,MyViewer" />
  </metadata>
  <dataset name="test inherited viewer ds 1" ID="tiv/ds1" urlPath="tiv/ds1.nc">
  <dataset name="test inherited viewer ds 2" ID="tiv/ds2" urlPath="tiv/ds2.nc">
</dataset>

When added to a datasetScan elements, the viewer property results in a viewer link being added to the HTML dataset pages for each generated dataset:

<datasetScan name="Test inherited viewer dsScan" ID="tivScan" path="tivScan" location="C:/some/good/data/">
  <metadata
  inherited="true">
    <serviceName>all</serviceName>
    <property name="viewer" value="https://www.unidata.ucar.edu/staff/caron/,MyViewer" />
  </metadata>
</datasetScan>

Adding the same viewer link to all your dataset pages may not be what you want. The TDS also supports inserting a dataset access URL into the viewer link URL. If your dataset has a single service, you can place {url} into your viewer link. The datasets access URL will be substituted in place of the {url} string. For instance, the following:

<dataset name="Test Viewer2" ID="testViewer2" serviceName="dapService" urlPath="test/testData.nc" dataType="Grid"
  <property name="viewer" value="http://some.tds.edu/cdmvalidator/validate?URL={url},Validation Service"/>
</dataset>

results in the following viewer link:

<a href="http://some.tds.edu/cdmvalidator/validate?URL=http://myhost:8080/thredds/dodsC/test/testData.nc">Validation Service</a>

When a Dataset has more than one kind of access, each access will have a separate URL. Use the service type inside of curly brackets to select which access URL to use.

Example

<service name="all" base="" serviceType="compound">
  <service name="odap" serviceType="OPENDAP" base="/thredds/dodsC/"/>
  <service name="http" serviceType="HTTPServer" base="/thredds/fileServer/"/>
  <service name="wcs" serviceType="WCS" base="/thredds/wcs/"/>
  <service name="wms" serviceType="WMS" base="/thredds/wms/"/>
  <service name="ncssGrid" serviceType="NetcdfSubset" base="/thredds/ncss/grid/"/>
  <service name="cdmremote" serviceType="CdmRemote" base="/thredds/cdmremote/"/>
  <service name="iso" serviceType="ISO" base="/thredds/iso/"/>
  <service name="ncml" serviceType="NCML" base="/thredds/ncml/"/>
  <service name="uddc" serviceType="UDDC" base="/thredds/uddc/"/>
</service>

<dataset name="test viewer select service" ID="tvss">
  <metadata inherited="true">
    <serviceName>all</serviceName>
  </metadata>

  <dataset name="test viewer select service ds 1" ID="tvss/ds1" urlPath="tvss/ds1.nc">
    <property name="viewer" value="http://some.tds.edu/cdmvalidator/validate?URL={OPENDAP},Validation Service" />
  </dataset>
  <dataset name="test viewer select service ds 2" ID="tvss/ds2" urlPath="tvss/ds2.nc">
    <property name="viewer" value="http://myhost:8080/wcsView/show?dataset={WCS},Validation Service" />
  </dataset>
</dataset>

generates a viewer link URL for the first dataset of:

http://some.tds.edu/cdmvalidator/validate?URL=http://myhost:8080/thredds/dodsC/tvss/ds1.nc

and for the second dataset, the viewer link is:

http://myhost:8080/wcsView/show?dataset=http://myhost:8080/thredds/wcs/tvss/ds2.nc

Create A Viewer Implementation Java class

This technique gives you full control over whether your viewer link appears, and what the URL looks like. You must create a Java class which implements the thredds.server.viewer.Viewer interface:

public interface Viewer {
 /* Your class is passed a `thredds.catalog.InvDatasetImpl` object, and it returns `true` if it is viewable by your viewer. */   
 boolean isViewable( thredds.catalog.InvDatasetImpl dataset); 

 /* Your class is passed a viewable `thredds.catalog.InvDatasetImpl`, and it must return a well-formed HTML string that has an `href` link in it. */
 String getViewerLinkHtml( InvDatasetImpl ds, HttpServletRequest req);

 /* Your class is passed a viewable `thredds.catalog.InvDatasetImpl`, and it must return a `ViewerLink` object*/
 ViewerLinkProvider.ViewerLink getViewerLink(Dataset ds, HttpServletRequest req);
}

A ViewerLink is an abstraction of the HTML link to a dataset viewer, containing the following properties:

  class ViewerLink {
  private String title;
  private String url;
  private String description;
  private ViewerType type;
}

Example

package my.package;
import thredds.catalog.*;

public class IDV implements Viewer {
   public boolean isViewable( InvDatasetImpl ds) {
      // 1) Requires there to be OPeNDAP access for the dataset.
      InvAccess access = ds.getAccess(ServiceType.DODS);
      if (access == null) access = ds.getAccess(ServiceType.OPENDAP);
      if (access == null) return false;
      // 2) Requires the dataset to be of DataType.GRID.
      return (ds.getDataType() == DataType.GRID);
   }

   public String getViewerLinkHtml( InvDatasetImpl ds, HttpServletRequest req) {
      InvAccess access = ds.getAccess(ServiceType.DODS);
      // 3) Get the OPeNDAP access object for the dataset.
      if (access == null) access = ds.getAccess(ServiceType.OPENDAP);
      // 4) Get the access URI.
      URI dataURI = access.getStandardUri();
      // 5) Resolves the access URI against the request, which turns it into an absolute URI
      try {
         URI base = new URI( req.getRequestURL().toString());
         dataURI = base.resolve( dataURI);
      } catch (URISyntaxException e) {
         log.error("Resolve URL with " + req.getRequestURL(), e);
      }

      // 6) Forms the HTML string, with an embedded href, to be placed on the dataset's TDS web page.
      return "<a href='/thredds/view/idv.jnlp?url="+dataURI.toString()+
              "'>Integrated Data Viewer (IDV) (webstart)</a>";
   }
   
   public ViewerLinkProvider.ViewerLink getViewerLink(Dataset ds, HttpServletRequest req) {
       // 7) Create a ViewerLink object for the viewer
       return new ViewerLinkProvider.ViewerLink("viewerIDV", getViewerLinkHtml(ds, req), 
               "IDV view of the dataset", ViewerType.Application));
   }
}

Referencing An External URL

If the viewer you want to reference is not part of the TDS, just make the href absolute, e.g.:

<a href='http://my.server/viewer?url=http://some.tds.edu/thredds/dodsC/model/data.grib2'>My Server</a>

In this example, the server would see the OPeNDAP data access URL and remotely read it.

Loading Your Class At Runtime

You must place your Viewer class into the ${tomcat_home}/webapps/thredds/WEB-INF/lib or ${tomcat_home}/webapps/thredds/WEB-INF/classes directory. (Previous instructions to place it into the ${tomcat_home}/shared directory doesn’t work, because of classloader problems).

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

Example

<viewer>my.package.MyViewer</viewer>