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