Using JNA with librpm

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.

2 thoughts on “Using JNA with librpm

  1. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.