/* * Copyright 1998-2014 University Corporation for Atmospheric Research/Unidata * * Portions of this software were developed by the Unidata Program at the * University Corporation for Atmospheric Research. * * Access and use of this software shall impose the following obligations * and understandings on the user. The user is granted the right, without * any fee or cost, to use, copy, modify, alter, enhance and distribute * this software, and any derivative works thereof, and its supporting * documentation for any purpose whatsoever, provided that this entire * notice appears in all copies of the software, derivative works and * supporting documentation. Further, UCAR requests that the user credit * UCAR/Unidata in any publications that result from the use of this * software or in any product that includes this software. The names UCAR * and/or Unidata, however, may not be used in any advertising or publicity * to endorse or promote any products or commercial entity unless specific * written permission is obtained from UCAR/Unidata. The user also * understands that UCAR/Unidata is not obligated to provide the user with * any support, consulting, training or assistance of any kind with regard * to the use, operation and performance of this software nor to provide * the user with any updates, revisions, new versions or "bug fixes." * * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE. */ package thredds.server.cdmremote; import java.util.Formatter; import ucar.nc2.stream.NcStreamCompression; import ucar.nc2.units.DateRange; import ucar.nc2.units.DateType; import ucar.nc2.units.TimeDuration; import ucar.unidata.geoloc.LatLonPoint; import ucar.unidata.geoloc.LatLonPointImpl; import ucar.unidata.geoloc.LatLonRect; /** * Parses the query parameters for cdmRemote datasets. * This is the Model in Spring MVC * * @author caron * @since May 11, 2009 */ public class CdmRemoteQueryBean { public enum RequestType { capabilities, cdl, data, dataForm, form, header, ncml, stations } public enum ResponseType { csv, netcdf, ncstream, html, xml } public enum SpatialSelection { all, bb, point, stns } public enum TemporalSelection { all, range, point } // type of request private String req = ""; // type of response private String accept = ""; // type of compression private NcStreamCompression compress = NcStreamCompression.none(); // comma delimited list of variable names private String variables; // (forms) all some private String var; //// spatial selection private String spatial; // (forms) all, bb, point, stns private TemporalSelection temporalSelection; // comma delimited list of station ids private String stn; // spatial extent - one or none private String bbox; private String west, east, south, north; private String latitude, longitude; //// time selection private String temporal; // (forms) all, range, point private SpatialSelection spatialSelection; // time range private String time_start, time_end, time_duration; private String time; // parsed quantities private DateRange dateRange; private DateType timePoint; private LatLonRect llbb; private LatLonPoint latlonPoint; private RequestType reqType = null; private ResponseType resType = null; private boolean fatal = false; private Formatter errs = new Formatter(); boolean hasFatalError() { return fatal; } String getErrorMessage() { return errs.toString(); } public LatLonRect getLatLonRect() { return (spatialSelection == SpatialSelection.bb) ? llbb : null; } DateRange getDateRange() { return dateRange; } public LatLonPoint getLatlonPoint() { return latlonPoint; } public DateType getTimePoint() { return timePoint; } public RequestType getRequestType() { if (reqType == null) { if (req.equalsIgnoreCase("capabilities")) reqType = RequestType.capabilities; else if (req.equalsIgnoreCase("cdl")) reqType = RequestType.cdl; else if (req.equalsIgnoreCase("data")) reqType = RequestType.data; else if (req.equalsIgnoreCase("dataForm")) reqType = RequestType.dataForm; else if (req.equalsIgnoreCase("form")) reqType = RequestType.form; else if (req.equalsIgnoreCase("header")) reqType = RequestType.header; else if (req.equalsIgnoreCase("ncml")) reqType = RequestType.ncml; else if (req.equalsIgnoreCase("stations")) reqType = RequestType.stations; else reqType = RequestType.data; // default } return reqType; } ResponseType getResponseType() { if (resType == null) { RequestType req = getRequestType(); if (req == RequestType.capabilities) resType = ResponseType.xml; else if (req == RequestType.form) resType = ResponseType.html; } if (resType == null) { if (accept.equalsIgnoreCase("csv")) resType = ResponseType.csv; else if (accept.equalsIgnoreCase("ncstream")) resType = ResponseType.ncstream; else if (accept.equalsIgnoreCase("netcdf")) resType = ResponseType.netcdf; else if (accept.equalsIgnoreCase("xml")) resType = ResponseType.xml; else resType = ResponseType.ncstream; // default } return resType; } NcStreamCompression getCompression() { return compress; } public void setDeflate(String level) { compress = NcStreamCompression.deflate(Integer.parseInt(level)); } SpatialSelection getSpatialSelection() { return spatialSelection; } TemporalSelection getTemporalSelection() { return temporalSelection; } boolean validate() { RequestType reqType = getRequestType(); if (reqType == RequestType.dataForm) { parseVariablesForm(); parseSpatialExtentForm(); parseTemporalExtentForm(); } else { parseSpatialExtent(); parseTimeExtent(); if ((spatialSelection == null) && (stn != null)) spatialSelection = SpatialSelection.stns; } return !fatal; } private void parseVariablesForm() { // from the form if (variables == null) { errs.format("form must have variables=(all|some)%n"); fatal = true; return; } if (variables.equalsIgnoreCase("all")) { setVar(null); } } private void parseSpatialExtentForm() { // from the form if (spatial == null) { errs.format("form must have spatial=(all|bb|point|stns)%n"); fatal = true; return; } if (spatial.equalsIgnoreCase("all")) spatialSelection = SpatialSelection.all; else if (spatial.equalsIgnoreCase("bb")) spatialSelection = SpatialSelection.bb; else if (spatial.equalsIgnoreCase("point")) spatialSelection = SpatialSelection.point; else if (spatial.equalsIgnoreCase("stns")) spatialSelection = SpatialSelection.stns; if (spatialSelection == SpatialSelection.bb) { parseSpatialExtent(); } else if (spatialSelection == SpatialSelection.point) { double lat = parseLat("latitude", latitude); double lon = parseLon("longitude", longitude); latlonPoint = new LatLonPointImpl(lat, lon); } } private void parseSpatialExtent() { if (bbox != null) { String[] s = bbox.split(","); if (s.length != 4) { errs.format("bbox must have form 'bbox=west,east,south,north'; found 'bbox=%s'%n", bbox); fatal = true; return; } west = s[0]; east = s[1]; south = s[2]; north = s[3]; } if ((west != null) || (east != null) || (south != null) || (north != null)) { if ((west == null) || (east == null) || (south == null) || (north == null)) { errs.format("All edges (west,east,south,north) must be specified; found west=%s east=%s south=%s north=%s %n", west, east, south, north); fatal = true; return; } double westd = parseLon("west", west); double eastd = parseLon("east", east); double southd = parseLat("south", south); double northd = parseLat("north", north); if (!fatal) { llbb = new LatLonRect(new LatLonPointImpl(southd, westd), new LatLonPointImpl(northd, eastd)); spatialSelection = SpatialSelection.bb; } } } private double parseLat(String key, String value) { double lat = parseDouble(key, value); if (!Double.isNaN(lat)) { if ((lat > 90.0) || (lat < -90.0)) { errs.format("Illegal param= param='%s=%s' must be between +/- 90.0 %n", key, value); lat = Double.NaN; fatal = true; } } return lat; } private double parseLon(String key, String value) { return parseDouble(key, value); } private double parseDouble(String key, String value) { value = value.trim(); try { return Double.parseDouble(value); } catch (NumberFormatException e) { errs.format("Illegal param='%s=%s' must be valid floating point number%n", key, value); fatal = true; } return Double.NaN; } //////////////////////////////////////// private void parseTemporalExtentForm() { // from the form if (temporal == null) { errs.format("form must have temporal=(all|range|point)%n"); fatal = true; return; } if (temporal.equalsIgnoreCase("all")) temporalSelection = TemporalSelection.all; else if (temporal.equalsIgnoreCase("range")) temporalSelection = TemporalSelection.range; else if (temporal.equalsIgnoreCase("point")) temporalSelection = TemporalSelection.point; if (temporal.equalsIgnoreCase("range")) { try { parseTimeExtent(); } catch (Throwable t) { errs.format("badly specified time range"); fatal = true; } } else if (temporal.equalsIgnoreCase("point")) { timePoint = parseDate("time", time); } } private void parseTimeExtent() { DateType startDate = parseDate("time_start", time_start); DateType endDate = parseDate("time_end", time_end); TimeDuration duration = parseW3CDuration("time_duration", time_duration); // no range if ((startDate != null) && (endDate != null)) dateRange = new DateRange(startDate, endDate, null, null); else if ((startDate != null) && (duration != null)) dateRange = new DateRange(startDate, null, duration, null); else if ((endDate != null) && (duration != null)) dateRange = new DateRange(null, endDate, duration, null); if (dateRange != null) temporalSelection = TemporalSelection.range; } public DateType parseDate(String key, String value) { if (value != null) { try { return new DateType(value, null, null); } catch (java.text.ParseException e) { errs.format("Illegal param='%s=%s' must be valid ISO Date%n", key, value); fatal = true; } } return null; } public TimeDuration parseW3CDuration(String key, String value) { if (value != null) { try { return new TimeDuration(value); } catch (java.text.ParseException e) { errs.format("Illegal param='%s=%s' must be valid ISO Duration%n", key, value); fatal = true; } } return null; } ///////////////////////////////////// public void setAccept(String accept) { this.accept = accept; } public void setReq(String req) { this.req = req; } // variable names public void setVariables(String variables) { this.variables = variables; } public void setVar(String var) { this.var = var; } public String getVar() { return var; } public String[] getVarNames() { return (var == null) ? null : var.split(","); } //////// spatial public void setSpatial(String spatial) { this.spatial = spatial; } public void setStn(String stn) { this.stn = stn; } public String getStn() { return stn; } public String[] getStnNames() { if (!(spatialSelection == SpatialSelection.stns)) return null; return (stn == null) ? null : stn.split(","); } public void setBbox(String bbox) { this.bbox = bbox; } public void setWest(String west) { this.west = west; } public void setEast(String east) { this.east = east; } public void setSouth(String south) { this.south = south; } public void setNorth(String north) { this.north = north; } public void setLatitude(String latitude) { this.latitude = latitude; } public void setLongitude(String longitude) { this.longitude = longitude; } //////// temporal public void setTemporal(String temporal) { this.temporal = temporal; } public void setTime_start(String timeStart) { this.time_start = timeStart; } public void setTime_end(String timeEnd) { this.time_end = timeEnd; } public void setTime_duration(String timeDuration) { this.time_duration = timeDuration; } public void setTime(String time) { this.time = time; } @Override public String toString() { Formatter f = new Formatter(); f.format("QueryBean: reqType=%s resType=%s", getRequestType(), getResponseType()); if (spatialSelection == SpatialSelection.all) f.format(" spatialSelection=all;"); else if (spatialSelection == SpatialSelection.bb) f.format(" bb=%s;", getLatLonRect()); else if (spatialSelection == SpatialSelection.stns) f.format(" stns=%s;", getStn()); if (temporalSelection == TemporalSelection.all) f.format(" temporalSelection=all;"); else if (temporalSelection == TemporalSelection.range) f.format(" range=%s;", getDateRange()); if (var != null) f.format(" vars=%s", var); return f.toString(); } }