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