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