2009-10-23 24 views
59

Compré una biblioteca Java de terceros que incluye un archivo JAR y dos archivos DLL. Escribí mi propio programa Java que invoca el archivo JAR de terceros. Ahora mi pregunta es ¿cómo puedo empaquetar todo mi código en un único archivo JAR que incluya todo mi código y el archivo JAR y DLL de terceros?¿Cómo hacer un archivo JAR que incluya archivos DLL?

SWT es un caso así. El swt.jar incluye archivos dll, pero no sé cómo hacer esto y cómo hacerlo funcionar correctamente.

Respuesta

68

Simplemente empaquételo en cualquier lugar de la jarra. Sin embargo, hay que tener en cuenta una cosa: antes de poder usar los DLL, necesita extraerlos del JAR y volcarlos en el disco duro; de lo contrario, no podrá cargar estos

Así que, básicamente, Hice el proyecto de JNI para el cliente donde usaré tal envase empaquetado dentro de la guerra. Sin embargo, antes de ejecutar cualquier método nativo, obtendría el archivo DLL como recurso y lo escribiría en el disco en el directorio temporal. Luego ejecutaba el código de inicialización regular donde mi DLL está configurada en la misma ubicación. Acabo de escribir una DLL en

Ah, y por las dudas: no hay nada especial en el empaquetado de dll o cualquier otro archivo en el contenedor. Es como el envasado de cosas en postal

Aquí hay un código que acaba de salir cavé

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 
} 
+7

Una palabra de precaución sobre este enfoque: asegúrese de limpiar los archivos temporales. Si vuelve a utilizar la misma ruta cada vez, considere lo que sucede si varias aplicaciones usan su JAR (una falla si la otra ya tiene un bloqueo en el archivo temporal). Solo tenga cuidado: a veces es más fácil implementar JAR y DLL por separado. –

+0

Se puede cambiar el código para sobrescribir el archivo previamente instalado. En mi caso, esta era una aplicación web que no se reciclaría frecuentemente, pero si copia el código "tal cual" obtendrá una nueva copia de archivos DLL cada vez que lo ejecute. – Bostone

+7

Una cosa a tener en cuenta: I estaba usando DLL JNI que dependían de otras DLL. Incluí todas las DLL dentro de un contenedor y usé el código anterior para descomprimir. Pero estaba obteniendo excepciones java.lang.UnsatisfiedLinkError que dicen "No se pueden encontrar bibliotecas dependientes". El problema es que debe llamar a System.load() en las DLL para que las DLL dependientes se carguen primero. –

6

Uso http://www.jdotsoft.com/JarClassLoader.php que podría cargar DLL y tarros de otro JAR con anidamiento ilimitado. Por ejemplo, DLL podría estar en JAR que está en otro root JAR. Todos los archivos DLL y JAR se cargan como si estuvieran en una ruta de acceso de clase o de biblioteca.

+23

Nota para otros: La licencia es GPLv3, lo que limita sustancialmente la aplicabilidad. –

+4

También tenga en cuenta: Este cargador de clases descomprime todos los archivos jar anidados en un directorio temporal. Entonces funciona como la primera respuesta. Las librerías nativas se desempaquetan solo si es necesario. – drzymala

+1

Licencia comercial disponible. – drzymala

Cuestiones relacionadas