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