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