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 http://hdfgroup.org/products/hdf-java/doc/Copyright.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;
016
017import java.io.File;
018import java.util.Enumeration;
019import java.util.Hashtable;
020import java.util.Map;
021import java.util.StringTokenizer;
022import java.util.Vector;
023
024import javax.swing.tree.DefaultMutableTreeNode;
025import javax.swing.tree.MutableTreeNode;
026import javax.swing.tree.TreeNode;
027
028/**
029 * FileFormat defines general interfaces for working with files whose data is
030 * organized according to a supported format.
031 * <p>
032 * FileFormat is a pluggable component. New implementing classes of FileFormat
033 * can be added to the list of supported file formats. Current implementing
034 * classes include H5File and H4File. By default, H5File and H4File are added to
035 * the list of supported file formats maintained by the static FileFormat
036 * instance.
037 *
038 * <pre>
039 *                                    FileFormat
040 *                       _________________|_________________
041 *                       |                |                |
042 *                     H5File          H4File           Other...
043 * </pre>
044 * <p>
045 * A FileFormat instance may exist without being associated with a given file. A
046 * FileFormat instance may be associated with a file that is not open for
047 * access. Most typically, a FileFormat instance is used to open the associated
048 * file and perform operations such as retrieval and manipulation (if the file
049 * access is read-write) of the file structure and objects.
050 *
051 * @author Peter X. Cao
052 * @version 2.4 9/4/2007
053 */
054public abstract class FileFormat extends File {
055    /***************************************************************************
056     * File access flags used in calls to createInstance( String, flag );
057     **************************************************************************/
058
059    /**
060     *
061     */
062    private static final long                    serialVersionUID   = -4700692313888420796L;
063
064    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FileFormat.class);
065
066    /**
067     * File first time access flag for open file. With this access flag, added
068     * to the regular value, indicates this file has no existing state.
069     *
070     */
071    public static final int                      OPEN_NEW           = 1;
072
073    /**
074     * File access flag for read-only permission. With this access flag,
075     * modifications to the file will not be allowed.
076     *
077     * @see #createInstance(String, int )
078     */
079    public static final int                      READ               = 2;
080
081    /**
082     * File access flag for read/write permission. With this access flag,
083     * modifications to the file will be allowed. Behavior if the file does not
084     * exist or cannot be opened for read/write access depends on the
085     * implementing class.
086     *
087     * @see #createInstance(String, int)
088     */
089    public static final int                      WRITE              = 4;
090
091    /**
092     * File access flag for creating/truncating with read-write permission. If
093     * the file already exists, it will be truncated when opened. With this
094     * access flag, modifications to the file will be allowed. Behavior if file
095     * can't be created, or if it exists but can't be opened for read/write
096     * access, depends on the implementing class.
097     *
098     * @see #createInstance(String, int )
099     */
100    public static final int                      CREATE             = 8;
101
102    /***************************************************************************
103     * File creation flags used in calls to createFile( String, flag );
104     **************************************************************************/
105
106    /**
107     * Flag for creating/truncating a file. If the file already exists, it will
108     * be truncated when opened. If the file does not exist, it will be created.
109     * Modifications to the file will be allowed.
110     *
111     * @see #createFile(String, int )
112     */
113    public static final int                      FILE_CREATE_DELETE = 10;
114
115    /**
116     * Flag for creating/opening a file. If the file already exists, it will be
117     * opened without changing the existing contents. If the file does not
118     * exist, it will be created. Modifications to the file will be allowed.
119     *
120     * @see #createFile(String, int )
121     */
122    public static final int                      FILE_CREATE_OPEN   = 20;
123
124    /**
125     * Flag to indicate if the earliest version of library is used when creating
126     * a new file.
127     *
128     * @see #createFile(String, int )
129     */
130    public static final int                      FILE_CREATE_EARLY_LIB   = 40;
131
132
133    /***************************************************************************
134     * Keys and fields related to supported file formats.
135     **************************************************************************/
136
137    /** Key for HDF4 file format. */
138    public static final String                   FILE_TYPE_HDF4     = "HDF4";
139
140    /** Key for HDF5 file format. */
141    public static final String                   FILE_TYPE_HDF5     = "HDF5";
142
143    /**
144     * A separator that separates file name and object name.
145     *
146     * @see hdf.object.FileFormat#getHObject(String)
147     */
148    public static final String                   FILE_OBJ_SEP       = "://";
149
150    /**
151     * FileList keeps a list of supported FileFormats. This list can be updated
152     * and queried at runtime.
153     *
154     * @see #addFileFormat(String,FileFormat)
155     * @see #getFileFormat(String)
156     * @see #getFileFormatKeys()
157     * @see #getFileFormats()
158     * @see #removeFileFormat(String)
159     */
160    private static final Map<String, FileFormat> FileList = new Hashtable<String, FileFormat>(10);
161
162    /**
163     * A list of file extensions for the supported file formats. This list of
164     * file extensions is not integrated with the supported file formats kept in
165     * FileList, but is provided as a convenience for applications who may
166     * choose to process only those files with recognized extensions.
167     */
168    private static String extensions         = "hdf, h4, hdf5, h5, nc, fits";
169
170    /***************************************************************************
171     * Sizing information and class metadata
172     **************************************************************************/
173
174    /**
175     * Current Java applications, such as HDFView, cannot handle files with
176     * large numbers of objects due to JVM memory limitations. For example,
177     * 1,000,000 objects is too many. max_members is defined so that
178     * applications such as HDFView will load up to <i>max_members</i> objects
179     * starting with the <i>start_members</i> -th object. The implementing class
180     * has freedom in its interpretation of how to "count" objects in the file.
181     */
182    private int                                  max_members        = 10000;                                // 10,000 by default
183    private int                                  start_members      = 0;                                    // 0 by default
184
185    /**
186     * File identifier. -1 indicates the file is not open.
187     */
188    protected int                                fid                = -1;
189
190    /**
191     * The absolute pathname (path+name) of the file.
192     */
193    protected String                             fullFileName       = null;
194
195    /**
196     * Flag indicating if the file access is read-only.
197     */
198    protected boolean                            isReadOnly         = false;
199
200    /***************************************************************************
201     * Class initialization method
202     **************************************************************************/
203
204    /**
205     * By default, HDF4 and HDF5 file formats are added to the supported formats
206     * list.
207     */
208    static {
209        // add HDF4 to default modules
210        if (FileFormat.getFileFormat(FILE_TYPE_HDF4) == null) {
211            try {
212                Class fileclass = Class.forName("hdf.object.h4.H4File");
213                FileFormat fileformat = (FileFormat) fileclass.newInstance();
214                if (fileformat != null) {
215                    FileFormat.addFileFormat(FILE_TYPE_HDF4, fileformat);
216                    log.debug("FILE_TYPE_HDF4 file format added");
217                }
218            }
219            catch (Throwable err) {
220                log.debug("FILE_TYPE_HDF4 instance failure: ", err);
221            }
222        }
223
224        // add HDF5 to default modules
225        if (FileFormat.getFileFormat(FILE_TYPE_HDF5) == null) {
226            try {
227                Class fileclass = Class.forName("hdf.object.h5.H5File");
228                FileFormat fileformat = (FileFormat) fileclass.newInstance();
229                if (fileformat != null) {
230                    FileFormat.addFileFormat(FILE_TYPE_HDF5, fileformat);
231                    log.debug("FILE_TYPE_HDF5 file format added");
232                }
233            }
234            catch (Throwable err) {
235                log.debug("FILE_TYPE_HDF5 instance failure: ", err);
236            }
237        }
238
239        // add NetCDF to default modules
240        if (FileFormat.getFileFormat("NetCDF") == null) {
241            try {
242                Class fileclass = Class.forName("hdf.object.nc2.NC2File");
243                FileFormat fileformat = (FileFormat) fileclass.newInstance();
244                if (fileformat != null) {
245                    FileFormat.addFileFormat("NetCDF", fileformat);
246                    log.debug("NetCDF file format added");
247                }
248            }
249            catch (Throwable err) {
250                log.debug("NetCDF instance failure: ", err);
251            }
252        }
253
254        // add Fits to default modules
255        if (FileFormat.getFileFormat("Fits") == null) {
256            try {
257                Class fileclass = Class.forName("hdf.object.fits.FitsFile");
258                FileFormat fileformat = (FileFormat) fileclass.newInstance();
259                if (fileformat != null) {
260                    FileFormat.addFileFormat("Fits", fileformat);
261                    log.debug("Fits file format added");
262                }
263            }
264            catch (Throwable err) {
265                log.debug("FITS instance failure: ", err);
266            }
267        }
268
269    }
270
271    /***************************************************************************
272     * Constructor
273     **************************************************************************/
274
275    /**
276     * Creates a new FileFormat instance with the given filename.
277     * <p>
278     * The filename in this method call is equivalent to the pathname in the
279     * java.io.File class. The filename is converted into an abstract pathname
280     * by the File class.
281     * <p>
282     * Typically this constructor is not called directly, but is called by a
283     * constructor of an implementing class. Applications most frequently use
284     * the <i>createFile()</i>, <i>createInstance()</i>, or <i>getInstance()</i>
285     * methods to generate a FileFormat instance with an associated filename.
286     * <p>
287     * The file is not opened by this call. The read-only flag is set to false
288     * by this call.
289     *
290     * @param filename
291     *            The filename; a pathname string.
292     * @throws NullPointerException
293     *             If the <code>filename</code> argument is <code>null</code>.
294     * @see java.io.File#File(String)
295     * @see #createFile(String, int)
296     * @see #createInstance(String, int)
297     * @see #getInstance(String)
298     */
299    public FileFormat(String filename) {
300        super(filename);
301
302        fullFileName = filename;
303
304        if ((filename != null) && (filename.length() > 0)) {
305            try {
306                fullFileName = this.getAbsolutePath();
307            }
308            catch (Exception ex) {
309                log.debug("File {} getAbsolutePath failure: ", filename, ex);
310           }
311        }
312        isReadOnly = false;
313    }
314
315    /***************************************************************************
316     * Class methods
317     **************************************************************************/
318
319    /**
320     * Adds a FileFormat with specified key to the list of supported formats.
321     * <p>
322     * This method allows a new FileFormat, tagged with an identifying key, to
323     * be added dynamically to the list of supported File Formats. Using it,
324     * applications can add new File Formats at runtime.
325     * <p>
326     * For example, to add a new File Format with the key "xyz" that is
327     * implemented by the class xyzFile in the package companyC.files, an
328     * application would make the following calls:
329     *
330     * <pre>
331     *    Class fileClass = Class.forName( "companyC.files.xyzFile" );
332     *    FileFormat ff = (FileFormat) fileClass.newInstance();
333     *    if ( ff != null ) {
334     *       ff.addFileFormat ("xyz", ff )
335     *    }
336     * </pre>
337     * <p>
338     * If either <code>key</code> or <code>fileformat</code> are
339     * <code>null</code>, or if <code>key</code> is already in use, the method
340     * returns without updating the list of supported File Formats.
341     *
342     * @param key
343     *            A string that identifies the FileFormat.
344     * @param fileformat
345     *            An instance of the FileFormat to be added.
346     * @see #getFileFormat(String)
347     * @see #getFileFormatKeys()
348     * @see #getFileFormats()
349     * @see #removeFileFormat(String)
350     */
351    public static final void addFileFormat(String key, FileFormat fileformat) {
352        if ((fileformat == null) || (key == null)) {
353            return;
354        }
355
356        key = key.trim();
357
358        if (!FileList.containsKey(key)) {
359            FileList.put(key, fileformat);
360        }
361    }
362
363    /**
364     * Returns the FileFormat with specified key from the list of supported
365     * formats.
366     * <p>
367     * This method returns a FileFormat instance, as identified by an
368     * identifying key, from the list of supported File Formats.
369     * <p>
370     * If the specified key is in the list of supported formats, the instance of
371     * the associated FileFormat object is returned. If the specified key is not
372     * in the list of supported formats, <code>null</code> is returned.
373     *
374     * @param key
375     *            A string that identifies the FileFormat.
376     * @return The FileFormat that matches the given key, or <code>null</code>
377     *         if the key is not found in the list of supported File Formats.
378     * @see #addFileFormat(String,FileFormat)
379     * @see #getFileFormatKeys()
380     * @see #getFileFormats()
381     * @see #removeFileFormat(String)
382     */
383    public static final FileFormat getFileFormat(String key) {
384        return FileList.get(key);
385    }
386
387    /**
388     * Returns an Enumeration of keys for all supported formats.
389     * <p>
390     * This method returns an Enumeration containing the unique keys (Strings)
391     * for the all File Formats in the list of supported File Formats.
392     *
393     * @return An Enumeration of keys that are in the list of supported formats.
394     * @see #addFileFormat(String,FileFormat)
395     * @see #getFileFormat(String)
396     * @see #getFileFormats()
397     * @see #removeFileFormat(String)
398     */
399    public static final Enumeration getFileFormatKeys() {
400        return ((Hashtable) FileList).keys();
401    }
402
403    /**
404     * Returns an array of supported FileFormat instances.
405     * <p>
406     * This method returns an array of FileFormat instances that appear in the
407     * list of supported File Formats.
408     * <p>
409     * If the list of supported formats is empty, <code>null</code> is returned.
410     *
411     * @return An array of all FileFormat instances in the list of supported
412     *         File Formats, or <code>null</code> if the list is empty.
413     * @see #addFileFormat(String,FileFormat)
414     * @see #getFileFormat(String)
415     * @see #getFileFormatKeys()
416     * @see #removeFileFormat(String)
417     */
418    public static final FileFormat[] getFileFormats() {
419        int n = FileList.size();
420        if (n <= 0) {
421            return null;
422        }
423
424        int i = 0;
425        FileFormat[] fileformats = new FileFormat[n];
426        Enumeration<?> local_enum = ((Hashtable) FileList).elements();
427        while (local_enum.hasMoreElements()) {
428            fileformats[i++] = (FileFormat) local_enum.nextElement();
429        }
430
431        return fileformats;
432    }
433
434    /**
435     * Removes a FileFormat from the list of supported formats.
436     * <p>
437     * This method removes a FileFormat, as identified by the specified key,
438     * from the list of supported File Formats.
439     * <p>
440     * If the specified key is in the list of supported formats, the instance of
441     * the FileFormat object that is being removed from the list is returned. If
442     * the key is not in the list of supported formats, <code>null</code> is
443     * returned.
444     *
445     * @param key
446     *            A string that identifies the FileFormat to be removed.
447     * @return The FileFormat that is removed, or <code>null</code> if the key
448     *         is not found in the list of supported File Formats.
449     * @see #addFileFormat(String,FileFormat)
450     * @see #getFileFormat(String)
451     * @see #getFileFormatKeys()
452     * @see #getFileFormats()
453     */
454    public static final FileFormat removeFileFormat(String key) {
455        return FileList.remove(key);
456    }
457
458    /**
459     * Adds file extension(s) to the list of file extensions for supported file
460     * formats.
461     * <p>
462     * Multiple extensions can be included in the single parameter if they are
463     * separated by commas.
464     * <p>
465     * The list of file extensions updated by this call is not linked with
466     * supported formats that implement FileFormat objects. The file extension
467     * list is maintained for the benefit of applications that may choose to
468     * recognize only those files with extensions that appear in the list of
469     * file extensions for supported file formats.
470     * <p>
471     * By default, the file extensions list includes: "hdf, h4, hdf5, h5"
472     *
473     * @param extension
474     *            The file extension(s) to add.
475     * @see #addFileFormat(String,FileFormat)
476     * @see #getFileExtensions()
477     */
478    public static final void addFileExtension(String extension) {
479        if ((extensions == null) || (extensions.length() <= 0)) {
480            extensions = extension;
481        }
482
483        StringTokenizer currentExt = new StringTokenizer(extensions, ",");
484        Vector<String> tokens = new Vector<String>(currentExt.countTokens() + 5);
485
486        while (currentExt.hasMoreTokens()) {
487            tokens.add(currentExt.nextToken().trim().toLowerCase());
488        }
489
490        currentExt = new StringTokenizer(extension, ",");
491        String ext = null;
492        while (currentExt.hasMoreTokens()) {
493            ext = currentExt.nextToken().trim().toLowerCase();
494            if (tokens.contains(ext)) {
495                continue;
496            }
497
498            extensions = extensions + ", " + ext;
499        }
500
501        tokens.setSize(0);
502    }
503
504    /**
505     * Returns a list of file extensions for all supported file formats.
506     * <p>
507     * The extensions in the returned String are separates by commas:
508     * "hdf, h4, hdf5, h5"
509     * <p>
510     * It is the responsibility of the application to update the file extension
511     * list using {@link #addFileExtension(String)} when new FileFormat
512     * implementations are added.
513     *
514     * @return A list of file extensions for all supported file formats.
515     * @see #addFileExtension(String)
516     */
517    public static final String getFileExtensions() {
518        return extensions;
519    }
520
521    /**
522     * Creates a FileFormat instance for the specified file.
523     * <p>
524     * This method checks the list of supported file formats to find one that
525     * matches the format of the specified file. If a match is found, the method
526     * returns an instance of the associated FileFormat object. If no match is
527     * found, <code>null</code> is returned.
528     * <p>
529     * For example, if "test_hdf5.h5" is an HDF5 file,
530     * FileFormat.getInstance("test_hdf5.h5") will return an instance of H5File.
531     * <p>
532     * The file is not opened as part of this call. Read/write file access is
533     * associated with the FileFormat instance if the matching file format
534     * supports read/write access. Some file formats only support read access.
535     *
536     * @param filename
537     *            A valid file name, with a relative or absolute path.
538     * @return An instance of the matched FileFormat; <code>null</code> if no
539     *         match.
540     * @throws IllegalArgumentException
541     *             If the <code>filename</code> argument is <code>null</code> or
542     *             does not specify an existing file.
543     * @throws Exception
544     *             If there are problems creating the new instance.
545     * @see #createFile(String, int)
546     * @see #createInstance(String, int)
547     * @see #getFileFormats()
548     */
549    public static final FileFormat getInstance(String filename) throws Exception {
550        if ((filename == null) || (filename.length() <= 0)) {
551            throw new IllegalArgumentException("Invalid file name: " + filename);
552        }
553
554        if (!(new File(filename)).exists()) {
555            throw new IllegalArgumentException("File " + filename + " does not exist.");
556        }
557
558        FileFormat fileFormat = null;
559        FileFormat knownFormat = null;
560        Enumeration<?> elms = ((Hashtable) FileList).elements();
561
562        while (elms.hasMoreElements()) {
563            knownFormat = (FileFormat) elms.nextElement();
564            if (knownFormat.isThisType(filename)) {
565                try {
566                    fileFormat = knownFormat.createInstance(filename, WRITE);
567                }
568                catch (Exception ex) {
569                    log.debug("File {} createInstance failure: ", filename, ex);
570                }
571                break;
572            }
573        }
574
575        return fileFormat;
576    }
577
578    /***************************************************************************
579     * Implementation Class methods. These methods are related to the
580     * implementing FileFormat class, but not to a particular instance of that
581     * class. Since we can't override class methods (they can only be shadowed
582     * in Java), these are instance methods.
583     *
584     * The non-abstract methods just throw an exception indicating that the
585     * implementing class doesn't support the functionality.
586     **************************************************************************/
587
588    /**
589     * Returns the version of the library for the implementing FileFormat class.
590     * <p>
591     * The implementing FileFormat classes have freedom in how they obtain or
592     * generate the version number that is returned by this method. The H5File
593     * and H4File implementations query the underlying HDF libraries and return
594     * the reported version numbers. Other implementing classes may generate the
595     * version string directly within the called method.
596     *
597     * @return The library version.
598     */
599    public abstract String getLibversion();
600
601    /**
602     * Checks if the class implements the specified FileFormat.
603     * <p>
604     * The Java "instanceof" operation is unable to check if an object is an
605     * instance of a FileFormat that is loaded at runtime. This method provides
606     * the "instanceof" functionality, and works for implementing classes that
607     * are loaded at runtime.
608     * <p>
609     * This method lets applications that only access the abstract object layer
610     * determine the format of a given instance of the abstract class.
611     * <p>
612     * For example, HDFView uses the following code to determine if a file is an
613     * HDF5 file:
614     *
615     * <pre>
616     * FileFormat h5F = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
617     *                                                                       HObject hObject = viewer.getTreeView()
618     *                                                                                               .getCurrentObject();
619     *                                                                                                                    FileFormat thisF = hObject
620     *                                                                                                                                             .getFileFormat();
621     *                                                                                                                                                               boolean isH5 = h5F.isThisType(thisF);
622     * </pre>
623     *
624     * @param fileFormat
625     *            The FileFormat to be checked.
626     * @return True if this instance implements the specified FileFormat;
627     *         otherwise returns false.
628     * @see #isThisType(String)
629     */
630    public abstract boolean isThisType(FileFormat fileFormat);
631
632    /**
633     * Checks if the implementing FileFormat class matches the format of the
634     * specified file.
635     * <p>
636     * For example, if "test.h5" is an HDF5 file, the first call to isThisType()
637     * in the code fragment shown will return <code>false</code>, and the second
638     * call will return <code>true</code>.
639     *
640     * <pre>
641     * FileFormat h4F = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4);
642     *                                                                       FileFormat h5F = FileFormat
643     *                                                                                              .getFileFormat(FileFormat.FILE_TYPE_HDF5);
644     *                                                                                                                                         boolean isH4 = h4F.isThisType(&quot;test.h5&quot;); // false
645     *                                                                                                                                                                                   boolean isH5 = h5F.isThisType(&quot;test.h5&quot;); // true
646     * </pre>
647     *
648     * @param filename
649     *            The name of the file to be checked.
650     * @return True if the format of the file matches the format of this
651     *         instance; otherwise returns false.
652     * @see #isThisType(FileFormat)
653     */
654    public abstract boolean isThisType(String filename);
655
656    /**
657     * Creates a file with the specified name and returns a new FileFormat
658     * implementation instance associated with the file.
659     * <p>
660     * This method creates a file whose format is the same as that of the
661     * implementing class. An instance of the FileFormat implementing class is
662     * created and associated with the file. That instance is returned by the
663     * method.
664     * <p>
665     * The filename in this method call is equivalent to the pathname in the
666     * java.io.File class. The filename is converted into an abstract pathname
667     * by the File class.
668     * <p>
669     * A flag controls the behavior if the named file already exists. The flag
670     * values and corresponding behaviors are:
671     * <ul>
672     * <li>FILE_CREATE_DELETE: Create a new file or truncate an existing one.
673     * <li>FILE_CREATE_OPEN: Create a new file or open an existing one.
674     * </ul>
675     * <p>
676     * If the flag is FILE_CREATE_DELETE, the method will create a new file or
677     * truncate an existing file. If the flag is FILE_CREATE_OPEN and the file
678     * does not exist, the method will create a new file.
679     * <p>
680     * This method does not open the file for access, nor does it confirm that
681     * the file can later be opened read/write. The file open is carried out by
682     * the <i>open()</i> call.
683     *
684     * @param filename
685     *            The filename; a pathname string.
686     * @param createFlag
687     *            The creation flag, which determines behavior when the file
688     *            already exists. Acceptable values are
689     *            <code>FILE_CREATE_DELETE</code> and
690     *            <code>FILE_CREATE_OPEN</code>.
691     * @throws NullPointerException
692     *             If the <code>filename</code> argument is <code>null</code>.
693     * @throws UnsupportedOperationException
694     *             If the implementing class does not support the file creation
695     *             operation.
696     * @throws Exception
697     *             If the file cannot be created or if the creation flag has an
698     *             unexpected value. The exceptions thrown vary depending on the
699     *             implementing class.
700     * @see #createInstance(String, int)
701     * @see #getInstance(String)
702     * @see #open()
703     *
704     * @return the FileFormat instance.
705     */
706    public FileFormat createFile(String filename, int createFlag) throws Exception {
707        // If the implementing subclass doesn't have this method then that
708        // format doesn't support File Creation and we throw an exception.
709        throw new UnsupportedOperationException("FileFormat FileFormat.createFile(...) is not implemented.");
710    }
711
712    /**
713     * Creates a FileFormat implementation instance with specified filename and
714     * access.
715     * <p>
716     * This method creates an instance of the FileFormat implementing class and
717     * sets the filename and file access parameters.
718     * <p>
719     * The filename in this method call is equivalent to the pathname in the
720     * java.io.File class. The filename is converted into an abstract pathname
721     * by the File class.
722     * <p>
723     * The access parameter values and corresponding behaviors at file open:
724     * <ul>
725     * <li>READ: Read-only access. Fail if file doesn't exist.
726     * <li>WRITE: Read/Write access. Behavior if file doesn't exist or can't be
727     * opened for read/write access depends on the implementing class.
728     * <li>CREATE: Read/Write access. Create a new file or truncate an existing
729     * one. Behavior if file can't be created, or if it exists but can't be
730     * opened read/write depends on the implementing class.
731     * </ul>
732     * <p>
733     * Some FileFormat implementing classes may only support READ access and
734     * will use READ regardless of the value specified in the call. Refer to the
735     * implementing class documentation for details.
736     * <p>
737     * This method does not open the file for access, nor does it confirm that
738     * the file can later be opened read/write or created. The file open is
739     * carried out by the <i>open()</i> call.
740     * <p>
741     * Example (without exception handling):
742     *
743     * <pre>
744     * // Request the implementing class of FileFormat: H5File
745     * FileFormat h5file = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
746     *
747     *                                                                          // Create
748     *                                                                          // an
749     *                                                                          // instance
750     *                                                                          // of
751     *                                                                          // H5File
752     *                                                                          // object
753     *                                                                          // with
754     *                                                                          // read/write
755     *                                                                          // access
756     *                                                                          H5File test1 = (H5File) h5file.createInstance(
757     *                                                                                               &quot;test_hdf5.h5&quot;,
758     *                                                                                               FileFormat.WRITE);
759     *                                                                                                                  // Open
760     *                                                                                                                  // the
761     *                                                                                                                  // file
762     *                                                                                                                  // and
763     *                                                                                                                  // load
764     *                                                                                                                  // the
765     *                                                                                                                  // file
766     *                                                                                                                  // structure;
767     *                                                                                                                  // file
768     *                                                                                                                  // id
769     *                                                                                                                  // is
770     *                                                                                                                  // returned.
771     *                                                                                                                  int fid = test1.open();
772     * </pre>
773     *
774     * @param filename
775     *            The filename; a pathname string.
776     * @param access
777     *            The file access flag, which determines behavior when file is
778     *            opened. Acceptable values are <code> READ, WRITE, </code> and
779     *            <code>CREATE</code>.
780     * @throws NullPointerException
781     *             If the <code>filename</code> argument is <code>null</code>.
782     * @throws Exception
783     *             If the instance cannot be created or if the access flag has
784     *             an unexpected value. The exceptions thrown vary depending on
785     *             the implementing class.
786     * @see #createFile(String, int)
787     * @see #getInstance(String)
788     * @see #open()
789     *
790     * @return the FileFormat instance.
791     */
792    public abstract FileFormat createInstance(String filename, int access) throws Exception;
793
794    // REVIEW DOCS for createInstance()
795    // What if READ ONLY in implementation? What if file already open?
796    // Can we doc exceptions better or in implementation methods?
797
798    /***************************************************************************
799     * Final instance methods
800     *
801     * Related to a given instance of the class, but at the FileFormat level,
802     * not at the implementing class level.
803     **************************************************************************/
804
805    /**
806     * Returns the absolute path for the file.
807     * <p>
808     * For example, "/samples/hdf5_test.h5". If there is no file associated with
809     * this FileFormat instance, <code>null</code> is returned.
810     *
811     * @return The full path (file path + file name) of the associated file, or
812     *         <code>null</code> if there is no associated file.
813     */
814    public final String getFilePath() {
815        return fullFileName;
816    }
817
818    /**
819     * Returns file identifier of open file associated with this instance.
820     *
821     * @return The file identifer, or -1 if there is no file open.
822     */
823    public final int getFID() {
824        return fid;
825    }
826
827    /**
828     * Returns true if the file access is read-only.
829     * <p>
830     * This method returns true if the file access is read-only. If the file
831     * access is read-write, or if there is no file associated with the
832     * FileFormat instance, false will be returned.
833     * <p>
834     * Note that this method may return true even if the file is not open for
835     * access when the method is called. The file access is set by the
836     * <i>createFile()</i>, <i>createInstance()</i>, or <i>getInstance()</i>
837     * call, and the file is opened for access by the <i>open()</i> call.
838     *
839     * @return True if the file access is read-only, otherwise returns false.
840     * @see #createFile(String, int)
841     * @see #createInstance(String, int)
842     * @see #getInstance(String)
843     * @see #open()
844     */
845    public final boolean isReadOnly() {
846        return isReadOnly;
847    }
848
849    /**
850     * Sets the maximum number of objects to be loaded into memory.
851     * <p>
852     * Current Java applications, such as HDFView, cannot handle files with
853     * large numbers of objects due to JVM memory limitations. The maximum
854     * number limits the number of objects that will be loaded for a given
855     * FileFormat instance.
856     * <p>
857     * The implementing FileFormat class has freedom in how it interprets the
858     * maximum number. H5File, for example, will load the maximum number of
859     * objects for each group in the file.
860     *
861     * @param n
862     *            The maximum number of objects to be loaded into memory.
863     * @see #getMaxMembers()
864     * @see #setStartMembers(int)
865     */
866    public final void setMaxMembers(int n) {
867        max_members = n;
868    }
869
870    /**
871     * Returns the maximum number of objects that can be loaded into memory.
872     *
873     * @return The maximum number of objects that can be loaded into memory.
874     * @see #setMaxMembers(int)
875     */
876    public final int getMaxMembers() {
877        if (max_members<0)
878            return Integer.MAX_VALUE; // load the whole file
879
880        return max_members;
881    }
882
883    /**
884     * Sets the starting index of objects to be loaded into memory.
885     * <p>
886     * The implementing FileFormat class has freedom in how it indexes objects
887     * in the file.
888     *
889     * @param idx
890     *            The starting index of the object to be loaded into memory
891     * @see #getStartMembers()
892     * @see #setMaxMembers(int)
893     */
894    public final void setStartMembers(int idx) {
895        start_members = idx;
896    }
897
898    /**
899     * Returns the index of the starting object to be loaded into memory.
900     *
901     * @return The index of the starting object to be loaded into memory.
902     * @see #setStartMembers(int)
903     */
904    public final int getStartMembers() {
905        return start_members;
906    }
907
908    /**
909     * Returns the number of objects in memory.
910     * <p>
911     * This method returns the total number of objects loaded into memory for
912     * this FileFormat instance. The method counts the objects that are loaded,
913     * which can take some time for a large number of objects.
914     * <p>
915     * It is worth noting that the total number of objects in memory may be
916     * different than the total number of objects in the file.
917     * <p>
918     * Since implementing classes have freedom in how they interpret and use the
919     * maximum number of members value, there may be differing numbers of
920     * objects in memory in different implementation instances, even with the
921     * same "use case".
922     * <p>
923     * For example, say the use case is a file that contains 20,000 objects, the
924     * maximum number of members for an instance is 10,000, and the start member
925     * index is 1. There are 2 groups in the file. The root group contains
926     * 10,500 objects and the group "/g1" contains 9,500 objects.
927     * <p>
928     * In an implementation that limits the total number of objects loaded to
929     * the maximum number of members, this method will return 10,000.
930     * <p>
931     * In contrast, the H5File implementation loads up to the maximum number of
932     * members objects for each group in the file. So, with our use case 10,000
933     * objects will be loaded in the root group and 9,500 objects will be loaded
934     * into group "/g1". This method will return the value 19,500, which exceeds
935     * the maximum number of members value.
936     *
937     * @return The number of objects in memory.
938     * @see #getMaxMembers()
939     * @see #setMaxMembers(int)
940     * @see #getStartMembers()
941     * @see #setStartMembers(int)
942     */
943    public final int getNumberOfMembers() {
944        int n_members = 0;
945        TreeNode rootNode = getRootNode();
946
947        if (rootNode != null) {
948            Enumeration local_enum = ((DefaultMutableTreeNode) rootNode).depthFirstEnumeration();
949
950            while (local_enum.hasMoreElements()) {
951                local_enum.nextElement();
952                n_members++;
953            }
954        }
955
956        return n_members;
957    }
958
959    /***************************************************************************
960     * Abstract Instance methods
961     *
962     * These methods are related to the Implementing FileFormat class and to
963     * particular instances of objects with those classes.
964     **************************************************************************/
965
966    /**
967     * Opens file and returns a file identifier.
968     * <p>
969     * This method uses the <code>filename</code> and <code>access</code>
970     * parameters specified in the <i>createFile()</i>, <i>createInstance()</i>,
971     * or <i>getInstance()</i> call to open the file. It returns the file
972     * identifier if successful, or a negative value in case of failure.
973     * <p>
974     * The method also loads the file structure and basic information (name,
975     * type) for data objects in the file into the FileFormat instance. It does
976     * not load the contents of any data object.
977     * <p>
978     * The structure of the file is stored in a tree starting from the root
979     * node.
980     *
981     * @return File identifier if successful; otherwise -1.
982     * @throws Exception
983     *             If the file cannot be opened. The exceptions thrown vary
984     *             depending on the implementing class.
985     * @see #createFile(String, int)
986     * @see #createInstance(String, int)
987     * @see #getInstance(String)
988     * @see #getRootNode()
989     *
990     * @return the file identifier.
991     */
992    public abstract int open() throws Exception;
993
994    /**
995     * Closes file associated with this instance.
996     * <p>
997     * This method closes the file associated with this FileFormat instance, as
998     * well as all objects associated with the file.
999     *
1000     * @throws Exception
1001     *             If the file or associated objects cannot be closed. The
1002     *             exceptions thrown vary depending on the implementing class.
1003     * @see #open()
1004     */
1005    public abstract void close() throws Exception;
1006
1007    // REVIEW DOCS for close()
1008    // What if we try to close a file whose fid is -1? Does this set fid to -1?
1009    // What if it's not open? What if no file? are structures & root node
1010    // still loaded?
1011    // Can we doc exceptions better or in implementation methods?
1012
1013    /**
1014     * Returns the root node for the file associated with this instance.
1015     * <p>
1016     * The root node is a Java TreeNode object
1017     * (javax.swing.tree.DefaultMutableTreeNode) that represents the root group
1018     * of a file. If the file has not yet been opened, or if there is no file
1019     * associated with this instance, <code>null</code> will be returned.
1020     * <p>
1021     * Starting from the root, applications can descend through the tree
1022     * structure and navigate among the file's objects. In the tree structure,
1023     * internal nodes represent non-empty groups. Leaf nodes represent datasets,
1024     * named datatypes, or empty groups.
1025     *
1026     * @return The root node of the file, or <code>null</code> there is no
1027     *         associated file or if the associated file has not yet been
1028     *         opened.
1029     * @see #open()
1030     */
1031    public abstract TreeNode getRootNode();
1032
1033    /**
1034     * Gets the HObject with the specified path from the file.
1035     * <p>
1036     * This method returns the specified object from the file associated with
1037     * this FileFormat instance.
1038     * <p>
1039     * If the specified object is a group, groups and datasets that are members
1040     * of the group will be accessible via the returned HObject instance. The
1041     * exact contents of the returned HObject instance depends on whether or not
1042     * {@link #open()} was called previously for this file.
1043     * <ul>
1044     * <li>If the file was opened prior to this method call, the complete tree
1045     * of objects under the group will be accessible via the returned HObject
1046     * instance.
1047     * <li>If the file was not opened prior to this method call, only the
1048     * members immediately under the group will be accessible via the returned
1049     * HOBject instance.
1050     * </ul>
1051     * <p>
1052     * The decision to have different behaviors was made to give users some
1053     * control over the "cost" of the method. In many cases, a user wants only
1054     * one level of a tree, and the performance penalty for loading the entire
1055     * hierarchy of objects in a large and complex file can be significant. In
1056     * the case where <i>open()</i> has already been called, the HObject
1057     * instances have already been created in memory and can be returned
1058     * quickly. If <i>open()</i> has not been called, this method creates the
1059     * HObject instances before returning the requested HObject.
1060     * <p>
1061     * For example, say we have the following structure in our file:
1062     *
1063     * <pre>
1064     *        /g0                      Group
1065     *        /g0/dataset_comp         Dataset {50, 10}
1066     *        /g0/dataset_int          Dataset {50, 10}
1067     *        /g0/g00                  Group
1068     *        /g0/g00/dataset_float    Dataset {50, 10}
1069     *        /g0/g01                  Group
1070     *        /g0/g01/dataset_string   Dataset {50, 10}
1071     * </pre>
1072     *
1073     * <ul>
1074     * <li>If <i>open()</i> is called before <i>get()</i>, the full structure of
1075     * file is loaded into memory. The call <code>get("/g0")</code> returns the
1076     * instance for /g0 with the information necessary to access
1077     * /g0/dataset_comp, /g0/dataset_int, /g0/g00, /g0/g00/dataset_float,
1078     * /g0/g01, and /g0/g01/dataset_string.
1079     * <li>If <i>open()</i> is not called before <i>get()</i>, only the objects
1080     * immediately under the specified group are accessible via the returned
1081     * HObject instance. In this example, the call <code>get("/go")</code>
1082     * returns the instance for /g0 with the information necessary to access
1083     * /g0/dataset_comp, /g0/dataset_int, /g0/g00, and /g0/g01.
1084     * </ul>
1085     *
1086     * @param path
1087     *            Full path of the data object to be returned.
1088     * @return The object if it exists in the file; otherwise <code>null</code>.
1089     * @throws Exception
1090     *             If there are unexpected problems in trying to retrieve the
1091     *             object. The exceptions thrown vary depending on the
1092     *             implementing class.
1093     */
1094    public abstract HObject get(String path) throws Exception;
1095
1096    // REVIEW DOCS for get(); What if no file associated w/ instance?
1097    // Look at exceptions. Confirm example. Make sure perf tradeoffs
1098    // documented properly.
1099
1100    /**
1101     * Creates a named datatype in a file.
1102     * <p>
1103     * The following code creates a named datatype in a file.
1104     *
1105     * <pre>
1106     * H5File file = (H5File) h5file.createInstance(&quot;test_hdf5.h5&quot;, FileFormat.WRITE);
1107     *                                                                                 H5Datatype dtype = file.createDatatype(
1108     *                                                                                                          Datatype.CLASS_INTEGER,
1109     *                                                                                                          4,
1110     *                                                                                                          Datatype.NATIVE,
1111     *                                                                                                          Datatype.NATIVE,
1112     *                                                                                                          &quot;Native Integer&quot;);
1113     * </pre>
1114     *
1115     * @param tclass
1116     *            class of datatype, e.g. Datatype.CLASS_INTEGER
1117     * @param tsize
1118     *            size of the datatype in bytes, e.g. 4 for 32-bit integer.
1119     * @param torder
1120     *            order of the byte endianing, Datatype.ORDER_LE.
1121     * @param tsign
1122     *            signed or unsigned of an integer, Datatype.SIGN_NONE.
1123     * @param name
1124     *            name of the datatype to create, e.g. "Native Integer".
1125     * @return The new datatype if successful; otherwise returns null.
1126     * @throws Exception
1127     *             The exceptions thrown vary depending on the implementing
1128     *             class.
1129     */
1130    public abstract Datatype createDatatype(int tclass, int tsize, int torder, int tsign, String name) throws Exception;
1131
1132    /**
1133     * Creates a named datatype in a file.
1134     * <p>
1135     * The following code creates a named datatype in a file.
1136     *
1137     * <pre>
1138     * H5File file = (H5File) h5file.createInstance(&quot;test_hdf5.h5&quot;, FileFormat.WRITE);
1139     *                                                                                 H5Datatype dtype = file.createDatatype(
1140     *                                                                                                          Datatype.CLASS_INTEGER,
1141     *                                                                                                          4,
1142     *                                                                                                          Datatype.NATIVE,
1143     *                                                                                                          Datatype.NATIVE,
1144     *                                                                                                          basetype,
1145     *                                                                                                          &quot;Native Integer&quot;);
1146     * </pre>
1147     *
1148     * @param tclass
1149     *            class of datatype, e.g. Datatype.CLASS_INTEGER
1150     * @param tsize
1151     *            size of the datatype in bytes, e.g. 4 for 32-bit integer.
1152     * @param torder
1153     *            order of the byte endianing, Datatype.ORDER_LE.
1154     * @param tsign
1155     *            signed or unsigned of an integer, Datatype.SIGN_NONE.
1156     * @param tbase
1157     *            the base datatype of the new datatype
1158     * @param name
1159     *            name of the datatype to create, e.g. "Native Integer".
1160     * @return The new datatype if successful; otherwise returns null.
1161     * @throws Exception
1162     *             The exceptions thrown vary depending on the implementing
1163     *             class.
1164     */
1165    public Datatype createDatatype(int tclass, int tsize, int torder, int tsign, Datatype tbase, String name) throws Exception
1166    {
1167        // Derived classes must override this function to use base type option
1168        return createDatatype(tclass, tsize, torder, tsign, name);
1169    }
1170
1171    // REVIEW DOCS for createDatatype(). Check and document exceptions.
1172
1173    /***************************************************************************
1174     * Methods related to Datatypes and HObjects in the implementing FileFormat.
1175     *
1176     * Strictly speaking, these methods aren't related to FileFormat and the
1177     * actions could be carried out through the HObject and Datatype classes.
1178     * But, in some cases they allow a null input and expect the generated
1179     * object to be of a type that has particular FileFormat. Therefore, we put
1180     * them in the implementing FileFormat class so that we create the proper
1181     * type of HObject... H5Group or H4Group for example.
1182     *
1183     * Here again, if there could be Implementation Class methods we'd use
1184     * those. But, since we can't override class methods (they can only be
1185     * shadowed in Java), these are instance methods.
1186     *
1187     * The non-abstract methods just throw an exception indicating that the
1188     * implementing class doesn't support the functionality.
1189     **************************************************************************/
1190
1191    /**
1192     * Creates a new datatype in memory.
1193     * <p>
1194     * The following code creates an instance of H5Datatype in memory.
1195     *
1196     * <pre>
1197     * H5File file = (H5File) h5file.createInstance(&quot;test_hdf5.h5&quot;, FileFormat.WRITE);
1198     *                                                                                 H5Datatype dtype = file.createDatatype(
1199     *                                                                                                          Datatype.CLASS_INTEGER,
1200     *                                                                                                          4,
1201     *                                                                                                          Datatype.NATIVE,
1202     *                                                                                                          Datatype.NATIVE);
1203     * </pre>
1204     *
1205     * @param tclass
1206     *            class of datatype, e.g. Datatype.CLASS_INTEGER
1207     * @param tsize
1208     *            size of the datatype in bytes, e.g. 4 for 32-bit integer.
1209     * @param torder
1210     *            order of the byte endian, e.g. Datatype.ORDER_LE.
1211     * @param tsign
1212     *            signed or unsigned of an integer, Datatype.SIGN_NONE.
1213     * @return The new datatype object if successful; otherwise returns null.
1214     * @throws Exception
1215     *             The exceptions thrown vary depending on the implementing
1216     *             class.
1217     */
1218    public abstract Datatype createDatatype(int tclass, int tsize, int torder, int tsign) throws Exception;
1219
1220    /**
1221     * Creates a new datatype in memory.
1222     * <p>
1223     * The following code creates an instance of H5Datatype in memory.
1224     *
1225     * <pre>
1226     * H5File file = (H5File) h5file.createInstance(&quot;test_hdf5.h5&quot;, FileFormat.WRITE);
1227     *                                                                                 H5Datatype dtype = file.createDatatype(
1228     *                                                                                                          Datatype.CLASS_INTEGER,
1229     *                                                                                                          4,
1230     *                                                                                                          Datatype.NATIVE,
1231     *                                                                                                          Datatype.NATIVE,
1232     *                                                                                                          basetype);
1233     * </pre>
1234     *
1235     * @param tclass
1236     *            class of datatype, e.g. Datatype.CLASS_INTEGER
1237     * @param tsize
1238     *            size of the datatype in bytes, e.g. 4 for 32-bit integer.
1239     * @param torder
1240     *            order of the byte endian, e.g. Datatype.ORDER_LE.
1241     * @param tsign
1242     *            signed or unsigned of an integer, Datatype.SIGN_NONE.
1243     * @param tbase
1244     *            the base datatype of the new datatype
1245     * @return The new datatype object if successful; otherwise returns null.
1246     * @throws Exception
1247     *             The exceptions thrown vary depending on the implementing
1248     *             class.
1249     */
1250    public Datatype createDatatype(int tclass, int tsize, int torder, int tsign, Datatype tbase) throws Exception
1251    {
1252        // Derived classes must override this function to use base type option
1253        return createDatatype(tclass, tsize, torder, tsign);
1254    }
1255
1256    // REVIEW DOCS for createDatatype(). Check and document exceptions.
1257
1258    /**
1259     * Creates a new dataset in a file with/without chunking/compression.
1260     * <p>
1261     * The following example creates a 2D integer dataset of size 100X50 at the
1262     * root group in an HDF5 file.
1263     *
1264     * <pre>
1265     * String name = &quot;2D integer&quot;;
1266     *                             Group pgroup = (Group) ((DefaultMutableTreeNode) getRootNode).getUserObject();
1267     *                                                                                                            Datatype dtype = new H5Datatype(
1268     *                                                                                                                                   Datatype.CLASS_INTEGER, // class
1269     *                                                                                                                                   4, // size
1270     *                                                                                                                                      // in
1271     *                                                                                                                                      // bytes
1272     *                                                                                                                                   Datatype.ORDER_LE, // byte
1273     *                                                                                                                                                      // order
1274     *                                                                                                                                   Datatype.SIGN_NONE); // signed
1275     *                                                                                                                                                        // or
1276     *                                                                                                                                                        // unsigned
1277     *                                                                                                                                                        long[] dims = {
1278     *         100, 50                                                                                                                                                   };
1279     *                                                                                                                                                                       long[] maxdims = dims;
1280     *                                                                                                                                                                                              long[] chunks = null; // no
1281     *                                                                                                                                                                                                                    // chunking
1282     *                                                                                                                                                                                                                    int gzip = 0; // no
1283     *                                                                                                                                                                                                                                  // compression
1284     *                                                                                                                                                                                                                                  Object data = null; // no
1285     *                                                                                                                                                                                                                                                      // initial
1286     *                                                                                                                                                                                                                                                      // data
1287     *                                                                                                                                                                                                                                                      // values
1288     *                                                                                                                                                                                                                                                      Dataset d = (H5File) file
1289     *                                                                                                                                                                                                                                                                        .createScalarDS(
1290     *                                                                                                                                                                                                                                                                                name,
1291     *                                                                                                                                                                                                                                                                                pgroup,
1292     *                                                                                                                                                                                                                                                                                dtype,
1293     *                                                                                                                                                                                                                                                                                dims,
1294     *                                                                                                                                                                                                                                                                                maxdims,
1295     *                                                                                                                                                                                                                                                                                chunks,
1296     *                                                                                                                                                                                                                                                                                gzip,
1297     *                                                                                                                                                                                                                                                                                data);
1298     * </pre>
1299     *
1300     * @param name
1301     *            name of the new dataset, e.g. "2D integer"
1302     * @param pgroup
1303     *            parent group where the new dataset is created.
1304     * @param type
1305     *            datatype of the new dataset.
1306     * @param dims
1307     *            dimension sizes of the new dataset, e.g. long[] dims = {100,
1308     *            50}.
1309     * @param maxdims
1310     *            maximum dimension sizes of the new dataset, null if maxdims is
1311     *            the same as dims.
1312     * @param chunks
1313     *            chunk sizes of the new dataset, null if no chunking.
1314     * @param gzip
1315     *            GZIP compression level (1 to 9), 0 or negative values if no
1316     *            compression.
1317     * @param fillValue
1318     *            default value.
1319     * @param data
1320     *            data written to the new dataset, null if no data is written to
1321     *            the new dataset.
1322     *
1323     * @return The new dataset if successful; otherwise returns null
1324     * @throws Exception
1325     *             The exceptions thrown vary depending on the implementing
1326     *             class.
1327     */
1328    public abstract Dataset createScalarDS(String name, Group pgroup, Datatype type, long[] dims, long[] maxdims,
1329            long[] chunks, int gzip, Object fillValue, Object data) throws Exception;
1330
1331    public Dataset createScalarDS(String name, Group pgroup, Datatype type, long[] dims, long[] maxdims, long[] chunks,
1332            int gzip, Object data) throws Exception {
1333        return createScalarDS(name, pgroup, type, dims, maxdims, chunks, gzip, null, data);
1334    }
1335
1336    // REVIEW DOCS for createScalarDS(). Check and document exceptions.
1337
1338    /**
1339     * Creates a new compound dataset in a file with/without chunking and
1340     * compression.
1341     * <p>
1342     * The following example creates a compressed 2D compound dataset with size
1343     * of 100X50 in a root group. The compound dataset has two members, x and y.
1344     * Member x is an interger, member y is an 1-D float array of size 10.
1345     *
1346     * <pre>
1347     * String name = "2D compound";
1348     * Group pgroup =
1349     *           (Group)((DefaultMutableTreeNode)getRootNode).getUserObject();
1350     * long[] dims = {100, 50};
1351     * long[] chunks = {1, 50};
1352     * int gzip = 9;
1353     * String[] memberNames = {"x", "y"};
1354     *
1355     * Datatype[] memberDatatypes = {
1356     *     new H5Datatype(Datatype.CLASS_INTEGER, Datatype.NATIVE,
1357     *                    Datatype.NATIVE, Datatype.NATIVE)
1358     *     new H5Datatype(Datatype.CLASS_FLOAT, Datatype.NATIVE,
1359     *                    Datatype.NATIVE, Datatype.NATIVE));
1360     *
1361     * int[] memberSizes = {1, 10};
1362     * Object data = null; // no initial data values
1363     * Dataset d = (H5File)file.createCompoundDS(name, pgroup, dims, null,
1364     *           chunks, gzip, memberNames, memberDatatypes, memberSizes, null);
1365     * </pre>
1366     *
1367     * @param name
1368     *            name of the new dataset
1369     * @param pgroup
1370     *            parent group where the new dataset is created.
1371     * @param dims
1372     *            dimension sizes of the new dataset.
1373     * @param maxdims
1374     *            maximum dimension sizes of the new dataset, null if maxdims is
1375     *            the same as dims.
1376     * @param chunks
1377     *            chunk sizes of the new dataset, null if no chunking.
1378     * @param gzip
1379     *            GZIP compression level (1 to 9), 0 or negative values if no
1380     *            compression.
1381     * @param memberNames
1382     *            names of the members.
1383     * @param memberDatatypes
1384     *            datatypes of the members.
1385     * @param memberSizes
1386     *            array sizes of the members.
1387     * @param data
1388     *            data written to the new dataset, null if no data is written to
1389     *            the new dataset.
1390     *
1391     * @return new dataset object if successful; otherwise returns null
1392     * @throws UnsupportedOperationException
1393     *             If the implementing class does not support compound datasets.
1394     * @throws Exception
1395     *             The exceptions thrown vary depending on the implementing
1396     *             class.
1397     */
1398    public Dataset createCompoundDS(String name, Group pgroup, long[] dims, long[] maxdims, long[] chunks, int gzip,
1399            String[] memberNames, Datatype[] memberDatatypes, int[] memberSizes, Object data) throws Exception
1400            // REVIEW DOCS for createCompoundDS(). Check and document exceptions.
1401            {
1402                // If the implementing subclass doesn't have this method then that
1403                // format doesn't support Compound DataSets and we throw an
1404                // exception.
1405                throw new UnsupportedOperationException("Dataset FileFormat.createCompoundDS(...) is not implemented.");
1406            }
1407
1408    /**
1409     * Creates a new image in a file.
1410     * <p>
1411     * The following example creates a 2D image of size 100X50 in a root group.
1412     *
1413     * <pre>
1414     * String name = &quot;2D image&quot;;
1415     *                           Group pgroup = (Group) ((DefaultMutableTreeNode) getRootNode).getUserObject();
1416     *                                                                                                          Datatype dtype = new H5Datatype(
1417     *                                                                                                                                 Datatype.CLASS_INTEGER,
1418     *                                                                                                                                 1,
1419     *                                                                                                                                 Datatype.NATIVE,
1420     *                                                                                                                                 Datatype.SIGN_NONE);
1421     *                                                                                                                                                      long[] dims = {
1422     *         100, 50                                                                                                                                                 };
1423     *                                                                                                                                                                     long[] maxdims = dims;
1424     *                                                                                                                                                                                            long[] chunks = null; // no
1425     *                                                                                                                                                                                                                  // chunking
1426     *                                                                                                                                                                                                                  int gzip = 0; // no
1427     *                                                                                                                                                                                                                                // compression
1428     *                                                                                                                                                                                                                                int ncomp = 3; // RGB
1429     *                                                                                                                                                                                                                                               // true
1430     *                                                                                                                                                                                                                                               // color
1431     *                                                                                                                                                                                                                                               // image
1432     *                                                                                                                                                                                                                                               int interlace = ScalarDS.INTERLACE_PIXEL;
1433     *                                                                                                                                                                                                                                                                                         Object data = null; // no
1434     *                                                                                                                                                                                                                                                                                                             // initial
1435     *                                                                                                                                                                                                                                                                                                             // data
1436     *                                                                                                                                                                                                                                                                                                             // values
1437     *                                                                                                                                                                                                                                                                                                             Dataset d = (H5File) file
1438     *                                                                                                                                                                                                                                                                                                                               .createScalarDS(
1439     *                                                                                                                                                                                                                                                                                                                                       name,
1440     *                                                                                                                                                                                                                                                                                                                                       pgroup,
1441     *                                                                                                                                                                                                                                                                                                                                       dtype,
1442     *                                                                                                                                                                                                                                                                                                                                       dims,
1443     *                                                                                                                                                                                                                                                                                                                                       maxdims,
1444     *                                                                                                                                                                                                                                                                                                                                       chunks,
1445     *                                                                                                                                                                                                                                                                                                                                       gzip,
1446     *                                                                                                                                                                                                                                                                                                                                       ncomp,
1447     *                                                                                                                                                                                                                                                                                                                                       interlace,
1448     *                                                                                                                                                                                                                                                                                                                                       data);
1449     * </pre>
1450     *
1451     * @param name
1452     *            name of the new image, "2D image".
1453     * @param pgroup
1454     *            parent group where the new image is created.
1455     * @param type
1456     *            datatype of the new image.
1457     * @param dims
1458     *            dimension sizes of the new dataset, e.g. long[] dims = {100,
1459     *            50}.
1460     * @param maxdims
1461     *            maximum dimension sizes of the new dataset, null if maxdims is
1462     *            the same as dims.
1463     * @param chunks
1464     *            chunk sizes of the new dataset, null if no chunking.
1465     * @param gzip
1466     *            GZIP compression level (1 to 9), 0 or negative values if no
1467     *            compression.
1468     * @param ncomp
1469     *            number of components of the new image, e.g. int ncomp = 3; //
1470     *            RGB true color image.
1471     * @param interlace
1472     *            interlace mode of the image. Valid values are
1473     *            ScalarDS.INTERLACE_PIXEL, ScalarDS.INTERLACE_PLANEL and
1474     *            ScalarDS.INTERLACE_LINE.
1475     * @param data
1476     *            data value of the image, null if no data.
1477     *
1478     * @return The new image object if successful; otherwise returns null
1479     *
1480     * @throws Exception
1481     *             The exceptions thrown vary depending on the implementing
1482     *             class.
1483     */
1484    public abstract Dataset createImage(
1485
1486            String name, Group pgroup, Datatype type, long[] dims, long[] maxdims, long[] chunks, int gzip, int ncomp,
1487            int interlace, Object data) throws Exception;
1488
1489    // REVIEW DOCS for createImage(). Check and document exceptions.
1490
1491    /**
1492     * Creates a new group with specified name in existing group.
1493     * <p>
1494     * If the parent group is null, the new group will be created in the root
1495     * group.
1496     *
1497     * @param name
1498     *            The name of the new group.
1499     * @param parentGroup
1500     *            The parent group, or null.
1501     *
1502     * @return The new group if successful; otherwise returns null.
1503     *
1504     * @throws Exception
1505     *             The exceptions thrown vary depending on the implementing
1506     *             class.
1507     */
1508    public abstract Group createGroup(String name, Group parentGroup) throws Exception;
1509
1510    // REVIEW DOCS for createLink().
1511    // Verify Implementing classes document these and also
1512    // 'do the right thing' if fid is -1, currentObj is non-null, if
1513    // object is null, or the root group then what? document & verify!
1514
1515    /**
1516     * Creates a soft, hard or external link to an existing object in the open
1517     * file.
1518     * <p>
1519     * If parentGroup is null, the new link is created in the root group.
1520     *
1521     * @param parentGroup
1522     *            The group where the link is created.
1523     * @param name
1524     *            The name of the link.
1525     * @param currentObj
1526     *            The existing object the new link will reference.
1527     * @param type
1528     *            The type of link to be created. It can be a hard link, a soft
1529     *            link or an external link.
1530     *
1531     * @return The object pointed to by the new link if successful; otherwise
1532     *         returns null.
1533     *
1534     * @throws Exception
1535     *             The exceptions thrown vary depending on the implementing
1536     *             class.
1537     */
1538    public HObject createLink(Group parentGroup, String name, HObject currentObj, int type) throws Exception {
1539        return createLink(parentGroup, name, currentObj);
1540    }
1541
1542    /**
1543     * Creates a soft or external links to objects in a file that do not exist
1544     * at the time the link is created.
1545     *
1546     * @param parentGroup
1547     *            The group where the link is created.
1548     * @param name
1549     *            The name of the link.
1550     * @param currentObj
1551     *            The name of the object the new link will reference. The object
1552     *            doesn't have to exist.
1553     * @param type
1554     *            The type of link to be created.
1555     *
1556     * @return The H5Link object pointed to by the new link if successful;
1557     *         otherwise returns null.
1558     *
1559     * @throws Exception
1560     *             The exceptions thrown vary depending on the implementing
1561     *             class.
1562     */
1563    public HObject createLink(Group parentGroup, String name, String currentObj, int type) throws Exception {
1564        return createLink(parentGroup, name, currentObj);
1565    }
1566
1567    /**
1568     * Copies the source object to a new destination.
1569     * <p>
1570     * This method copies the source object to a destination group, and assigns
1571     * the specified name to the new object.
1572     * <p>
1573     * The copy may take place within a single or across files. If the source
1574     * object and destination group are in different files, the files must have
1575     * the same file format (both HDF5 for example).
1576     * <p>
1577     * The source object can be a group, a dataset, or a named datatype. This
1578     * method copies the object along with all of its attributes and other
1579     * properties. If the source object is a group, this method also copies all
1580     * objects and sub-groups below the group.
1581     * <p>
1582     * The following example shows how to use the copy method to create two
1583     * copies of an existing HDF5 file structure in a new HDF5 file. One copy
1584     * will be under /copy1 and the other under /copy2 in the new file.
1585     *
1586     * <pre>
1587     * // Open the existing file with the source object.
1588     * H5File existingFile = new H5File(&quot;existingFile.h5&quot;, FileFormat.READ);
1589     * existingFile.open();
1590     * // Our source object will be the root group.
1591     * HObject srcObj = existingFile.get(&quot;/&quot;);
1592     * // Create a new file.
1593     * H5File newFile = new H5File(&quot;newFile.h5&quot;, FileFormat.CREATE);
1594     * newFile.open();
1595     * // Both copies in the new file will have the root group as their
1596     * // destination group.
1597     * Group dstGroup = (Group) newFile.get(&quot;/&quot;);
1598     * // First copy goes to &quot;/copy1&quot; and second goes to &quot;/copy2&quot;.
1599     * // Notice that we can use either H5File instance to perform the copy.
1600     * TreeNode copy1 = existingFile.copy(srcObj, dstGroup, &quot;copy1&quot;);
1601     * TreeNode copy2 = newFile.copy(srcObj, dstGroup, &quot;copy2&quot;);
1602     * // Close both the files.
1603     * file.close();
1604     * newFile.close();
1605     * </pre>
1606     *
1607     * @param srcObj
1608     *            The object to copy.
1609     * @param dstGroup
1610     *            The destination group for the new object.
1611     * @param dstName
1612     *            The name of the new object. If dstName is null, the name of
1613     *            srcObj will be used.
1614     *
1615     * @return The tree node that contains the new object, or null if the copy
1616     *         fails.
1617     *
1618     * @throws Exception
1619     *             are specific to the implementing class.
1620     */
1621    public abstract TreeNode copy(HObject srcObj, Group dstGroup, String dstName) throws Exception;
1622
1623    // REVIEW DOCS for copy().
1624    // CONFIRM USE SRC.copy not DEST.copy. Also what is returned on
1625    // failure. ALSO exceptions. ALSO, does it copy data or just structure?
1626
1627    /**
1628     * Deletes an object from a file.
1629     *
1630     * @param obj
1631     *            The object to delete.
1632     * @throws Exception
1633     *             The exceptions thrown vary depending on the implementing
1634     *             class.
1635     */
1636    public abstract void delete(HObject obj) throws Exception;
1637
1638    // REVIEW DOCS for delete(). Check and document exceptions.
1639
1640    /**
1641     * Attaches a given attribute to an object.
1642     * <p>
1643     * If an HDF(4&amp;5) attribute exists in file, the method updates its value. If
1644     * the attribute does not exists in file, it creates the attribute in file
1645     * and attaches it to the object. It will fail to write a new attribute to
1646     * the object where an attribute with the same name already exists. To
1647     * update the value of an existing attribute in file, one needs to get the
1648     * instance of the attribute by getMetadata(), change its values, and use
1649     * writeAttribute() to write the value.
1650     *
1651     * @param obj
1652     *            The object to which the attribute is attached to.
1653     * @param attr
1654     *            The atribute to attach.
1655     * @param attrExisted
1656     *            The indicator if the given attribute exists.
1657     *
1658     * @throws Exception
1659     *             The exceptions thrown vary depending on the implementing class.
1660     */
1661    public abstract void writeAttribute(HObject obj, Attribute attr, boolean attrExisted) throws Exception;
1662
1663    // REVIEW DOCS for writeAttribute(). Check and document exceptions.
1664
1665    /***************************************************************************
1666     * Deprecated methods.
1667     **************************************************************************/
1668
1669    /**
1670     * @deprecated As of 2.4, replaced by {@link #createFile(String, int)}
1671     *             <p>
1672     *             The replacement method has an additional parameter that
1673     *             controls the behavior if the file already exists. Use
1674     *             <code>FileFormat.FILE_CREATE_DELETE</code> as the second
1675     *             argument in the replacement method to mimic the behavior
1676     *             originally provided by this method.
1677     *
1678     * @param fileName
1679     *            The filename; a pathname string.
1680     *
1681     * @return the created file object
1682     *
1683     * @throws Exception if file cannot be created
1684     */
1685    @Deprecated
1686    public final FileFormat create(String fileName) throws Exception {
1687        return createFile(fileName, FileFormat.FILE_CREATE_DELETE);
1688    }
1689
1690    /**
1691     * @deprecated As of 2.4, replaced by {@link #createInstance(String, int)}
1692     *
1693     *             The replacement method has identical functionality and a more
1694     *             descriptive name. Since <i>open</i> is used elsewhere to
1695     *             perform a different function this method has been deprecated.
1696     *
1697     * @param pathname
1698     *            The pathname string.
1699     * @param access
1700     *            The file access properties
1701     *
1702     * @return the opened file object
1703     *
1704     * @throws Exception if the file cannot be opened
1705     */
1706    @Deprecated
1707    public final FileFormat open(String pathname, int access) throws Exception {
1708        return createInstance(pathname, access);
1709    }
1710
1711    /**
1712     * @deprecated As of 2.4, replaced by
1713     *             {@link #createCompoundDS(String, Group, long[], long[], long[], int, String[], Datatype[], int[], Object)}
1714     *             <p>
1715     *             The replacement method has additional parameters:
1716     *             <code>maxdims, chunks,</code> and <code>gzip</code>. To mimic
1717     *             the behavior originally provided by this method, call the
1718     *             replacement method with the following parameter list:
1719     *             <code> ( name, pgroup, dims, null, null, -1,
1720     * memberNames, memberDatatypes, memberSizes, data ); </code>
1721     *
1722     * @param name
1723     *            The dataset name.
1724     * @param pgroup
1725     *            The dataset parent.
1726     * @param dims
1727     *            The dataset dimensions.
1728     * @param memberNames
1729     *            The dataset compound member names.
1730     * @param memberDatatypes
1731     *            The dataset compound member datatypes.
1732     * @param memberSizes
1733     *            The dataset compound member sizes.
1734     * @param data
1735     *            The dataset data.
1736     *
1737     * @return
1738     *            The dataset created.
1739     *
1740     * @return the dataset that has been created
1741     *
1742     * @throws Exception if the dataset cannot be created
1743     */
1744    @Deprecated
1745    public final Dataset createCompoundDS(String name, Group pgroup, long[] dims, String[] memberNames,
1746            Datatype[] memberDatatypes, int[] memberSizes, Object data) throws Exception {
1747        return createCompoundDS(name, pgroup, dims, null, null, -1, memberNames, memberDatatypes, memberSizes, data);
1748    }
1749
1750    /**
1751     * @deprecated As of 2.4, replaced by {@link #copy(HObject, Group, String)}
1752     *             <p>
1753     *             To mimic the behavior originally provided by this method,
1754     *             call the replacement method with <code>null</code> as the 3rd
1755     *             parameter.
1756     *
1757     * @param srcObj
1758     *             The object to be copied
1759     * @param dstGroup
1760     *             The group to contain the copied object
1761     *
1762     * @return the copied object
1763     *
1764     * @throws Exception if object can not be copied
1765     */
1766    @Deprecated
1767    public final TreeNode copy(HObject srcObj, Group dstGroup) throws Exception {
1768        return copy(srcObj, dstGroup, null);
1769    }
1770
1771    /**
1772     * @deprecated As of 2.4, replaced by {@link #get(String)}
1773     *             <p>
1774     *             This static method, which as been deprecated, causes two
1775     *             problems:
1776     *             <ul>
1777     *             <li>It can be very expensive if it is called many times or in
1778     *             a loop because each call to the method creates an instance of
1779     *             a file.
1780     *             <li>Since the method does not return the instance of the
1781     *             file, the file cannot be closed directly and may be left open
1782     *             (memory leak). The only way to close the file is through the
1783     *             object returned by this method.
1784     *             </ul>
1785     *
1786     * @param fullPath
1787     *            The file path string.
1788     *
1789     * @return the object that has the given full path
1790     *
1791     * @throws Exception if the object can not be found
1792     */
1793    @Deprecated
1794    public static final HObject getHObject(String fullPath) throws Exception {
1795        if ((fullPath == null) || (fullPath.length() <= 0)) {
1796            return null;
1797        }
1798
1799        String filename = null, path = null;
1800        int idx = fullPath.indexOf(FILE_OBJ_SEP);
1801
1802        if (idx > 0) {
1803            filename = fullPath.substring(0, idx);
1804            path = fullPath.substring(idx + FILE_OBJ_SEP.length());
1805            if ((path == null) || (path.length() == 0)) {
1806                path = "/";
1807            }
1808        }
1809        else {
1810            filename = fullPath;
1811            path = "/";
1812        }
1813
1814        return FileFormat.getHObject(filename, path);
1815    };
1816
1817    /**
1818     * @deprecated As of 2.4, replaced by {@link #get(String)}
1819     *             <p>
1820     *             This static method, which as been deprecated, causes two
1821     *             problems:
1822     *             <ul>
1823     *             <li>It can be very expensive if it is called many times or in
1824     *             a loop because each call to the method creates an instance of
1825     *             a file.
1826     *             <li>Since the method does not return the instance of the
1827     *             file, the file cannot be closed directly and may be left open
1828     *             (memory leak). The only way to close the file is through the
1829     *             object returned by this method, for example:
1830     *             <pre>
1831     * Dataset dset = H5File.getObject("hdf5_test.h5", "/images/iceburg");
1832     * ...
1833     * // close the file through dset
1834     * dset.getFileFormat().close();
1835     * </pre>
1836     *
1837     *             </li>
1838     *             </ul>
1839     *
1840     * @param filename
1841     *            The filename string.
1842     * @param path
1843     *            The path of the file
1844     *
1845     * @return the object that has the given filename and path returns null
1846     *
1847     * @throws Exception if the object can not be found
1848     */
1849    @Deprecated
1850    public static final HObject getHObject(String filename, String path) throws Exception {
1851        if ((filename == null) || (filename.length() <= 0)) {
1852            throw new IllegalArgumentException("Invalid file name. " + filename);
1853        }
1854
1855        if (!(new File(filename)).exists()) {
1856            throw new IllegalArgumentException("File does not exists");
1857        }
1858
1859        HObject obj = null;
1860        FileFormat file = FileFormat.getInstance(filename);
1861
1862        if (file != null) {
1863            obj = file.get(path);
1864            if (obj == null) {
1865                file.close();
1866            }
1867        }
1868
1869        return obj;
1870    }
1871
1872    /**
1873     * Finds an object by its object ID
1874     *
1875     * @param file
1876     *            the file containing the object
1877     * @param oid
1878     *            the oid to search for
1879     *
1880     * @return the object that has the given OID; otherwise returns null
1881     */
1882    public final static HObject findObject(FileFormat file, long[] oid) {
1883        if ((file == null) || (oid == null)) {
1884            return null;
1885        }
1886
1887        HObject theObj = null;
1888        DefaultMutableTreeNode theNode = null;
1889
1890        MutableTreeNode theRoot = (MutableTreeNode) file.getRootNode();
1891        if (theRoot == null) {
1892            return null;
1893        }
1894
1895        Enumeration local_enum = ((DefaultMutableTreeNode) theRoot).breadthFirstEnumeration();
1896        while (local_enum.hasMoreElements()) {
1897            theNode = (DefaultMutableTreeNode) local_enum.nextElement();
1898            theObj = (HObject) theNode.getUserObject();
1899            if (theObj.equalsOID(oid)) {
1900                break;
1901            }
1902        }
1903
1904        return theObj;
1905    }
1906
1907    /**
1908     * Finds an object by the full path of the object (path+name)
1909     *
1910     * @param file
1911     *            the file containing the object
1912     * @param path
1913     *            the full path of the object to search for
1914     *
1915     * @return the object that has the given path; otherwise returns null
1916     */
1917    public final static HObject findObject(FileFormat file, String path) {
1918        if ((file == null) || (path == null)) {
1919            return null;
1920        }
1921
1922        if (!path.endsWith("/")) {
1923            path = path + "/";
1924        }
1925
1926        DefaultMutableTreeNode theRoot = (DefaultMutableTreeNode) file.getRootNode();
1927
1928        if (theRoot == null) {
1929            return null;
1930        }
1931        else if (path.equals("/")) {
1932            return (HObject) theRoot.getUserObject();
1933        }
1934
1935        Enumeration local_enum = (theRoot).breadthFirstEnumeration();
1936        DefaultMutableTreeNode theNode = null;
1937        HObject theObj = null;
1938        while (local_enum.hasMoreElements()) {
1939            theNode = (DefaultMutableTreeNode) local_enum.nextElement();
1940            theObj = (HObject) theNode.getUserObject();
1941            String fullPath = theObj.getFullName() + "/";
1942
1943            if (path.equals(fullPath) && theObj.getPath() != null) {
1944                break;
1945            }
1946            else {
1947                theObj = null;
1948            }
1949        }
1950
1951        return theObj;
1952    }
1953
1954    // ////////////////////////////////////////////////////////////////////////////////////
1955    // Added to support HDF5 1.8 features //
1956    // ////////////////////////////////////////////////////////////////////////////////////
1957
1958    /**
1959     * Opens file and returns a file identifier.
1960     *
1961     * @param indexList
1962     *            The property list is the list of parameters, like index type
1963     *            and the index order. The index type can be alphabetical or
1964     *            creation. The index order can be increasing order or
1965     *            decreasing order.
1966     *
1967     * @return File identifier if successful; otherwise -1.
1968     *
1969     * @throws Exception
1970     *             The exceptions thrown vary depending on the implementing class.
1971     */
1972    public int open(int... indexList) throws Exception {
1973        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
1974    }
1975
1976    /**
1977     * Creates a new group with specified name in existing group.
1978     * <p>
1979     * If the parent group is null, the new group will be created in the root
1980     * group.
1981     *
1982     * @param name
1983     *            The name of a new group.
1984     * @param pgroup
1985     *            The parent group object.
1986     * @param gplist
1987     *            The group creation properties, in which the order of the
1988     *            properties conforms the HDF5 library API, H5Gcreate(), i.e.
1989     *            lcpl, gcpl and gapl, where
1990     *            <ul>
1991     *            <li>lcpl : Property list for link creation <li>gcpl : Property
1992     *            list for group creation <li>gapl : Property list for group
1993     *            access
1994     *            </ul>
1995     *
1996     * @return The new group if successful; otherwise returns null.
1997     *
1998     * @throws Exception
1999     *             The exceptions thrown vary depending on the implementing class.
2000     */
2001    public Group createGroup(String name, Group pgroup, int... gplist) throws Exception {
2002        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2003    }
2004
2005    /***
2006     * Creates the group creation property list identifier, gcpl. This
2007     * identifier is used when creating Groups.
2008     *
2009     * @param creationorder
2010     *            The order in which the objects in a group should be created.
2011     *            It can be Tracked or Indexed.
2012     * @param maxcompact
2013     *            The maximum number of links to store in the group in a compact
2014     *            format.
2015     * @param mindense
2016     *            The minimum number of links to store in the indexed
2017     *            format.Groups which are in indexed format and in which the
2018     *            number of links falls below this threshold are automatically
2019     *            converted to compact format.
2020     *
2021     * @return The gcpl identifier.
2022     *
2023     * @throws Exception
2024     *             The exceptions thrown vary depending on the implementing class.
2025     */
2026    public int createGcpl(int creationorder, int maxcompact, int mindense) throws Exception {
2027        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2028    }
2029
2030    /**
2031     * Creates a link to an existing object in the open file.
2032     * <p>
2033     * If linkGroup is null, the new link is created in the root group.
2034     *
2035     * @param linkGroup
2036     *            The group where the link is created.
2037     * @param name
2038     *            The name of the link.
2039     * @param currentObj
2040     *            The existing object the new link will reference.
2041     *
2042     * @return The object pointed to by the new link if successful; otherwise
2043     *         returns null.
2044     *
2045     * @throws Exception
2046     *             The exceptions thrown vary depending on the implementing class.
2047     */
2048    public HObject createLink(Group linkGroup, String name, Object currentObj) throws Exception {
2049        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2050    }
2051
2052    /**
2053     * Export dataset.
2054     *
2055     * @param file_export_name
2056     *            The file name to export data into.
2057     * @param file_name
2058     *            The name of the HDF5 file containing the dataset.
2059     * @param object_path
2060     *            The full path of the dataset to be exported.
2061     * @param binary_order
2062     *            The data byte order
2063     *
2064     * @throws Exception
2065     *             The exceptions thrown vary depending on the implementing class.
2066     */
2067    public void exportDataset(String file_export_name, String file_name, String object_path, int binary_order) throws Exception {
2068        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2069    }
2070
2071    /**
2072     * Renames an attribute.
2073     *
2074     * @param obj
2075     *            The object whose attribute is to be renamed.
2076     * @param oldAttrName
2077     *            The current name of the attribute.
2078     * @param newAttrName
2079     *            The new name of the attribute.
2080     *
2081     * @throws Exception
2082     *             The exceptions thrown vary depending on the implementing class.
2083     */
2084    public void renameAttribute(HObject obj, String oldAttrName, String newAttrName) throws Exception {
2085        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2086    }
2087
2088    /**
2089     * Sets the bounds of library versions.
2090     *
2091     * @param low
2092     *            The earliest version of the library.
2093     * @param high
2094     *            The latest version of the library.
2095     *
2096     * @throws Exception
2097     *             The exceptions thrown vary depending on the implementing class.
2098     */
2099    public void setLibBounds(int low, int high) throws Exception {
2100        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2101    }
2102
2103    /**
2104     * Gets the bounds of library versions
2105     *
2106     * @return The earliest and latest library versions in an int array.
2107     *
2108     * @throws Exception
2109     *             The exceptions thrown vary depending on the implementing class.
2110     */
2111    public int[] getLibBounds() throws Exception {
2112        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2113    }
2114
2115    public static int getIndexTypeValue(String strtype) {
2116        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2117    }
2118
2119    public int getIndexType(String strtype) {
2120        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2121    }
2122
2123    public void setIndexType(int indexType) {
2124        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2125    }
2126
2127    public static int getIndexOrderValue(String strorder) {
2128        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2129    }
2130
2131    public int getIndexOrder(String strorder) {
2132        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2133    }
2134
2135    public void setIndexOrder(int indexOrder) {
2136        throw new UnsupportedOperationException("Unsupported operation. Subclasses must implement it.");
2137    }
2138
2139}