| 1 | <HTML> |
|---|
| 2 | <HEAD> |
|---|
| 3 | <TITLE>The NeXus API for Java</TITLE> |
|---|
| 4 | </HEAD> |
|---|
| 5 | <BODY bgcolor=#FFFFFF> |
|---|
| 6 | <p align="center"> |
|---|
| 7 | <IMG src="NeXus.gif" WIDTH=597 HEIGHT=90> |
|---|
| 8 | </p> |
|---|
| 9 | <H1>The NeXus API for Java</H1> |
|---|
| 10 | <P> |
|---|
| 11 | <h2>Contents</h2> |
|---|
| 12 | <ul> |
|---|
| 13 | <li>Introduction |
|---|
| 14 | <li><a href="#ack">Acknowledgement</a> |
|---|
| 15 | <li><a href="#install">Installation</a> |
|---|
| 16 | <li><a href="#run">Running Programs</a> with the NeXus API for Java. |
|---|
| 17 | <li><a href="jnexustut.html">NeXus for Java Programming Tutorial</a> |
|---|
| 18 | <li><a href="#prog">Programming</a> with the NeXus API for Java (for |
|---|
| 19 | experienced NeXus API Programmers). |
|---|
| 20 | <li><a href="#lim">Known Limitations</a>. |
|---|
| 21 | <li><a href="#comp">Compiling</a> the NeXus API for Java |
|---|
| 22 | <li><a href="#sup">Support</a> |
|---|
| 23 | </ul> |
|---|
| 24 | </P> |
|---|
| 25 | |
|---|
| 26 | <h2>Introduction</h2> |
|---|
| 27 | <p> |
|---|
| 28 | <a href="http://lns00.psi.ch/Nexus">NeXus</a> is a proposal for a |
|---|
| 29 | common file format for neutron and X-ray scattering. NeXus uses <a |
|---|
| 30 | href="http://hdf.ncsa.uiuc.edu/">HDF</a> as its physical file format. |
|---|
| 31 | Since October 2000 a Java NeXus API has been available which supports |
|---|
| 32 | HDF version 4. Since then, the HDF team at NCSA has released a new |
|---|
| 33 | incompatible version of HDF, HDF version 5. This now is version 2 of |
|---|
| 34 | the Java NeXus API which supports both HDF versions. |
|---|
| 35 | As recoding the HDF library in Java was no option the Java |
|---|
| 36 | API for NeXus (jnexus) was implemented through the Java Native |
|---|
| 37 | Methods Interface (JNI). This has the consequence that the Java API |
|---|
| 38 | for NeXus cannot be used in applets as the security restrictions for |
|---|
| 39 | applets prohibit downloading of shared libraries and local file |
|---|
| 40 | access. Applets can use a NeXus Data Server in order to access NeXus |
|---|
| 41 | files in readonly mode. |
|---|
| 42 | </p> |
|---|
| 43 | |
|---|
| 44 | <h2><a name="ack">Acknowledgement</a></h2> |
|---|
| 45 | <p> |
|---|
| 46 | This implementation uses classes and native methods from NCSA's Java |
|---|
| 47 | HDF Interface project. Basically all conversions from native types to |
|---|
| 48 | Java types is done through code from the NCSA HDF group. Without this |
|---|
| 49 | code the implementation of this API would have taken much longer. See <a |
|---|
| 50 | href="COPYING.NCSA">NCSA's copyright</a> for more information. |
|---|
| 51 | </p> |
|---|
| 52 | <h2><a name="install">Installation</a></h2> |
|---|
| 53 | <h3>Requirements</h3> |
|---|
| 54 | <p> |
|---|
| 55 | For the binary distribution only a JDK1.1 compatible Java runtime is |
|---|
| 56 | required. Suitable runtime environments for Solaris, Linux and |
|---|
| 57 | Windows32 can be downloaded from <a |
|---|
| 58 | href="http://www.javasoft.com">Sun's Java</a> homepage. This website |
|---|
| 59 | also holds pointers to Java runtime systems for other |
|---|
| 60 | platforms. |
|---|
| 61 | |
|---|
| 62 | </p> |
|---|
| 63 | <p> |
|---|
| 64 | In order to compile the Java API for NeXus the following components |
|---|
| 65 | are required: |
|---|
| 66 | <ul> |
|---|
| 67 | <li>A Java Development Kit 1.1 or better. For downloads see above. |
|---|
| 68 | <li>A C compiler for your platform. |
|---|
| 69 | <li>The HDF libraries version 4.1r3 or better and the HDF-5 libraries, |
|---|
| 70 | newest version available. Both can be downloaded from <a |
|---|
| 71 | href="http://hdf.ncsa.uiuc.edu/">NCSA's HDF</a> homepage. |
|---|
| 72 | <li>A complete copy of the latest |
|---|
| 73 | <a href="http://sutekh.nd.rl.ac.uk/NAPI"> NAPI sources</a> (including jnexus |
|---|
| 74 | sources). |
|---|
| 75 | </ul> |
|---|
| 76 | </p> |
|---|
| 77 | <h3>Installation under Windows32 (Windows NT, Windows 95, 98, ME)</h3> |
|---|
| 78 | <p> |
|---|
| 79 | <ol> |
|---|
| 80 | <li>Copy the HDF DLL's (*413m.dll) and the file jnexus.dll to a |
|---|
| 81 | directory in your path. For instance C:\Windows\system32. |
|---|
| 82 | <li>Copy the jnexus.jar to the place where you usually keep library |
|---|
| 83 | jar files. |
|---|
| 84 | </ol> |
|---|
| 85 | </p> |
|---|
| 86 | <h3>Installation under Unix</h3> |
|---|
| 87 | <p> |
|---|
| 88 | Two files are needed: the jnexus.so shared library and the jnexus.jar |
|---|
| 89 | file holding the required Java class. Copy them wherever you like and |
|---|
| 90 | see below for instructions how to run programs using jnexus. |
|---|
| 91 | </p> |
|---|
| 92 | |
|---|
| 93 | <h2><a name="#run">Running Programs with the NeXus API for Java</a></h2> |
|---|
| 94 | <p> |
|---|
| 95 | In order to successfully run a program with jnexus the Java runtime |
|---|
| 96 | systems needs to locate two items: |
|---|
| 97 | <ul> |
|---|
| 98 | <li>The shared library implementing the native methods. |
|---|
| 99 | <li>The nexus.jar file in order to find the Java classes. |
|---|
| 100 | </ul> |
|---|
| 101 | </p> |
|---|
| 102 | <h3>Locating the shared library</h3> |
|---|
| 103 | <p> |
|---|
| 104 | Of course the method for locating a shared library differ between |
|---|
| 105 | systems. Under Windows32 systems the best method is to copy the |
|---|
| 106 | jnexus.dll and the HDF-libarary DLL's into a directory in your |
|---|
| 107 | path. The HDF DLL's have to go there anyway. |
|---|
| 108 | </p> |
|---|
| 109 | <p> |
|---|
| 110 | On a unix system the problem can be solved in three different ways: |
|---|
| 111 | <ul> |
|---|
| 112 | <li>Make your system administrator copy the jnexus.so file into the |
|---|
| 113 | systems default shared library directory (usually /usr/sbin). |
|---|
| 114 | <li>Put the jnexus.so file wherever you see fit and set the |
|---|
| 115 | LD_LIBRARY_PATH environment variable to point to the directory of your |
|---|
| 116 | choice. |
|---|
| 117 | <li>Specify the full pathname of the jnexus shared library on the |
|---|
| 118 | java command line with the |
|---|
| 119 | -Dorg.nexusformat.JNEXUSLIB=full-path-2-shared-library option. |
|---|
| 120 | </ul> |
|---|
| 121 | </p> |
|---|
| 122 | <h3>Locating jnexus.jar</h3> |
|---|
| 123 | <p> |
|---|
| 124 | This is easier: just add the the full pathname to jnexus.jar to the |
|---|
| 125 | classpath when starting java. |
|---|
| 126 | </p> |
|---|
| 127 | <h3>Examples</h3> |
|---|
| 128 | <p> |
|---|
| 129 | A unix example shell script: |
|---|
| 130 | <pre> |
|---|
| 131 | #!/sbin/sh |
|---|
| 132 | java -classpath /usr/lib/classes.zip:../jnexus.jar:. \ |
|---|
| 133 | -Dorg.nexusformat.JNEXUSLIB=../bin/du40/libjnexus.so TestJapi |
|---|
| 134 | </pre> |
|---|
| 135 | A Windows 32 example batch file: |
|---|
| 136 | <pre> |
|---|
| 137 | set JL=-Dorg.nexusformat.JNEXUSLIB=..\jnexus\bin\win32\jnexus.dll |
|---|
| 138 | java -classpath C:\jdk1.1.5\lib\classes.zip;..\jnexus.jar;. %JL% TestJapi |
|---|
| 139 | </pre> |
|---|
| 140 | </p> |
|---|
| 141 | |
|---|
| 142 | <h2><a name="prog">Programming</a> with the NeXus API for Java.</h2> |
|---|
| 143 | <p> |
|---|
| 144 | The NeXus C-API is good enough but for Java a few adaptions of the API |
|---|
| 145 | have been made in order to match the API better to the idioms used by |
|---|
| 146 | Java programmers. In order to understand the Java -API it is useful to |
|---|
| 147 | study the NeXus C-API because many methods work in the same way as |
|---|
| 148 | their C equivalents. A full API documentation is available in Java |
|---|
| 149 | documentation format. For full reference look especially at: |
|---|
| 150 | <ul> |
|---|
| 151 | <li>The interface <a |
|---|
| 152 | href="apidoc/org.nexusformat.NeXusFileInterface.html">NeXusFileInterface |
|---|
| 153 | </a> first. It gives an uncluttered view of the API. |
|---|
| 154 | <li>The implementation <a |
|---|
| 155 | href="apidoc/org.nexusformat.NexusFile.html">NexusFile</a> which gives more |
|---|
| 156 | details about constructors and constants. However this documentation |
|---|
| 157 | is interspersed with information about native methods which should not |
|---|
| 158 | be called by an application programmer as they are not part of the |
|---|
| 159 | standard and might change in future. |
|---|
| 160 | </ul> |
|---|
| 161 | Some more general explanation will be given below. |
|---|
| 162 | </p> |
|---|
| 163 | <h3>General Things</h3> |
|---|
| 164 | <p> |
|---|
| 165 | See the following code example for opening a file, opening a vGroup |
|---|
| 166 | and closing the file again in order to get a feeling for the API. |
|---|
| 167 | <pre> |
|---|
| 168 | try{ |
|---|
| 169 | NexusFile nf = new NexusFile(filename, |
|---|
| 170 | NexusFile.NXACC_READ); |
|---|
| 171 | nf.opengroup("entry1","NXentry"); |
|---|
| 172 | nf.finalize(); |
|---|
| 173 | }catch(NexusException ne) { |
|---|
| 174 | // oh shit! something was wrong! |
|---|
| 175 | } |
|---|
| 176 | </pre> |
|---|
| 177 | Some notes on this little example: |
|---|
| 178 | <ul> |
|---|
| 179 | <li>Each NeXus file is represented by a NexusFile object which is |
|---|
| 180 | created through the constructor. |
|---|
| 181 | <li>The NexusFile object takes care of all file handles for you. So |
|---|
| 182 | there is no need to pass in a handle anymore to each method as in |
|---|
| 183 | the C language API. |
|---|
| 184 | <li>All error handling is done through the Java exception handling |
|---|
| 185 | mechanism. This saves all the code checking return values in the C |
|---|
| 186 | language API. Most API functions return void. |
|---|
| 187 | <li>Closing files is tricky. The Java garbage collector is supposed to |
|---|
| 188 | call the finalize method for each object it decides to delete. In |
|---|
| 189 | order to enable this mechanism, the NXclose function was replaced by |
|---|
| 190 | the finalize method. In practice it seems not to be guranteed that the |
|---|
| 191 | garbage collector calls the finalize method. It is safer to call |
|---|
| 192 | finalize yourself in order to properly close a file. Multiple calls to |
|---|
| 193 | the finalize method for the same object are safe and do no harm. |
|---|
| 194 | </ul> |
|---|
| 195 | </p> |
|---|
| 196 | <h3>Data Writing and Reading</h3> |
|---|
| 197 | <p> |
|---|
| 198 | Again a code sample which shows how this looks like: |
|---|
| 199 | <pre> |
|---|
| 200 | int idata[][] = new idata[10][20]; |
|---|
| 201 | int iDim[] = new int[2]; |
|---|
| 202 | |
|---|
| 203 | // put some data into iData....... |
|---|
| 204 | |
|---|
| 205 | // write iData |
|---|
| 206 | iDim[0] = 10; |
|---|
| 207 | iDim[1] = 20; |
|---|
| 208 | nf.makedata("idata",NexusFile.NX_INT32,2,iDim); |
|---|
| 209 | nf.opendata("idata"); |
|---|
| 210 | nf.putdata(idata); |
|---|
| 211 | |
|---|
| 212 | // read idata |
|---|
| 213 | nf.getdata(idata); |
|---|
| 214 | </pre> |
|---|
| 215 | The dataset is created as usual with makedata and opened with |
|---|
| 216 | putdata. The trick is in putdata. Java is meant to be type safe. One |
|---|
| 217 | would think then that a putdata method would be required for each Java |
|---|
| 218 | data type. In order to avoid this the data to write is passed into |
|---|
| 219 | putdata as type Object. Then the API proceeds to analyze this object |
|---|
| 220 | through the Java introspection API and convert the data to a byte |
|---|
| 221 | stream for writing through the native method call. This is an elegant |
|---|
| 222 | solution with one drawback: An array is needed at all times. Even if |
|---|
| 223 | only a single data value is written (or read) an array of length one |
|---|
| 224 | and an appropriate type is the required argument. |
|---|
| 225 | </p> |
|---|
| 226 | <p> |
|---|
| 227 | Another issue are strings. Strings are first class objects in |
|---|
| 228 | Java. HDF (and NeXus) sees them as dumb arrays of bytes. Thus strings |
|---|
| 229 | have to be converted to and from bytes when reading string data. See a |
|---|
| 230 | writing example: |
|---|
| 231 | <pre> |
|---|
| 232 | String ame = "Alle meine Entchen"; |
|---|
| 233 | nf.makedata("string_data",NexusFile.NX_CHAR,1, |
|---|
| 234 | ame.length()+2); |
|---|
| 235 | nf.opendata("string_data"); |
|---|
| 236 | nf.putdata(ame.getBytes()); |
|---|
| 237 | </pre> |
|---|
| 238 | And reading: |
|---|
| 239 | <pre> |
|---|
| 240 | byte bData[] = new byte[132]; |
|---|
| 241 | nf.opendata("string_data"); |
|---|
| 242 | nf.getdata(bData); |
|---|
| 243 | String string_data = new String(bData); |
|---|
| 244 | </pre> |
|---|
| 245 | The aforementioned holds for all strings written as SDS content or as |
|---|
| 246 | an attribute. SDS or vGroup names do not need this treatment. |
|---|
| 247 | </p> |
|---|
| 248 | <h3>Inquiry Routines</h3> |
|---|
| 249 | <p> |
|---|
| 250 | Let us compare the C-API and Java-API signatures of the getinfo |
|---|
| 251 | routine or method: |
|---|
| 252 | <pre> |
|---|
| 253 | /* C -API */ |
|---|
| 254 | NXstatus NXgetinfo(NXhandle handle, int *rank, int iDim[], |
|---|
| 255 | int *datatype); |
|---|
| 256 | // Java |
|---|
| 257 | void getinfo(int iDim[], int args[]); |
|---|
| 258 | </pre> |
|---|
| 259 | The problem is that Java passes arguments only by value, which means |
|---|
| 260 | they cannot be modified by the method. Only array arguments can be |
|---|
| 261 | modified. Thus args in the getinfo method holds the rank and datatype |
|---|
| 262 | information passed in separate items in the C-API version. For |
|---|
| 263 | resolving which one is which consult a debugger or the API-reference. |
|---|
| 264 | </p> |
|---|
| 265 | <p> |
|---|
| 266 | The attribute and vGroup search routines have been simplified using |
|---|
| 267 | Hashtables. The Hastable returned by <b>groupdir()</b> holds the name |
|---|
| 268 | of the item as a key and the classname or the string SDS as ths stored |
|---|
| 269 | object for the key. Thus the code for a vGroup search looks like this: |
|---|
| 270 | <pre> |
|---|
| 271 | nf.opengroup(group,nxclass); |
|---|
| 272 | h = nf.groupdir(); |
|---|
| 273 | e = h.keys(); |
|---|
| 274 | System.out.println("Found in vGroup entry:"); |
|---|
| 275 | while(e.hasMoreElements()) |
|---|
| 276 | { |
|---|
| 277 | vname = (String)e.nextElement(); |
|---|
| 278 | vclass = (String)h.get(vname); |
|---|
| 279 | System.out.println(" Item: " + vname + " class: " + vclass); |
|---|
| 280 | } |
|---|
| 281 | </pre> |
|---|
| 282 | For an attribute search both at global or SDS level the returned |
|---|
| 283 | Hashtable will hold the name as the key and a little class holding the |
|---|
| 284 | type and size information as value. Thus an attribute search looks |
|---|
| 285 | like this in the Java-API: |
|---|
| 286 | <pre> |
|---|
| 287 | Hashtable h = nf.attrdir(); |
|---|
| 288 | Enumeration e = h.keys(); |
|---|
| 289 | while(e.hasMoreElements()) |
|---|
| 290 | { |
|---|
| 291 | attname = (String)e.nextElement(); |
|---|
| 292 | atten = (AttributeEntry)h.get(attname); |
|---|
| 293 | System.out.println("Found global attribute: " + attname + |
|---|
| 294 | " type: "+ atten.type + " ,length: " + atten.length); |
|---|
| 295 | } |
|---|
| 296 | </pre> |
|---|
| 297 | </p> |
|---|
| 298 | <p> |
|---|
| 299 | For more information about the usage of the API routines see the |
|---|
| 300 | reference or the NeXus C-API reference pages. Another good source of |
|---|
| 301 | information is the source code of the <a href="test/TestJapi.java">test |
|---|
| 302 | program </a> which exercises each API routine. |
|---|
| 303 | </p> |
|---|
| 304 | |
|---|
| 305 | <h2><a name="lim">Limitations</a></h2> |
|---|
| 306 | <p> |
|---|
| 307 | These are a couple of known problems which you might run into: |
|---|
| 308 | <dl> |
|---|
| 309 | <DT>Memory |
|---|
| 310 | <DD>As the Java API for NeXus has to convert between native and Java |
|---|
| 311 | number types a copy of the data must be made in the process. This |
|---|
| 312 | means that if you want to read or write 20MB of data your memory requirement |
|---|
| 313 | will be 40MB! This can be reduced by using getslab/putslab for data |
|---|
| 314 | transfers. |
|---|
| 315 | <DT>Java.lang.OutOfMemoryException |
|---|
| 316 | <DD>By default the Java runtime has a ceiling of 16MB of memory |
|---|
| 317 | use. This ceiling can be increased through the -mxXXm option to the |
|---|
| 318 | Java runtime. An example: java -mx32m ..... starts the Java runtime |
|---|
| 319 | with a memory ceiling of 32MB. |
|---|
| 320 | <dT>Trouble with compressed dataset on True64Unix with jdk118 |
|---|
| 321 | <DD>True64Unix's JDK-1.1.8 from HP, Compaq, DEC or however the company |
|---|
| 322 | is called these days is built with a version of zlib incompatible with |
|---|
| 323 | the version used by the HDF libraries. This causes failures to write or read |
|---|
| 324 | compressed datasets when classes are loaded from jar-files. They |
|---|
| 325 | promised to fix this a long time ago but SIGHHHHHHH! The newer |
|---|
| 326 | JDK-1.3.1 does not exhibit this problem. |
|---|
| 327 | <DT>Maximum 8192 files open. |
|---|
| 328 | <DD>The NeXus API for Java has a fixed buffer for file handles which |
|---|
| 329 | allows only 8192 NeXus files to be open at the same time. If you ever |
|---|
| 330 | hit this limit, increase the MAXHANDLE define in native/handle.h and |
|---|
| 331 | recompile everything. |
|---|
| 332 | </dl> |
|---|
| 333 | </p> |
|---|
| 334 | <h2><a name="comp">Compiling</a> the Java API for NeXus</h2> |
|---|
| 335 | <p> |
|---|
| 336 | You will need <li>a complete copy of the latest |
|---|
| 337 | <a href="http://sutekh.nd.rl.ac.uk/NAPI"> NAPI sources</a> (including jnexus |
|---|
| 338 | sources). See other <a href="#install">requirements</a> under |
|---|
| 339 | installation above. |
|---|
| 340 | </p> |
|---|
| 341 | <p> |
|---|
| 342 | For Windows32 the free <a href="http://www.borland.com/jbuilder">Borland bcc55 |
|---|
| 343 | </a> command line compiler is used. Just run make -fmake.win32 and |
|---|
| 344 | everything will be built. If not, adapt the directory settings in the |
|---|
| 345 | make.win32 file to match your systems configuration. A hint: The import |
|---|
| 346 | libraries for bcc where created from the HDF DLL's with the impdef, implib |
|---|
| 347 | utilities using the -a option. There was a problem with dplicate symbols for |
|---|
| 348 | Hopen, Hclose. This was solved by removing the HOPEN, HCLOSE entries in the |
|---|
| 349 | definition file. This is case sensitivity problem. |
|---|
| 350 | </p> |
|---|
| 351 | <p> |
|---|
| 352 | For DigitalUnix4.0D and Redhat Linux 6.2 Makefiles are provided |
|---|
| 353 | (Makefile and Make.tux repectively). For these systems everything can |
|---|
| 354 | be build with make du40 of make -f make.tux respectively. |
|---|
| 355 | If the Makefiles do not work edit the |
|---|
| 356 | directory paths in the configuration section to match your |
|---|
| 357 | installation. If you wish to compile on another unix system, create a |
|---|
| 358 | copy of one of the above mentioned Makefiles and edit the |
|---|
| 359 | configuration section in your copy to match your installation of java |
|---|
| 360 | and the HDF libraries. If you succeed in building the NeXus API for |
|---|
| 361 | Java on a new system, please put back modified sources into the CVS |
|---|
| 362 | repository and make your Makefile and the compiled shared library |
|---|
| 363 | available to the NAPI team in order to provide a new binary |
|---|
| 364 | distribution. |
|---|
| 365 | </p> |
|---|
| 366 | <h2><a name="sup">Support</a></h2> |
|---|
| 367 | <p> |
|---|
| 368 | I'am sure this software contains swarms of bugs. If you manage to find |
|---|
| 369 | one you may send requests either to the <a |
|---|
| 370 | href="mailto:napi@isis.rl.ac.uk">NAPI developer mailing list </a> or |
|---|
| 371 | to <a href="mailto:Mark.Koennecke@psi.ch">Mark Könnecke</a> who |
|---|
| 372 | wrote the Java API for NeXus. |
|---|
| 373 | </p> |
|---|
| 374 | <hr> |
|---|
| 375 | <p> |
|---|
| 376 | Author:<br> |
|---|
| 377 | Mark Könnecke<br> |
|---|
| 378 | Laboratory for Neutron Scattering<br> |
|---|
| 379 | Paul Scherrer Institut<br> |
|---|
| 380 | CH-5232-Villigen-PSI<br> |
|---|
| 381 | Switzerland<br> |
|---|
| 382 | and the NeXus Design team.<br> |
|---|
| 383 | Last Update: November, 22, 2002 |
|---|
| 384 | <p> |
|---|
| 385 | </BODY> |
|---|
| 386 | </HTML> |
|---|