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.h5; 016 017import java.util.List; 018import java.util.Vector; 019 020import hdf.object.Attribute; 021import hdf.object.FileFormat; 022import hdf.object.Group; 023import hdf.object.HObject; 024import hdf.object.h5.H5MetaDataContainer; 025 026import hdf.hdf5lib.H5; 027import hdf.hdf5lib.HDF5Constants; 028import hdf.hdf5lib.HDFArray; 029import hdf.hdf5lib.HDFNativeData; 030import hdf.hdf5lib.exceptions.HDF5Exception; 031import hdf.hdf5lib.structs.H5G_info_t; 032import hdf.hdf5lib.structs.H5O_info_t; 033import hdf.hdf5lib.structs.H5O_token_t; 034 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038/** 039 * An H5Group object represents an existing HDF5 group in file. 040 * 041 * In HDF5, every object has at least one name. An HDF5 group is used to store a set of the names together in 042 * one place, i.e. a group. The general structure of a group is similar to that of the UNIX file system in 043 * that the group may contain references to other groups or data objects just as the UNIX directory may 044 * contain sub-directories or files. 045 * 046 * For more information on HDF5 Groups, 047 * 048 * <a href= 049 * "https://support.hdfgroup.org/releases/hdf5/v1_14/v1_14_5/documentation/doxygen/_h5_g__u_g.html#sec_group">HDF5 050 * Groups in HDF5 User Guide</a> 051 * 052 * @version 1.1 9/4/2007 053 * @author Peter X. Cao 054 */ 055public class H5Group extends Group { 056 private static final long serialVersionUID = -951164512330444150L; 057 058 private static final Logger log = LoggerFactory.getLogger(H5Group.class); 059 060 /** 061 * The metadata object for this data object. Members of the metadata are instances of Attribute. 062 */ 063 private H5MetaDataContainer objMetadata; 064 065 /** the object properties */ 066 private H5O_info_t objInfo; 067 068 /** 069 * Constructs an HDF5 group with specific name, path, and parent. 070 * 071 * @param theFile 072 * the file that contains the group. 073 * @param theName 074 * the name of this group, e.g. "grp01". 075 * @param thePath 076 * the full path of this group, e.g. "/groups/". 077 * @param theParent 078 * the parent of this group. 079 */ 080 public H5Group(FileFormat theFile, String theName, String thePath, Group theParent) 081 { 082 this(theFile, theName, thePath, theParent, null); 083 } 084 085 /** 086 * @deprecated Not for public use in the future.<br> 087 * Using {@link #H5Group(FileFormat, String, String, Group)} 088 * 089 * @param theFile 090 * the file that contains the group. 091 * @param theName 092 * the name of this group, e.g. "grp01". 093 * @param thePath 094 * the full path of this group, e.g. "/groups/". 095 * @param theParent 096 * the parent of this group. 097 * @param oid 098 * the oid of this group. 099 */ 100 @Deprecated 101 public H5Group(FileFormat theFile, String theName, String thePath, Group theParent, long[] oid) 102 { 103 super(theFile, theName, thePath, theParent, oid); 104 nMembersInFile = -1; 105 objMetadata = new H5MetaDataContainer(theFile, theName, thePath, this); 106 107 if (theFile != null) { 108 if (oid == null) { 109 // retrieve the object ID 110 byte[] refBuf = null; 111 try { 112 refBuf = 113 H5.H5Rcreate_object(theFile.getFID(), this.getFullName(), HDF5Constants.H5P_DEFAULT); 114 this.oid = HDFNativeData.byteToLong(refBuf); 115 log.trace("constructor REF {} to OID {}", refBuf, this.oid); 116 } 117 catch (Exception ex) { 118 log.debug("constructor ID {} for {} failed H5Rcreate_object", theFile.getFID(), 119 this.getFullName()); 120 } 121 finally { 122 if (refBuf != null) 123 H5.H5Rdestroy(refBuf); 124 } 125 } 126 log.trace("constructor OID {}", this.oid); 127 try { 128 objInfo = H5.H5Oget_info_by_name(theFile.getFID(), this.getFullName(), 129 HDF5Constants.H5O_INFO_BASIC, HDF5Constants.H5P_DEFAULT); 130 } 131 catch (Exception ex) { 132 objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L); 133 } 134 } 135 else { 136 this.oid = null; 137 objInfo = new H5O_info_t(-1L, null, 0, 0, 0L, 0L, 0L, 0L, 0L); 138 } 139 } 140 141 /* 142 * (non-Javadoc) 143 * 144 * @see hdf.object.HObject#open() 145 */ 146 @Override 147 public long open() 148 { 149 long gid = HDF5Constants.H5I_INVALID_HID; 150 151 try { 152 if (isRoot()) { 153 gid = H5.H5Gopen(getFID(), SEPARATOR, HDF5Constants.H5P_DEFAULT); 154 } 155 else { 156 gid = H5.H5Gopen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT); 157 } 158 log.trace("open(): gid={}", gid); 159 } 160 catch (HDF5Exception ex) { 161 log.debug("open(): Failed to open group {}", getPath() + getName(), ex); 162 gid = HDF5Constants.H5I_INVALID_HID; 163 } 164 165 return gid; 166 } 167 168 /* 169 * (non-Javadoc) 170 * 171 * @see hdf.object.HObject#close(int) 172 */ 173 @Override 174 public void close(long gid) 175 { 176 if (gid >= 0) { 177 try { 178 H5.H5Gclose(gid); 179 } 180 catch (HDF5Exception ex) { 181 log.debug("close(): H5Gclose(gid {}): ", gid, ex); 182 } 183 } 184 } 185 186 /** 187 * Get the token for this object. 188 * 189 * @return true if it has any attributes, false otherwise. 190 */ 191 public long[] getToken() 192 { 193 H5O_token_t token = objInfo.token; 194 return HDFNativeData.byteToLong(token.data); 195 } 196 197 /** 198 * Check if the object has any attributes attached. 199 * 200 * @return true if it has any attributes, false otherwise. 201 */ 202 @Override 203 public boolean hasAttribute() 204 { 205 objInfo.num_attrs = objMetadata.getObjectAttributeSize(); 206 207 if (objInfo.num_attrs < 0) { 208 long gid = open(); 209 if (gid > 0) { 210 try { 211 objInfo = H5.H5Oget_info(gid); 212 } 213 catch (Exception ex) { 214 objInfo.num_attrs = 0; 215 log.debug("hasAttribute(): get object info failure: ", ex); 216 } 217 finally { 218 close(gid); 219 } 220 objMetadata.setObjectAttributeSize((int)objInfo.num_attrs); 221 } 222 else { 223 log.debug("hasAttribute(): could not open group"); 224 } 225 } 226 227 log.trace("hasAttribute(): nAttributes={}", objInfo.num_attrs); 228 return (objInfo.num_attrs > 0); 229 } 230 231 /* 232 * (non-Javadoc) 233 * 234 * @see hdf.object.Group#getNumberOfMembersInFile() 235 */ 236 @Override 237 public int getNumberOfMembersInFile() 238 { 239 if (nMembersInFile < 0) { 240 long gid = open(); 241 if (gid > 0) { 242 try { 243 H5G_info_t group_info = null; 244 group_info = H5.H5Gget_info(gid); 245 nMembersInFile = (int)group_info.nlinks; 246 } 247 catch (Exception ex) { 248 nMembersInFile = 0; 249 } 250 close(gid); 251 } 252 } 253 return nMembersInFile; 254 } 255 256 /** 257 * Removes all of the elements from metadata list. 258 * The list should be empty after this call returns. 259 */ 260 @Override 261 public void clear() 262 { 263 super.clear(); 264 objMetadata.clear(); 265 } 266 267 /** 268 * Retrieves the object's metadata, such as attributes, from the file. 269 * 270 * Metadata, such as attributes, is stored in a List. 271 * 272 * @return the list of metadata objects. 273 * 274 * @throws HDF5Exception 275 * if the metadata can not be retrieved 276 */ 277 @Override 278 public List<Attribute> getMetadata() throws HDF5Exception 279 { 280 int gmIndexType = 0; 281 int gmIndexOrder = 0; 282 283 try { 284 gmIndexType = fileFormat.getIndexType(null); 285 } 286 catch (Exception ex) { 287 log.debug("getMetadata(): getIndexType failed: ", ex); 288 } 289 try { 290 gmIndexOrder = fileFormat.getIndexOrder(null); 291 } 292 catch (Exception ex) { 293 log.debug("getMetadata(): getIndexOrder failed: ", ex); 294 } 295 return this.getMetadata(gmIndexType, gmIndexOrder); 296 } 297 298 /** 299 * Retrieves the object's metadata, such as attributes, from the file. 300 * 301 * Metadata, such as attributes, is stored in a List. 302 * 303 * @param attrPropList 304 * the list of properties to get 305 * 306 * @return the list of metadata objects. 307 * 308 * @throws HDF5Exception 309 * if the metadata can not be retrieved 310 */ 311 public List<Attribute> getMetadata(int... attrPropList) throws HDF5Exception 312 { 313 try { 314 this.linkTargetObjName = H5File.getLinkTargetName(this); 315 } 316 catch (Exception ex) { 317 log.debug("getMetadata(): getLinkTargetName failed: ", ex); 318 } 319 320 List<Attribute> attrlist = null; 321 try { 322 attrlist = objMetadata.getMetadata(attrPropList); 323 } 324 catch (Exception ex) { 325 log.debug("getMetadata(): getMetadata failed: ", ex); 326 } 327 return attrlist; 328 } 329 330 /** 331 * Writes a specific piece of metadata (such as an attribute) into the file. 332 * 333 * If an HDF(4&5) attribute exists in the file, this method updates its 334 * value. If the attribute does not exist in the file, it creates the 335 * attribute in the file and attaches it to the object. It will fail to 336 * write a new attribute to the object where an attribute with the same name 337 * already exists. To update the value of an existing attribute in the file, 338 * one needs to get the instance of the attribute by getMetadata(), change 339 * its values, then use writeMetadata() to write the value. 340 * 341 * @param info 342 * the metadata to write. 343 * 344 * @throws Exception 345 * if the metadata can not be written 346 */ 347 @Override 348 public void writeMetadata(Object info) throws Exception 349 { 350 try { 351 objMetadata.writeMetadata(info); 352 } 353 catch (Exception ex) { 354 log.debug("writeMetadata(): Object not an Attribute"); 355 } 356 } 357 358 /** 359 * Deletes an existing piece of metadata from this object. 360 * 361 * @param info 362 * the metadata to delete. 363 * 364 * @throws HDF5Exception 365 * if the metadata can not be removed 366 */ 367 @Override 368 public void removeMetadata(Object info) throws HDF5Exception 369 { 370 try { 371 objMetadata.removeMetadata(info); 372 } 373 catch (Exception ex) { 374 log.debug("removeMetadata(): Object not an Attribute"); 375 return; 376 } 377 378 Attribute attr = (Attribute)info; 379 log.trace("removeMetadata(): {}", attr.getAttributeName()); 380 long gid = open(); 381 if (gid >= 0) { 382 try { 383 H5.H5Adelete(gid, attr.getAttributeName()); 384 } 385 catch (Exception ex) { 386 log.debug("removeMetadata(): ", ex); 387 } 388 finally { 389 close(gid); 390 } 391 } 392 else { 393 log.debug("removeMetadata(): failed to open group"); 394 } 395 } 396 397 /** 398 * Updates an existing piece of metadata attached to this object. 399 * 400 * @param info 401 * the metadata to update. 402 * 403 * @throws HDF5Exception 404 * if the metadata can not be updated 405 */ 406 @Override 407 public void updateMetadata(Object info) throws HDF5Exception 408 { 409 try { 410 objMetadata.updateMetadata(info); 411 } 412 catch (Exception ex) { 413 log.debug("updateMetadata(): Object not an Attribute"); 414 return; 415 } 416 } 417 418 /* 419 * (non-Javadoc) 420 * 421 * @see hdf.object.HObject#setName(java.lang.String) 422 */ 423 @Override 424 public void setName(String newName) throws Exception 425 { 426 if (newName == null) 427 throw new IllegalArgumentException("The new name is NULL"); 428 429 H5File.renameObject(this, newName); 430 super.setName(newName); 431 } 432 433 /* 434 * (non-Javadoc) 435 * 436 * @see hdf.object.HObject#setPath(java.lang.String) 437 */ 438 @SuppressWarnings("rawtypes") 439 @Override 440 public void setPath(String newPath) throws Exception 441 { 442 super.setPath(newPath); 443 444 List members = this.getMemberList(); 445 if (members == null) 446 return; 447 448 int n = members.size(); 449 HObject obj = null; 450 for (int i = 0; i < n; i++) { 451 obj = (HObject)members.get(i); 452 obj.setPath(getPath() + getName() + HObject.SEPARATOR); 453 } 454 } 455 456 /** 457 * Creates a new group with a name in a group and with the group creation 458 * properties specified in gplist. 459 * 460 * The gplist contains a sequence of group creation property list 461 * identifiers, lcpl, gcpl, gapl. It allows the user to create a group with 462 * group creation properties. It will close the group creation properties 463 * specified in gplist. 464 * 465 * @see hdf.hdf5lib.H5#H5Gcreate(long, String, long, long, long) for the 466 * order of property list identifiers. 467 * 468 * @param name 469 * The name of a new group. 470 * @param pgroup 471 * The parent group object. 472 * @param gplist 473 * The group creation properties, in which the order of the 474 * properties conforms the HDF5 library API, H5Gcreate(), i.e. 475 * lcpl, gcpl and gapl, where 476 * <ul> 477 * <li>lcpl : Property list for link creation <li>gcpl : Property 478 * list for group creation <li>gapl : Property list for group 479 * access 480 * </ul> 481 * 482 * @return The new group if successful; otherwise returns null. 483 * 484 * @throws Exception if there is a failure. 485 */ 486 public static H5Group create(String name, Group pgroup, long... gplist) throws Exception 487 { 488 H5Group group = null; 489 String fullPath = null; 490 long lcpl = HDF5Constants.H5P_DEFAULT; 491 long gcpl = HDF5Constants.H5P_DEFAULT; 492 long gapl = HDF5Constants.H5P_DEFAULT; 493 494 if (gplist.length > 0) { 495 lcpl = gplist[0]; 496 if (gplist.length > 1) { 497 gcpl = gplist[1]; 498 if (gplist.length > 2) 499 gapl = gplist[2]; 500 } 501 } 502 503 if ((name == null) || (pgroup == null)) { 504 log.debug("create(): one or more parameters are null"); 505 return null; 506 } 507 508 H5File file = (H5File)pgroup.getFileFormat(); 509 if (file == null) { 510 log.debug("create(): parent group FileFormat is null"); 511 return null; 512 } 513 514 String path = HObject.SEPARATOR; 515 if (!pgroup.isRoot()) { 516 path = pgroup.getPath() + pgroup.getName() + HObject.SEPARATOR; 517 if (name.endsWith("/")) 518 name = name.substring(0, name.length() - 1); 519 int idx = name.lastIndexOf('/'); 520 if (idx >= 0) 521 name = name.substring(idx + 1); 522 } 523 524 fullPath = path + name; 525 526 // create a new group and add it to the parent node 527 long gid = H5.H5Gcreate(file.open(), fullPath, lcpl, gcpl, gapl); 528 try { 529 H5.H5Gclose(gid); 530 } 531 catch (Exception ex) { 532 log.debug("create(): H5Gcreate {} H5Gclose(gid {}) failure: ", fullPath, gid, ex); 533 } 534 535 group = new H5Group(file, name, path, pgroup); 536 537 if (group != null) 538 pgroup.addToMemberList(group); 539 540 if (gcpl > 0) { 541 try { 542 H5.H5Pclose(gcpl); 543 } 544 catch (final Exception ex) { 545 log.debug("create(): create prop H5Pclose(gcpl {}) failure: ", gcpl, ex); 546 } 547 } 548 549 return group; 550 } 551}