Thursday, October 9, 2014

20 steps to Java/DLL integration over JNI

I'm not well-versed in C++ nor .Net, so I was still learning as I encountered this at work. While not being overly generic yet not too specific about the ordeal I encountered, it involved getting a DLL to work with our Java components. Sounds straightforward enough? It was... kind of. Guy 1 is in charge of developing the main DLL and its compilation stuff. Guy 2 is versed in C++ but understands Java sufficiently to provide the DLL for the Java Native Interface (JNI) adapter to the main DLL from Guy 1, along with basic testing classes in Java.

It certainly looked like he had already done all my work for me. Not quite. I'd have to proceed with his setup to get their bits working with the rest of our web application in a Java framework. Here's how it went... (WARNING: wall of text that includes technical stuff and bitching)

TL;DR - integrated Java with DLL using JNI, shenanigans with co-workers ensue, Java calls to DLL success.

Step 1: Setup the DLL paths and environment provided by Guy 2 in my Eclipse,

Step 2: Realise Guy 2 provided basic XML parsing via DocumentBuilder,

Step 3: Convert everything he's done into XStream-friendly POJO,

Step 4: Realise XStream is an external library and commence search for alternative to reduce additional footprint,

Step 5: Took the advice of Blaise Doughan and adopted Java Architecture for XML Binding (JAXB) because it's part of the javax.xml.bind package,

Step 6: Discovered the joys of source annotations and XML adapters,

Step 7: Realise that the XML definition that was long decided before I was brought on board (and already implemented on the .Net server side) is complicated (e.g.:
<fans>
  <fan type="standing"/>
  <fan type="desk"/>
  <fan type="celebrity"/>
</fans>
) by attribute naming that prevented JAXB from unmarshalling the String to object,

Step 8: Came up with my own convoluted (I swear it's as elegant as I could get it) solution to first read the <fans> to determine what types were in the list provided, before manually stripping <fans> from the String front and back and running it through JAXB another time, (if you have a better way, let me know!)

Step 9: Attempt to run the whole shebang with the DLL,

Step 10: Act surprised that JNI complained of an UnsatisfiedLinkError for the DLL,

Step 11: Figured that Eclipse had to be told where to look with -Djava.library.path="C:/that_dumb_place/Dlls" when running my test program,

Step 12: Nope still won't work, spend the morning poking around some more before giving up and asking Guy 2 if I'd missed out anything,

Step 13: Guy 2 refers me to Guy 1 for the DLL portion, "fair enough" I lied to myself,

Step 14: Decided I should test further without the Java components by first running the .exe test program they provided... crashed,

Step 15: Approach Guy 1 who tells me he'd investigate the error on his end first, while I proceed to lunch,

Step 16: Guy 1 returns to offer me his solution of running his test program on his spare laptop that's been configured to work bug-free, instead of my problematic laptop that's long been tainted with other muck from previous projects,

Step 17: "Does this thing have Java installed?", I queried. Guy 1immediately forbids me from running my codes on his precious laptop. Explained to him I needed to run my codes with his because I had to integrate them for this project. Seeing there was no other way to squirm out of this, he promptly took over my laptop to figure out how to get his test program running,

Step 18: I twirled around in my chair for almost 2 hours before he returned triumphant. It worked! At last, his test program works on my laptop. He had installed a new driver that goes along with a new model of the Human-Interface Device (HID) that we have already provided the client.

Step 19: Indeed, System.load("That_Darn_JNI") works with the DLL from Guy 2 in his codes that I've since adopted and turned it from a baby into an adolescent, complete with full-blown set of beans and action classes, just as long Eclipse knows about that -Djava.library.path it cleverly denies knowing about,

Step 20: Try running my test program. Nope, Unsatisfied remains. Made comparison between JNI DLL and existing known working DLL from another product, and finally getting around to rectify minor bugs in my codes to marshal/unmarshal between the XML and POJO.

So I finally got what I wanted... well almost. The following addendum is the cherry missing from my cake...

Step 21: Realised that because I'd shifted the DLL away from the original XYZ.Product package into my Java-convention style of com.XYZ.asia.product.client caused the JNI to not map to the native DLL, and that it'd be confusing to leave the product package as XYZ.Product while the rest of the project is differently identified,

Step 22: Ask Guy 2 about the JNI, he patiently explained about how the header works but ultimately suggested that I should talk to Guy 1,

Step 23: Locate Guy 1 about passing him the JNI header to generate the DLL for me. Nope, his bunch of codes would take him way longer to generate the resulting DLL,

Step 24: Return to Guy 2 about it. He relents, and I generate the JNI header via javah.exe mapping to the relocated JNI wrapper

Step 25: I have yet to test this new DLL yet, although I reckon it should function as expected... and hopefully this tiring liaison with them is over for the time being...

And thus, at the end of the day, I got my DLL the way I wanted it, the HID works on my machine, the client-server calls are working and I'm getting the XML strings parsed correctly into Java objects. It's been gruelling, but educational.

To be continued...

No comments:

Post a Comment