/* * 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. */ // $Id: NcDAS.java 51 2006-07-12 17:13:13Z caron $ package thredds.server.opendap; import opendap.dap.DASException; import ucar.nc2.*; import ucar.nc2.constants.CDM; import ucar.nc2.dods.*; import ucar.ma2.DataType; import java.util.Iterator; import java.util.HashMap; import java.util.Map; import opendap.dap.AttributeExistsException; /** * Netcdf DAS object * * @author jcaron */ public class NcDAS extends opendap.dap.DAS { static private org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NcDAS.class); private Map<String, Dimension> usedDims = new HashMap<>(50); /** * Create a DAS for this netcdf file */ NcDAS(NetcdfFile ncfile) { // Variable attributes Iterator iter = ncfile.getVariables().iterator(); while (iter.hasNext()) { Variable v = (Variable) iter.next(); doVariable(v, null); } // Global attributes opendap.dap.AttributeTable gtable = new opendap.dap.AttributeTable("NC_GLOBAL"); int count = addAttributes(gtable, null, ncfile.getGlobalAttributes().iterator()); if (count > 0) try { addAttributeTable("NC_GLOBAL", gtable); } catch (AttributeExistsException e) { log.error("Cant add NC_GLOBAL", e); } // unlimited dimension iter = ncfile.getDimensions().iterator(); while (iter.hasNext()) { Dimension d = (Dimension) iter.next(); if (d.isUnlimited()) { opendap.dap.AttributeTable table = new opendap.dap.AttributeTable("DODS_EXTRA"); try { table.appendAttribute("Unlimited_Dimension", opendap.dap.Attribute.STRING, d.getShortName()); addAttributeTable("DODS_EXTRA", table); } catch (Exception e) { log.error("Error adding Unlimited_Dimension", e); } break; } } // unused dimensions opendap.dap.AttributeTable dimTable = null; iter = ncfile.getDimensions().iterator(); while (iter.hasNext()) { Dimension d = (Dimension) iter.next(); if (null == usedDims.get(d.getShortName())) { if (dimTable == null) dimTable = new opendap.dap.AttributeTable("EXTRA_DIMENSION"); try { dimTable.appendAttribute(d.getShortName(), opendap.dap.Attribute.INT32, Integer.toString(d.getLength())); } catch (Exception e) { log.error("Error adding Unlimited_Dimension", e); } } } if (dimTable != null) try { addAttributeTable("EXTRA_DIMENSION", dimTable); } catch (AttributeExistsException e) { log.error("Cant add EXTRA_DIMENSION", e); } } private void doVariable(Variable v, opendap.dap.AttributeTable parentTable) { for (Dimension dim : v.getDimensions()) { if (dim.isShared()) usedDims.put(dim.getShortName(), dim); } //if (v.getAttributes().size() == 0) return; // LOOK DAP 2 say must have empty // The variable names as taken from the variable, // are not dap escaped, so we need to make sure that happens. String name = Variable.getDAPName(v); opendap.dap.AttributeTable table; if (parentTable == null) { table = new opendap.dap.AttributeTable(name); try { addAttributeTable(name, table); } catch (AttributeExistsException e) { log.error("Cant add " + name, e); } } else { table = parentTable.appendContainer(name); } addAttributes(table, v, v.getAttributes().iterator()); if (v instanceof Structure) { Structure s = (Structure) v; for (Variable nv : s.getVariables()) { doVariable(nv, table); } } } private int addAttributes(opendap.dap.AttributeTable table, Variable v, Iterator iter) { int count = 0; boolean isVbyte = (v != null && (v.getDataType() == DataType.BYTE)); // always indicate if byte is signed or not ; see JIRA issue TDS-334 if (isVbyte) try { table.appendAttribute(CDM.UNSIGNED, opendap.dap.Attribute.STRING, v.isUnsigned() ? "true" : "false"); } catch (DASException e) { log.error("Error appending unsigned attribute ", e); } // add attribute table for this variable while (iter.hasNext()) { Attribute att = (Attribute) iter.next(); if (isVbyte && att.getShortName().equalsIgnoreCase(CDM.UNSIGNED)) continue; // got this covered int dods_type = DODSNetcdfFile.convertToDODSType(att.getDataType(), false); try { // The attribute names as taken from the variable are not escaped, so we need to make sure that happens. String attName = att.getShortName(); if (att.isString()) { /* do in Attribute.print() String value = EscapeStrings.backslashEscape(att.getStringValue(),"\"\\"); table.appendAttribute(attName, dods_type, value); */ table.appendAttribute(attName, dods_type, att.getStringValue()); } else { // cant send signed bytes if (att.getDataType() == DataType.BYTE) { boolean signed = false; for (int i = 0; i < att.getLength(); i++) { if (att.getNumericValue(i).byteValue() < 0) signed = true; } if (signed) // promote to signed short dods_type = opendap.dap.Attribute.INT16; } for (int i = 0; i < att.getLength(); i++) table.appendAttribute(attName, dods_type, att.getNumericValue(i).toString()); } count++; } catch (Exception e) { log.error("Error appending attribute " + att.getShortName() + " = " + att.getStringValue(), e); } } // loop over variable attributes // kludgy thing to map char arrays to DODS Strings if ((v != null) && (v.getDataType().getPrimitiveClassType() == char.class)) { int rank = v.getRank(); int strlen = (rank == 0) ? 0 : v.getShape(rank - 1); Dimension dim = (rank == 0) ? null : v.getDimension(rank - 1); try { opendap.dap.AttributeTable dodsTable = table.appendContainer("DODS"); dodsTable.appendAttribute("strlen", opendap.dap.Attribute.INT32, Integer.toString(strlen)); if ((dim != null) && dim.isShared()) dodsTable.appendAttribute("dimName", opendap.dap.Attribute.STRING, dim.getShortName()); count++; } catch (Exception e) { log.error("Error appending attribute strlen\n", e); } } return count; } }