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.h4; 016 017import java.util.List; 018import java.util.Vector; 019 020import org.slf4j.Logger; 021import org.slf4j.LoggerFactory; 022 023import hdf.hdflib.HDFConstants; 024import hdf.hdflib.HDFException; 025import hdf.hdflib.HDFLibrary; 026 027import hdf.object.Attribute; 028import hdf.object.Dataset; 029import hdf.object.FileFormat; 030import hdf.object.Group; 031import hdf.object.HObject; 032 033import hdf.object.h4.H4ScalarAttribute; 034 035/** 036 * An H4Group is a vgroup in HDF4, inheriting from Group. 037 * A vgroup is a structure designed to associate related data objects. The 038 * general structure of a vgroup is similar to that of the UNIX file system in 039 * that the vgroup may contain references to other vgroups or HDF data objects 040 * just as the UNIX directory may contain subdirectories or files. 041 * 042 * @version 1.1 9/4/2007 043 * @author Peter X. Cao 044 */ 045public class H4Group extends Group 046{ 047 private static final long serialVersionUID = 3785240955078867900L; 048 049 private static final Logger log = LoggerFactory.getLogger(H4Group.class); 050 051 /** 052 * The list of attributes of this data object. Members of the list are 053 * instance of H4ScalarAttribute. 054 */ 055 @SuppressWarnings("rawtypes") 056 private List attributeList; 057 058 /** the number of attributes */ 059 private int nAttributes = -1; 060 061 /** The default object ID for HDF4 objects */ 062 private static final long[] DEFAULT_OID = {0, 0}; 063 064 /** 065 * Creates a group object with specific name, path, and parent. 066 * 067 * @param theFile the HDF file. 068 * @param name the name of this group. 069 * @param path the full path of this group. 070 * @param parent the parent of this group. 071 */ 072 public H4Group(FileFormat theFile, String name, String path, Group parent) 073 { 074 this(theFile, name, path, parent, null); 075 } 076 077 /** 078 * Creates a group object with specific name, path, parent and oid. 079 * 080 * @param theFile the HDF file. 081 * @param name the name of this group. 082 * @param path the full path of this group. 083 * @param parent the parent of this group. 084 * @param oid the unique identifier of this data object. 085 */ 086 @SuppressWarnings("deprecation") 087 public H4Group(FileFormat theFile, String name, String path, Group parent, long[] oid) { 088 super (theFile, name, path, parent, ((oid == null) ? DEFAULT_OID : oid)); 089 } 090 091 /* 092 * (non-Javadoc) 093 * @see hdf.object.DataFormat#hasAttribute() 094 */ 095 @Override 096 public boolean hasAttribute() { 097 if (nAttributes < 0) { 098 long vgid = open(); 099 100 if (vgid > 0) { 101 try { 102 nAttributes = HDFLibrary.Vnattrs(vgid); 103 nMembersInFile = HDFLibrary.Vntagrefs(vgid); 104 } 105 catch (Exception ex) { 106 log.debug("hasAttribute(): failure: ", ex); 107 nAttributes = 0; 108 } 109 110 log.trace("hasAttribute(): nAttributes={}", nAttributes); 111 112 close(vgid); 113 } 114 } 115 116 return (nAttributes > 0); 117 } 118 119 // Implementing DataFormat 120 /** 121 * Retrieves the object's metadata, such as attributes, from the file. 122 * 123 * Metadata, such as attributes, is stored in a List. 124 * 125 * @return the list of metadata objects. 126 * 127 * @throws HDFException 128 * if the metadata can not be retrieved 129 */ 130 @Override 131 @SuppressWarnings({"rawtypes", "unchecked"}) 132 public List getMetadata() throws HDFException { 133 if (attributeList != null) { 134 log.trace("getMetadata(): attributeList != null"); 135 return attributeList; 136 } 137 else { 138 attributeList = new Vector(); 139 } 140 141 // Library methods cannot be called on HDF4 dummy root group since it has a ref of 0 142 if (oid[1] > 0) { 143 long vgid = open(); 144 log.trace("getMetadata(): open: id={}", vgid); 145 if (vgid < 0) { 146 log.debug("getMetadata(): Invalid VG ID"); 147 return attributeList; 148 } 149 150 int n = -1; 151 152 try { 153 n = HDFLibrary.Vnattrs(vgid); 154 log.trace("getMetadata(): Vnattrs: n={}", n); 155 156 boolean b = false; 157 String[] attrName = new String[1]; 158 int[] attrInfo = new int[5]; 159 for (int i=0; i<n; i++) { 160 attrName[0] = ""; 161 try { 162 b = HDFLibrary.Vattrinfo(vgid, i, attrName, attrInfo); 163 // mask off the litend bit 164 attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND); 165 } 166 catch (HDFException ex) { 167 log.trace("getMetadata(): attribute[{}] Vattrinfo failure: ", i, ex); 168 b = false; 169 } 170 171 if (!b) 172 continue; 173 174 long[] attrDims = {attrInfo[1]}; 175 H4ScalarAttribute attr = new H4ScalarAttribute(this, attrName[0], new H4Datatype(attrInfo[0]), attrDims); 176 attributeList.add(attr); 177 178 Object buf = null; 179 try { 180 buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]); 181 } 182 catch (OutOfMemoryError e) { 183 log.debug("getMetadata(): out of memory: ", e); 184 } 185 186 try { 187 HDFLibrary.Vgetattr(vgid, i, buf); 188 } 189 catch (HDFException ex) { 190 log.trace("getMetadata(): attribute[{}] Vgetattr failure: ", i, ex); 191 buf = null; 192 } 193 194 if (buf != null) { 195 if ((attrInfo[0] == HDFConstants.DFNT_CHAR) || (attrInfo[0] == HDFConstants.DFNT_UCHAR8)) 196 buf = Dataset.byteToString((byte[])buf, attrInfo[1]); 197 198 attr.setAttributeData(buf); 199 } 200 } 201 } 202 catch (Exception ex) { 203 log.trace("getMetadata(): failure: ", ex); 204 } 205 finally { 206 close(vgid); 207 } 208 } 209 210 return attributeList; 211 } 212 213 // To do: implementing DataFormat 214 /** 215 * Writes a specific piece of metadata (such as an attribute) into the file. 216 * 217 * If an HDF(4&5) attribute exists in the file, this method updates its 218 * value. If the attribute does not exist in the file, it creates the 219 * attribute in the file and attaches it to the object. It will fail to 220 * write a new attribute to the object where an attribute with the same name 221 * already exists. To update the value of an existing attribute in the file, 222 * one needs to get the instance of the attribute by getMetadata(), change 223 * its values, then use writeMetadata() to write the value. 224 * 225 * @param info 226 * the metadata to write. 227 * 228 * @throws Exception 229 * if the metadata can not be written 230 */ 231 @Override 232 @SuppressWarnings({"rawtypes", "unchecked"}) 233 public void writeMetadata(Object info) throws Exception { 234 // only attribute metadata is supported. 235 if (!(info instanceof Attribute)) { 236 log.debug("writeMetadata(): Object not an H4ScalarAttribute"); 237 return; 238 } 239 240 try { 241 getFileFormat().writeAttribute(this, (H4ScalarAttribute)info, true); 242 243 if (attributeList == null) 244 attributeList = new Vector(); 245 246 attributeList.add(info); 247 nAttributes = attributeList.size(); 248 } 249 catch (Exception ex) { 250 log.debug("writeMetadata(): failure: ", ex); 251 } 252 } 253 254 255 /** 256 * Deletes an existing piece of metadata from this object. 257 * 258 * @param info 259 * the metadata to delete. 260 * 261 * @throws HDFException 262 * if the metadata can not be removed 263 */ 264 @Override 265 public void removeMetadata(Object info) throws HDFException { 266 log.trace("removeMetadata(): disabled"); 267 } 268 269 /** 270 * Updates an existing piece of metadata attached to this object. 271 * 272 * @param info 273 * the metadata to update. 274 * 275 * @throws Exception 276 * if the metadata can not be updated 277 */ 278 @Override 279 public void updateMetadata(Object info) throws Exception { 280 log.trace("updateMetadata(): disabled"); 281 } 282 283 // Implementing HObject 284 @Override 285 public long open() { 286 log.trace("open(): start: for file={} with ref={}", getFID(), oid[1]); 287 288 if (oid[1] <= 0) { 289 log.debug("open(): oid[1] <= 0"); 290 return -1; // Library methods cannot be called on HDF4 dummy group with ref 0 291 } 292 293 long vgid = -1; 294 295 if (!getFileFormat().isReadOnly()) { 296 // try to open with write permission 297 try { 298 vgid = HDFLibrary.Vattach(getFID(), (int)oid[1], "w"); 299 log.trace("open(): Vattach write id={}", vgid); 300 } 301 catch (HDFException ex) { 302 log.debug("open(): Vattach failure: ", ex); 303 vgid = -1; 304 } 305 } 306 307 // try to open with read-only permission 308 if (getFileFormat().isReadOnly() || vgid < 0) { 309 try { 310 vgid = HDFLibrary.Vattach(getFID(), (int)oid[1], "r"); 311 log.trace("open(): Vattach readonly id={}", vgid); 312 } 313 catch (HDFException ex) { 314 log.debug("open(): Vattach failure: ", ex); 315 vgid = -1; 316 } 317 } 318 319 return vgid; 320 } 321 322 /** close group access. */ 323 @Override 324 public void close(long vgid) { 325 log.trace("close(): id={}", vgid); 326 327 if (vgid >= 0) { 328 try { 329 HDFLibrary.Vdetach(vgid); 330 } 331 catch (Exception ex) { 332 log.debug("close(): Vdetach failure: ", ex); 333 } 334 } 335 } 336 337 /** 338 * Creates a new group. 339 * 340 * @param name the name of the group to create. 341 * @param pgroup the parent group of the new group. 342 * 343 * @return the new group if successful. Otherwise returns null. 344 * 345 * @throws Exception if the group can not be created 346 */ 347 public static H4Group create(String name, Group pgroup) throws Exception { 348 log.trace("create(): start: name={} parentGroup={}", name, pgroup); 349 350 H4Group group = null; 351 if ((pgroup == null) || 352 (name == null)) { 353 log.debug("create(): one or more parameters are null"); 354 return null; 355 } 356 357 H4File file = (H4File)pgroup.getFileFormat(); 358 359 if (file == null) { 360 log.debug("create(): Parent group FileFormat is null"); 361 return null; 362 } 363 364 String path = HObject.SEPARATOR; 365 if (!pgroup.isRoot()) 366 path = pgroup.getPath()+pgroup.getName()+HObject.SEPARATOR; 367 long fileid = file.open(); 368 if (fileid < 0) { 369 log.debug("create(): Invalid File ID"); 370 return null; 371 } 372 373 long gid = HDFLibrary.Vattach(fileid, -1, "w"); 374 if (gid < 0) { 375 log.debug("create(): Invalid Group ID"); 376 return null; 377 } 378 379 HDFLibrary.Vsetname(gid, name); 380 int ref = HDFLibrary.VQueryref(gid); 381 int tag = HDFLibrary.VQuerytag(gid); 382 383 if (!pgroup.isRoot()) { 384 // add the dataset to the parent group 385 long pid = pgroup.open(); 386 if (pid < 0) { 387 log.debug("create(): Invalid Parent Group ID"); 388 throw (new HDFException("Unable to open the parent group.")); 389 } 390 391 HDFLibrary.Vinsert(pid, gid); 392 393 pgroup.close(pid); 394 } 395 396 try { 397 HDFLibrary.Vdetach(gid); 398 } 399 catch (Exception ex) { 400 log.debug("create(): Vdetach failure: ", ex); 401 } 402 403 long[] oid = {tag, ref}; 404 group = new H4Group(file, name, path, pgroup, oid); 405 406 if (group != null) 407 pgroup.addToMemberList(group); 408 409 return group; 410 } 411 412 //Implementing DataFormat 413 /** 414 * Retrieves the object's metadata, such as attributes, from the file. 415 * 416 * Metadata, such as attributes, is stored in a List. 417 * 418 * @param attrPropList 419 * the list of properties to get 420 * 421 * @return the list of metadata objects. 422 * 423 * @throws Exception 424 * if the metadata can not be retrieved 425 */ 426 @SuppressWarnings("rawtypes") 427 public List getMetadata(int... attrPropList) throws Exception { 428 throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported"); 429 } 430}