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}