    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 final static 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        log.trace("getMetadata(): start");
    201        if (attributeList == null) {
    202            log.trace("getMetadata(): get attributeList");
    203
    204            int indxType = fileFormat.getIndexType(null);
    205            int order = fileFormat.getIndexOrder(null);
    206
    207            if (attrPropList.length > 0) {
    208                indxType = attrPropList[0];
    209                if (attrPropList.length > 1) {
    210                    order = attrPropList[1];
    211                }
    212            }
    213            try {
    214                attributeList = H5File.getAttribute(this, indxType, order);
    215            }
    216            catch (Exception ex) {
    217                log.debug("getMetadata(): H5File.getAttribute failure: ", ex);
    218            }
    219        }
    220
    221        try {
    222            if (!this.isRoot()) this.linkTargetObjName = H5File.getLinkTargetName(this);
    223        }
    224        catch (Exception ex) {
    225            log.debug("getMetadata(): getLinkTargetName failure: ", ex);
    226        }
    227
    228        log.trace("getMetadata(): finish");
    229        return attributeList;
    230    }
    231
    232    /*
    233     * (non-Javadoc)
    234     *
    235     * @see hdf.object.DataFormat#writeMetadata(java.lang.Object)
    236     */
    237    @Override
    238    @SuppressWarnings("unchecked")
    239    public void writeMetadata(Object info) throws Exception {
    240        log.trace("writeMetadata(): start");
    241        // only attribute metadata is supported.
    242        if (!(info instanceof Attribute)) {
    243            log.debug("writeMetadata(): Object not an Attribute");
    244            log.trace("writeMetadata(): finish");
    245            return;
    246        }
    247
    248        boolean attrExisted = false;
    249        Attribute attr = (Attribute) info;
    250        log.trace("writeMetadata(): {}", attr.getName());
    251
    252        if (attributeList == null) {
    253            this.getMetadata();
    254        }
    255
    256        if (attributeList != null) attrExisted = attributeList.contains(attr);
    257
    258        getFileFormat().writeAttribute(this, attr, attrExisted);
    259        // add the new attribute into attribute list
    260        if (!attrExisted) {
    261            attributeList.add(attr);
    262            nAttributes = attributeList.size();
    263        }
    264        log.trace("writeMetadata(): finish");
    265    }
    266
    267    /*
    268     * (non-Javadoc)
    269     *
    270     * @see hdf.object.DataFormat#removeMetadata(java.lang.Object)
    271     */
    272    @Override
    273    @SuppressWarnings("rawtypes")
    274    public void removeMetadata(Object info) throws HDF5Exception {
    275        log.trace("removeMetadata(): start");
    276        // only attribute metadata is supported.
    277        if (!(info instanceof Attribute)) {
    278            log.debug("removeMetadata(): Object not an Attribute");
    279            log.trace("removeMetadata(): finish");
    280            return;
    281        }
    282
    283        Attribute attr = (Attribute) info;
    284        log.trace("removeMetadata(): {}", attr.getName());
    285        long gid = open();
    286        if(gid >= 0) {
    287            try {
    288                H5.H5Adelete(gid, attr.getName());
    289                List attrList = getMetadata();
    290                attrList.remove(attr);
    291                nAttributes = attributeList.size();
    292            }
    293            finally {
    294                close(gid);
    295            }
    296        }
    297        else {
    298            log.debug("removeMetadata(): failed to open group");
    299        }
    300
    301        log.trace("removeMetadata(): finish");
    302    }
    303
    304    /*
    305     * (non-Javadoc)
    306     *
    307     * @see hdf.object.DataFormat#updateMetadata(java.lang.Object)
    308     */
    309    @Override
    310    public void updateMetadata(Object info) throws HDF5Exception {
    311        log.trace("updateMetadata(): start");
    312        // only attribute metadata is supported.
    313        if (!(info instanceof Attribute)) {
    314            log.debug("updateMetadata(): Object not an Attribute");
    315            log.trace("updateMetadata(): finish");
    316            return;
    317        }
    318
    319        nAttributes = -1;
    320        log.trace("updateMetadata(): finish");
    321    }
    322
    323    /*
    324     * (non-Javadoc)
    325     *
    326     * @see hdf.object.HObject#open()
    327     */
    328    @Override
    329    public long open() {
    330        log.trace("open(): start");
    331        long gid = -1;
    332
    333        try {
    334            if (isRoot()) {
    335                gid = H5.H5Gopen(getFID(), separator, HDF5Constants.H5P_DEFAULT);
    336            }
    337            else {
    338                gid = H5.H5Gopen(getFID(), getPath() + getName(), HDF5Constants.H5P_DEFAULT);
    339            }
    340
    341        }
    342        catch (HDF5Exception ex) {
    343            gid = -1;
    344        }
    345
    346        log.trace("open(): finish");
    347        return gid;
    348    }
    349
    350    /*
    351     * (non-Javadoc)
    352     *
    353     * @see hdf.object.HObject#close(int)
    354     */
    355    @Override
    356    public void close(long gid) {
    357        try {
    358            H5.H5Gclose(gid);
    359        }
    360        catch (HDF5Exception ex) {
    361            log.debug("close(): H5Gclose(gid {}): ", gid, ex);
    362        }
    363    }
    364
    365    /**
    366     * Creates a new group with a name in a group and with the group creation
    367     * properties specified in gplist.
    368     * <p>
    369     * The gplist contains a sequence of group creation property list
    370     * identifiers, lcpl, gcpl, gapl. It allows the user to create a group with
    371     * group creation properties. It will close the group creation properties
    372     * specified in gplist.
    373     *
    374     * @see hdf.hdf5lib.H5#H5Gcreate(long, String, long, long, long) for the
    375     *      order of property list identifiers.
    376     *
    377     * @param name
    378     *            The name of a new group.
    379     * @param pgroup
    380     *            The parent group object.
    381     * @param gplist
    382     *            The group creation properties, in which the order of the
    383     *            properties conforms the HDF5 library API, H5Gcreate(), i.e.
    384     *            lcpl, gcpl and gapl, where
    385     *            <ul>
    386     *            <li>lcpl : Property list for link creation <li>gcpl : Property
    387     *            list for group creation <li>gapl : Property list for group
    388     *            access
    389     *            </ul>
    390     *
    391     * @return The new group if successful; otherwise returns null.
    392     *
    393     * @throws Exception if there is a failure.
    394     */
    395    public static H5Group create(String name, Group pgroup, long... gplist) throws Exception {
    396        log.trace("create(): start");
    397        H5Group group = null;
    398        String fullPath = null;
    399        long lcpl = HDF5Constants.H5P_DEFAULT;
    400        long gcpl = HDF5Constants.H5P_DEFAULT;
    401        long gapl = HDF5Constants.H5P_DEFAULT;
    402
    403        if (gplist.length > 0) {
    404            lcpl = gplist[0];
    405            if (gplist.length > 1) {
    406                gcpl = gplist[1];
    407                if (gplist.length > 2) gapl = gplist[2];
    408            }
    409        }
    410
    411        if ((name == null) || (pgroup == null)) {
    412            log.debug("create(): one or more parameters are null");
    413            log.trace("create(): finish");
    414            System.err.println("(name == null) || (pgroup == null)");
    415            return null;
    416        }
    417
    418        H5File file = (H5File) pgroup.getFileFormat();
    419
    420        if (file == null) {
    421            log.debug("create(): Parent Group FileFormat is null");
    422            log.trace("create(): finish");
    423            System.err.println("Could not get file that contains object");
    424            return null;
    425        }
    426
    427        String path = HObject.separator;
    428        if (!pgroup.isRoot()) {
    429            path = pgroup.getPath() + pgroup.getName() + HObject.separator;
    430            if (name.endsWith("/")) {
    431                name = name.substring(0, name.length() - 1);
    432            }
    433            int idx = name.lastIndexOf("/");
    434            if (idx >= 0) {
    435                name = name.substring(idx + 1);
    436            }
    437        }
    438
    439        fullPath = path + name;
    440
    441        // create a new group and add it to the parent node
    442        long gid = H5.H5Gcreate(file.open(), fullPath, lcpl, gcpl, gapl);
    443        try {
    444            H5.H5Gclose(gid);
    445        }
    446        catch (Exception ex) {
    447            log.debug("create(): H5Gcreate {} H5Gclose(gid {}) failure: ", fullPath, gid, ex);
    448        }
    449
    450        byte[] ref_buf = H5.H5Rcreate(file.open(), fullPath, HDF5Constants.H5R_OBJECT, -1);
    451        long l = HDFNativeData.byteToLong(ref_buf, 0);
    452        long[] oid = { l };
    453
    454        group = new H5Group(file, name, path, pgroup, oid);
    455
    456        if (group != null) {
    457            pgroup.addToMemberList(group);
    458        }
    459
    460        if (gcpl > 0) {
    461            try {
    462                H5.H5Pclose(gcpl);
    463            }
    464            catch (final Exception ex) {
    465                log.debug("create(): create prop H5Pclose(gcpl {}) failure: ", gcpl, ex);
    466            }
    467        }
    468
    469        log.trace("create(): finish");
    470        return group;
    471    }
    472
    473    /*
    474     * (non-Javadoc)
    475     *
    476     * @see hdf.object.HObject#setName(java.lang.String)
    477     */
    478    @Override
    479    public void setName(String newName) throws Exception {
    480        H5File.renameObject(this, newName);
    481        super.setName(newName);
    482    }
    483
    484    /*
    485     * (non-Javadoc)
    486     *
    487     * @see hdf.object.HObject#setPath(java.lang.String)
    488     */
    489    @SuppressWarnings("rawtypes")
    490    @Override
    491    public void setPath(String newPath) throws Exception {
    492        super.setPath(newPath);
    493
    494        List members = this.getMemberList();
    495        if (members == null) {
    496            return;
    497        }
    498
    499        int n = members.size();
    500        HObject obj = null;
    501        for (int i = 0; i < n; i++) {
    502            obj = (HObject) members.get(i);
    503            obj.setPath(getPath() + getName() + HObject.separator);
    504        }
    505    }
    506}