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.h4; 016 017import java.util.List; 018import java.util.Vector; 019 020import hdf.hdflib.HDFConstants; 021import hdf.hdflib.HDFException; 022import hdf.hdflib.HDFLibrary; 023import hdf.object.Attribute; 024import hdf.object.Dataset; 025import hdf.object.FileFormat; 026import hdf.object.Group; 027import hdf.object.HObject; 028import hdf.object.h4.H4ScalarAttribute; 029 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033/** 034 * An H4Group is a vgroup in HDF4, inheriting from Group. 035 * A vgroup is a structure designed to associate related data objects. The 036 * general structure of a vgroup is similar to that of the UNIX file system in 037 * that the vgroup may contain references to other vgroups or HDF data objects 038 * just as the UNIX directory may contain subdirectories or files. 039 * 040 * @version 1.1 9/4/2007 041 * @author Peter X. Cao 042 */ 043public class H4Group extends Group { 044 private static final long serialVersionUID = 3785240955078867900L; 045 046 private static final Logger log = LoggerFactory.getLogger(H4Group.class); 047 048 /** 049 * The list of attributes of this data object. Members of the list are 050 * instance of H4ScalarAttribute. 051 */ 052 @SuppressWarnings("rawtypes") 053 private List attributeList; 054 055 /** the number of attributes */ 056 private int nAttributes = -1; 057 058 /** The default object ID for HDF4 objects */ 059 private static final long[] DEFAULT_OID = {0, 0}; 060 061 /** 062 * Creates a group object with specific name, path, and parent. 063 * 064 * @param theFile the HDF file. 065 * @param name the name of this group. 066 * @param path the full path of this group. 067 * @param parent the parent of this group. 068 */ 069 public H4Group(FileFormat theFile, String name, String path, Group parent) 070 { 071 this(theFile, name, path, parent, null); 072 } 073 074 /** 075 * Creates a group object with specific name, path, parent and oid. 076 * 077 * @param theFile the HDF file. 078 * @param name the name of this group. 079 * @param path the full path of this group. 080 * @param parent the parent of this group. 081 * @param oid the unique identifier of this data object. 082 */ 083 @SuppressWarnings("deprecation") 084 public H4Group(FileFormat theFile, String name, String path, Group parent, long[] oid) 085 { 086 super(theFile, name, path, parent, ((oid == null) ? DEFAULT_OID : oid)); 087 } 088 089 /* 090 * (non-Javadoc) 091 * @see hdf.object.DataFormat#hasAttribute() 092 */ 093 @Override 094 public boolean hasAttribute() 095 { 096 if (nAttributes < 0) { 097 long vgid = open(); 098 099 if (vgid > 0) { 100 try { 101 nAttributes = HDFLibrary.Vnattrs(vgid); 102 nMembersInFile = HDFLibrary.Vntagrefs(vgid); 103 } 104 catch (Exception ex) { 105 log.debug("hasAttribute(): failure: ", ex); 106 nAttributes = 0; 107 } 108 109 log.trace("hasAttribute(): nAttributes={}", nAttributes); 110 111 close(vgid); 112 } 113 } 114 115 return (nAttributes > 0); 116 } 117 118 // Implementing DataFormat 119 /** 120 * Retrieves the object's metadata, such as attributes, from the file. 121 * 122 * Metadata, such as attributes, is stored in a List. 123 * 124 * @return the list of metadata objects. 125 * 126 * @throws HDFException 127 * if the metadata can not be retrieved 128 */ 129 @Override 130 @SuppressWarnings({"rawtypes", "unchecked"}) 131 public List getMetadata() throws HDFException 132 { 133 if (attributeList != null) { 134 log.trace("getMetadata(): attributeList != null"); 135 return attributeList; 136 } 137 else { 138 attributeList = new Vector(); 139 } 140 141 // Library methods cannot be called on HDF4 dummy root group since it has a ref of 0 142 if (oid[1] > 0) { 143 long vgid = open(); 144 log.trace("getMetadata(): open: id={}", vgid); 145 if (vgid < 0) { 146 log.debug("getMetadata(): Invalid VG ID"); 147 return attributeList; 148 } 149 150 int n = -1; 151 152 try { 153 n = HDFLibrary.Vnattrs(vgid); 154 log.trace("getMetadata(): Vnattrs: n={}", n); 155 156 boolean b = false; 157 String[] attrName = new String[1]; 158 int[] attrInfo = new int[5]; 159 for (int i = 0; i < n; i++) { 160 attrName[0] = ""; 161 try { 162 b = HDFLibrary.Vattrinfo(vgid, i, attrName, attrInfo); 163 // mask off the litend bit 164 attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND); 165 } 166 catch (HDFException ex) { 167 log.trace("getMetadata(): attribute[{}] Vattrinfo failure: ", i, ex); 168 b = false; 169 } 170 171 if (!b) 172 continue; 173 174 long[] attrDims = {attrInfo[1]}; 175 H4ScalarAttribute attr = 176 new H4ScalarAttribute(this, attrName[0], new H4Datatype(attrInfo[0]), attrDims); 177 attributeList.add(attr); 178 179 Object buf = null; 180 try { 181 buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]); 182 } 183 catch (OutOfMemoryError e) { 184 log.debug("getMetadata(): out of memory: ", e); 185 } 186 187 try { 188 HDFLibrary.Vgetattr(vgid, i, buf); 189 } 190 catch (HDFException ex) { 191 log.trace("getMetadata(): attribute[{}] Vgetattr failure: ", i, ex); 192 buf = null; 193 } 194 195 if (buf != null) { 196 if ((attrInfo[0] == HDFConstants.DFNT_CHAR) || 197 (attrInfo[0] == HDFConstants.DFNT_UCHAR8)) 198 buf = Dataset.byteToString((byte[])buf, attrInfo[1]); 199 200 attr.setAttributeData(buf); 201 } 202 } 203 } 204 catch (Exception ex) { 205 log.trace("getMetadata(): failure: ", ex); 206 } 207 finally { 208 close(vgid); 209 } 210 } 211 212 return attributeList; 213 } 214 215 // To do: implementing DataFormat 216 /** 217 * Writes a specific piece of metadata (such as an attribute) into the file. 218 * 219 * If an HDF(4&5) attribute exists in the file, this method updates its 220 * value. If the attribute does not exist in the file, it creates the 221 * attribute in the file and attaches it to the object. It will fail to 222 * write a new attribute to the object where an attribute with the same name 223 * already exists. To update the value of an existing attribute in the file, 224 * one needs to get the instance of the attribute by getMetadata(), change 225 * its values, then use writeMetadata() to write the value. 226 * 227 * @param info 228 * the metadata to write. 229 * 230 * @throws Exception 231 * if the metadata can not be written 232 */ 233 @Override 234 @SuppressWarnings({"rawtypes", "unchecked"}) 235 public void writeMetadata(Object info) throws Exception 236 { 237 // only attribute metadata is supported. 238 if (!(info instanceof Attribute)) { 239 log.debug("writeMetadata(): Object not an H4ScalarAttribute"); 240 return; 241 } 242 243 try { 244 getFileFormat().writeAttribute(this, (H4ScalarAttribute)info, true); 245 246 if (attributeList == null) 247 attributeList = new Vector(); 248 249 attributeList.add(info); 250 nAttributes = attributeList.size(); 251 } 252 catch (Exception ex) { 253 log.debug("writeMetadata(): failure: ", ex); 254 } 255 } 256 257 /** 258 * Deletes an existing piece of metadata from this object. 259 * 260 * @param info 261 * the metadata to delete. 262 * 263 * @throws HDFException 264 * if the metadata can not be removed 265 */ 266 @Override 267 public void removeMetadata(Object info) throws HDFException 268 { 269 log.trace("removeMetadata(): disabled"); 270 } 271 272 /** 273 * Updates an existing piece of metadata attached to this object. 274 * 275 * @param info 276 * the metadata to update. 277 * 278 * @throws Exception 279 * if the metadata can not be updated 280 */ 281 @Override 282 public void updateMetadata(Object info) throws Exception 283 { 284 log.trace("updateMetadata(): disabled"); 285 } 286 287 // Implementing HObject 288 @Override 289 public long open() 290 { 291 log.trace("open(): start: for file={} with ref={}", getFID(), oid[1]); 292 293 if (oid[1] <= 0) { 294 log.debug("open(): oid[1] <= 0"); 295 return -1; // Library methods cannot be called on HDF4 dummy group with ref 0 296 } 297 298 long vgid = -1; 299 300 if (!getFileFormat().isReadOnly()) { 301 // try to open with write permission 302 try { 303 vgid = HDFLibrary.Vattach(getFID(), (int)oid[1], "w"); 304 log.trace("open(): Vattach write id={}", vgid); 305 } 306 catch (HDFException ex) { 307 log.debug("open(): Vattach failure: ", ex); 308 vgid = -1; 309 } 310 } 311 312 // try to open with read-only permission 313 if (getFileFormat().isReadOnly() || vgid < 0) { 314 try { 315 vgid = HDFLibrary.Vattach(getFID(), (int)oid[1], "r"); 316 log.trace("open(): Vattach readonly id={}", vgid); 317 } 318 catch (HDFException ex) { 319 log.debug("open(): Vattach failure: ", ex); 320 vgid = -1; 321 } 322 } 323 324 return vgid; 325 } 326 327 /** close group access. */ 328 @Override 329 public void close(long vgid) 330 { 331 log.trace("close(): id={}", vgid); 332 333 if (vgid >= 0) { 334 try { 335 HDFLibrary.Vdetach(vgid); 336 } 337 catch (Exception ex) { 338 log.debug("close(): Vdetach failure: ", ex); 339 } 340 } 341 } 342 343 /** 344 * Creates a new group. 345 * 346 * @param name the name of the group to create. 347 * @param pgroup the parent group of the new group. 348 * 349 * @return the new group if successful. Otherwise returns null. 350 * 351 * @throws Exception if the group can not be created 352 */ 353 public static H4Group create(String name, Group pgroup) throws Exception 354 { 355 log.trace("create(): start: name={} parentGroup={}", name, pgroup); 356 357 H4Group group = null; 358 if ((pgroup == null) || (name == null)) { 359 log.debug("create(): one or more parameters are null"); 360 return null; 361 } 362 363 H4File file = (H4File)pgroup.getFileFormat(); 364 365 if (file == null) { 366 log.debug("create(): Parent group FileFormat is null"); 367 return null; 368 } 369 370 String path = HObject.SEPARATOR; 371 if (!pgroup.isRoot()) 372 path = pgroup.getPath() + pgroup.getName() + HObject.SEPARATOR; 373 long fileid = file.open(); 374 if (fileid < 0) { 375 log.debug("create(): Invalid File ID"); 376 return null; 377 } 378 379 long gid = HDFLibrary.Vattach(fileid, -1, "w"); 380 if (gid < 0) { 381 log.debug("create(): Invalid Group ID"); 382 return null; 383 } 384 385 HDFLibrary.Vsetname(gid, name); 386 int ref = HDFLibrary.VQueryref(gid); 387 int tag = HDFLibrary.VQuerytag(gid); 388 389 if (!pgroup.isRoot()) { 390 // add the dataset to the parent group 391 long pid = pgroup.open(); 392 if (pid < 0) { 393 log.debug("create(): Invalid Parent Group ID"); 394 throw(new HDFException("Unable to open the parent group.")); 395 } 396 397 HDFLibrary.Vinsert(pid, gid); 398 399 pgroup.close(pid); 400 } 401 402 try { 403 HDFLibrary.Vdetach(gid); 404 } 405 catch (Exception ex) { 406 log.debug("create(): Vdetach failure: ", ex); 407 } 408 409 long[] oid = {tag, ref}; 410 group = new H4Group(file, name, path, pgroup, oid); 411 412 if (group != null) 413 pgroup.addToMemberList(group); 414 415 return group; 416 } 417 418 // Implementing DataFormat 419 /** 420 * Retrieves the object's metadata, such as attributes, from the file. 421 * 422 * Metadata, such as attributes, is stored in a List. 423 * 424 * @param attrPropList 425 * the list of properties to get 426 * 427 * @return the list of metadata objects. 428 * 429 * @throws Exception 430 * if the metadata can not be retrieved 431 */ 432 @SuppressWarnings("rawtypes") 433 public List getMetadata(int... attrPropList) throws Exception 434 { 435 throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported"); 436 } 437}