Skip to content

Commit

Permalink
Refactor DAP4 CDM file reading
Browse files Browse the repository at this point in the history
Previously, reading datasets via the CDM was reliant upon extracting a
filesystem path from the incoming request through implementation of the
abstract method dap4.servlet.DapController#getResourcePath. This has
been refactored to use dap4.servlet.DapController#getCDMWrap as the
abstract method used to interface the CDM reading code. D4TS continues
to use the getResourcePath code in its implementation of getCDMWrap. The
TDS utilizes TdsRequestedDataset in its implementation, which takes care
of virtual datasets, such as NcML aggregations, object storage based
data, etc., as well as authentication/authorization.

Fixes #568
  • Loading branch information
lesserwhirls committed Feb 12, 2025
1 parent 5ce926d commit 8667d97
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 49 deletions.
27 changes: 12 additions & 15 deletions dap4/d4servlet/src/main/java/dap4/servlet/DapController.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,16 @@ public DapController() {}
abstract protected String getWebContentRoot(DapRequest drq) throws DapException;

/**
* Convert a URL path for a dataset into an absolute file path
*
* @param drq dap request
* @param location suffix of url path
* @return path in a string builder so caller can extend.
* @throws IOException
* Obtain a wrapped CDM source (NetcdfDataset) to Provide a DAP4 API
* <p>
* This method assumes a resource on the local filesystem. Override
* this method to provide other request/dataset location mappings. *
* </p>
*
* @param drq DapRequest
* @throws IOException error obtaining the dataset described by the DapRequest
*/
abstract protected String getResourcePath(DapRequest drq, String location) throws DapException;
abstract protected CDMWrap getCDMWrap(DapRequest drq) throws IOException;

//////////////////////////////////////////////////////////

Expand Down Expand Up @@ -257,10 +259,8 @@ protected void doDSR(DapRequest drq, DapContext cxt) throws IOException {
*/

protected void doDMR(DapRequest drq, DapContext cxt) throws IOException {
// Convert the url to an absolute path
String realpath = drq.getResourcePath(drq.getDatasetPath());

CDMWrap c4 = new CDMWrap().open(realpath); // Create the wrapper
CDMWrap c4 = getCDMWrap(drq);
DapDataset dmr = c4.getDMR();
CEConstraint ce = constrainDapContext(cxt, dmr);
ChecksumMode csummode = (ChecksumMode) cxt.get(DapConstants.CHECKSUMTAG);
Expand Down Expand Up @@ -310,12 +310,9 @@ protected void doDMR(DapRequest drq, DapContext cxt) throws IOException {
*/

protected void doData(DapRequest drq, DapContext cxt) throws IOException {
// Convert the url to an absolute path
String realpath = drq.getResourcePath(drq.getDatasetPath());

CDMWrap c4 = new CDMWrap().open(realpath);
CDMWrap c4 = getCDMWrap(drq);
if (c4 == null)
throw new DapException("No such file: " + realpath);
throw new DapException("Unknown resource");

DapDataset dmr = c4.getDMR();
CEConstraint ce = constrainDapContext(cxt, dmr);
Expand Down
11 changes: 0 additions & 11 deletions dap4/d4servlet/src/main/java/dap4/servlet/DapRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,17 +205,6 @@ public String getServletID() throws DapException {
return controller.getServletID();
}

/**
* Convert a URL path for a dataset into an absolute file path
*
* @param location suffix of url path
* @return path in a string builder so caller can extend.
* @throws IOException
*/
public String getResourcePath(String location) throws DapException {
return controller.getResourcePath(this, location);
}

/**
* Convert a URL path for a web-content related file into an absolute file path
*
Expand Down
1 change: 1 addition & 0 deletions dap4/d4ts/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies {

implementation 'edu.ucar:dap4'
implementation project(":dap4:d4servlet")
implementation 'edu.ucar:cdm-core'

providedCompile "jakarta.servlet:jakarta.servlet-api:${depVersion.jakartaServletApi}"

Expand Down
14 changes: 12 additions & 2 deletions dap4/d4ts/src/main/java/dap4/d4ts/D4TSServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se
@Override
protected void doFavicon(String icopath, DapContext cxt) throws IOException {
DapRequest drq = (DapRequest) cxt.get(DapRequest.class);
String favfile = drq.getResourcePath(icopath);
String favfile = getResourcePath(drq, icopath);
if (favfile != null) {
try (FileInputStream fav = new FileInputStream(favfile);) {
byte[] content = DapUtil.readbinaryfile(fav);
Expand Down Expand Up @@ -113,7 +113,7 @@ protected FrontPage getFrontPage(DapRequest drq, DapContext cxt) throws DapExcep
if (this.defaultroots == null) {
// Figure out the directory containing
// the files to display.
String testroot = drq.getResourcePath("/");
String testroot = getResourcePath(drq, "/");
if (testroot == null)
throw new DapException("Cannot locate dataset directory");
this.defaultroots = new ArrayList<>();
Expand Down Expand Up @@ -141,6 +141,16 @@ public String getWebContentRoot(DapRequest drq) throws DapException {
}
}

public CDMWrap getCDMWrap(DapRequest drq) throws IOException {
// Convert the url to an absolute path
String realpath = getResourcePath(drq, drq.getDatasetPath());

CDMWrap c4 = new CDMWrap().open(realpath); // Create the wrapper
if (c4 == null)
DapLog.debug("No such file: " + realpath);
return c4;
}

/**
* Convert a URL path for a dataset into an absolute file path
*
Expand Down
39 changes: 18 additions & 21 deletions tds/src/main/java/thredds/server/dap4/Dap4Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
import dap4.core.util.DapException;
import dap4.core.util.DapUtil;
import dap4.dap4lib.DapCodes;
import dap4.servlet.CDMWrap;
import dap4.servlet.DapController;
import dap4.servlet.DapRequest;
import java.util.EnumSet;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -20,6 +23,9 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.*;
import ucar.nc2.NetcdfFile;
import ucar.nc2.dataset.NetcdfDataset;
import ucar.nc2.dataset.NetcdfDataset.Enhance;

@Controller
@RequestMapping("/dap4")
Expand All @@ -35,7 +41,8 @@ public class Dap4Controller extends DapController {
static final String SERVICEID = "/dap4";

// NetcdfDataset enhancement to use: need only coord systems
// static Set<NetcdfDataset.Enhance> ENHANCEMENT = EnumSet.of(NetcdfDataset.Enhance.CoordSystems);
// match dap4.servlet.CDMWrap.ENHANCEMENT
static Set<Enhance> ENHANCEMENT = EnumSet.of(NetcdfDataset.Enhance.CoordSystems);

//////////////////////////////////////////////////
// Instance variables
Expand Down Expand Up @@ -104,26 +111,16 @@ public String getWebContentRoot(DapRequest drq) throws DapException {
return DapUtil.canonicalpath(rootpath);
}

/**
* Convert a URL path for a dataset into an absolute file path
*
* @param location suffix of url path
* @return path in a string builder so caller can extend.
* @throws IOException
*/
public String getResourcePath(DapRequest drq, String location) throws DapException {
assert (location.charAt(0) == '/');
// Remove the leading service name, if any
if (location.startsWith(SERVICEID))
location = location.substring(SERVICEID.length());
String path = TdsRequestedDataset.getLocationFromRequestPath(location);
if (path == null || path.length() == 0)
throw new DapException(String.format("getLocationFromRequestPath: location=|%s| path=null", location, path))
.setCode(DapCodes.SC_NOT_FOUND);
File f = new File(path);
if (!f.exists() || !f.canRead() || !f.isFile())
throw new DapException("Cannot locate resource: " + location).setCode(DapCodes.SC_NOT_FOUND);
return DapUtil.canonicalpath(path);
public CDMWrap getCDMWrap(DapRequest drq) throws IOException {
String datasetPath = drq.getDatasetPath();
String prefix = SERVICEID + "/";
if (datasetPath.startsWith(prefix)) {
datasetPath = datasetPath.substring(prefix.length());
}
NetcdfFile ncf = TdsRequestedDataset.getNetcdfFile(drq.getRequest(), drq.getResponse(), datasetPath);
NetcdfDataset ncd;
ncd = NetcdfDataset.wrap(ncf, ENHANCEMENT);
return new CDMWrap().open(ncd);
}

}
Expand Down

0 comments on commit 8667d97

Please sign in to comment.