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