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 COPYING file, which can be found  *
009 * at the root of the source code distribution tree,                         *
010 * or in https://www.hdfgroup.org/licenses.                                  *
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.nc2;
016
017import java.util.Arrays;
018import java.util.List;
019import java.util.Vector;
020
021import hdf.object.FileFormat;
022import hdf.object.Group;
023
024import org.slf4j.Logger;
025import org.slf4j.LoggerFactory;
026
027import ucar.nc2.NetcdfFile;
028
029/**
030 * An NC2Group represents NetCDF3 group, inheriting from Group. Every NetCDF3 object
031 * has at least one name. An NetCDF3 group is used to store a set of the names
032 * together in one place, i.e. a group. The general structure of a group is
033 * similar to that of the UNIX file system in that the group may contain
034 * references to other groups or data objects just as the UNIX directory may
035 * contain subdirectories or files.
036 *
037 * @version 1.1 9/4/2007
038 * @author Peter X. Cao
039 */
040public class NC2Group extends Group {
041    private static final long serialVersionUID = -1261533010442193447L;
042
043    private static final Logger log = LoggerFactory.getLogger(NC2Group.class);
044
045    /**
046     * The corresponding netcdf Group for this group.
047     */
048    protected ucar.nc2.Group netCDFGroup;
049
050    /**
051     * @return the corresponding netcdf Group for this group.
052     */
053    public ucar.nc2.Group getNetCDFGroup() { return netCDFGroup; }
054
055    /**
056     * Set the corresponding netcdf Group for this group.
057     *
058     * @param netCDFGroup
059     *        the ucar.nc2.Group to associate to this group
060     */
061    public void setNetCDFGroup(ucar.nc2.Group netCDFGroup) { this.netCDFGroup = netCDFGroup; }
062
063    /**
064     * The list of attributes of this data object. Members of the list are
065     * instance of NC2Attribute.
066     */
067    private List attributeList;
068
069    /** The list of netcdf typedefs of this data object. Members of the list are instance of ucar.nc2.*. */
070    private List netcdfTypedefList;
071    /** The list of netcdf dimensions of this data object. Members of the list are instance of ucar.nc2.*. */
072    private List netcdfDimensionList;
073    /**
074     * The list of netcdf attributes of this data object. Members of the list are * instance of ucar.nc2.*.
075     */
076    private List netcdfAttributeList;
077
078    /** The default object ID for NC2 objects */
079    private static final long[] DEFAULT_OID = {0};
080
081    /**
082     * Constructs an NC2 group with specific name, path, and parent.
083     *
084     * @param fileFormat
085     *            the file which containing the group.
086     * @param name
087     *            the name of this group.
088     * @param path
089     *            the full path of this group.
090     * @param parent
091     *            the parent of this group.
092     * @param theID
093     *            the unique identifier of this data object.
094     */
095    public NC2Group(FileFormat fileFormat, String name, String path, Group parent, long[] theID)
096    {
097        super(fileFormat, name, path, parent, ((theID == null) ? DEFAULT_OID : theID));
098        ucar.nc2.Group parentGroup = null;
099        if (parent != null)
100            parentGroup = ((NC2Group)parent).getNetCDFGroup();
101        netCDFGroup = new ucar.nc2.Group(((NC2File)fileFormat).getNetcdfFile(), parentGroup, name);
102        log.trace("NC2Group:{}", name);
103    }
104
105    /**
106     * Check if the object has any attributes attached.
107     *
108     * @return true if it has any attributes, false otherwise.
109     */
110    public boolean hasAttribute() { return false; }
111
112    /**
113     * @return true if this group has an attached dimension.
114     */
115    public boolean hasDimension() { return false; }
116
117    // Implementing DataFormat
118    /**
119     * Retrieves the object's metadata, such as attributes, from the file.
120     *
121     * Metadata, such as attributes, is stored in a List.
122     *
123     * @return the list of metadata objects.
124     *
125     * @throws Exception
126     *             if the metadata can not be retrieved
127     */
128    @SuppressWarnings("rawtypes")
129    public List getMetadata() throws Exception
130    {
131        if (attributeList != null)
132            return attributeList;
133
134        NC2File theFile   = (NC2File)getFileFormat();
135        NetcdfFile ncFile = theFile.getNetcdfFile();
136        if (!isRoot() && (netCDFGroup != null)) {
137            netcdfDimensionList = netCDFGroup.getDimensions();
138
139            netcdfTypedefList = netCDFGroup.getEnumTypedefs();
140
141            netcdfAttributeList = netCDFGroup.getAttributes();
142        }
143        else {
144            netcdfDimensionList = ncFile.getDimensions();
145
146            netcdfAttributeList = ncFile.getGlobalAttributes();
147        }
148        if (netcdfAttributeList == null) {
149            attributeList = null;
150        }
151        else {
152            int n = netcdfAttributeList.size();
153            log.trace("Attribute size:{}", n);
154            attributeList = new Vector(n);
155
156            ucar.nc2.Attribute netcdfAttr = null;
157            for (int i = 0; i < n; i++) {
158                netcdfAttr = (ucar.nc2.Attribute)netcdfAttributeList.get(i);
159                log.trace("getMetadata(): Attribute[{}]:{}", i, netcdfAttr.toString());
160                attributeList.add(NC2File.convertAttribute(this, netcdfAttr));
161            }
162        }
163        return attributeList;
164    }
165
166    /**
167     * Creates a new attribute and attached to this dataset if attribute does
168     * not exist. Otherwise, just update the value of the attribute.
169     *
170     * @param info
171     *            the attribute to attach
172     *
173     * @throws Exception
174     *            if there is an error
175     */
176    public void writeMetadata(Object info) throws Exception
177    {
178        // not supported
179        throw new UnsupportedOperationException("Unsupported operation for NetCDF.");
180    }
181
182    /**
183     * Deletes an attribute from this dataset.
184     *
185     * @param info
186     *            the attribute to delete.
187     *
188     * @throws Exception
189     *            if there is an error
190     */
191    public void removeMetadata(Object info) throws Exception
192    {
193        // not supported
194        throw new UnsupportedOperationException("Unsupported operation for NetCDF.");
195    }
196
197    // implementing DataFormat
198    /**
199     * Updates an attribute from this dataset.
200     *
201     * @param info
202     *            the attribute to update.
203     *
204     * @throws Exception
205     *            if there is an error
206     */
207    public void updateMetadata(Object info) throws Exception
208    {
209        // not supported
210        throw new UnsupportedOperationException("Unsupported operation for NetCDF.");
211    }
212
213    // Implementing DataFormat
214    /**
215     * open a group.
216     *
217     * @return the group identifier if successful.
218     */
219    @Override
220    public long open()
221    {
222        // not supported
223        throw new UnsupportedOperationException("Unsupported operation for NetCDF.");
224    }
225
226    /**
227     * Close a group.
228     *
229     * @param gid
230     *            the identifier of the group to close.
231     */
232    @Override
233    public void close(long gid)
234    {
235        // not supported
236        throw new UnsupportedOperationException("Unsupported operation for NetCDF.");
237    }
238
239    /**
240     * Creates a new group.
241     *
242     * @param name
243     *            the name of the group to create.
244     * @param pgroup
245     *            the parent group of the new group.
246     *
247     * @return the new group if successful. Otherwise returns null.
248     *
249     * @throws Exception
250     *            if there is an error
251     */
252    public static NC2Group create(String name, Group pgroup) throws Exception
253    {
254        // not supported
255        throw new UnsupportedOperationException("Unsupported operation for NetCDF.");
256    }
257
258    /**
259     * Retrieves the object's metadata, such as attributes, from the file.
260     *
261     * Metadata, such as attributes, is stored in a List.
262     *
263     * @param attrPropList
264     *             the list of properties to get
265     *
266     * @return the list of metadata objects.
267     *
268     * @throws Exception
269     *             if the metadata can not be retrieved
270     */
271    @SuppressWarnings("rawtypes")
272    public List getMetadata(int... attrPropList) throws Exception
273    {
274        int hdfType     = 0;
275        int attrType    = 0;
276        int dimType     = 0;
277        int enumType    = 0;
278        List returnList = null;
279
280        // use 0 to skip or 1 select in attrPropList to get the list
281        // hdf attributes first netcdf attributes second, dimensions third, enumTypes fourth
282        log.trace("getMetadata(...): attrPropList={}", attrPropList.length);
283        if (attrPropList.length > 0)
284            hdfType = attrPropList[0];
285        if (attrPropList.length > 1)
286            attrType = attrPropList[1];
287        if (attrPropList.length > 2)
288            dimType = attrPropList[2];
289        if (attrPropList.length > 3)
290            enumType = attrPropList[3];
291        if ((hdfType != 0) && (attributeList != null))
292            returnList = attributeList;
293        else if ((attrType != 0) && (netcdfAttributeList != null))
294            returnList = netcdfAttributeList;
295        else if ((dimType != 0) && (netcdfDimensionList != null))
296            returnList = netcdfDimensionList;
297        else if ((enumType != 0) && (netcdfTypedefList != null))
298            returnList = netcdfTypedefList;
299
300        return returnList;
301    }
302
303    /**
304     * Retrieves the attribute name.
305     *
306     * @param index
307     *             the index of the attribute to get
308     *
309     * @return the attribute string.
310     */
311    public String netcdfAttributeString(int index)
312    {
313        ucar.nc2.Attribute netcdfAttr = (ucar.nc2.Attribute)netcdfAttributeList.get(index);
314        log.trace("netcdfAttributeString(): netcdfAttribute[{}]:{}", index, netcdfAttr.toString());
315        String returnStr = netcdfAttr.toString();
316        return returnStr;
317    }
318
319    /**
320     * Retrieves the Dimension name.
321     *
322     * @param index
323     *             the index of the Dimension to get
324     *
325     * @return the Dimension string.
326     */
327    public String netcdfDimensionString(int index)
328    {
329        ucar.nc2.Dimension netcdfDim = (ucar.nc2.Dimension)netcdfDimensionList.get(index);
330        log.trace("netcdfDimensionString(): netcdfDimension[{}]:{}", index, netcdfDim.toString());
331        StringBuilder objDimensionStr = new StringBuilder(netcdfDim.getShortName());
332        if (netcdfDim.isShared())
333            objDimensionStr.append("[SHARED]");
334        if (netcdfDim.isUnlimited())
335            objDimensionStr.append(" = UNLIMITED");
336        else if (netcdfDim.isVariableLength())
337            objDimensionStr.append(" = UNKNOWN");
338        else
339            objDimensionStr.append(" = " + netcdfDim.getLength());
340        return objDimensionStr.toString();
341    }
342
343    /**
344     * Retrieves the EnumTypedef name.
345     *
346     * @param index
347     *             the index of the EnumTypedef to get
348     *
349     * @return the EnumTypedef string.
350     */
351    public String netcdfTypedefString(int index)
352    {
353        ucar.nc2.EnumTypedef netcdfType = (ucar.nc2.EnumTypedef)netcdfTypedefList.get(index);
354        log.trace("netcdfEnumTypedefString(): netcdfTypedef[{}]:{}", index, netcdfType.toString());
355        StringBuilder objEnumTypedefStr = new StringBuilder(netcdfType.getShortName() + " {");
356        int count                       = 0;
357        List<Object> keyset             = Arrays.asList(netcdfType.getMap().keySet().toArray());
358        for (Object key : keyset) {
359            String s = netcdfType.getMap().get(key);
360            if (0 < count++)
361                objEnumTypedefStr.append(", ");
362            objEnumTypedefStr.append("'" + s + "' = " + key);
363        }
364        objEnumTypedefStr.append(" }");
365        return objEnumTypedefStr.toString();
366    }
367}