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