001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.object.nc2; 016 017import java.io.IOException; 018import java.util.ArrayList; 019import java.util.Iterator; 020import java.util.LinkedList; 021import java.util.List; 022import java.util.Queue; 023import java.util.Vector; 024 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028import ucar.nc2.NetcdfFile; 029import ucar.nc2.Variable; 030import ucar.nc2.iosp.netcdf3.N3header; 031 032import hdf.object.Attribute; 033import hdf.object.Dataset; 034import hdf.object.Datatype; 035import hdf.object.FileFormat; 036import hdf.object.Group; 037import hdf.object.HObject; 038 039/** 040 * This class provides file level APIs. File access APIs include retrieving the 041 * file hierarchy, opening and closing file, and writing file content to disk. 042 * 043 * @version 2.4 9/4/2007 044 * @author Peter X. Cao 045 */ 046public class NC2File extends FileFormat { 047 private static final long serialVersionUID = 6941235662108358451L; 048 049 private static final Logger log = LoggerFactory.getLogger(NC2File.class); 050 051 /** 052 * The root object of this file. 053 */ 054 private HObject rootObject; 055 056 /** 057 * The list of unique (tag, ref) pairs. It is used to avoid duplicate 058 * objects in memory. 059 */ 060 @SuppressWarnings("rawtypes") 061 private List objList; 062 063 /** the netcdf file */ 064 private NetcdfFile ncFile; 065 066 private static boolean isFileOpen; 067 068 /** 069 * Constructs an empty NC2File with read-only access. 070 */ 071 public NC2File() { 072 this(""); 073 } 074 075 /** 076 * Creates an NC2File object of given file name with read-only access. 077 * 078 * @param fileName 079 * A valid file name, with a relative or absolute path. 080 */ 081 public NC2File(String fileName) { 082 super(fileName); 083 084 isFileOpen = false; 085 isReadOnly = true; 086 objList = new Vector(); 087 ncFile = null; 088 089 this.fid = -1; 090 091 if ((fullFileName != null) && (fullFileName.length() > 0)) { 092 try { 093 log.trace("NetcdfFile:{}", fullFileName); 094 ncFile = NetcdfFile.open(fullFileName); 095 this.fid = 1; 096 } 097 catch (Exception ex) { 098 log.trace("NC2File:{}", fullFileName, ex); 099 } 100 } 101 } 102 103 /** 104 * Checks if the given file format is a NetCDF3 file. 105 * 106 * @param fileformat 107 * the fileformat to be checked. 108 * 109 * @return true if the given file is a NetCDF3 file; otherwise returns false. 110 */ 111 @Override 112 public boolean isThisType(FileFormat fileformat) { 113 return (fileformat instanceof NC2File); 114 } 115 116 /** 117 * Checks if the given file is a NetCDF file. 118 * 119 * @param filename 120 * the file to be checked. 121 * 122 * @return true if the given file is a NetCDF file; otherwise returns false. 123 */ 124 @Override 125 public boolean isThisType(String filename) { 126 boolean isNetcdf = false; 127 ucar.unidata.io.RandomAccessFile raf = null; 128 129 try { 130 raf = new ucar.unidata.io.RandomAccessFile(filename, "r"); 131 } 132 catch (Exception ex) { 133 log.trace("raf null - exit", ex); 134 raf = null; 135 } 136 137 if (raf == null) { 138 return false; 139 } 140 141 try { 142 isNetcdf = N3header.isValidFile(raf); 143 } 144 catch (IOException e) { 145 log.trace("raf isValidFile - failure", e); 146 return false; 147 } 148 149 try { 150 raf.close(); 151 } 152 catch (Exception ex) { 153 log.trace("raf close:", ex); 154 } 155 156 log.trace("{} - isNetcdf:{}", filename, isNetcdf); 157 return isNetcdf; 158 } 159 160 /** 161 * Creates a NC2File instance with specified file name and READ access. 162 * Regardless of specified access, the NC2File implementation uses READ. 163 * 164 * @see hdf.object.FileFormat#createInstance(java.lang.String, int) 165 */ 166 @Override 167 public FileFormat createInstance(String filename, int access) 168 throws Exception { 169 return new NC2File(filename); 170 } 171 172 // Implementing FileFormat 173 @Override 174 public long open() throws Exception { 175 log.trace("open(): start isFileOpen={}", isFileOpen); 176 177 if (!isFileOpen) { 178 isFileOpen = true; 179 rootObject = loadTree(); 180 } 181 182 return 0; 183 } 184 185 private HObject loadTree() { 186 long[] oid = { 0 }; 187 // root object does not have a parent path or a parent node 188 NC2Group rootGroup = new NC2Group(this, "/", null, null, oid); 189 190 if (ncFile == null) { 191 return rootGroup; 192 } 193 194 log.trace("loadTree(): iterate members"); 195 Iterator it = ncFile.getVariables().iterator(); 196 Variable ncDataset = null; 197 NC2Dataset d = null; 198 while (it.hasNext()) { 199 ncDataset = (Variable) it.next(); 200 oid[0] = ncDataset.hashCode(); 201 d = new NC2Dataset(this, ncDataset, oid); 202 rootGroup.addToMemberList(d); 203 } 204 205 return rootGroup; 206 } 207 208 // Implementing FileFormat 209 @Override 210 public void close() throws IOException { 211 if (ncFile != null) { 212 ncFile.close(); 213 } 214 215 isFileOpen = false; 216 fid = -1; 217 objList = null; 218 } 219 220 // Implementing FileFormat 221 @Override 222 public HObject getRootObject() { 223 return rootObject; 224 } 225 226 /** 227 * @return the NetCDF file. 228 */ 229 public NetcdfFile getNetcdfFile() { 230 return ncFile; 231 } 232 233 @Override 234 public Group createGroup(String name, Group pgroup) throws Exception { 235 throw new UnsupportedOperationException("Unsupported operation - create group."); 236 } 237 238 @Override 239 public Datatype createDatatype(int tclass, int tsize, int torder, int tsign) 240 throws Exception { 241 throw new UnsupportedOperationException("Unsupported operation - create datatype."); 242 } 243 244 @Override 245 public Datatype createDatatype(int tclass, int tsize, int torder, 246 int tsign, Datatype tbase) throws Exception { 247 throw new UnsupportedOperationException("Unsupported operation - create datatype."); 248 } 249 250 @Override 251 public Datatype createNamedDatatype(Datatype tnative, String name) throws Exception { 252 throw new UnsupportedOperationException("netcdf3 does not support named datatype."); 253 } 254 255 @Override 256 public Dataset createScalarDS(String name, Group pgroup, Datatype type, 257 long[] dims, long[] maxdims, long[] chunks, 258 int gzip, Object fillValue, Object data) throws Exception { 259 throw new UnsupportedOperationException("Unsupported operation create dataset."); 260 } 261 262 @Override 263 public Dataset createImage(String name, Group pgroup, Datatype type, 264 long[] dims, long[] maxdims, long[] chunks, 265 int gzip, int ncomp, int intelace, Object data) throws Exception { 266 throw new UnsupportedOperationException("Unsupported operation create image."); 267 } 268 269 @Override 270 public void delete(HObject obj) throws Exception { 271 throw new UnsupportedOperationException("Unsupported operation."); 272 } 273 274 @Override 275 public HObject copy(HObject srcObj, Group dstGroup, String dstName) 276 throws Exception { 277 throw new UnsupportedOperationException("Unsupported operation - copy."); 278 } 279 280 @Override 281 public void writeAttribute(HObject obj, hdf.object.Attribute attr, boolean attrExisted) throws Exception { 282 throw new UnsupportedOperationException("Unsupported operation - write attribute."); 283 } 284 285 private HObject copyGroup(NC2Group srcGroup, NC2Group pgroup) 286 throws Exception { 287 throw new UnsupportedOperationException("Unsupported operation - copy group."); 288 } 289 290 private void copyDataset(Dataset srcDataset, NC2Group pgroup) 291 throws Exception { 292 throw new UnsupportedOperationException("Unsupported operation - copy dataset."); 293 } 294 295 /** 296 * Copies the attributes of one object to another object. 297 * 298 * NC3 does not support attribute copy 299 * 300 * @param src 301 * The source object. 302 * @param dst 303 * The destination object. 304 */ 305 public void copyAttributes(HObject src, HObject dst) { 306 throw new UnsupportedOperationException("Unsupported operation copy attributes with HObject."); 307 } 308 309 /** 310 * Copies the attributes of one object to another object. 311 * 312 * NC3 does not support attribute copy 313 * 314 * @param srcID 315 * The source identifier. 316 * @param dstID 317 * The destination identifier. 318 */ 319 public void copyAttributes(int srcID, int dstID) { 320 throw new UnsupportedOperationException("Unsupported operation - copy attributes."); 321 } 322 323 /** 324 * converts a ucar.nc2.Attribute into an hdf.object.nc2.NC2Attribute 325 * 326 * @param parent 327 * the parent object. 328 * @param netcdfAttr 329 * the ucar.nc2.Attribute object. 330 * 331 * @return the hdf.object.nc2.NC2Attribute if successful 332 */ 333 public static hdf.object.nc2.NC2Attribute convertAttribute(HObject parent, ucar.nc2.Attribute netcdfAttr) { 334 hdf.object.nc2.NC2Attribute ncsaAttr = null; 335 336 if (netcdfAttr == null) { 337 return null; 338 } 339 340 String attrName = netcdfAttr.getShortName(); 341 long[] attrDims = { netcdfAttr.getLength() }; 342 log.trace("convertAttribute(): attrName={} len={}", attrName, netcdfAttr.getLength()); 343 Datatype attrType = null; 344 try { 345 attrType = new NC2Datatype(netcdfAttr.getDataType()); 346 } 347 catch (Exception ex) { 348 attrType = null; 349 } 350 ncsaAttr = new hdf.object.nc2.NC2Attribute(parent, attrName, attrType, attrDims); 351 Object[] attrValues = { netcdfAttr.getValue(0) }; 352 ncsaAttr.setData(attrValues); 353 354 log.trace("convertAttribute(): finish data={}", netcdfAttr.getValue(0)); 355 return ncsaAttr; 356 } 357 358 /** 359 * Retrieves the file structure from disk and returns the root object. 360 * 361 * First gets the top level objects or objects that do not belong to any 362 * groups. If a top level object is a group, call the depth_first() to 363 * retrieve the sub-tree of that group, recursively. 364 */ 365 private void loadIntoMemory() { 366 if (fid < 0) { 367 log.debug("loadIntoMemory(): Invalid File Id"); 368 return; 369 } 370 } 371 372 /** 373 * Retrieves the tree structure of the file by depth-first order. The 374 * current implementation only retrieves groups and datasets. 375 * 376 * @param parentObject 377 * the parent object. 378 */ 379 private void depth_first(HObject parentObj) { 380 log.trace("depth_first(pobj = {})", parentObj); 381 382 if (parentObj == null) { 383 log.debug("depth_first(): Parent object is null"); 384 return; 385 } 386 } // private depth_first() 387 388 /** 389 * Returns a list of all the members of this NetCDF3 in a 390 * breadth-first ordering that are rooted at the specified 391 * object. 392 */ 393 private static List<HObject> getMembersBreadthFirst(HObject obj) { 394 List<HObject> allMembers = new ArrayList<>(); 395 Queue<HObject> queue = new LinkedList<>(); 396 HObject currentObject = obj; 397 398 queue.add(currentObject); 399 400 while(!queue.isEmpty()) { 401 currentObject = queue.remove(); 402 allMembers.add(currentObject); 403 404 if(currentObject instanceof Group) { 405 queue.addAll(((Group) currentObject).getMemberList()); 406 } 407 } 408 409 return allMembers; 410 } 411 412 /** 413 * Returns the version of the library. 414 */ 415 @Override 416 public String getLibversion() { 417 return "NetCDF Java (version 4.3)"; 418 } 419 420 // implementing FileFormat 421 @Override 422 public HObject get(String path) throws Exception { 423 throw new UnsupportedOperationException("get() is not supported"); 424 } 425}