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}