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