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