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