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