Java tutorial
/* * Copyright 2008-2012 Jeff McWhirter/ramadda.org * Don Murray/CU-CIRES * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies * or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ package org.ramadda.geodata.cdmdata; import opendap.dap.DAP2Exception; import opendap.servlet.GuardedDataset; import opendap.servlet.ReqState; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.AxisLocation; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYAreaRenderer; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.data.time.FixedMillisecond; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.time.TimeSeriesDataItem; import org.jfree.data.xy.XYDataset; import org.jfree.ui.RectangleInsets; import org.ramadda.repository.Entry; import org.ramadda.repository.Link; import org.ramadda.repository.Repository; import org.ramadda.repository.Request; import org.ramadda.repository.Resource; import org.ramadda.repository.Result; import org.ramadda.repository.Service; import org.ramadda.repository.auth.AccessException; import org.ramadda.repository.auth.AuthorizationMethod; import org.ramadda.repository.auth.Permission; import org.ramadda.repository.map.MapInfo; import org.ramadda.repository.map.MapProperties; import org.ramadda.repository.metadata.ContentMetadataHandler; import org.ramadda.repository.metadata.Metadata; import org.ramadda.repository.output.OutputHandler; import org.ramadda.repository.output.OutputHandler.State; import org.ramadda.repository.output.OutputType; import org.ramadda.repository.type.TypeHandler; import org.ramadda.util.HtmlUtils; import org.ramadda.util.TempDir; import org.w3c.dom.Element; import thredds.server.ncSubset.GridPointWriter; import thredds.server.ncSubset.QueryParams; import thredds.server.opendap.GuardedDatasetImpl; import ucar.ma2.Array; import ucar.ma2.DataType; import ucar.ma2.StructureData; import ucar.ma2.StructureMembers; import ucar.nc2.NetcdfFile; import ucar.nc2.VariableSimpleIF; import ucar.nc2.dataset.CoordinateAxis1DTime; import ucar.nc2.dataset.NetcdfDataset; import ucar.nc2.dataset.VariableEnhanced; import ucar.nc2.dt.GridCoordSystem; import ucar.nc2.dt.GridDatatype; import ucar.nc2.dt.TrajectoryObsDataset; import ucar.nc2.dt.TrajectoryObsDatatype; import ucar.nc2.dt.grid.GridDataset; import ucar.nc2.dt.grid.NetcdfCFWriter; import ucar.nc2.ft.FeatureCollection; import ucar.nc2.ft.FeatureDatasetPoint; import ucar.nc2.ft.NestedPointFeatureCollection; import ucar.nc2.ft.PointFeature; import ucar.nc2.ft.PointFeatureCollection; import ucar.nc2.ft.PointFeatureIterator; import ucar.nc2.ncml.NcMLWriter; import ucar.nc2.units.DateType; import ucar.nc2.util.DiskCache2; import ucar.unidata.data.gis.KmlUtil; import ucar.unidata.geoloc.LatLonPointImpl; import ucar.unidata.geoloc.LatLonRect; import ucar.unidata.ui.ImageUtils; import ucar.unidata.util.Cache; import ucar.unidata.util.Counter; import ucar.unidata.util.DateUtil; import ucar.unidata.util.GuiUtils; import ucar.unidata.util.IOUtil; import ucar.unidata.util.Misc; import ucar.unidata.util.StringUtil; import ucar.unidata.util.TwoFacedObject; import ucar.unidata.util.WrapperException; import ucar.unidata.xml.XmlUtil; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.regex.Pattern; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; /** * A class for handling CDM data output */ public class CdmDataOutputHandler extends OutputHandler { /** OPeNDAP icon */ public static final String ICON_OPENDAP = "/cdmdata/opendap.gif"; /** CSV format */ public static final String FORMAT_CSV = "csv"; /** KML format */ public static final String FORMAT_KML = "kml"; /** NCML format */ public static final String FORMAT_NCML = "ncml"; /** NCML suffix */ public static final String SUFFIX_NCML = ".ncml"; /** GrADS CTL suffix */ public static final String SUFFIX_CTL = ".ctl"; /** bounding box argument */ public static final String ARG_POINT_BBOX = "bbox"; /** Variable prefix */ public static final String VAR_PREFIX = ARG_VARIABLE + "."; /** add lat lon argument */ public static final String ARG_ADDLATLON = "addlatlon"; /** horizontal stride */ public static final String ARG_HSTRIDE = "hstride"; /** level */ public static final String ARG_LEVEL = "level"; /** format */ public static final String ARG_FORMAT = "format"; /** format */ public static final String ARG_IMAGE_WIDTH = "image_width"; /** format */ public static final String ARG_IMAGE_HEIGHT = "image_height"; /** spatial arguments */ private static final String[] SPATIALARGS = new String[] { ARG_AREA_NORTH, ARG_AREA_WEST, ARG_AREA_SOUTH, ARG_AREA_EAST, }; /** chart format */ private static final String FORMAT_TIMESERIES = "timeseries"; /** chart format */ private static final String FORMAT_TIMESERIES_CHART = "timeserieschart"; /** chart format */ private static final String FORMAT_TIMESERIES_CHART_DATA = "timeserieschartdata"; /** chart image format */ private static final String FORMAT_TIMESERIES_IMAGE = "timeseriesimage"; /** Data group */ public static final String GROUP_DATA = "Data"; /** CDM Type */ public static final String TYPE_CDM = "cdm"; /** GRID type */ public static final String TYPE_GRID = "grid"; /** TRAJECTORY type */ public static final String TYPE_TRAJECTORY = "trajectory"; /** POINT_TYPE */ public static final String TYPE_POINT = "point"; /** GrADS type */ public static final String TYPE_GRADS = "gradsbinary"; /** set of suffixes */ private HashSet<String> suffixSet; /** hash of patterns */ private Hashtable<String, List<Pattern>> patterns; /** not patterns */ private Hashtable<String, List<Pattern>> notPatterns; /** OPeNDAP Output Type */ public static final OutputType OUTPUT_OPENDAP = new OutputType("OPeNDAP", "data.opendap", OutputType.TYPE_FEEDS, OutputType.SUFFIX_NONE, ICON_OPENDAP, GROUP_DATA); /** CDL Output Type */ public static final OutputType OUTPUT_CDL = new OutputType("File Metadata", "data.cdl", OutputType.TYPE_OTHER, OutputType.SUFFIX_NONE, "/cdmdata/page_white_text.png", GROUP_DATA); /** WCS Output Type */ public static final OutputType OUTPUT_WCS = new OutputType("WCS", "data.wcs", OutputType.TYPE_FEEDS); /** Point map Output Type */ public static final OutputType OUTPUT_POINT_MAP = new OutputType("Plot Points on a Map", "data.point.map", OutputType.TYPE_OTHER, OutputType.SUFFIX_NONE, ICON_MAP, GROUP_DATA); /** CSV Output Type */ public static final OutputType OUTPUT_POINT_SUBSET = new OutputType("CSV, KML Output", "data.point.subset", OutputType.TYPE_OTHER, OutputType.SUFFIX_NONE, ICON_CSV, GROUP_DATA); /** Trajectory map Output Type */ public static final OutputType OUTPUT_TRAJECTORY_MAP = new OutputType("Show track on Map", "data.trajectory.map", OutputType.TYPE_OTHER, OutputType.SUFFIX_NONE, ICON_MAP, GROUP_DATA); /** Radar map Output Type */ public static final OutputType OUTPUT_RADAR_MAP = new OutputType("Show radar on Map", "data.radar.map", OutputType.TYPE_OTHER, OutputType.SUFFIX_NONE, ICON_MAP, GROUP_DATA); /** Grid subset form Output Type */ public static final OutputType OUTPUT_GRIDSUBSET_FORM = new OutputType("Subset Grid", "data.gridsubset.form", OutputType.TYPE_OTHER, OutputType.SUFFIX_NONE, "/cdmdata/subsetgrid.png", GROUP_DATA); /** Grid subset Output Type */ public static final OutputType OUTPUT_GRIDSUBSET = new OutputType("data.gridsubset", OutputType.TYPE_FEEDS); /** Grid as point form Output Type */ public static final OutputType OUTPUT_GRIDASPOINT_FORM = new OutputType("Extract Time Series", "data.gridaspoint.form", OutputType.TYPE_OTHER, OutputType.SUFFIX_NONE, "/cdmdata/chart_line.png", GROUP_DATA); /** Grid as point Output Type */ public static final OutputType OUTPUT_GRIDASPOINT = new OutputType("data.gridaspoint", OutputType.TYPE_FEEDS); /** opendap counter */ Counter opendapCounter = new Counter(); /** the CDM manager */ private static CdmManager cdmManager; /** * Get the CdmManager * * @return the CDM data manager */ public CdmManager getCdmManager() { if (cdmManager == null) { try { getRepository().addRepositoryManager(cdmManager = new CdmManager(getRepository())); } catch (Exception exc) { throw new RuntimeException(exc); } } return cdmManager; } /** * Create a new CdmDataOutputHandler * * @param repository the repository * @param name the name of this handler * * @throws Exception problem creating class */ public CdmDataOutputHandler(Repository repository, String name) throws Exception { super(repository, name); } /** * Create a CdmDataOutputHandler * * @param repository the repository * @param element the element * @throws Exception On badness */ public CdmDataOutputHandler(Repository repository, Element element) throws Exception { super(repository, element); getCdmManager(); addType(OUTPUT_OPENDAP); addType(OUTPUT_CDL); addType(OUTPUT_WCS); addType(OUTPUT_TRAJECTORY_MAP); addType(OUTPUT_POINT_MAP); addType(OUTPUT_POINT_SUBSET); addType(OUTPUT_GRIDSUBSET); addType(OUTPUT_GRIDSUBSET_FORM); addType(OUTPUT_GRIDASPOINT); addType(OUTPUT_GRIDASPOINT_FORM); } /** * Get the system stats * * @param sb the stats */ public void getSystemStats(StringBuffer sb) { super.getSystemStats(sb); getCdmManager().getSystemStats(sb); } /** * clear the cache */ public void clearCache() { super.clearCache(); getCdmManager().clearCache(); } /** * Add to an entry * * @param request the request * @param entry the entry * @param node the node * * @throws Exception on badness */ public void addToEntryNode(Request request, Entry entry, Element node) throws Exception { super.addToEntryNode(request, entry, node); if (!getCdmManager().canLoadAsCdm(entry)) { return; } if (!getRepository().getAccessManager().canAccessFile(request, entry)) { return; } String url = getAbsoluteOpendapUrl(request, entry); Element serviceNode = XmlUtil.create(TAG_SERVICE, node); XmlUtil.setAttributes(serviceNode, new String[] { ATTR_TYPE, SERVICE_OPENDAP, ATTR_URL, url }); } /** * Get the Entry links * * @param request the request * @param state the state * @param links the links * * @throws Exception on badness */ public void getEntryLinks(Request request, State state, List<Link> links) throws Exception { Entry entry = state.entry; if ((state.group != null) && getCdmManager().isAggregation(state.group)) { entry = state.group; } if (entry == null) { return; } if (!getRepository().getAccessManager().canAccessFile(request, entry)) { return; } long t1 = System.currentTimeMillis(); boolean canLoadAsCdm = getCdmManager().canLoadAsCdm(entry); if (!canLoadAsCdm) { long t2 = System.currentTimeMillis(); if ((t2 - t1) > 1) { // System.err.println("CdmDataOutputHandler (cdm) getEntryLinks " // + entry.getName() + " time:" + (t2 - t1)); } return; } if (getCdmManager().canLoadAsGrid(entry)) { addOutputLink(request, entry, links, OUTPUT_GRIDSUBSET_FORM); addOutputLink(request, entry, links, OUTPUT_GRIDASPOINT_FORM); } else if (getCdmManager().canLoadAsTrajectory(entry)) { addOutputLink(request, entry, links, OUTPUT_TRAJECTORY_MAP); } else if (getCdmManager().canLoadAsPoint(entry)) { addOutputLink(request, entry, links, OUTPUT_POINT_MAP); addOutputLink(request, entry, links, OUTPUT_POINT_SUBSET); } else { // System.err.println ("Don't know what this is:"+ entry); } Object oldOutput = request.getOutput(); request.put(ARG_OUTPUT, OUTPUT_OPENDAP); String opendapUrl = getOpendapUrl(entry); links.add(new Link(opendapUrl, getRepository().iconUrl(ICON_OPENDAP), "OPeNDAP", OUTPUT_OPENDAP)); request.put(ARG_OUTPUT, oldOutput); Link cdlLink = makeLink(request, entry, OUTPUT_CDL); // cdlLink.setLinkType(OutputType.TYPE_ACTION); links.add(cdlLink); long t2 = System.currentTimeMillis(); if ((t2 - t1) > 1) { // System.err.println("CdmDataOutputHandler getEntryLinks " // + entry.getName() + " time:" + (t2 - t1)); } } /** * Get the OPeNDAP URL * * @param entry the Entry * * @return the URL as a string */ public String getOpendapUrl(Entry entry) { return getOpendapHandler().getOpendapUrl(entry); } /** * Get the absolute OPeNDAP URL * * * @param request the request * @param entry the entry * * @return the URL as a String */ public String getAbsoluteOpendapUrl(Request request, Entry entry) { return getOpendapHandler().getAbsoluteOpendapUrl(request, entry); } /** * Check if we can load the Entry * * @param entry the Entry * * @return true if we can load it */ private boolean canLoadEntry(Entry entry) { String url = entry.getResource().getPath(); if (url == null) { return false; } if (url.endsWith("~")) { return false; } if (url.endsWith("#")) { return false; } if (entry.isGroup()) { return false; } if (entry.getResource().isRemoteFile()) { return true; } if (entry.getResource().isFileType()) { return entry.getFile().exists(); } if (!entry.getResource().isUrl()) { return false; } if (url.indexOf("dods") >= 0) { return true; } return true; } /** * Output the CDL for the Entry * * @param request the Request * @param entry the Entry * * @return the CDL Result * * @throws Exception problems */ public Result outputCdl(final Request request, Entry entry) throws Exception { String path = getPath(request, entry); String dodspath = getAbsoluteOpendapUrl(request, entry); if (request.getString(ARG_FORMAT, "").equals(FORMAT_NCML)) { /** * This gets hung up calling back into the repository * so for now don't do it and just use the file * path = getAbsoluteOpendapUrl(request, entry); */ NetcdfFile ncFile = NetcdfDataset.openFile(path, null); NcMLWriter writer = new NcMLWriter(); String xml = writer.writeXML(ncFile); xml = xml.replace("file:" + path, dodspath).replace(path, dodspath); Result result = new Result("", new StringBuffer(xml), "text/xml"); ncFile.close(); return result; } StringBuffer sb = new StringBuffer(); if (request.get(ARG_METADATA_ADD, false)) { if (getRepository().getAccessManager().canDoAction(request, entry, Permission.ACTION_EDIT)) { sb.append(HtmlUtils.p()); List<Entry> entries = (List<Entry>) Misc.newList(entry); getEntryManager().addInitialMetadata(request, entries, false, request.get(ARG_SHORT, false)); getEntryManager().updateEntries(request, entries); sb.append(getPageHandler().showDialogNote("Properties added")); sb.append(getRepository().getHtmlOutputHandler().getInformationTabs(request, entry, false, false)); } else { sb.append("You cannot add properties"); } return makeLinksResult(request, "CDL", sb, new State(entry)); } if (getRepository().getAccessManager().canDoAction(request, entry, Permission.ACTION_EDIT)) { request.put(ARG_METADATA_ADD, HtmlUtils.VALUE_TRUE); sb.append(HtmlUtils.href(request.getUrl() + "&" + HtmlUtils.arg(ARG_SHORT, HtmlUtils.VALUE_TRUE), msg("Add temporal and spatial properties"))); sb.append(HtmlUtils.span(" | ", HtmlUtils.cssClass(CSS_CLASS_SEPARATOR))); sb.append(HtmlUtils.href(request.getUrl(), msg("Add full properties"))); sb.append(HtmlUtils.span(" | ", HtmlUtils.cssClass(CSS_CLASS_SEPARATOR))); } String tail = IOUtil.stripExtension(getStorageManager().getFileTail(entry)); sb.append(HtmlUtils.href( HtmlUtils.url(getRepository().URL_ENTRY_SHOW + "/" + tail + SUFFIX_NCML, new String[] { ARG_ENTRYID, entry.getId(), ARG_OUTPUT, OUTPUT_CDL.getId(), ARG_FORMAT, FORMAT_NCML }), "NCML")); NetcdfDataset dataset = getCdmManager().createNetcdfDataset(path); if (dataset == null) { sb.append("Could not open dataset"); } else { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ucar.nc2.NCdump.print(dataset, "", bos, null); String cdl = bos.toString(); cdl = cdl.replace("file:" + path, dodspath).replace(path, dodspath); sb.append("<pre>" + cdl + "</pre>"); getCdmManager().returnNetcdfDataset(path, dataset); } return makeLinksResult(request, "CDL", sb, new State(entry)); } /** * Output the Entry as a WCS result * * @param request the Request * @param entry the Entry * * @return the Result */ public Result outputWcs(Request request, Entry entry) { return new Result("", new StringBuffer("TBD")); } /** * Process a grid as point request * * @param request the request * @param entry the entry * @param gds the corresponding grid dataset * @param sb the StringBuffer * * @return a Result * * @throws Exception problem doing what was asked */ public Result outputGridAsPointProcess(Request request, Entry entry, GridDataset gds, StringBuffer sb) throws Exception { List varNames = new ArrayList<String>(); Hashtable args = request.getArgs(); for (Enumeration keys = args.keys(); keys.hasMoreElements();) { String arg = (String) keys.nextElement(); if (arg.startsWith(VAR_PREFIX) && request.get(arg, false)) { varNames.add(arg.substring(VAR_PREFIX.length())); } } // System.err.println(varNames); LatLonRect llr = gds.getBoundingBox(); double deflat = 0; double deflon = 0; if (llr != null) { deflat = llr.getLatMin() + llr.getHeight() / 2; deflon = llr.getCenterLon(); } LatLonPointImpl llp = null; if (request.get(ARG_LOCATION, true)) { llp = new LatLonPointImpl(request.getLatOrLonValue(ARG_LOCATION + ".latitude", deflat), request.getLatOrLonValue(ARG_LOCATION + ".longitude", deflon)); } double levelVal = request.get(ARG_LEVEL, Double.NaN); int timeStride = 1; Date[] dates = new Date[] { request.defined(ARG_FROMDATE) ? request.getDate(ARG_FROMDATE, null) : null, request.defined(ARG_TODATE) ? request.getDate(ARG_TODATE, null) : null }; //have to have both dates if ((dates[0] != null) && (dates[1] == null)) { dates[0] = null; } if ((dates[1] != null) && (dates[0] == null)) { dates[1] = null; } if ((dates[0] != null) && (dates[1] != null) && (dates[0].getTime() > dates[1].getTime())) { sb.append(getPageHandler().showDialogWarning("From date is after to date")); } else if (varNames.size() == 0) { sb.append(getPageHandler().showDialogWarning("No variables selected")); } else { // System.err.println ("varNames:" + varNames); QueryParams qp = new QueryParams(); String format = request.getString(ARG_FORMAT, QueryParams.NETCDF); qp.acceptType = (format.equals(FORMAT_TIMESERIES_CHART) || format.equals(FORMAT_TIMESERIES_IMAGE)) ? QueryParams.CSV : format; qp.vars = varNames; qp.hasLatlonPoint = true; qp.lat = llp.getLatitude(); qp.lon = llp.getLongitude(); if (dates[0] != null) { qp.time_start = new DateType(false, dates[0]); if (dates[1] != null) { qp.time_end = new DateType(false, dates[1]); qp.hasDateRange = true; } else { qp.hasTimePoint = true; qp.hasDateRange = false; qp.time = qp.time_start; } } if (levelVal == levelVal) { qp.hasVerticalCoord = true; qp.vertCoord = levelVal; } String suffix = ".nc"; if (qp.acceptType.equals(QueryParams.CSV) || format.equals(FORMAT_TIMESERIES_CHART_DATA) || format.equals(FORMAT_TIMESERIES_IMAGE)) { suffix = ".csv"; } else if (qp.acceptType.equals(QueryParams.XML)) { suffix = ".xml"; } String baseName = IOUtil.stripExtension(entry.getName()); if (format.equals(FORMAT_TIMESERIES_CHART)) { StringBuffer buf = new StringBuffer(); String chartTemplate = getRepository() .getResource("/org/ramadda/repository/resources/chart/dycharts.html"); chartTemplate = chartTemplate.replaceAll("\\$\\{urlroot\\}", getRepository().getUrlBase()); //String title = request.getString(ARG_POINT_TIMESERIES_TITLE, // entry.getName()); String title = "Data at: " + llp.toString(); if (title.equals("")) { title = entry.getName(); } chartTemplate = chartTemplate.replace("${title}", title); StringBuffer vizsb = new StringBuffer("visibility: [false, false"); if (qp.hasVerticalCoord) { vizsb.append(", false"); } for (int var = 0; var < varNames.size(); var++) { vizsb.append(", true"); } vizsb.append("],"); chartTemplate = chartTemplate.replace("${options}", vizsb.toString()); String html = chartTemplate; request.put(ARG_FORMAT, QueryParams.CSV); String dataUrl = request.getRequestPath() + "/" + baseName + suffix + "?" + request.getUrlArgs(); html = html.replace("${dataurl}", dataUrl); buf.append(html); return new Result("Point As Grid Time Series", buf); } File tmpFile = getStorageManager().getTmpFile(request, "pointsubset" + suffix); GridPointWriter writer = new GridPointWriter(gds, new DiskCache2( getRepository().getStorageManager().getScratchDir().getDir().toString(), false, 0, 0)); OutputStream outStream = (qp.acceptType.equals(QueryParams.NETCDF)) ? System.out : getStorageManager().getUncheckedFileOutputStream(tmpFile); PrintWriter pw = new PrintWriter(outStream); File f = writer.write(qp, pw); if (f == null) { outStream.close(); f = tmpFile; } if (doingPublish(request)) { return getEntryManager().processEntryPublish(request, f, (Entry) entry.clone(), entry, "point series of"); } Result result = null; if (format.equals(FORMAT_TIMESERIES_IMAGE)) { result = outputTimeSeriesImage(request, entry, f); } else { result = new Result(getStorageManager().getFileInputStream(f), qp.acceptType); //Set return filename sets the Content-Disposition http header so the browser saves the file //with the correct name and suffix result.setReturnFilename(baseName + "_pointsubset" + suffix); } return result; } return new Result("", sb); } /** * Output the grid as a point form * * @param request the request * @param entry the entry * @param dataset the corresponding dataset * @param sb the string buffer * * @return the result * * @throws Exception problem creating form */ public Result outputGridAsPointForm(Request request, Entry entry, GridDataset dataset, StringBuffer sb) throws Exception { boolean canAdd = getRepository().getAccessManager().canDoAction(request, entry.getParentEntry(), Permission.ACTION_NEW); String formUrl = request.url(getRepository().URL_ENTRY_SHOW); String fileName = IOUtil.stripExtension(entry.getName()) + "_point"; sb.append(HtmlUtils.form(formUrl + "/" + fileName)); sb.append(HtmlUtils.br()); sb.append(HtmlUtils.submit("Get Point", ARG_SUBMIT)); sb.append(HtmlUtils.br()); sb.append(HtmlUtils.hidden(ARG_OUTPUT, OUTPUT_GRIDASPOINT)); sb.append(HtmlUtils.hidden(ARG_ENTRYID, entry.getId())); sb.append(HtmlUtils.formTable()); Date[] dateRange = null; List<Date> dates = getGridDates(dataset); StringBuffer varSB = getVariableForm(dataset, true); LatLonRect llr = dataset.getBoundingBox(); String lat = ""; String lon = ""; if (llr != null) { lat = Misc.format(llr.getLatMin() + llr.getHeight() / 2); lon = Misc.format(llr.getCenterLon()); } MapInfo map = getRepository().getMapManager().createMap(request, true); map.addBox("", llr, new MapProperties("blue", false, true)); String llb = map.makeSelector(ARG_LOCATION, true, new String[] { lat, lon }); sb.append(HtmlUtils.formEntryTop(msgLabel("Location"), llb)); if ((dates != null) && (dates.size() > 0)) { List formattedDates = new ArrayList(); formattedDates.add(new TwoFacedObject("---", "")); for (Date date : dates) { formattedDates.add(getPageHandler().formatDate(request, date)); } String fromDate = request.getUnsafeString(ARG_FROMDATE, ""); String toDate = request.getUnsafeString(ARG_TODATE, ""); sb.append(HtmlUtils.formEntry(msgLabel("Time Range"), HtmlUtils.select(ARG_FROMDATE, formattedDates, fromDate) + HtmlUtils.img(iconUrl(ICON_ARROW)) + HtmlUtils.select(ARG_TODATE, formattedDates, toDate))); } List formats = Misc.toList(new Object[] { new TwoFacedObject("NetCDF", QueryParams.NETCDF), new TwoFacedObject("XML", QueryParams.XML), new TwoFacedObject("Time Series Image", FORMAT_TIMESERIES), // Comment out until it works better to handled dates //new TwoFacedObject("Interactive Time Series", // FORMAT_TIMESERIES_CHART), new TwoFacedObject("Comma Separated Values (CSV)", QueryParams.CSV) }); String format = request.getString(ARG_FORMAT, QueryParams.NETCDF); sb.append(HtmlUtils.formEntry(msgLabel("Format"), HtmlUtils.select(ARG_FORMAT, formats, format))); addPublishWidget(request, entry, sb, msg("Select a folder to publish the results to")); sb.append(HtmlUtils.formTableClose()); sb.append("<hr>"); sb.append(msgLabel("Select Variables")); sb.append(HtmlUtils.insetDiv( HtmlUtils.table(varSB.toString(), HtmlUtils.attrs(HtmlUtils.ATTR_CELLPADDING, "5", HtmlUtils.ATTR_CELLSPACING, "0")), 0, 30, 0, 0)); sb.append(HtmlUtils.submit("Get Point")); //sb.append(submitExtra); sb.append(HtmlUtils.formClose()); return makeLinksResult(request, msg("Grid At Point"), sb, new State(entry)); } /** * Get the grid dates * * @param dataset the dataset * * @return the dates or null */ private List<Date> getGridDates(GridDataset dataset) { List<Date> gridDates = null; List<GridDatatype> grids = dataset.getGrids(); HashSet<Date> dateHash = new HashSet<Date>(); List<CoordinateAxis1DTime> timeAxes = new ArrayList<CoordinateAxis1DTime>(); for (GridDatatype grid : grids) { GridCoordSystem gcs = grid.getCoordinateSystem(); CoordinateAxis1DTime timeAxis = gcs.getTimeAxis1D(); if ((timeAxis != null) && !timeAxes.contains(timeAxis)) { timeAxes.add(timeAxis); Date[] timeDates = timeAxis.getTimeDates(); for (Date timeDate : timeDates) { dateHash.add(timeDate); } } } if (!dateHash.isEmpty()) { gridDates = Arrays.asList(dateHash.toArray(new Date[dateHash.size()])); Collections.sort(gridDates); } return gridDates; } /** * Get the variable selector form * * @param dataset the dataset * @param withLevelSelector if true, include a level selector widget * * @return the form */ protected StringBuffer getVariableForm(GridDataset dataset, boolean withLevelSelector) { int varCnt = 0; StringBuffer varSB = new StringBuffer(); StringBuffer varSB2D = new StringBuffer(); StringBuffer varSB3D = new StringBuffer(); List<GridDatatype> grids = sortGrids(dataset); for (GridDatatype grid : grids) { String cbxId = "varcbx_" + (varCnt++); String call = HtmlUtils.attr(HtmlUtils.ATTR_ONCLICK, HtmlUtils.call("checkboxClicked", HtmlUtils.comma("event", HtmlUtils.squote(ARG_VARIABLE), HtmlUtils.squote(cbxId)))); VariableEnhanced var = grid.getVariable(); StringBuffer sbToUse = (grid.getZDimension() == null) ? varSB2D : varSB3D; sbToUse.append(HtmlUtils.row(HtmlUtils.cols( HtmlUtils.checkbox(ARG_VARIABLE + "." + var.getShortName(), HtmlUtils.VALUE_TRUE, (grids.size() == 1), HtmlUtils.id(cbxId) + call) + HtmlUtils.space(1) + var.getName() + HtmlUtils.space(1) + ((var.getUnitsString() != null) ? "(" + var.getUnitsString() + ")" : ""), "<i>" + var.getDescription() + "</i>"))); } if (varSB2D.length() > 0) { if (varSB3D.length() > 0) { varSB.append(HtmlUtils.row(HtmlUtils.headerCols(new Object[] { "2D Grids" }))); } varSB.append(varSB2D); } if (varSB3D.length() > 0) { if ((varSB2D.length() > 0) || withLevelSelector) { String header = " 3D Grids"; if (withLevelSelector) { header += HtmlUtils.space(3) + "Level:" + HtmlUtils.space(1) + HtmlUtils.input(ARG_LEVEL, ""); } varSB.append(HtmlUtils.row(HtmlUtils.headerCols(new Object[] { header }))); } varSB.append(varSB3D); } return varSB; } /** * Handle a grid as point request * * @param request the request * @param entry the entry * * @return the result * * @throws Exception problems */ public Result outputGridAsPoint(Request request, Entry entry) throws Exception { String format = request.getString(ARG_FORMAT, QueryParams.NETCDF); String baseName = IOUtil.stripExtension(entry.getName()); if (format.equals(FORMAT_TIMESERIES)) { request.put(ARG_FORMAT, FORMAT_TIMESERIES_IMAGE); String redirectUrl = request.getRequestPath() + "/" + baseName + ".png" + "?" + request.getUrlArgs(); return new Result("Point As Grid Time Series Image", new StringBuffer(HtmlUtils.img(redirectUrl, "Image is being processed..."))); } StringBuffer sb = new StringBuffer(); String path = getPath(request, entry); GridDataset gds = getCdmManager().getGridDataset(entry, path); OutputType output = request.getOutput(); try { if (output.equals(OUTPUT_GRIDASPOINT)) { Result result = outputGridAsPointProcess(request, entry, gds, sb); if (result != null) { return result; } } return outputGridAsPointForm(request, entry, gds, sb); } finally { getCdmManager().returnGridDataset(path, gds); } } /** * Handle a grid subset request * * @param request the request * @param entry the entry * * @return a Result * * @throws Exception problem handling the request */ public Result outputGridSubset(Request request, Entry entry) throws Exception { boolean canAdd = getRepository().getAccessManager().canDoAction(request, entry.getParentEntry(), Permission.ACTION_NEW); String path = getPath(request, entry); StringBuffer sb = new StringBuffer(); OutputType output = request.getOutput(); if (output.equals(OUTPUT_GRIDSUBSET)) { List varNames = new ArrayList(); Hashtable args = request.getArgs(); for (Enumeration keys = args.keys(); keys.hasMoreElements();) { String arg = (String) keys.nextElement(); if (arg.startsWith(VAR_PREFIX) && request.get(arg, false)) { varNames.add(arg.substring(VAR_PREFIX.length())); } } // System.err.println(varNames); LatLonRect llr = null; boolean anySpatialDifferent = false; boolean haveAllSpatialArgs = true; for (String spatialArg : SPATIALARGS) { if (!Misc.equals(request.getString(spatialArg, ""), request.getString(spatialArg + ".original", ""))) { anySpatialDifferent = true; break; } } for (String spatialArg : SPATIALARGS) { if (!request.defined(spatialArg)) { haveAllSpatialArgs = false; break; } } if (haveAllSpatialArgs && anySpatialDifferent) { llr = new LatLonRect( new LatLonPointImpl(request.get(ARG_AREA_NORTH, 90.0), request.get(ARG_AREA_WEST, -180.0)), new LatLonPointImpl(request.get(ARG_AREA_SOUTH, 0.0), request.get(ARG_AREA_EAST, 180.0))); // System.err.println("llr:" + llr); } int hStride = request.get(ARG_HSTRIDE, 1); int zStride = 1; boolean includeLatLon = request.get(ARG_ADDLATLON, false); int timeStride = 1; Date[] dates = new Date[] { request.defined(ARG_FROMDATE) ? request.getDate(ARG_FROMDATE, null) : null, request.defined(ARG_TODATE) ? request.getDate(ARG_TODATE, null) : null }; //have to have both dates if ((dates[0] != null) && (dates[1] == null)) { dates[0] = null; } if ((dates[1] != null) && (dates[0] == null)) { dates[1] = null; } if ((dates[0] != null) && (dates[1] != null) && (dates[0].getTime() > dates[1].getTime())) { sb.append(getPageHandler().showDialogWarning("From date is after to date")); } else if (varNames.size() == 0) { sb.append(getPageHandler().showDialogWarning("No variables selected")); } else { NetcdfCFWriter writer = new NetcdfCFWriter(); File f = getRepository().getStorageManager().getTmpFile(request, "subset.nc"); GridDataset gds = getCdmManager().getGridDataset(entry, path); writer.makeFile(f.toString(), gds, varNames, llr, ((dates[0] == null) ? null : new ucar.nc2.units.DateRange(dates[0], dates[1])), includeLatLon, hStride, zStride, timeStride); getCdmManager().returnGridDataset(path, gds); if (doingPublish(request)) { TypeHandler typeHandler = getRepository().getTypeHandler(TypeHandler.TYPE_FILE); Entry newEntry = typeHandler.createEntry(getRepository().getGUID()); return getEntryManager().processEntryPublish(request, f, newEntry, entry, "subset of"); } Result result = new Result(entry.getName() + ".nc", getStorageManager().getFileInputStream(f), "application/x-netcdf"); result.setReturnFilename(entry.getName() + "_subset.nc"); return result; } } String formUrl = request.url(getRepository().URL_ENTRY_SHOW); String fileName = IOUtil.stripExtension(entry.getName()) + "_subset.nc"; sb.append(HtmlUtils.form(formUrl + "/" + fileName)); sb.append(HtmlUtils.br()); sb.append(HtmlUtils.submit("Subset Grid", ARG_SUBMIT)); sb.append(HtmlUtils.br()); sb.append(HtmlUtils.hidden(ARG_OUTPUT, OUTPUT_GRIDSUBSET)); sb.append(HtmlUtils.hidden(ARG_ENTRYID, entry.getId())); sb.append(HtmlUtils.formTable()); sb.append(HtmlUtils.formEntry(msgLabel("Horizontal Stride"), HtmlUtils.input(ARG_HSTRIDE, request.getString(ARG_HSTRIDE, "1"), HtmlUtils.SIZE_3))); GridDataset dataset = getCdmManager().getGridDataset(entry, path); Date[] dateRange = null; List<Date> dates = getGridDates(dataset); StringBuffer varSB = getVariableForm(dataset, false); LatLonRect llr = dataset.getBoundingBox(); if (llr != null) { MapInfo map = getRepository().getMapManager().createMap(request, true); map.addBox("", llr, new MapProperties("blue", false, true)); String[] points = new String[] { "" + llr.getLatMax(), "" + llr.getLonMin(), "" + llr.getLatMin(), "" + llr.getLonMax(), }; for (int i = 0; i < points.length; i++) { sb.append(HtmlUtils.hidden(SPATIALARGS[i] + ".original", points[i])); } String llb = map.makeSelector(ARG_AREA, true, points); sb.append(HtmlUtils.formEntryTop(msgLabel("Subset Spatially"), llb)); } if ((dates != null) && (dates.size() > 0)) { List formattedDates = new ArrayList(); formattedDates.add(new TwoFacedObject("---", "")); for (Date date : dates) { formattedDates.add(getPageHandler().formatDate(request, date)); } /* for now default to "" for dates String fromDate = request.getUnsafeString(ARG_FROMDATE, getPageHandler().formatDate(request, dates.get(0))); String toDate = request.getUnsafeString(ARG_TODATE, getPageHandler().formatDate(request, dates.get(dates.size() - 1))); */ String fromDate = request.getUnsafeString(ARG_FROMDATE, ""); String toDate = request.getUnsafeString(ARG_TODATE, ""); sb.append(HtmlUtils.formEntry(msgLabel("Time Range"), HtmlUtils.select(ARG_FROMDATE, formattedDates, fromDate) + HtmlUtils.img(iconUrl(ICON_ARROW)) + HtmlUtils.select(ARG_TODATE, formattedDates, toDate))); } sb.append(HtmlUtils.formEntry(msgLabel("Add Lat/Lon Variables"), HtmlUtils.checkbox(ARG_ADDLATLON, HtmlUtils.VALUE_TRUE, request.get(ARG_ADDLATLON, true)))); addPublishWidget(request, entry, sb, msg("Select a folder to publish the results to")); sb.append(HtmlUtils.formTableClose()); sb.append("<hr>"); sb.append(msgLabel("Select Variables")); sb.append("<ul>"); sb.append("<table>"); sb.append(varSB); sb.append("</table>"); sb.append("</ul>"); sb.append(HtmlUtils.br()); sb.append(HtmlUtils.submit(msg("Subset Grid"))); sb.append(HtmlUtils.formClose()); getCdmManager().returnGridDataset(path, dataset); return makeLinksResult(request, msg("Grid Subset"), sb, new State(entry)); } /** * Sort the grids * * @param dataset the grid dataset * * @return the grids */ public List<GridDatatype> sortGrids(GridDataset dataset) { List tuples = new ArrayList(); for (GridDatatype grid : dataset.getGrids()) { VariableEnhanced var = grid.getVariable(); tuples.add(new Object[] { var.getShortName().toLowerCase(), grid }); } tuples = Misc.sortTuples(tuples, true); List<GridDatatype> result = new ArrayList<GridDatatype>(); for (Object[] tuple : (List<Object[]>) tuples) { result.add((GridDatatype) tuple[1]); } return result; } /** * Get the PointFeatureIterator * * @param input the dataset * * @return the iterator * * @throws Exception problem getting the iterator */ public static PointFeatureIterator getPointIterator(FeatureDatasetPoint input) throws Exception { List<FeatureCollection> collectionList = input.getPointFeatureCollectionList(); if (collectionList.size() > 1) { throw new IllegalArgumentException("Can't handle point data with multiple collections"); } FeatureCollection fc = collectionList.get(0); PointFeatureCollection collection = null; if (fc instanceof PointFeatureCollection) { collection = (PointFeatureCollection) fc; } else if (fc instanceof NestedPointFeatureCollection) { NestedPointFeatureCollection npfc = (NestedPointFeatureCollection) fc; collection = npfc.flatten(null, null); } else { throw new IllegalArgumentException("Can't handle collection of type " + fc.getClass().getName()); } return collection.getPointFeatureIterator(16384); } /** * Output a point map * * @param request the request * @param entry the entry * * @return the Result * * @throws Exception on badness */ public Result outputPointMap(Request request, Entry entry) throws Exception { MapInfo map = getRepository().getMapManager().createMap(request, false); String path = getPath(request, entry); FeatureDatasetPoint pod = getCdmManager().getPointDataset(entry, path); StringBuffer sb = new StringBuffer(); List vars = pod.getDataVariables(); int skip = request.get(ARG_SKIP, 0); int max = request.get(ARG_MAX, 200); int cnt = 0; int total = 0; String icon = iconUrl("/icons/pointdata.gif"); PointFeatureIterator dataIterator = getPointIterator(pod); List columnDataList = new ArrayList(); while (dataIterator.hasNext()) { PointFeature po = (PointFeature) dataIterator.next(); // ucar.unidata.geoloc.EarthLocation el = po.getLocation(); ucar.unidata.geoloc.EarthLocation el = po.getLocation(); if (el == null) { continue; } double lat = el.getLatitude(); double lon = el.getLongitude(); if ((lat != lat) || (lon != lon)) { continue; } if ((lat < -90) || (lat > 90) || (lon < -180) || (lon > 180)) { continue; } total++; if (total <= skip) { continue; } if (total > (max + skip)) { continue; } cnt++; List columnData = new ArrayList(); StructureData structure = po.getData(); StringBuffer info = new StringBuffer(""); info.append("<b>Date:</b> " + po.getNominalTimeAsDate() + "<br>"); for (VariableSimpleIF var : (List<VariableSimpleIF>) vars) { //{name:\"Ashley\",breed:\"German Shepherd\",age:12} StructureMembers.Member member = structure.findMember(var.getShortName()); if ((var.getDataType() == DataType.STRING) || (var.getDataType() == DataType.CHAR)) { String value = structure.getScalarString(member); columnData.add(var.getShortName() + ":" + HtmlUtils.quote(value)); info.append("<b>" + var.getName() + ": </b>" + value + "</br>"); } else { float value = structure.convertScalarFloat(member); info.append("<b>" + var.getName() + ": </b>" + value + "</br>"); columnData.add(var.getShortName() + ":" + value); } } columnDataList.add("{" + StringUtil.join(",", columnData) + "}\n"); map.addMarker("", new LatLonPointImpl(el.getLatitude(), el.getLongitude()), icon, info.toString()); } List columnDefs = new ArrayList(); List columnNames = new ArrayList(); for (VariableSimpleIF var : (List<VariableSimpleIF>) vars) { columnNames.add(HtmlUtils.quote(var.getShortName())); String label = var.getDescription(); // if(label.trim().length()==0) label = var.getName(); columnDefs.add("{key:" + HtmlUtils.quote(var.getShortName()) + "," + "sortable:true," + "label:" + HtmlUtils.quote(label) + "}"); } if (total > max) { sb.append((skip + 1) + "-" + (skip + cnt) + " of " + total + " "); } else { sb.append((skip + 1) + "-" + (skip + cnt)); } if (total > max) { boolean didone = false; if (skip > 0) { sb.append(HtmlUtils.space(2)); sb.append(HtmlUtils.href( HtmlUtils.url(request.getRequestPath(), new String[] { ARG_OUTPUT, request.getOutput().toString(), ARG_ENTRYID, entry.getId(), ARG_SKIP, "" + (skip - max), ARG_MAX, "" + max }), msg("Previous"))); didone = true; } if (total > (skip + cnt)) { sb.append(HtmlUtils.space(2)); sb.append(HtmlUtils.href( HtmlUtils.url(request.getRequestPath(), new String[] { ARG_OUTPUT, request.getOutput().toString(), ARG_ENTRYID, entry.getId(), ARG_SKIP, "" + (skip + max), ARG_MAX, "" + max }), msg("Next"))); didone = true; } //Just come up with some max number if (didone && (total < 2000)) { sb.append(HtmlUtils.space(2)); sb.append( HtmlUtils.href( HtmlUtils.url(request.getRequestPath(), new String[] { ARG_OUTPUT, request.getOutput().toString(), ARG_ENTRYID, entry.getId(), ARG_SKIP, "" + 0, ARG_MAX, "" + total }), msg("All"))); } } map.center(); sb.append(map.getHtml()); getCdmManager().returnPointDataset(path, pod); return new Result(msg("Point Data Map"), sb); } /** Fixed var name for lat */ public static final String VAR_LATITUDE = "Latitude"; /** Fixed var name for lon */ public static final String VAR_LONGITUDE = "Longitude"; /** Fixed var name for alt */ public static final String VAR_ALTITUDE = "Altitude"; /** Fixed var name for time */ public static final String VAR_TIME = "Time"; /** * Get the 1D values for an array as floats. * * @param arr Array of values * @return float representation */ public static float[] toFloatArray(Array arr) { Object dst = arr.get1DJavaArray(float.class); Class fromClass = dst.getClass().getComponentType(); if (fromClass.equals(float.class)) { //It should always be a float return (float[]) dst; } else { float[] values = new float[(int) arr.getSize()]; if (fromClass.equals(byte.class)) { byte[] fromArray = (byte[]) dst; for (int i = 0; i < fromArray.length; ++i) { values[i] = fromArray[i]; } } else if (fromClass.equals(short.class)) { short[] fromArray = (short[]) dst; for (int i = 0; i < fromArray.length; ++i) { values[i] = fromArray[i]; } } else if (fromClass.equals(int.class)) { int[] fromArray = (int[]) dst; for (int i = 0; i < fromArray.length; ++i) { values[i] = fromArray[i]; } } else if (fromClass.equals(double.class)) { double[] fromArray = (double[]) dst; for (int i = 0; i < fromArray.length; ++i) { values[i] = (float) fromArray[i]; } } else { throw new IllegalArgumentException("Unknown array type:" + fromClass.getName()); } return values; } } /** * Output a trajectory map * * @param request the request * @param entry the entry * * @return the result * * @throws Exception on badness */ public Result outputTrajectoryMap(Request request, Entry entry) throws Exception { String path = getPath(request, entry); TrajectoryObsDataset tod = getCdmManager().getTrajectoryDataset(path); StringBuffer sb = new StringBuffer(); MapInfo map = getRepository().getMapManager().createMap(request, 800, 600, false); List trajectories = tod.getTrajectories(); //TODO: Use new openlayers map for (int i = 0; i < trajectories.size(); i++) { List allVariables = tod.getDataVariables(); TrajectoryObsDatatype todt = (TrajectoryObsDatatype) trajectories.get(i); float[] lats = toFloatArray(todt.getLatitude(null)); float[] lons = toFloatArray(todt.getLongitude(null)); float lastLat = 0, lastLon = 0; int stride = lats.length / 500; for (int ptIdx = 0; ptIdx < lats.length; ptIdx += stride) { float lat = lats[ptIdx]; float lon = lons[ptIdx]; if (ptIdx > 0) { if (ptIdx + stride >= lats.length) { map.addMarker("", lat, lon, null, "End time:" + todt.getEndDate()); } //#FF0000 map.addLine("", lastLat, lastLon, lat, lon); } else { map.addMarker("", lat, lon, null, "Start time:" + todt.getEndDate()); } lastLat = lat; lastLon = lon; } StructureData structure = todt.getData(0); VariableSimpleIF theVar = null; for (int varIdx = 0; varIdx < allVariables.size(); varIdx++) { VariableSimpleIF var = (VariableSimpleIF) allVariables.get(varIdx); if (var.getRank() != 0) { continue; } theVar = var; break; } if (theVar == null) { continue; } } map.centerOn(entry); sb.append(map.getHtml()); getCdmManager().returnTrajectoryDataset(path, tod); return new Result(msg("Trajectory Map"), sb); } /* public Result outputTrajectoryChart(Request request, Entry entry) throws Exception { TrajectoryObsDataset tod = trajectoryPool.get(entry.getResource().getPath()); StringBuffer sb = new StringBuffer(); StringBuffer head = new StringBuffer(); head.append("<script type='text/javascript' src='http://www.google.com/jsapi'></script>\n"); head.append("<script type='text/javascript'>\n"); head.append("google.load('visualization', '1', {'packages':['annotatedtimeline']});\n"); head.append("google.setOnLoadCallback(drawChart);\n"); head.append("function drawChart() {"); head.append("var data = new google.visualization.DataTable();\n"); head.append("data.addColumn('date', 'Date');\n"); head.append("data.addColumn('number', 'Value');\n"); head.append("var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart_div'));\n"); sb.append("<div id='chart_div' style='width: 700px; height: 240px;'></div>\n"); StringBuffer values = new StringBuffer(); int numRows = 0; synchronized (tod) { List trajectories = tod.getTrajectories(); List allVariables = tod.getDataVariables(); TrajectoryObsDatatype todt = (TrajectoryObsDatatype) trajectories.get(0); float[] lats = toFloatArray(todt.getLatitude(null)); numRows = lats.length; for (int ptIdx = 0; ptIdx < lats.length; ptIdx++) { StructureData structure = todt.getData(0); VariableSimpleIF theVar = null; for (int varIdx = 0; varIdx < allVariables.size(); varIdx++) { VariableSimpleIF var = (VariableSimpleIF) allVariables.get(varIdx); if (var.getRank() != 0) { continue; } theVar = var; break; } if (theVar == null) { continue; } values.append("data.setValue(0, 0, new Date(2008, 1 ,1));\n"); values.append("data.setValue(0, 1, 30000);\n"); } } head.append(values); head.append("data.addRows(" + numRows+");\n"); head.append("chart.draw(data, {displayAnnotations: true});\n"); head.append("}\n</script>\n"); Result result = new Result(msg("Trajectory Time Series"), sb); result.putProperty(PROP_HTML_HEAD,head.toString()); return result; } */ /** * Make the Point Subset form * * @param request the Request * @param entry the Entry * @param suffix the type as a suffix * * @return the Result */ private Result makePointSubsetForm(Request request, Entry entry, String suffix) { StringBuffer sb = new StringBuffer(); String formUrl = request.url(getRepository().URL_ENTRY_SHOW); sb.append(HtmlUtils.form(formUrl + suffix)); sb.append(HtmlUtils.submit("Subset Point Data", ARG_SUBMIT)); sb.append(HtmlUtils.hidden(ARG_OUTPUT, request.getString(ARG_OUTPUT, ""))); sb.append(HtmlUtils.hidden(ARG_ENTRYID, entry.getId())); sb.append(HtmlUtils.formTable()); List<TwoFacedObject> formats = new ArrayList<TwoFacedObject>(); formats.add(new TwoFacedObject("CSV", FORMAT_CSV)); formats.add(new TwoFacedObject("KML", FORMAT_KML)); String format = request.getString(ARG_FORMAT, FORMAT_CSV); sb.append(HtmlUtils.formEntry(msgLabel("Format"), HtmlUtils.select(ARG_FORMAT, formats, format))); MapInfo map = getRepository().getMapManager().createMap(request, true); map.addBox(entry, new MapProperties("blue", false, true)); map.centerOn(entry); String llb = map.makeSelector(ARG_POINT_BBOX, true, null); sb.append(HtmlUtils.formEntryTop(msgLabel("Location"), llb)); sb.append(HtmlUtils.formTableClose()); sb.append(HtmlUtils.submit("Subset Point Data", ARG_SUBMIT)); sb.append(HtmlUtils.formClose()); return new Result("", sb); } /** * Get the services for the request * * @param request the Request * @param entry the Entry * @param services the list of services */ @Override public void getServices(Request request, Entry entry, List<Service> services) { super.getServices(request, entry, services); if (!getCdmManager().canLoadAsCdm(entry)) { return; } String url = getAbsoluteOpendapUrl(request, entry); services.add(new Service("opendap", "OPeNDAP Link", url)); } /** * Output a point subset * * @param request the Request * @param entry the Entry * * @return the Result * * @throws Exception problem making subset */ public Result outputPointSubset(Request request, Entry entry) throws Exception { if (!request.defined(ARG_FORMAT)) { return makePointSubsetForm(request, entry, ""); } String format = request.getString(ARG_FORMAT, FORMAT_CSV); if (format.equals(FORMAT_CSV)) { request.getHttpServletResponse().setContentType("text/csv"); request.setReturnFilename(IOUtil.stripExtension(entry.getName()) + ".csv"); } else { request.getHttpServletResponse().setContentType("application/vnd.google-earth.kml+xml"); request.setReturnFilename(IOUtil.stripExtension(entry.getName()) + ".kml"); } // System.out.println("name: " + request); OutputStream os = request.getHttpServletResponse().getOutputStream(); PrintWriter pw = new PrintWriter(os); if (format.equals(FORMAT_CSV)) { outputPointCsv(request, entry, pw); } else { outputPointKml(request, entry, pw); } pw.close(); Result result = new Result(); result.setNeedToWrite(false); return result; } /** * Output the point data as CSV * * @param request the Request * @param entry the Entry * @param pw the PrintWriter * * * @throws Exception problem getting data */ private void outputPointCsv(Request request, Entry entry, PrintWriter pw) throws Exception { String path = getPath(request, entry); FeatureDatasetPoint pod = getCdmManager().getPointDataset(entry, path); ; List vars = pod.getDataVariables(); PointFeatureIterator dataIterator = getPointIterator(pod); int cnt = 0; while (dataIterator.hasNext()) { PointFeature po = (PointFeature) dataIterator.next(); ucar.unidata.geoloc.EarthLocation el = po.getLocation(); if (el == null) { continue; } cnt++; double lat = el.getLatitude(); double lon = el.getLongitude(); StructureData structure = po.getData(); if (cnt == 1) { pw.print(HtmlUtils.quote("Time")); pw.print(","); pw.print(HtmlUtils.quote("Latitude")); pw.print(","); pw.print(HtmlUtils.quote("Longitude")); for (VariableSimpleIF var : (List<VariableSimpleIF>) vars) { pw.print(","); String unit = var.getUnitsString(); if (unit != null) { pw.print(HtmlUtils.quote(var.getShortName() + " (" + unit + ")")); } else { pw.print(HtmlUtils.quote(var.getShortName())); } } pw.print("\n"); } pw.print(HtmlUtils.quote("" + po.getNominalTimeAsDate())); pw.print(","); pw.print(el.getLatitude()); pw.print(","); pw.print(el.getLongitude()); for (VariableSimpleIF var : (List<VariableSimpleIF>) vars) { StructureMembers.Member member = structure.findMember(var.getShortName()); pw.print(","); if ((var.getDataType() == DataType.STRING) || (var.getDataType() == DataType.CHAR)) { pw.print(HtmlUtils.quote(structure.getScalarString(member))); } else { pw.print(structure.convertScalarFloat(member)); } } pw.print("\n"); } getCdmManager().returnPointDataset(path, pod); } /** * Output the points as KML * * @param request the Request * @param entry the Entry * @param pw the PrintWriter * * * @throws Exception problem generating KML */ private void outputPointKml(Request request, Entry entry, PrintWriter pw) throws Exception { String path = getPath(request, entry); FeatureDatasetPoint pod = getCdmManager().getPointDataset(entry, path); List vars = pod.getDataVariables(); PointFeatureIterator dataIterator = getPointIterator(pod); Element root = KmlUtil.kml(entry.getName()); Element docNode = KmlUtil.document(root, entry.getName()); while (dataIterator.hasNext()) { PointFeature po = (PointFeature) dataIterator.next(); ucar.unidata.geoloc.EarthLocation el = po.getLocation(); if (el == null) { continue; } double lat = el.getLatitude(); double lon = el.getLongitude(); double alt = 0; if ((lat != lat) || (lon != lon)) { continue; } StructureData structure = po.getData(); StringBuffer info = new StringBuffer(""); info.append("<b>Date:</b> " + po.getNominalTimeAsDate() + "<br>"); for (VariableSimpleIF var : (List<VariableSimpleIF>) vars) { StructureMembers.Member member = structure.findMember(var.getShortName()); if ((var.getDataType() == DataType.STRING) || (var.getDataType() == DataType.CHAR)) { info.append("<b>" + var.getName() + ": </b>" + structure.getScalarString(member) + "<br>"); } else { info.append("<b>" + var.getName() + ": </b>" + structure.convertScalarFloat(member) + "<br>"); } } KmlUtil.placemark(docNode, "" + po.getNominalTimeAsDate(), info.toString(), lat, lon, alt, null); } pw.print(XmlUtil.toString(root)); getCdmManager().returnPointDataset(path, pod); } /** * Get the Authorization method * * @param request the Request * * @return the autorization method */ public AuthorizationMethod getAuthorizationMethod(Request request) { OutputType output = request.getOutput(); if (output.equals(OUTPUT_WCS) || output.equals(OUTPUT_OPENDAP)) { return AuthorizationMethod.AUTH_HTTP; } return super.getAuthorizationMethod(request); } /** * Output a group of entries * * @param request the Request * @param outputType the output type * @param group the group * @param subGroups the subgroups * @param entries the List of Entrys * * @return the Result * * @throws Exception problem outputting group */ public Result outputGroup(Request request, OutputType outputType, Entry group, List<Entry> subGroups, List<Entry> entries) throws Exception { if (getCdmManager().isAggregation(group)) { return outputEntry(request, outputType, group); } // System.err.println("group:" + group + " " + group.getType()); return super.outputGroup(request, outputType, group, subGroups, entries); } /** * Serve up the entry * * @param request the Request * @param outputType the output type * @param entry the Entry * * @return the Result * * @throws Exception On badness */ public Result outputEntry(Request request, OutputType outputType, Entry entry) throws Exception { if (!getRepository().getAccessManager().canDoAction(request, entry, Permission.ACTION_FILE)) { throw new AccessException("Cannot access data", request); } if (!getRepository().getAccessManager().canAccessFile(request, entry)) { throw new AccessException("Cannot access data", request); } if (outputType.equals(OUTPUT_CDL)) { return outputCdl(request, entry); } if (outputType.equals(OUTPUT_WCS)) { return outputWcs(request, entry); } if (outputType.equals(OUTPUT_GRIDSUBSET) || outputType.equals(OUTPUT_GRIDSUBSET_FORM)) { return outputGridSubset(request, entry); } if (outputType.equals(OUTPUT_GRIDASPOINT) || outputType.equals(OUTPUT_GRIDASPOINT_FORM)) { return outputGridAsPoint(request, entry); } if (outputType.equals(OUTPUT_TRAJECTORY_MAP)) { return outputTrajectoryMap(request, entry); } if (outputType.equals(OUTPUT_POINT_MAP)) { return outputPointMap(request, entry); } if (outputType.equals(OUTPUT_POINT_SUBSET)) { return outputPointSubset(request, entry); } if (outputType.equals(OUTPUT_OPENDAP)) { //If its a head request then just return the content description if (request.isHeadRequest()) { Result result = new Result("", new StringBuffer()); result.addHttpHeader(HtmlUtils.HTTP_CONTENT_DESCRIPTION, "dods-dds"); return result; } Result result = outputOpendap(request, entry); return result; } throw new IllegalArgumentException("Unknown output type:" + outputType); } /** * Get the path to the data * * @param entry the Entry * * @return the path * * @throws Exception problemo */ public String getPath(Entry entry) throws Exception { return getPath(null, entry); } /** * Get the path for the Entry * * * @param request the Request * @param entry the Entry * * @return the path * * @throws Exception problem getting the path */ public String getPath(Request request, Entry entry) throws Exception { return getCdmManager().getPath(request, entry); /* String location; if (entry.getType().equals(OpendapLinkTypeHandler.TYPE_OPENDAPLINK)) { Resource resource = entry.getResource(); location = resource.getPath(); String ext = IOUtil.getFileExtension(location).toLowerCase(); if (ext.equals(".html") || ext.equals(".das") || ext.equals(".dds")) { location = IOUtil.stripExtension(location); } } else if (getCdmManager().isAggregation(entry)) { GridAggregationTypeHandler gridAggregation = (GridAggregationTypeHandler) entry.getTypeHandler(); long[] timestamp = { 0 }; location = gridAggregation.getNcmlFile(request, entry, timestamp).toString(); // Something must be fixed to check if its empty } else { location = getStorageManager().getFastResourcePath(entry); } getStorageManager().checkPath(location); List<Metadata> metadataList = getMetadataManager().findMetadata(entry, ContentMetadataHandler.TYPE_ATTACHMENT, true); // System.err.println("getPath"); if (metadataList == null) { return location; } // System.err.println("nd:" + metadataList); for (Metadata metadata : metadataList) { String fileAttachment = metadata.getAttr1(); boolean isNcml = fileAttachment.endsWith(SUFFIX_NCML); boolean isCtl = fileAttachment.endsWith(SUFFIX_CTL); if (isNcml || isCtl) { File templateNcmlFile = new File( IOUtil.joinDir( getRepository().getStorageManager().getEntryDir( metadata.getEntryId(), false), metadata.getAttr1())); String ncml = getStorageManager().readSystemResource(templateNcmlFile); if (isNcml) { ncml = ncml.replace("${location}", location); } else { // CTL int dsetIdx = ncml.indexOf("${location}"); if (dsetIdx >= 0) { ncml = ncml.replace("${location}", location); } else { //ncml = ncml.replaceAll("(dset|DSET).*\n", // "nDSET " + location + "\n"); ncml = Pattern.compile( "^dset.*$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE).matcher( ncml).replaceAll("DSET " + location); } } // System.err.println("ncml:" + ncml); //Use the last modified time of the ncml file so we pick up any updated file String dttm = templateNcmlFile.lastModified() + ""; String fileName = dttm + "_" + entry.getId() + "_" + metadata.getId() + (isNcml ? SUFFIX_NCML : SUFFIX_CTL); File ncmlFile = getStorageManager().getScratchFile(fileName); IOUtil.writeBytes(ncmlFile, ncml.getBytes()); location = ncmlFile.toString(); break; } } return location; */ } /** * Get the OPeNDAP handler * * @return the handler */ public OpendapApiHandler getOpendapHandler() { return (OpendapApiHandler) getRepository().getApiManager().getApiHandler(OpendapApiHandler.API_ID); } /** * Output OPeNDAP * * @param request the Request * @param entry the Entry * * @return the Result * * @throws Exception problems */ public Result outputOpendap(final Request request, final Entry entry) throws Exception { request.remove(ARG_ENTRYID); request.remove(ARG_OUTPUT); //Get the file location for the entry String location = getPath(request, entry); //Get the ncFile from the pool NetcdfFile ncFile = getCdmManager().createNetcdfFile(location); opendapCounter.incr(); //Bridge the ramadda servlet to the opendap servlet NcDODSServlet servlet = new NcDODSServlet(request, entry, ncFile) { public ServletConfig getServletConfig() { return request.getHttpServlet().getServletConfig(); } public ServletContext getServletContext() { return request.getHttpServlet().getServletContext(); } public String getServletInfo() { return request.getHttpServlet().getServletInfo(); } public Enumeration getInitParameterNames() { return request.getHttpServlet().getInitParameterNames(); } }; //If we are running as a normal servlet then init the ncdods servlet with the servlet config info if ((request.getHttpServlet() != null) && (request.getHttpServlet().getServletConfig() != null)) { servlet.init(request.getHttpServlet().getServletConfig()); } //Do the work servlet.doGet(request.getHttpServletRequest(), request.getHttpServletResponse()); //We have to pass back a result though we set needtowrite to false because the opendap servlet handles the writing Result result = new Result(""); result.setNeedToWrite(false); opendapCounter.decr(); getCdmManager().returnNetcdfFile(location, ncFile); return result; } /** * NcDODSServlet to wrap the OPeNDAP servelet * */ public class NcDODSServlet extends opendap.servlet.AbstractServlet { /** repository request */ Request repositoryRequest; /** the NetcdfFile object */ NetcdfFile ncFile; /** the Entry */ Entry entry; /** * Construct a new NcDODSServlet * * @param request the Request * @param entry the Entry * @param ncFile the NetcdfFile object */ public NcDODSServlet(Request request, Entry entry, NetcdfFile ncFile) { this.repositoryRequest = request; this.entry = entry; this.ncFile = ncFile; } /** * Make the dataset * * @param preq preq * * @return The dataset * * @throws DAP2Exception On badness * @throws IOException On badness */ protected GuardedDataset getDataset(ReqState preq) throws DAP2Exception, IOException /*, ParseException*/ { HttpServletRequest request = preq.getRequest(); String reqPath = entry.getName(); try { GuardedDatasetImpl guardedDataset = new GuardedDatasetImpl(reqPath, ncFile, true); return guardedDataset; } catch (Exception exc) { throw new WrapperException(exc); } } /** * Get the server version * * @return the version */ public String getServerVersion() { return "opendap/3.7"; } } /** * Output the timeseries image * * @param request the request * @param entry the entry * @param f the file * * @return the image * * @throws Exception problem creating image */ private Result outputTimeSeriesImage(Request request, Entry entry, File f) throws Exception { StringBuffer sb = new StringBuffer(); //sb.append(getHeader(request, entry)); sb.append(header(msg("Chart"))); TimeSeriesCollection dummy = new TimeSeriesCollection(); JFreeChart chart = createChart(request, entry, dummy); XYPlot xyPlot = (XYPlot) chart.getPlot(); Hashtable<String, MyTimeSeries> seriesMap = new Hashtable<String, MyTimeSeries>(); List<MyTimeSeries> allSeries = new ArrayList<MyTimeSeries>(); int paramCount = 0; int colorCount = 0; boolean axisLeft = true; Hashtable<String, List<ValueAxis>> axisMap = new Hashtable<String, List<ValueAxis>>(); Hashtable<String, double[]> rangeMap = new Hashtable<String, double[]>(); List<String> units = new ArrayList<String>(); List<String> paramUnits = new ArrayList<String>(); List<String> paramNames = new ArrayList<String>(); long t1 = System.currentTimeMillis(); String contents = IOUtil.readContents(getStorageManager().getFileInputStream(f)); List<String> lines = StringUtil.split(contents, "\n", true, true); String header = lines.get(0); String[] headerToks = header.split(","); for (int i = 0; i < headerToks.length; i++) { paramNames.add(getParamName(headerToks[i])); paramUnits.add(getUnitFromName(headerToks[i])); } boolean hasLevel = paramNames.get(3).equals("vertCoord"); boolean readHeader = false; for (String line : lines) { if (!readHeader) { readHeader = true; continue; } String[] lineTokes = line.split(","); Date date = DateUtil.parse(lineTokes[0]); int startIdx = hasLevel ? 4 : 3; for (int i = startIdx; i < lineTokes.length; i++) { double value = Double.parseDouble(lineTokes[i]); if (value != value) { continue; } List<ValueAxis> axises = null; double[] range = null; String u = paramUnits.get(i); String paramName = paramNames.get(i); String formatName = paramName.replaceAll("_", " "); String formatUnit = ((u == null) || (u.length() == 0)) ? "" : "[" + u + "]"; if (u != null) { axises = axisMap.get(u); range = rangeMap.get(u); if (axises == null) { axises = new ArrayList<ValueAxis>(); range = new double[] { value, value }; rangeMap.put(u, range); axisMap.put(u, axises); units.add(u); } range[0] = Math.min(range[0], value); range[1] = Math.max(range[1], value); } MyTimeSeries series = seriesMap.get(paramName); if (series == null) { paramCount++; TimeSeriesCollection dataset = new TimeSeriesCollection(); series = new MyTimeSeries(formatName, FixedMillisecond.class); allSeries.add(series); ValueAxis rangeAxis = new NumberAxis(formatName + " " + formatUnit); if (axises != null) { axises.add(rangeAxis); } XYItemRenderer renderer = new XYAreaRenderer(XYAreaRenderer.LINES); if (colorCount >= GuiUtils.COLORS.length) { colorCount = 0; } renderer.setSeriesPaint(0, GuiUtils.COLORS[colorCount]); colorCount++; xyPlot.setRenderer(paramCount, renderer); xyPlot.setRangeAxis(paramCount, rangeAxis, false); AxisLocation side = (axisLeft ? AxisLocation.TOP_OR_LEFT : AxisLocation.BOTTOM_OR_RIGHT); axisLeft = !axisLeft; xyPlot.setRangeAxisLocation(paramCount, side); dataset.setDomainIsPointsInTime(true); dataset.addSeries(series); seriesMap.put(paramNames.get(i), series); xyPlot.setDataset(paramCount, dataset); xyPlot.mapDatasetToRangeAxis(paramCount, paramCount); } //series.addOrUpdate(new FixedMillisecond(pointData.date),value); TimeSeriesDataItem item = new TimeSeriesDataItem(new FixedMillisecond(date), value); series.addItem(item); } } for (MyTimeSeries timeSeries : allSeries) { timeSeries.finish(); } for (String unit : units) { List<ValueAxis> axises = axisMap.get(unit); double[] range = rangeMap.get(unit); for (ValueAxis rangeAxis : axises) { rangeAxis.setRange(new org.jfree.data.Range(range[0], range[1])); } } long t2 = System.currentTimeMillis(); BufferedImage newImage = chart.createBufferedImage(request.get(ARG_IMAGE_WIDTH, 1000), request.get(ARG_IMAGE_HEIGHT, 400)); long t3 = System.currentTimeMillis(); //System.err.println("timeseries image time:" + (t2 - t1) + " " // + (t3 - t2)); File file = getStorageManager().getTmpFile(request, "point.png"); ImageUtils.writeImageToFile(newImage, file); InputStream is = getStorageManager().getFileInputStream(file); Result result = new Result("", is, "image/png"); return result; } /** * get the parameter name from the raw name * * @param rawname the raw name * * @return the parameter name */ public String getParamName(String rawname) { String name = rawname; int index = rawname.indexOf("[unit="); if (index >= 0) { name = rawname.substring(0, index); } return name; } /** * Get the parameter unit from the raw name * * @param rawname the raw name * * @return the unit or null */ private String getUnitFromName(String rawname) { String unit = null; int index = rawname.indexOf("[unit="); if (index >= 0) { unit = rawname.substring(index + 6, rawname.indexOf("]")); unit = unit.replaceAll("\"", ""); } return unit; } /** * A wrapper for TimeSeries * * @author RAMADDA Development Team */ private static class MyTimeSeries extends TimeSeries { /** the items */ List<TimeSeriesDataItem> items = new ArrayList<TimeSeriesDataItem>(); /** seen items */ HashSet<TimeSeriesDataItem> seen = new HashSet<TimeSeriesDataItem>(); /** * Construct the time series * * @param name the name * @param c the class */ public MyTimeSeries(String name, Class c) { super(name, c); } /** * Add an item to the timeseries * * @param item the item to add */ public void addItem(TimeSeriesDataItem item) { if (seen.contains(item)) { return; } seen.add(item); items.add(item); } /** * finish this */ public void finish() { items = new ArrayList<TimeSeriesDataItem>(Misc.sort(items)); for (TimeSeriesDataItem item : items) { this.data.add(item); } fireSeriesChanged(); } } /** * Create the chart * * * @param request the request * @param entry the entry * @param dataset the dataset * * @return the chart */ private static JFreeChart createChart(Request request, Entry entry, XYDataset dataset) { LatLonPointImpl llp = new LatLonPointImpl(request.getLatOrLonValue(ARG_LOCATION + ".latitude", 0), request.getLatOrLonValue(ARG_LOCATION + ".longitude", 0)); String title = entry.getName() + " at " + llp.toString(); JFreeChart chart = ChartFactory.createTimeSeriesChart( //entry.getName(), // title title, // title "Date", // x-axis label "", // y-axis label dataset, // data true, // create legend? true, // generate tooltips? false // generate URLs? ); chart.setBackgroundPaint(Color.white); ValueAxis rangeAxis = new NumberAxis(""); rangeAxis.setVisible(false); XYPlot plot = (XYPlot) chart.getPlot(); if (request.get("gray", false)) { plot.setBackgroundPaint(Color.lightGray); plot.setDomainGridlinePaint(Color.white); plot.setRangeGridlinePaint(Color.white); } else { plot.setBackgroundPaint(Color.white); plot.setDomainGridlinePaint(Color.lightGray); plot.setRangeGridlinePaint(Color.lightGray); } plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); plot.setDomainCrosshairVisible(true); plot.setRangeCrosshairVisible(true); plot.setRangeAxis(0, rangeAxis, false); XYItemRenderer r = plot.getRenderer(); DateAxis axis = (DateAxis) plot.getDomainAxis(); //axis.setDateFormatOverride(new SimpleDateFormat("MMM-yyyy")); return chart; } }