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