This section includes installation notes, instructions for running NeXus for Java programs and a brief introduction to the API.
The Java API for NeXus (jnexus) was implemented through the Java Native Interface (JNI) to call on to the native C library. This has a number of disadvantages over using pure Java, however the most popular file backend HDF5 is only available using a JNI wrapper anyway.
This implementation uses classes and native methods from NCSA’s Java HDF Interface project. Basically all conversions from native types to Java types is done through code from the NCSA HDF group. Without this code the implementation of this API would have taken much longer. See NCSA’s copyright for more information.
Caution
Documentation is old and may need revision.
For running an application with jnexus an recent Java runtime environment (JRE) will do.
In order to compile the Java API for NeXus a Java Development Kit is required on top of the build requirements for the C API.
Note that the location or the naming of these files in the binary Nexus distributions have changed over the years. In the Nexus 4.3.0 Windows 64-bit distribution (http://download.nexusformat.org/kits/4.3.0/win64/), By default, the DLL is at: C:\Program Files\NeXus Data Format\bin\libjnexus-0.dll. Please rename this file to jnexus.dll before making it available in your path. This is important, otherwise, JVM runtime will not be able to locate this file.
For the same distribution, the location of jnexus.jar is at: C:\Program Files\NeXus Data Format\share\java.
The jnexus.so shared library as well as all required file backend .so libraries are required as well as the jnexus.jar file holding the required Java classes. Copy them wherever you like and see below for instructions how to run programs using jnexus.
In order to successfully run a program with jnexus, the Java runtime systems needs to locate two items:
This is easier, just add the the full pathname to jnexus.jar to the classpath when starting java. Here are examples for a UNIX shell and the Windows shell.
UNIX example shell script to start jnexus.jar
1 2 3 | #!/sbin/sh
java -classpath /usr/lib/classes.zip:../jnexus.jar:. \
-Dorg.nexusformat.JNEXUSLIB=../libjnexus.so TestJapi
|
Windows 32 example batch file to start jnexus.jar
1 2 | set JL=-Dorg.nexusformat.JNEXUSLIB=..\jnexus\bin\win32\jnexus.dll
java -classpath C:\jdk1.5\lib\classes.zip;..\jnexus.jar;. %JL% TestJapi
|
The NeXus C-API is good enough but for Java a few adaptions of the API have been made in order to match the API better to the idioms used by Java programmers. In order to understand the Java-API, it is useful to study the NeXus C-API because many methods work in the same way as their C equivalents. A full API documentation is available in Java documentation format. For full reference look especially at:
See the following code example for opening a file, opening a vGroup and closing the file again in order to get a feeling for the API:
fragment for opening and closing
1 2 3 4 5 6 7 | try{
NexusFile nf = new NexusFile(filename, NexusFile.NXACC_READ);
nf.opengroup("entry1","NXentry");
nf.finalize();
}catch(NexusException ne) {
// Something was wrong!
}
|
Some notes on this little example:
Again a code sample which shows how this looks like:
fragment for writing and reading
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int idata[][] = new idata[10][20];
int iDim[] = new int[2];
// put some data into idata.......
// write idata
iDim[0] = 10;
iDim[1] = 20;
nf.makedata("idata",NexusFile.NX_INT32,2,iDim);
nf.opendata("idata");
nf.putdata(idata);
// read idata
nf.getdata(idata);
|
The dataset is created as usual with makedata() and opened with putdata(). The trick is in putdata(). Java is meant to be type safe. One would think then that a putdata() method would be required for each Java data type. In order to avoid this, the data to write() is passed into putdata() as type Object. Then the API proceeds to analyze this object through the Java introspection API and convert the data to a byte stream for writing through the native method call. This is an elegant solution with one drawback: An array is needed at all times. Even if only a single data value is written (or read) an array of length one and an appropriate type is the required argument.
Another issue are strings. Strings are first class objects in Java. HDF (and NeXus) sees them as dumb arrays of bytes. Thus strings have to be converted to and from bytes when reading string data. See a writing example:
String writing
1 2 3 4 5 | String ame = "Alle meine Entchen";
nf.makedata("string_data",NexusFile.NX_CHAR,
1,ame.length()+2);
nf.opendata("string_data");
nf.putdata(ame.getBytes());
|
And reading:
String reading
1 2 3 4 5 | String ame = "Alle meine Entchen";
nf.makedata("string_data",NexusFile.NX_CHAR,
1,ame.length()+2);
nf.opendata("string_data");
nf.putdata(ame.getBytes());
|
The aforementioned holds for all strings written as SDS content or as an attribute. SDS or vGroup names do not need this treatment.
Let us compare the C-API and Java-API signatures of the getinfo() routine (C) or method (Java):
C API signature of getinfo()
1 2 3 | /* C -API */
NXstatus NXgetinfo(NXhandle handle, int *rank, int iDim[],
int *datatype);
|
Java API signature of getinfo()
1 2 | // Java
void getinfo(int iDim[], int args[]);
|
The problem is that Java passes arguments only by value, which means they cannot be modified by the method. Only array arguments can be modified. Thus args in the getinfo() method holds the rank and datatype information passed in separate items in the C-API version. For resolving which one is which, consult a debugger or the API-reference.
The attribute and vGroup search routines have been simplified using Hashtables. The Hashtable returned by groupdir() holds the name of the item as a key and the classname or the string SDS as the stored object for the key. Thus the code for a vGroup search looks like this:
vGroup search
1 2 3 4 5 6 7 8 9 10 | nf.opengroup(group,nxclass);
h = nf.groupdir();
e = h.keys();
System.out.println("Found in vGroup entry:");
while(e.hasMoreElements())
{
vname = (String)e.nextElement();
vclass = (String)h.get(vname);
System.out.println(" Item: " + vname + " class: " + vclass);
}
|
For an attribute search both at global or SDS level the returned Hashtable will hold the name as the key and a little class holding the type and size information as value. Thus an attribute search looks like this in the Java-API:
attribute search
1 2 3 4 5 6 7 8 9 | Hashtable h = nf.attrdir();
Enumeration e = h.keys();
while(e.hasMoreElements())
{
attname = (String)e.nextElement();
atten = (AttributeEntry)h.get(attname);
System.out.println("Found global attribute: " + attname +
" type: "+ atten.type + " ,length: " + atten.length);
}
|
For more information about the usage of the API routines see the reference or the NeXus C-API reference pages. Another good source of information is the source code of the test program which exercises each API routine.
These are a couple of known problems which you might run into:
The following documentation is browsable online:
[1] | http://download.nexusformat.org/doxygen/html-java/ |