    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 COPYING file, which can be found  *
    009 * at the root of the source code distribution tree,                         *
    010 * or in https://www.hdfgroup.org/licenses.                                  *
    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&amp;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}