Java tutorial
/* Copyright 2012, UCAR/Unidata. See the LICENSE file for more information. */ package dap4.servlet; import dap4.core.data.*; import dap4.core.dmr.*; import dap4.core.util.*; import dap4.dap4shared.*; import dap4.cdmshared.*; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import ucar.ma2.*; import ucar.nc2.*; import ucar.nc2.dataset.*; import ucar.nc2.jni.netcdf.Nc4Iosp; import ucar.nc2.util.CancelTask; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.ByteBuffer; import java.util.*; /** * CDM->DAP DSP */ public class CDMDSP extends AbstractDSP { ////////////////////////////////////////////////// // Constants static protected final boolean DEBUG = false; static protected final Object FACTORYKEY = DapFactory.class; static protected final String DAPVERSION = "4.0"; static protected final String DMRVERSION = "1.0"; static protected final Class NC4CLASS = ucar.nc2.jni.netcdf.Nc4Iosp.class; // NetcdfDataset enhancement to use: need only coord systems static protected Set<NetcdfDataset.Enhance> ENHANCEMENT = EnumSet.of(NetcdfDataset.Enhance.CoordSystems); ////////////////////////////////////////////////// // Class variables static protected boolean nc4loaded = false; ////////////////////////////////////////////////// // Class methods /** * Make sure that NC4Iosp is registered and library loaded */ static public void loadNc4Iosp() throws DapException { if (nc4loaded) return; nc4loaded = true; if (!NetcdfFile.iospRegistered(NC4CLASS)) { try { // register before H5Iosp NetcdfFile.registerIOProvider(NC4CLASS, false); Nc4Iosp.setLibraryAndPath(null, null); // use defaults } catch (Throwable e) { DapLog.error("Cant load IOSP Nc4Iosp"); throw new DapException(e.getMessage(), e.getCause()); } } } ////////////////////////////////////////////////// // Instance variables protected NetcdfDataset ncdfile = null; protected DapFactory factory = null; // Map between cdmnode and dapnode protected NodeMap nodemap = new NodeMap(); protected boolean closed = false; protected CDMDataDataset data = null; // root of the DataXXX tree protected HttpServletRequest request = null; protected HttpServletResponse response = null; ////////////////////////////////////////////////// // Constructor(s) public CDMDSP() { } public CDMDSP(String path, DapContext cxt) throws DapException { super(); setContext(cxt); setRequestResponse(); init(createNetcdfFile(path, null)); } public CDMDSP(NetcdfFile ncd, DapContext cxt) throws DapException { super(); setContext(cxt); setRequestResponse(); init(ncd); } protected void init(NetcdfFile ncfile) throws DapException { if (ncfile == null) throw new DapException("CDMDSP: cannot open: " + path); setPath(ncfile.getLocation()); if (this.context == null || (this.factory = (DapFactory) this.context.get(FACTORYKEY)) == null) this.factory = new DapFactoryDMR(); //if(ncfile instanceof NetcdfDataset) // ncdfile = (NetcdfDataset) ncfile; //else try { ncdfile = new NetcdfDataset(ncfile, ENHANCEMENT); } catch (IOException ioe) { throw new DapException(ioe); } build(); buildDataDataset(); } ////////////////////////////////////////////////// protected void setRequestResponse() { this.request = (HttpServletRequest) this.context.get(HttpServletRequest.class); this.response = (HttpServletResponse) this.context.get(HttpServletResponse.class); } ////////////////////////////////////////////////// // DSP Interface // This is intended to be the last DSP checked static public boolean match(String path, DapContext context) { return true; } @Override public DSP open(String path) throws DapException { return open(path, new DapContext()); } @Override public DSP open(String path, DapContext context) throws DapException { return new CDMDSP(path, context); } @Override public void close() throws IOException { if (ncdfile != null) ncdfile.close(); } @Override public DataDataset getDataDataset() { return data; } ////////////////////////////////////////////////// // CDMDSP Specific Accessors public NetcdfDataset getNetcdfDataset() { return ncdfile; } public void setDataDataset(CDMDataDataset data) { this.data = data; } /** * Lookup a dapnode in the dap nodemap. * * @param dapnode The DapNode * @return The corresponding CDMNode or null */ public CDMNode getCDMNode(DapNode dapnode) { return nodemap.get(dapnode); } ////////////////////////////////////////////////// // Nodemap control /** * Record a cdmnode+dapnode in the nodemap. * Make sure that we use the proper * object in order to avoid identity * problems. * * @param cdmnode The CMDNode (variable, dimension, etc) to record * @param dapnode The DapNode to which the cdmnode is to be mapped. */ protected void recordNode(CDMNode cdmnode, DapNode dapnode) { CDMSort sort = cdmnode.getSort(); switch (sort) { case VARIABLE: case STRUCTURE: case SEQUENCE: Variable basev = CDMUtil.unwrap((Variable) cdmnode); assert (basev != null) : "Unwrap() failed"; cdmnode = (CDMNode) basev; break; } nodemap.put(dapnode, cdmnode); } /** * Lookup a cdmnode in the cdmnodemap. * Make sure that we use the proper * object in order to avoid identity * problems. * * @param cdmnode The CMDNode (variable, dimension, etc) to record * @return The DapNode to which the cdmnode is to be mapped or null. */ protected DapNode lookupNode(CDMNode cdmnode) { CDMSort sort = cdmnode.getSort(); if (sort == CDMSort.VARIABLE || sort == CDMSort.STRUCTURE) { Variable basev = CDMUtil.unwrap((Variable) cdmnode); assert (basev != null) : "Unwrap() failed"; cdmnode = (CDMNode) basev; } return nodemap.get(cdmnode); } ////////////////////////////////////////////////// /** * Extract the metadata from the NetcdfDataset * and build the DMR. */ public void build() throws DapException { if (dmr != null) return; try { if (DEBUG) { System.out.println("writecdl:"); ncdfile.writeCDL(System.out, false); System.out.flush(); } // Initialize the root dataset node dmr = (DapDataset) newNode(DapSort.DATASET); // Map the CDM root group to this group recordNode(ncdfile.getRootGroup(), dmr); // Use the file path to define the dataset name String name = ncdfile.getLocation(); // Normalize the name name = DapUtil.canonicalpath(name); // Remove any path prefix int index = name.lastIndexOf('/'); if (index >= 0) name = name.substring(index + 1, name.length()); dmr.setShortName(name); dmr.setDataset(this.dmr); dmr.setDapVersion(DAPVERSION); dmr.setDMRVersion(DMRVERSION); dmr.setBase(DapUtil.canonicalpath(ncdfile.getLocation())); dmr.setNS("http://xml.opendap.org/ns/DAP/4.0#"); // Now recursively build the tree. Start by // Filling the dataset with the contents of the ncfile // root group. fillgroup(dmr, ncdfile.getRootGroup()); // Add an order index to the tree dmr.sort(); // Now locate the coordinate variables for maps /* Walk looking for VariableDS instances */ processmappedvariables(ncdfile.getRootGroup()); // Now set the view dmr.finish(); setDataset(dmr); } catch (DapException e) { throw new DapException(e); } } ////////////////////////////////////////////////// // Actions protected void fillgroup(DapGroup dapgroup, Group cdmgroup) throws DapException { // Create decls in dap group for Dimensions for (Dimension cdmdim : cdmgroup.getDimensions()) { DapDimension dapdim = builddim(cdmdim); } // Create decls in dap group for Enumerations for (EnumTypedef cdmenum : cdmgroup.getEnumTypedefs()) { String name = cdmenum.getShortName(); DapEnum dapenum = buildenum(cdmenum); dapenum.setShortName(name); dapgroup.addDecl(dapenum); } // Create decls in dap group for Variables for (Variable cdmvar : cdmgroup.getVariables()) { DapNode newvar = buildvariable(cdmvar, dapgroup); } // Create decls in dap group for subgroups for (Group subgroup : cdmgroup.getGroups()) { DapGroup newgroup = buildgroup(subgroup); dapgroup.addDecl(newgroup); } // Create decls in dap group for group-level attributes buildattributes(dapgroup, cdmgroup.getAttributes()); } ////////////////////////////////////////////////// // Declaration Builders protected DapDimension builddim(Dimension cdmdim) throws DapException { DapDimension dapdim = null; long cdmsize = dapsize(cdmdim); String name = cdmdim.getShortName(); if (name != null && name.length() == 0) name = null; boolean shared = cdmdim.isShared(); if (!shared) { // Unlike the parser, since we are working // from a NetcdfDataset instance, there might // be multiple anonymous dimension objects // the same size. So, just go ahead and create // multiple instances. dapdim = (DapDimension) newNode(DapSort.DIMENSION); if (cdmdim.isVariableLength()) dapdim.setSize(DapDimension.VARIABLELENGTH); else dapdim.setSize(cdmsize); dmr.addDecl(dapdim); } else { // Non anonymous; create in current group dapdim = (DapDimension) newNode(DapSort.DIMENSION); dapdim.setShortName(name); dapdim.setSize(cdmsize); dapdim.setShared(true); Group cdmparent = cdmdim.getGroup(); DapGroup dapparent = (DapGroup) lookupNode(cdmparent); assert (dapparent != null); dapparent.addDecl(dapdim); } recordNode(cdmdim, dapdim); return dapdim; } protected DapEnum buildenum(EnumTypedef cdmenum) throws DapException { DapEnum dapenum = (DapEnum) newNode(DapSort.ENUMERATION); recordNode(cdmenum, dapenum); dapenum.setShortName(cdmenum.getShortName()); // Set the enum's basetype switch (cdmenum.getBaseType()) { case ENUM1: dapenum.setBaseType(DapType.INT8); break; case ENUM2: dapenum.setBaseType(DapType.INT16); break; case ENUM4: default: dapenum.setBaseType(DapType.INT32); break; } // Create the enum constants Map<Integer, String> ecvalues = cdmenum.getMap(); for (Map.Entry<Integer, String> entry : ecvalues.entrySet()) { String name = entry.getValue(); assert (name != null); int value = (int) entry.getKey(); dapenum.addEnumConst(name, new Long(value)); } return dapenum; } protected DapNode buildvariable(Variable cdmvar, DapNode parent) throws DapException { cdmvar = CDMUtil.unwrap(cdmvar); List<Dimension> cdmdims = cdmvar.getDimensions(); return buildvariable(cdmvar, cdmdims, parent); } protected DapNode buildvariable(Variable cdmbasevar, List<Dimension> cdmdims, DapNode parent) throws DapException { DapVariable dapvar = null; /* If this var has a variable length last dimension, then we must convert to a sequence. */ if (cdmdims != null && cdmdims.size() > 0 && cdmdims.get(cdmdims.size() - 1).isVariableLength()) { // Create the sequence using the dimensions of the variable // and the variable as the sequence field. dapvar = buildsequence(cdmbasevar); } else switch (cdmbasevar.getSort()) { case VARIABLE: switch (cdmbasevar.getDataType()) { case ENUM1: case ENUM2: case ENUM4: dapvar = buildenumvar(cdmbasevar); break; case OPAQUE: dapvar = buildopaquevar(cdmbasevar); break; case STRING: dapvar = buildstringvar(cdmbasevar); break; case STRUCTURE: // How does this ever happen? dapvar = buildstructvar(cdmbasevar); break; default: dapvar = buildatomicvar(cdmbasevar); } break; case STRUCTURE: dapvar = buildstructvar(cdmbasevar); break; default: assert false : "Internal Error"; } if (parent != null) { switch (parent.getSort()) { case GROUP: case DATASET: ((DapGroup) parent).addDecl(dapvar); break; case STRUCTURE: case SEQUENCE: ((DapStructure) parent).addField(dapvar); break; default: assert (false) : "Internal error"; } } builddimrefs(dapvar, cdmdims); return dapvar; } protected DapAtomicVariable buildatomicvar(Variable cdmvar) throws DapException { // Atomic => not opaque and not enum DapType basetype = CDMUtil.cdmtype2daptype(cdmvar.getDataType(), cdmvar.isUnsigned()); if (basetype == null) throw new DapException("DapFile: illegal CDM variable base type: " + cdmvar.getDataType()); DapAtomicVariable dapvar = (DapAtomicVariable) newNode(DapSort.ATOMICVARIABLE); dapvar.setShortName(cdmvar.getShortName()); dapvar.setBaseType(basetype); recordNode(cdmvar, dapvar); buildattributes(dapvar, cdmvar.getAttributes()); return dapvar; } protected DapAtomicVariable buildopaquevar(Variable cdmvar) throws DapException { assert (cdmvar.getDataType() == DataType.OPAQUE) : "Internal error"; DapAtomicVariable dapvar = (DapAtomicVariable) newNode(DapSort.ATOMICVARIABLE); recordNode(cdmvar, dapvar); dapvar.setShortName(cdmvar.getShortName()); dapvar.setBaseType(DapType.OPAQUE); buildattributes(dapvar, cdmvar.getAttributes()); return dapvar; } protected DapAtomicVariable buildstringvar(Variable cdmvar) throws DapException { assert (cdmvar.getDataType() == DataType.STRING) : "Internal error"; DapAtomicVariable dapvar = (DapAtomicVariable) newNode(DapSort.ATOMICVARIABLE); recordNode(cdmvar, dapvar); dapvar.setShortName(cdmvar.getShortName()); dapvar.setBaseType(DapType.STRING); buildattributes(dapvar, cdmvar.getAttributes()); return dapvar; } protected DapAtomicVariable buildenumvar(Variable cdmvar) throws DapException { assert (cdmvar.getDataType() == DataType.ENUM1 || cdmvar.getDataType() == DataType.ENUM2 || cdmvar.getDataType() == DataType.ENUM4) : "Internal error"; DapAtomicVariable dapvar = (DapAtomicVariable) newNode(DapSort.ATOMICVARIABLE); recordNode(cdmvar, dapvar); dapvar.setShortName(cdmvar.getShortName()); // Now, we need to locate the actual enumeration decl EnumTypedef enumdef = cdmvar.getEnumTypedef(); EnumTypedef trueenumdef = findMatchingEnum(enumdef); // Modify the cdmvar cdmvar.setEnumTypedef(trueenumdef); // Now, map to a DapEnum DapEnum dapenum = (DapEnum) lookupNode(trueenumdef); assert (dapenum != null); dapvar.setBaseType(dapenum); buildattributes(dapvar, cdmvar.getAttributes()); return dapvar; } /** * Unfortunately, the CDM Iosp does not * actually use the declared enums. Rather, * for every enum type'd variable, a new * enum decl is defined. So, we need * to find the original enum decl that matches * the variable's enum. */ protected EnumTypedef findMatchingEnum(EnumTypedef varenum) throws DapException { List<EnumTypedef> candidates = new ArrayList<>(); for (Map.Entry<DapNode, CDMNode> entry : nodemap.getCDMMap().entrySet()) { CDMNode cdmnode = entry.getValue(); if (cdmnode.getSort() != CDMSort.ENUMERATION) continue; // Compare the enumeration (note names will differ) EnumTypedef target = (EnumTypedef) cdmnode; /* Ideally, we should test the types of the enums, but, unfortunately, the var enum is always enum4. if(target.getBaseType() != varenum.getBaseType()) continue; */ Map<Integer, String> targetmap = target.getMap(); Map<Integer, String> varmap = varenum.getMap(); if (targetmap.size() != varmap.size()) continue; boolean match = true; // until otherwise shown for (Map.Entry<Integer, String> tpair : targetmap.entrySet()) { String tname = tpair.getValue(); int value = (int) tpair.getKey(); boolean found = false; for (Map.Entry<Integer, String> vpair : varmap.entrySet()) { if (tname.equals(vpair.getValue()) && value == (int) vpair.getKey()) { found = true; break; } } if (!found) { match = false; break; } } if (!match) continue; // Save it unless it is shadowed by a closer enum boolean shadowed = false; for (EnumTypedef etd : candidates) { if (shadows(etd.getGroup(), target.getGroup())) { shadowed = true; break; } } if (!shadowed) candidates.add(target); } switch (candidates.size()) { case 0: throw new DapException("CDMDSP: No matching enum type decl: " + varenum.getShortName()); case 1: break; default: throw new DapException("CDMDSP: Multiple matching enum type decls: " + varenum.getShortName()); } return candidates.get(0); } protected boolean shadows(Group parent, Group child) { if (child == parent) return true; Group candidate = child; do { candidate = candidate.getGroup(); } while (candidate != null && candidate != parent); return (candidate == parent); } protected DapStructure buildstructvar(Variable cdmvar) throws DapException { assert (cdmvar.getDataType() == DataType.STRUCTURE) : "Internal error"; DapStructure dapvar = (DapStructure) newNode(DapSort.STRUCTURE); recordNode(cdmvar, dapvar); dapvar.setShortName(cdmvar.getShortName()); // We need to build the field variables Structure structvar = (Structure) cdmvar; for (CDMNode node : structvar.getVariables()) { Variable var = (Variable) node; buildvariable(var, dapvar); } buildattributes(dapvar, cdmvar.getAttributes()); return dapvar; } /* Create a sequence from a variable with a variable length last dimension. Suppose we have cdm equivalent to this: int32 var[d1][*] We convert to the following <Sequence name="var"> <Int32 name="var"/> <Dim name=d1/> </Sequence> */ protected DapSequence buildsequence(Variable cdmbasevar) throws DapException { DapSequence seq = (DapSequence) newNode(DapSort.SEQUENCE); recordNode(cdmbasevar, seq); seq.setShortName(cdmbasevar.getShortName()); // We need to build the sequence field from cdmvar // But dimensionless and as fields of the sequence. Sequence seqvar = (Sequence) cdmbasevar; for (CDMNode node : seqvar.getVariables()) { Variable var = (Variable) node; buildvariable(var, seq); } return seq; } protected void buildattributes(DapNode node, List<Attribute> attributes) throws DapException { for (Attribute attr : attributes) { if (!suppress(attr.getShortName())) { DapAttribute dapattr = buildattribute(attr); node.addAttribute(dapattr); } } } protected DapAttribute buildattribute(Attribute attr) throws DapException { DapAttribute dapattr = (DapAttribute) newNode(DapSort.ATTRIBUTE); recordNode(attr, dapattr); dapattr.setShortName(attr.getShortName()); DapType basetype = CDMUtil.cdmtype2daptype(attr.getDataType(), attr.isUnsigned()); if (basetype == null) throw new DapException("DapFile: illegal CDM variable attribute type: " + attr.getDataType()); dapattr.setBaseType(basetype); // Transfer the values Array values = attr.getValues(); if (!validatecdmtype(attr.getDataType(), attr.isUnsigned(), values.getElementType())) throw new DapException("DapFile: attr type versus attribute data mismatch: " + values.getElementType()); IndexIterator iter = values.getIndexIterator(); while (iter.hasNext()) { Object o = iter.next(); o = fixvalue(o, basetype); dapattr.addValue(o); } return dapattr; } /** * Assign dimensions to a variable * * @param dapvar The variable to which we wish to assign dimensions * @param cdmdims The cdm dimensions from which we will find the dimension info */ protected void builddimrefs(DapVariable dapvar, List<Dimension> cdmdims) throws DapException { if (cdmdims == null || cdmdims.size() == 0) return; // It is unfortunately the case that the dimensions // associated with the variable are not // necessarily the same object as those dimensions // as declared, so we need to use a non-trivial // matching algorithm. for (Dimension cdmdim : cdmdims) { DapDimension dapdim = null; if (cdmdim.isShared()) { Dimension declareddim = finddimdecl(cdmdim); if (declareddim == null) throw new DapException("Unprocessed cdm dimension: " + cdmdim); dapdim = (DapDimension) lookupNode(declareddim); } else if (cdmdim.isVariableLength()) {// ignore continue; } else {//anonymous dapdim = builddim(cdmdim); } assert (dapdim != null) : "Internal error"; dapvar.addDimension(dapdim); } } protected void processmappedvariables(Group g) throws DapException { for (Variable v0 : g.getVariables()) { Variable cdmvar = CDMUtil.unwrap(v0); if (cdmvar == null) throw new DapException("NetcdfDataset synthetic variable: " + v0); DapNode dapvar = lookupNode(cdmvar); if (dapvar == null) throw new DapException("Unknown variable: " + cdmvar); if (!(dapvar instanceof DapVariable)) throw new DapException("CDMVariable not mapping to dap variable: " + cdmvar); buildmaps((DapVariable) dapvar, v0); } } /** * @param dapvar The variable to which we wish to assign maps * @param var The NetcdfDataset variable from which to extract coord system */ protected void buildmaps(DapVariable dapvar, Variable var) throws DapException { // See if this cdm variable has one (or more) coordinate system List<CoordinateSystem> css = null; if (var.getSort() == CDMSort.VARIABLE) { VariableDS vds = (VariableDS) var; css = vds.getCoordinateSystems(); } else { StructureDS sds = (StructureDS) var; css = sds.getCoordinateSystems(); } if (css != null && css.size() > 0) { // Not sure what to do with multiple coordinate systems // For now, only use the first CoordinateSystem coordsystems = css.get(0); for (CoordinateAxis axis : coordsystems.getCoordinateAxes()) { // First step is to find the dap variable // corresponding to the map VariableDS vds = (VariableDS) axis.getOriginalVariable(); if (vds != null) { Variable v = CDMUtil.unwrap(vds); if (v != null) { DapVariable mapvar = (DapVariable) lookupNode((CDMNode) v); if (mapvar == null) throw new DapException("Illegal map variable:" + v.toString()); if (mapvar.getSort() != DapSort.ATOMICVARIABLE) throw new DapException("Non-atomic map variable:" + v.toString()); // Ignore maps where the map variable is inside this scope if (!mapvar.isTopLevel()) { DapVariable parent = (DapVariable) mapvar.getContainer(); assert parent.getSort() == DapSort.STRUCTURE; if (dapvar != parent) {// Do we need to do transitive closure? DapMap map = (DapMap) newNode(DapSort.MAP); map.setVariable((DapAtomicVariable) mapvar); dapvar.addMap(map); } } } } } } } protected DapGroup buildgroup(Group cdmgroup) throws DapException { DapGroup dapgroup = (DapGroup) newNode(DapSort.GROUP); recordNode(cdmgroup, dapgroup); dapgroup.setShortName(cdmgroup.getShortName()); fillgroup(dapgroup, cdmgroup); return dapgroup; } ////////////////////////////////////////////////// // Utilities // Create new node protected DapNode newNode(DapSort sort) { DapNode node = (DapNode) factory.newNode(sort); if (dmr != null) node.setDataset(dmr); return node; } // Convert cdm size to DapDimension size protected long dapsize(Dimension cdmdim) { if (cdmdim.isVariableLength()) return DapDimension.VARIABLELENGTH; return (long) cdmdim.getLength(); } protected boolean validatecdmtype(DataType datatype, boolean unsigned, Class typeclass) { switch (datatype) { case CHAR: return typeclass == char.class; case BYTE: if (unsigned) return typeclass == byte.class; //was short.class; else return typeclass == byte.class; case SHORT: if (unsigned) return typeclass == short.class; //was int.class; else return typeclass == short.class; case INT: if (unsigned) return typeclass == int.class; // was long.class; else return typeclass == int.class; case LONG: if (unsigned) return typeclass == long.class; else return typeclass == long.class; case FLOAT: return typeclass == float.class; case DOUBLE: return typeclass == double.class; case STRING: return typeclass == String.class; case OPAQUE: return typeclass == Byte[].class; // For these, return the integer basetype case ENUM1: return typeclass == byte.class; case ENUM2: return typeclass == short.class; case ENUM4: return typeclass == int.class; // Undefined case SEQUENCE: case STRUCTURE: default: break; } return false; } protected Dimension finddimdecl(Dimension dimref) { // Search on the full name, but be careful, // the rule is that the declared dimension's fqn // must be a prefix of the dimension reference. for (Map.Entry<DapNode, CDMNode> entry : nodemap.getCDMMap().entrySet()) { if (entry.getValue().getSort() != CDMSort.DIMENSION) continue; Dimension d = (Dimension) entry.getValue(); if (isdeclfor(d, dimref)) return d; } return null; } protected boolean isdeclfor(Dimension decl, Dimension ref) { // First check shortname and size if (!decl.getShortName().equals(ref.getShortName())) return false; if (decl.getLength() != ref.getLength()) return false; // Make sure they are in the same group String dprefix = decl.getGroup().getFullName(); String rprefix = ref.getGroup().getFullName(); return (dprefix.equals(rprefix)); } protected Object fixvalue(Object o, DapType datatype) { AtomicType atype = datatype.getAtomicType(); if (o instanceof Character) { long l = (long) ((Character) o).charValue(); if (atype.isUnsigned()) l = l & 0xffL; o = Long.valueOf(l); } else if (o instanceof Float || o instanceof Double) { if (atype == AtomicType.Float32) o = Float.valueOf(((Number) o).floatValue()); else if (atype == AtomicType.Float64) o = Double.valueOf(((Number) o).doubleValue()); else assert false : "Internal error"; } else if (o instanceof Number) { long l = ((Number) o).longValue(); switch (atype) { case Char: case UInt8: l = l & 0xffL; break; case UInt16: l = l & 0xffffL; break; case UInt32: l = l & 0xffffffffL; break; default: break; } o = Long.valueOf(l); } else if (o instanceof String) { o = o.toString(); } else if (o instanceof ByteBuffer) { // leave it unchanged } else if (o instanceof byte[]) { o = ByteBuffer.wrap((byte[]) o); } else if (o instanceof Byte[]) { Byte[] ob = (Byte[]) o; byte[] bb = new byte[ob.length]; for (int i = 0; i < bb.length; i++) { bb[i] = (byte) ob[i]; } o = ByteBuffer.wrap(bb); } //else { // leave it unchanged return o; } ////////////////////////////////////////////////// // Data Compilation /** * Build a tree of Data objects corresponding * to the DMR. */ protected DataDataset buildDataDataset() throws DataException { List<Variable> cdmvars = ncdfile.getVariables(); CDMDataDataset dds = new CDMDataDataset(this, dmr); for (Variable v : cdmvars) { DapVariable dv = (DapVariable) nodemap.get(v); if (dv == null) throw new DataException("Unknown cdm variable: " + v.getShortName()); DataVariable cdv = buildData(dv); dds.addVariable(cdv); } return dds; } protected DataVariable buildData(DapVariable dap) throws DataException { Variable cdmv = null; DataVariable dv; cdmv = (Variable) nodemap.get(dap); if (cdmv == null) throw new DataException("Node has no cdm match: " + dap.getShortName()); switch (dap.getSort()) { case ATOMICVARIABLE: try { Array array = cdmv.read(); dv = new CDMDataAtomic(this, (DapAtomicVariable) dap, array); } catch (IOException ioe) { throw new DataException(ioe); } break; case STRUCTURE: DapStructure ds = (DapStructure) dap; ArrayStructure array; try { array = (ArrayStructure) cdmv.read(); } catch (IOException ioe) { throw new DataException(ioe); } if (ds.getRank() == 0) { CDMDataStructure cds = new CDMDataStructure(this, ds, null, 0, array.getStructureData(0)); dv = cds; } else { CDMDataCompoundArray cdca = new CDMDataCompoundArray(this, ds, array); dv = cdca; } break; case SEQUENCE: throw new DataException("Sequence not yet supported"); default: throw new DataException("Unexpected DapNode: " + dap.getSort()); } return dv; } ////////////////////////////////////////////////// protected NetcdfFile createNetcdfFile(String location, CancelTask canceltask) throws DapException { try { path = DapUtil.canonicalpath(location); NetcdfFile ncfile = NetcdfFile.open(location, canceltask); return ncfile; } catch (Exception e) { return null; } } ////////////////////////////////////////////////// // Utilities /** * Some attributes that are added by the NetcdfDataset * need to be kept out of the DMR. This function * defines that set. * * @param attrname A non-escaped attribute name to be tested for suppression * @return true if the attribute should be suppressed, false otherwise. */ protected boolean suppress(String attrname) { if (attrname.startsWith("_Coord")) return true; if (attrname.equals("_Unsigned")) return true; return false; } }