Much has changed in the Java world since my last professional project in Java. One significant advance has been in native bindings. JNA-Java Native Access, is a much more straightforward approach than the old Java Native Interface approach. As a prrof of concept, I tried reading the information in my systems RPM database using librpm and the code generated by JNAEATOR from the rpm headers in /usr/include/rpm.
Here’s how I generated the headers in the first place.
java -jar ~/Download/jnaerator-v0.8-b519.jar -I /usr/include/linux -package rpm -library rpm /usr/include/rpm/*
This was overkill, but, as we all know, you can never have too much overkill. I forced them all into a single package (called rpm for now) and forced them all into a single inteface in rpm/RpmLibrary.java.
Here is a simple unit test proviong that it works. I don’t claim that this doesn’t leak memory, won’t corrupt your database, or steal your wallet. Caveat Coder. It isn’t even a decent unit test.
package rpmdb;
import java.nio.ByteBuffer;
import junit.framework.TestCase;
import rpm.RpmLibrary;
import rpm.RpmLibrary.headerToken_s;
import rpm.RpmLibrary.rpmdbMatchIterator_s;
import rpm.RpmLibrary.rpmts_s;import com.sun.jna.NativeLong;
import com.sun.jna.ptr.PointerByReference;public class RpmdbTest extends TestCase {
public void testReadDbPath() {
int status = RpmLibrary.INSTANCE.rpmReadConfigFiles((ByteBuffer) null,
null);
assertEquals(0, status);
ByteBuffer buffer = ByteBuffer.wrap(“%_dbpath”.getBytes());String value = RpmLibrary.INSTANCE.rpmExpand(buffer, (Object[]) null);
System.out.println(“Value of macro is ” + value);
}
public void testReadFromDB() {
int status = RpmLibrary.INSTANCE.rpmReadConfigFiles((ByteBuffer) null,
null);
assertEquals(0, status);rpmts_s ts = RpmLibrary.INSTANCE.rpmtsCreate();
assertNotNull(ts);rpmdbMatchIterator_s iter = RpmLibrary.INSTANCE.rpmtsInitIterator(ts,
rpm.RpmLibrary.rpmTag_e.RPMTAG_NAME, “java-1.6.0-openjdk”,
new NativeLong(0));
headerToken_s header;
while ((header = RpmLibrary.INSTANCE.rpmdbNextIterator(iter)) != null) {
PointerByReference namePtr = new PointerByReference();
PointerByReference releasePtr = new PointerByReference();
PointerByReference versionPtr = new PointerByReference();
RpmLibrary.INSTANCE.headerNVR(header, namePtr, versionPtr,
releasePtr);
System.out.println(“Name   = “+ namePtr.getValue().getString(0));
System.out.println(“release = “+ releasePtr.getValue().getString(0));
System.out.println(“version = “+ versionPtr.getValue().getString(0));
}if (ts != null) {
RpmLibrary.INSTANCE.rpmtsFree(ts);
}
}
}
I did have to massage some of the generated code by hand:Â rpmExpand returned a BytePointerByReference, and modifying the method signature to a return a String worked fine.
Hi Adam,
That’s a nice post, thanks for using JNAerator !
Would you like to create an RPM page on http://nativelibs4java.googlecode.com with your test case and JNAeration command ?
Wishing you the best,
Olivier
Olivier
I’m not necessarily making this into a complete solution, just trying to get it to work as a way to explore the JNA code. I’ll post if I end up doing anything with this.