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