hdf images hdf images

Java HDF-5 Exceptions

The Java HDF-5 Interface replaces the error return codes of the HDF-5 C library with Java Exceptions. There are two sub-classes of HDF5Exception: HDF5LibraryException and HDF5JavaException. The former represent error messages from the HDF-5 library, the latter represent exceptions in the Java HDF-5 Interface. The class HDF5Exception overrides the standard method printStackTrace(), to print the HDF 5 library error stack, as described in the HDF-5 H5Eprint routine.

HDF5LibraryException

An HDF5LibraryException is raised from errors caused by the HDF5 library calls. When an error occurs in an HDF5 library call, the JHI5 retrieves the major error code and minor code from the HDF5 library error stack.

An instance of hdf.hdf5.exceptions.HDF5LibraryException is raised based on the major error code and the error message is put into the exception according to the minor error code. There is a sub-class of HDF5LibraryException for each HDF-5 major error code (in the file H5Epublic.h). The method HDF5LibraryException.printStackTrace() prints the error stack from the HDF-5 library to the Java console or log file. For example, consider the code below:

 import hdf.hdf5lib.*;
 import hdf.hdf5lib.exceptions.*
 try {
 file = H5.H5Fopen("nosuchFile.h5",
 HDF5Constants.H5F_ACC_RDWR,
 HDF5Constants.H5P_DEFAULT);
 } catch (HDF5Exception ex) {
 ex.printStackTrace();
 }
In this example, suppose the file does not exist. In this case, the HDF-5 library returns "FAIL" and the major error code set to "File Interface Error". The JHI5 detects the error, and raises an HDF5FileInterfaceException. The detailed error message from the HDF5 library error stack is printed on the Java console, followed by the standard Java stack trace. This might look something like this:
 hdf.hdf5lib.exceptions.HDF5FileInterfaceException: Unable to open file
 HDF5-DIAG: Error detected in thread 0. Back trace follows.
 #000: D:\work\MyHDFstuff\hdf5\src\H5F.c line 1463 in H5Fopen(): unable to open file
 major(04): File interface
 minor(12): Unable to open file
 #001: D:\work\MyHDFstuff\hdf5\src\H5F.c line 1059 in H5F_open(): file does not exist
 major(04): File interface
 minor(12): Unable to open file
 hdf.hdf5lib.exceptions.HDF5FileInterfaceException: Unable to open file
 at hdf.hdf5lib.H5.H5Fopen(Native Method)
 at hdf.hdf5lib.test.TestException.testNoSuchFile(TestException.java:124)
 at hdf.hdf5lib.test.TestException.runTest(TestException.java:76)
 at hdf.hdf5lib.test.TestHDF5Library.main(TestHDF5Library.java:575)
Alternatively, the exception handling code could generate an alert dialog or other appropriate action instead of printing the stack.

HDF5JavaException

If errors or exceptions occur in the JHI5 wrapper code itself, these are raised either as standard Java exceptions (e.g., NullPointerException) or as sub-classes of HDF5JavaException. The former may occur due to errors in calling parameters or other programming errors. The latter may occur due to resource exhaustion or attempts to use unsupported data types. For example, an attempt to write an array of non-numerical objects will fail. Also, if an array is very large, the data conversion may not be able to obtain sufficient memory, which will generate an exception.

Implementation Notes

The Java HDF-5 Interface uses the Java Native Interface to create and throw Java Exceptions directly from the C interface code. This causes the Java native method to raise an exception instead of returning.

When an error status ("FAIL") is returned by the HDF5 library, the JHI calls the C function libraryError(). This subroutine examines the HDF-5 library error stack to determine the major error code. The error code is used to decide which class of exception to create and throw. This routine never returns. The following code is an extract from native/hdf5lib/exceptionImp.c.

#include "hdf5.h"
#include <stdio.h>
#include "jni.h"
/*
#include "H5Eprivate.h"
*/
/* These types are copied from H5Eprivate.h
* They should be moved to a public include file, and deleted from
* here.
*/
#define H5E_NSLOTS 32 /*number of slots in an error stack */
/*
* The list of error messages in the system is kept as an array of
* error_code/message pairs, one for major error numbers and another for
* minor error numbers.
*/
typedef struct H5E_major_mesg_t {
 H5E_major_t error_code;
 const char *str;
} H5E_major_mesg_t;
typedef struct H5E_minor_mesg_t {
 H5E_minor_t error_code;
 const char *str;
} H5E_minor_mesg_t;
/* An error stack */
typedef struct H5E_t {
 /*intn*/int nused; /*num slots currently used in stack */
 H5E_error_t slot[H5E_NSLOTS]; /*array of error records */
} H5E_t;
/*
* The error stack. Eventually we'll have some sort of global table so each
* thread has it's own stack. The stacks will be created on demand when the
* thread first calls H5E_push().
*/
extern H5E_t H5E_stack_g[1];
#define H5E_get_my_stack() (H5E_stack_g+0)
/* end of declarations from H5private.h */
/*
* 'libraryError' is called by routines of the JHI C interface.
* This routine does the following:
* 1. looks up the major error number from the global error stack
* (See getMajorErrorNumber below)
* 2. determines which exception to raise
* (See defineHDF5LibraryException, below)
* 3. calls the JNI to look up, and create a Java Exception of the
* appropriate class, with the appropriate message.
* 4. calls the JNI to throw the exception.
*
* This routine never returns.
*/
jboolean libraryError( JNIEnv *env)
{
 jmethodID jm;
 jclass jc;
 char *args[2];
 char *exception;
 jobject ex;
 jstring str;
 char *msg;
 int rval, min_num, maj_num;
 maj_num = (int)getMajorErrorNumber();
 exception = (char *)defineHDF5LibraryException(maj_num);
 jc = (*env)->FindClass(env, exception);
 if (jc == NULL)
 return JNI_FALSE;
 }
 jm = (*env)->GetMethodID(env, jc, "<init>", "(Ljava/lang/String;)V");
 if (jm == NULL) {
 return JNI_FALSE;
 }
 min_num = (int)getMinorErrorNumber();
 msg = (char *)H5Eget_minor((H5E_minor_t)min_num);
 str = (*env)->NewStringUTF(env,msg);
 /* call the constructor for 'exception'
 * with the minor error message as the message
 */
 args[0] = (char *)str;
 args[1] = 0;
 ex = (*env)->NewObjectA ( env, jc, jm, (jvalue *)args );
 rval = (*env)->Throw(env, ex );
 /* NOT REACHED */
 return JNI_TRUE;
}
/* getMajorErrorNumber
* look at the HDF5 library error stack, get the major error code
*/
int getMajorErrorNumber()
{
 H5E_t *estack = H5E_get_my_stack ();
 H5E_error_t *err_desc;
 H5E_major_t maj_num = H5E_NONE_MAJOR;
 if (estack && estack->nused>0){
 err_desc = estack->slot+0;
 maj_num = err_desc->maj_num;
 }
 return (int) maj_num;
}
char *defineHDF5LibraryException(int maj_num)
{
 H5E_major_t err_num = (H5E_major_t) maj_num;
 /* Map the error code to the name of an exception */
 switch (err_num)
 {
 case H5E_ARGS:
 return "hdf/hdf5lib/exceptions/HDF5FunctionArgumentException";
 case H5E_RESOURCE:
 return "hdf/hdf5lib/exceptions/HDF5ResourceUnavailabletException";
 case H5E_INTERNAL:
 /* ... etc. */
 default:
 return "hdf/hdf5lib/exceptions/HDF5LibraryException";
 }
}
The libraryError() routine is called in the JHI5 whenever a return status indicates an HDF5 error. For example:
JNIEXPORT jint JNICALL Java_hdf_hdf5lib_H5_H5Fopen
 (JNIEnv *env, jclass class, jstring name, jint flags, jint access_id)
{
 hid_t status;
 char* file;
 jboolean isCopy;

 if (name == NULL) {
 /* raise Java exception -- bad argument? */
 nullArgument( env,"H5Fopen: name is NULL");
 return -1;
 }

 file = (char *)(*env)->GetStringUTFChars(env,name,&isCopy);
 if (file == NULL) {
 /* Raise Java exception -- out of memory or something? */
 JNIFatalError( env,"H5Fopen: file name not pinned");
 return -1;
 }
 status = H5Fopen(file, (unsigned) flags, (hid_t) access_id );

 (*env)->ReleaseStringUTFChars(env,name,file);
 /* If status < 0, there was an error */
 if (status < 0) {
 /* Call routine to look up and throw a Java exception */
 libraryError(env);
 }
 return (jint)status;
}
The code above shows the implementation of the interface to the HDF-5 H5Fopen() routine. If the call to the HDF-5 library returns "FAIL" (< 0), then the JHI5 code calls "libraryError()", which will create and throw a Java exception. This example also shows that other exceptions may be thrown in cases where the JHI5 itself detects an error, such as a NULL argument.

In the calling Java program, calls to the JHI5 must catch possible exceptions from the HDF-5 library. The program may ignore exceptions, look at the information in the exception, or take appropriate action such as raising an alert box. The calling program may handle different exceptions differently. The following shows how the H5Fopen() method would be called.

try {
 H5.H5Fopen(file, accessFlags, otherflags);
} catch (HDF5LibraryException ex) {
 /* handle some exception */
 /* or raise alert or something...*/
}

- - Last modified: 06 July 2016