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