1

I've been looking for in the forum questions related with my issue, but I didn't found anything. Any help with this will be appreciated.

I have an application in Java, using IntelliJ, which has, among others, the library RXTXcomm.jar, which comes with a native library with it, rxtxSerial.dll, both in separated files.

I have used this libraries without any issue in my project, by setting properly the dependency of the RXTXcomm.jar library and setting as Native Library Location the rxtxSerial.dll in the Dependencies section of the Project Structure.

The problem comes when I want to generate an artifact of my project. I've created many artifacts with different projects, but is the first time I have to add to the artifact a library with a native .dll library with it. From the Project Structure/Artifacts I double-click over the RXTXcomm.jar as I do in the Project Structure/Modules/Dependencies section to add the rxtxSerial.dll, but of course it doesn't works. I've tried to add the .dll native library to the artifact as any other .jar library I've added before, but it doesn't works. When I run my artifact, this is the error thrown:

Image of exception thrown when running the artifact

I think that the problem is how I am adding this library to the artifact, but I can't find how to do this searching on the web. If read about the NativeUtils class, but I think this is not what I need here because is more an artifact configuration issue. Here I show you how I have added the RXTXcomm.jar and its native library to make it works from the IDE: Library added in Project Structure/Modules/Dependencies

And with this, running the application from the IDE everything works perfectly.

Now here is how I am adding the library and its native to build the artifact: Library added in Project Structure/Artifacts

For sure I am doing something wrong here but can't find what. Which is the proper way to add in my artifact this native library (rxtxSerial.dll) to the RXTXcomm.jar library to not have this exception and make it works?

Any help will be appreciated and if some more info is needed please tell me.

Thanks a lot,

Daniel.

EDIT: Following the advice of @Andrey I tried to load the .dll library in the way it is explained in the link he provided: How to make a JAR file that includes DLL files?, but it seems it doesn't work for me and I don't understand why. Here is the code I've used:

public class Main extends Application {
private static DataBase database= new DataBase();
private final static Log logger = LogFactory.getLog(ACWrapper.class);
private static final String LIB_BIN = "/lib-bin/";
private final static String rxtxSerial = "rxtxSerial";
/**
 * Function to launch the application
 * @param args .
 */
public static void main(String[] args) {
    // Merge the Swing and JavaFX threads - needs Java 8
    //System.setProperty("javafx.embed.singleThread", "true");

    // Verify that Direct3D is enabled (the default setting), to avoid resize issues.
    try {
        if (Boolean.valueOf(System.getProperty("sun.java2d.noddraw", "false")) ||
                !Boolean.valueOf(System.getProperty("sun.java2d.d3d", "true"))) {
            throw new IllegalStateException("Do not change the Direct3D default settings (Windows specific), "
                    + "it may cause glitches during frame re-sizing.");
        }

        Application.launch(args);
    } catch (IllegalStateException ex){
        ex.printStackTrace();
        database.insertSystemErrorLog(Thread.currentThread().getStackTrace()[1].getMethodName(),ex);
    }
}

/**
 * Function to configure the stage where the view will be added
 * @param primaryStage the stage to be configured
 */
@Override
public void start(Stage primaryStage) {

    try {
        if (!EventQueue.isDispatchThread()) {
            throw new IllegalStateException(
                    "FX and Swing thread should be merged. Are you using Java 8 and the javafx.embed.singleThread flag?");
        }

        loadExternalDllFiles();

        //Add Swing view and interface components to the FX frame
        SwingNode viewNode = addSwingNodeToFXFrame(primaryStage);
        //----------------------------------------------

        //Add FX view and interface components to the FX frame

        //----------------------------------------------

        // Auxiliary panel with provisional content
        Accordion auxiliaryPanelFX = new Accordion();

        // Do the lay-out using FX
        HBox hbox = new HBox(viewNode, auxiliaryPanelFX);
        HBox.setHgrow(viewNode, Priority.ALWAYS);

        // Show the window
        primaryStage.setScene(new Scene(hbox));
        primaryStage.setFullScreen(true);
        primaryStage.setTitle("FXApp");
        primaryStage.setResizable(true);
        primaryStage.show();

    } catch (IllegalStateException ex){
        ex.printStackTrace();
        database.insertSystemErrorLog(Thread.currentThread().getStackTrace()[1].getMethodName(),ex);
    }

}

private void loadExternalDllFiles() {
    logger.info("Loading DLL");
    try {
        System.loadLibrary(rxtxSerial);
        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, rxtxSerial);
}

/**
 * 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) {
        System.out.println("Failed to load required DLL");
    }
}

/**
 * Function to create a SwingNode with all the components using Swing format
 * @param primaryStage_ JavaFX Stage where all the Swing components will be added
 * @return The SwingNode already built
 */
private SwingNode addSwingNodeToFXFrame(Stage primaryStage_) {

    //Set the initial language of the application
    Locale locale = new Locale("en", "GB");
    LanguageConfiguration.setLanguageSelected(locale);
    LanguageConfiguration.setKeyboardLanguage(LanguageConfiguration.KeyboardLanguage.LATIN);

    //Create all interface components and add it to the view
    InterfaceControlsManager interfaceControlsManager = new InterfaceControlsManager();
    TLspSwingView view = interfaceControlsManager.loadSwingInterfaceControls();

    // Wrap the Swing view in an FX node so it can be added to the FX hierarchy
    SwingNode viewNode = new SwingNode();
    viewNode.setContent(view.getHostComponent());

    // Clean-up the view when the window is closed
    primaryStage_.setOnCloseRequest(event -> view.destroy());

    return viewNode;
}

When I call to loadExternalDllFiles(); I start to load the .dll file (rxtxSerial.dll), and it seems that it is being added properly when I see the information printed in my console, where the message "DLL is loaded from memory" is printed. After it is printed, I am getting the same error of the picture I've uploaded before. Here is what I am getting now: Error thrown after load the .dll file

Notice that the .jar library I want to add, RXTXcomm.jar, which allows me to read GPS frames, and its native library, rxtxSerial.dll, are in separated files, so the .dll is not package inside the .jar I think. See the image below of what the artifact has in its folder when it is created with the artifact configuration I show in the picture above: RXTXcomm.jar and rxtxSerial.dll in the artifact folder

Sorry for the lenght of the question. I am trying to put as many information I can because this is getting me crazy...

daniel lozano
  • 421
  • 6
  • 19

2 Answers2

1

Finally I found a way to not have this exception when I try to run my .jar application with the RXTXcomm.jar library on it.

I've followed the instructions of this link rxtx.qbang.org, "unjar section", from the RXTXcomm library wiki. I've unpackaged the RXTXcomm.jar library as it was a .zip or .rar file, and it unzip, among others, a folder called gnu. What I need to do is exactly what I was doing in the images of my question when I configured the artifact from "Project Structure / Artifacts".

After the artifact is built, I have to go to the artifact folder and paste the gnu folder retrieved from the unziping of the RXTXcomm.jar file.

After paste the gnu folder, I only need to use the command line to go to the artifact's path and run (only the first time) the command:

jar uvf Your_Apps_Name_here.jar gnu

In my case, "Your_Apps_Name_here.jar" is my FOMAD.jar. It will aggregate its classes like this: Adding gnu package

After running this command, only once, when the artifact is created, now I can run any time and with any problem my application, having no errors with the RXTXcomm.jar library during the execution as I had before (running as always: "java -jar MyApplication.jar").

daniel lozano
  • 421
  • 6
  • 19
0

You can add any file into the artifact from the Artifatc's Output Layout page using Add Copy of action or just include the file into project's resource directory - IDE will package it into the artifact.

enter image description here

But please note that you still will need to un-pack this file form the jar to be able to load it, see https://stackoverflow.com/a/1611367/2000323

Community
  • 1
  • 1
Andrey
  • 15,144
  • 25
  • 91
  • 187
  • thanks for your answer. The picture you attach is the same I am attaching in my question, I am adding the libraries in the same way you show in your picture. About the link you provide, I tried to follow the instructions and it seems that the .dll library is properly loaded. Notice that my RXTXcomm.jar, and its Native Library rxtxSerial.dll are already in separated files, so I think I don't need to unpackage it, am I wrong? I've updated the question with the result I get following the link you provide. What you think am I doing wrong here? Thanks a lot. – daniel lozano May 08 '20 at 16:32
  • `my RXTXcomm.jar, and its Native Library rxtxSerial.dll are already in separated files, so I think I don't need to unpackage it, am I wrong?` If you package them into single jar artifact you then will need to un-package the .dll out of jar to be able to read it. The point is - java can not read resource from the jar file archive - so it needs to be un-packed first. – Andrey May 09 '20 at 06:28
  • Thanks @Andrey, but I think I'm not getting it. As they already are two different files, they are not packaged. In the dependencies I am adding the RXTXcomm.jar, and as its Native Library, the rxtxSerial.dll, as I show in the third picture of my question, I am adding them independently, because they are two files. The .dll file is not inside the .jar, and when I create the artifact, you can see in my last picture how they are added to the artifact as two files. I am not getting the point of unpackage the RXTXcomm.jar and its native library because for me they are unpackaged from the beginning – daniel lozano May 09 '20 at 09:45
  • The resulting .jar of my project is called FOMAD.jar, and the RXTXcomm.jar library is a library to manage the frames of a gps from the COM port. The rxtxSerial.dll file is the native library of this RXTXcomm.jar I am trying to use. There is not a way to link the RXTXcomm.jar and its native library in the artifact configuration as it can be done in the Project Structure / Modules / Dependencies of the project (shown in the third picture)? – daniel lozano May 09 '20 at 09:48