Monday, February 14, 2011

how to make a jar file that include dll files

(Ref: http://stackoverflow.com/questions/1611357/how-to-make-a-jar-file-that-include-dll-files)
Just package it anywhere in the jar. One thing you have to keep in mind though - before you can use the DLLs you need to actually extract these from the JAR and dump these on the hard disk somewhere otherwise you won't be able to load these

So basically - I did JNI project for the client where I will use such jar packaged within the war. However - before running any native methods I would get the DLL as a resource and write it to the disc into temp directory. Then I would run regular initialization code where my DLL is set to the same location I just wrote DLL to

Oh, and just in case: there's nothing special about packaging dll or any other file into jar. It's just like packaging stuff into zip

Here's some code I just digged out
public class Foo {
private static final String LIB_BIN = "/lib-bin/";
private final static Log logger = LogFactory.getLog(ACWrapper.class);
private final static String ACWRAPPER = "acwrapper";
private final static String AAMAPI = "aamapi51";
private final static String LIBEAU = "libeay32";

static {
        logger.info("Loading DLL");
        try {
                System.loadLibrary(ACWRAPPER);
                logger.info("DLL is loaded from memory");
        } catch (UnsatisfiedLinkError e) {
                loadFromJar();
        }
}

/**
 * When packaged into JAR extracts DLLs, places these into
 */
private static void loadFromJar() {
        // we need to put both DLLs to temp dir
        String path = "AC_" + new Date().getTime();
        loadLib(path, ACWRAPPER);
        loadLib(path, AAMAPI);
        loadLib(path, LIBEAU);
}

/**
 * Puts library to temp dir and loads to memory
 */
private static void loadLib(String path, String name) {
        name = name + ".dll";
        try {
                // have to use a stream
                InputStream in = ACWrapper.class.getResourceAsStream(LIB_BIN + name);
                // always write to different location
                File fileOut = new File(System.getProperty("java.io.tmpdir") + "/" + path + LIB_BIN + name);
                logger.info("Writing dll to: " + fileOut.getAbsolutePath());
                OutputStream out = FileUtils.openOutputStream(fileOut);
                IOUtils.copy(in, out);
                in.close();
                out.close();
                System.load(fileOut.toString());
        } catch (Exception e) {
                throw new ACCoreException("Failed to load required DLL", e);
        }
}
    // blah-blah - more stuff
}


A word of caution on this approach - be sure you clean up the temp files. If you re-use the same path each time, consider what happens if multiple applications use your JAR (one will fail if the other already has a lock on the temp file). Just be careful - sometimes it's easier to deploy the JAR and DLLs separately. – Kevin Day Oct 24 '09 at 5:50

Code can be changed to overwrite previously installed file. In my case - this was a web app which will not be frequently recycled, bu indeed - if you just copy the code "as is" you will get new copy of DLLs each time you execute it – DroidIn.net Oct 24 '09 at 6:03

One thing to keep in mind: I was using JNI DLLs that were dependent on other DLLs. I included all DLLs inside a jar and used the code above to unpack. But I was getting java.lang.UnsatisfiedLinkError exceptions saying "Can't find dependent libraries". The problem is that you must call System.load() on the DLLs in order such that dependent DLLs are loaded first. – Liron Yahdav May 24 '10 at 21:27

No comments:

Post a Comment