    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 static final 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 static final 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        if (attributeList != null) {
    117            log.trace("getMetadata(): attributeList != null");
    118            return attributeList;
    119        }
    120        else {
    121            attributeList = new Vector();
    122        }
    123
    124        // Library methods cannot be called on HDF4 dummy root group since it has a ref of 0
    125        if (oid[1] > 0) {
    126            long vgid = open();
    127            log.trace("getMetadata(): open: id={}", vgid);
    128            if (vgid < 0) {
    129                log.debug("getMetadata(): Invalid VG ID");
    130                return attributeList;
    131            }
    132
    133            int n = -1;
    134
    135            try {
    136                n = HDFLibrary.Vnattrs(vgid);
    137                log.trace("getMetadata(): Vnattrs: n={}", n);
    138
    139                boolean b = false;
    140                String[] attrName = new String[1];
    141                int[] attrInfo = new int[5];
    142                for (int i=0; i<n; i++) {
    143                    attrName[0] = "";
    144                    try {
    145                        b = HDFLibrary.Vattrinfo(vgid, i, attrName, attrInfo);
    146                        // mask off the litend bit
    147                        attrInfo[0] = attrInfo[0] & (~HDFConstants.DFNT_LITEND);
    148                    }
    149                    catch (HDFException ex) {
    150                        log.trace("getMetadata(): attribute[{}] Vattrinfo failure: ", i, ex);
    151                        b = false;
    152                    }
    153
    154                    if (!b) {
    155                        continue;
    156                    }
    157
    158                    long[] attrDims = {attrInfo[1]};
    159                    Attribute attr = new Attribute(this, attrName[0], new H4Datatype(attrInfo[0]), attrDims);
    160                    attributeList.add(attr);
    161
    162                    Object buf = null;
    163                    try {
    164                        buf = H4Datatype.allocateArray(attrInfo[0], attrInfo[1]);
    165                    }
    166                    catch (OutOfMemoryError e) {
    167                        log.debug("getMetadata(): out of memory: ", e);
    168                    }
    169
    170                    try {
    171                        HDFLibrary.Vgetattr(vgid, i, buf);
    172                    }
    173                    catch (HDFException ex) {
    174                        log.trace("getMetadata(): attribute[{}] Vgetattr failure: ", i, ex);
    175                        buf = null;
    176                    }
    177
    178                    if (buf != null) {
    179                        if ((attrInfo[0] == HDFConstants.DFNT_CHAR) ||
    180                                (attrInfo[0] ==  HDFConstants.DFNT_UCHAR8)) {
    181                            buf = Dataset.byteToString((byte[])buf, attrInfo[1]);
    182                        }
    183
    184                        attr.setData(buf);
    185                    }
    186                }
    187            }
    188            catch (Exception ex) {
    189                log.trace("getMetadata(): failure: ", ex);
    190            }
    191            finally {
    192                close(vgid);
    193            }
    194        }
    195
    196        return attributeList;
    197    }
    198
    199    // To do: implementing DataFormat
    200    @Override
    201    @SuppressWarnings({"rawtypes", "unchecked"})
    202    public void writeMetadata(Object info) throws Exception
    203    {
    204        // only attribute metadata is supported.
    205        if (!(info instanceof Attribute)) {
    206            log.debug("writeMetadata(): Object not an Attribute");
    207            return;
    208        }
    209
    210        try {
    211            getFileFormat().writeAttribute(this, (Attribute)info, true);
    212
    213            if (attributeList == null) {
    214                attributeList = new Vector();
    215            }
    216
    217            attributeList.add(info);
    218            nAttributes = attributeList.size();
    219        }
    220        catch (Exception ex) {
    221            log.debug("writeMetadata(): failure: ", ex);
    222        }
    223    }
    224
    225
    226    // To do: implementing DataFormat
    227    @Override
    228    public void removeMetadata(Object info) throws HDFException {
    229        log.trace("removeMetadata(): disabled");
    230    }
    231
    232    // implementing DataFormat
    233    @Override
    234    public void updateMetadata(Object info) throws Exception {
    235        log.trace("updateMetadata(): disabled");
    236    }
    237
    238    // Implementing HObject
    239    @Override
    240    public long open()
    241    {
    242        log.trace("open(): start: for file={} with ref={}", getFID(), oid[1]);
    243
    244        if (oid[1] <= 0) {
    245            log.debug("open(): oid[1] <= 0");
    246            return -1; // Library methods cannot be called on HDF4 dummy group with ref 0
    247        }
    248
    249        long vgid = -1;
    250
    251        if (!getFileFormat().isReadOnly()) {
    252            // try to open with write permission
    253            try {
    254                vgid = HDFLibrary.Vattach(getFID(), (int)oid[1], "w");
    255                log.trace("open(): Vattach write id={}", vgid);
    256            }
    257            catch (HDFException ex) {
    258                log.debug("open(): Vattach failure: ", ex);
    259                vgid = -1;
    260            }
    261        }
    262
    263        // try to open with read-only permission
    264        if (getFileFormat().isReadOnly() || vgid < 0) {
    265            try {
    266                vgid = HDFLibrary.Vattach(getFID(), (int)oid[1], "r");
    267                log.trace("open(): Vattach readonly id={}", vgid);
    268            }
    269            catch (HDFException ex) {
    270                log.debug("open(): Vattach failure: ", ex);
    271                vgid = -1;
    272            }
    273        }
    274
    275        return vgid;
    276    }
    277
    278    /** close group access. */
    279    @Override
    280    public void close(long vgid)
    281    {
    282        log.trace("close(): id={}", vgid);
    283
    284        if (vgid >= 0) {
    285            try {
    286                HDFLibrary.Vdetach(vgid);
    287            }
    288            catch (Exception ex) {
    289                log.debug("close(): Vdetach failure: ", ex);
    290            }
    291        }
    292    }
    293
    294    /**
    295     * Creates a new group.
    296     *
    297     * @param name the name of the group to create.
    298     * @param pgroup the parent group of the new group.
    299     *
    300     * @return the new group if successful. Otherwise returns null.
    301     *
    302     * @throws Exception if the group can not be created
    303     */
    304    public static H4Group create(String name, Group pgroup)
    305            throws Exception
    306    {
    307        log.trace("create(): start: name={} parentGroup={}", name, pgroup);
    308
    309        H4Group group = null;
    310        if ((pgroup == null) ||
    311            (name == null)) {
    312            log.debug("create(): one or more parameters are null");
    313            return null;
    314        }
    315
    316        H4File file = (H4File)pgroup.getFileFormat();
    317
    318        if (file == null) {
    319            log.debug("create(): Parent group FileFormat is null");
    320            return null;
    321        }
    322
    323        String path = HObject.SEPARATOR;
    324        if (!pgroup.isRoot()) {
    325            path = pgroup.getPath()+pgroup.getName()+HObject.SEPARATOR;
    326        }
    327        long fileid = file.open();
    328        if (fileid < 0) {
    329            log.debug("create(): Invalid File ID");
    330            return null;
    331        }
    332
    333        long gid = HDFLibrary.Vattach(fileid, -1, "w");
    334        if (gid < 0) {
    335            log.debug("create(): Invalid Group ID");
    336            return null;
    337        }
    338
    339        HDFLibrary.Vsetname(gid, name);
    340        int ref = HDFLibrary.VQueryref(gid);
    341        int tag = HDFLibrary.VQuerytag(gid);
    342
    343        if (!pgroup.isRoot()) {
    344            // add the dataset to the parent group
    345            long pid = pgroup.open();
    346            if (pid < 0) {
    347                log.debug("create(): Invalid Parent Group ID");
    348                throw (new HDFException("Unable to open the parent group."));
    349            }
    350
    351            HDFLibrary.Vinsert(pid, gid);
    352
    353            pgroup.close(pid);
    354        }
    355
    356        try {
    357            HDFLibrary.Vdetach(gid);
    358        }
    359        catch (Exception ex) {
    360            log.debug("create(): Vdetach failure: ", ex);
    361        }
    362
    363        long[] oid = {tag, ref};
    364        group = new H4Group(file, name, path, pgroup, oid);
    365
    366        if (group != null) {
    367            pgroup.addToMemberList(group);
    368        }
    369
    370        return group;
    371    }
    372
    373    //Implementing DataFormat
    374    @SuppressWarnings("rawtypes")
    375    public List getMetadata(int... attrPropList) throws Exception {
    376        throw new UnsupportedOperationException("getMetadata(int... attrPropList) is not supported");
    377    }
    378}