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