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