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