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.

Reading the links from a webpage

I needed to see the set of RPMs in a YUM repository. I wanted to do this as part of a larger script. To do this, I fetched the page via wget, and then applied an xsl transform on it using the command line tool xsltproc.

Here is how I called it:

wget -q -O – http://spacewalk.redhat.com/yum/0.5/Fedora/10/x86_64/os/Packages/ | xsltproc –html showhrefs.xslt –

And here is the xslt file showrefs.xslt

<?xml version=”1.0″ encoding=”UTF-8″?>
<xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0″>
<xsl:output method=”xml” indent=”yes”/>

<!–  shut off the default matchin rule –>
<xsl:template match=”text()” />

<!– print the href value of the hyperlinks –>
<xsl:template match=”a”>
<xsl:value-of select=”@href” />
<xsl:text >
</xsl:text>

</xsl:template>

</xsl:stylesheet>