1

Hi am working on a Java application that is built into a distribution file (a zip file) using the appassembler-maven-plugin. End-users extract the contents of the zip.

Using this plugin, we build a distribution structure that includes the required jars and two execution scripts (a shell script for unix and a batch script for windows). These scripts are generated automatically by the build process.

The pom file contains the following:

    ...
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <attach>true</attach>
                <descriptors>
                    <descriptor>src/main/resources/distribution.xml</descriptor>
                </descriptors>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- this is used for inheritance merges -->
                    <phase>package</phase>
                    <!-- bind to the packaging phase -->
                    <goals>
                        <goal>assembly</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>appassembler-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>assemble-standalone</id>
                    <phase>package</phase>
                    <goals>
                        <goal>assemble</goal>
                    </goals>
                    <configuration>
                        <programs>
                            <program>
                                <name>mixnet</name>
                                <mainClass>com.company.products.Application</mainClass>
                            </program>
                        </programs>
                        <repositoryLayout>flat</repositoryLayout>
                        <repositoryName>lib</repositoryName>
                        <configurationDirectory>properties</configurationDirectory>
                        <binFileExtensions>
                            <unix>.sh</unix>
                        </binFileExtensions>
                        <copyConfigurationDirectory>true</copyConfigurationDirectory>
                        <configurationSourceDirectory>src/main/resources</configurationSourceDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>build-helper-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>attach-distribution</id>
                    <phase>package</phase>
                    <goals>
                        <goal>attach-artifact</goal>
                    </goals>
                    <configuration>
                        <artifacts>
                            <artifact>
                                <file>target/${project.artifactId}-${project.version}-distribution.zip</file>
                                <type>zip</type>
                            </artifact>
                        </artifacts>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>

The generated shell script contains the following line which makes the actual call to Java:

%JAVACMD% %JAVA_OPTS% %EXTRA_JVM_ARGUMENTS% -classpath%CLASSPATH_PREFIX%;%CLASSPATH% -Dapp.name="mixnet" -Dapp.repo="%REPO%" -Dbasedir="%BASEDIR%" com.company.products.Application %CMD_LINE_ARGS%

The batch script contains the following line which makes the actual call to Java:

exec "$JAVACMD" $JAVA_OPTS \
  $EXTRA_JVM_ARGUMENTS \
 -classpath "$CLASSPATH" \
 -Dapp.name="mixnet" \
 -Dapp.pid="$$" \
 -Dapp.repo="$REPO" \
 -Dapp.home="$BASEDIR" \
 -Dbasedir="$BASEDIR" \
  com.company.products.Application \
  "$@"

We have now extended the Java program so that it uses native library files, these files are included in the distribution in a folder called "native" ( .dll files for windows and .so files for unix environments are included in the native directory)

I would like to edit the build process so that the generated scripts (both the shell script for unix and the batch script for windows) include the parameter "-Djava.library.path=PATH_OF_LIBRARY_FILES".

I have done some searching, but I cant find any documentation regarding support for this parameter in the appassembler plugin.

I tried to find a "hacky" solution by adding the "extraJvmArguments" tag to the application pom file, and specifing the "-Djava.library.path" parameter there, but I ran into problems with the path separator being different on windows and linux ("\" or "/"). I also thought about using "extraJvmArguments" and using a system variable to specify the path of the directory (which would have to be defined by the user), but this approach also has platform problems because a system variable is referenced using $VARIABLE_NAME on linux, but with %VARIABLE_NAME% on windows.

We could ask the end-users to edit the execution script themselves before they execute it, but it would be much better if the process was automatic, and totally transparent to the end-users. In this way, the end-users would not even know that they are running a Java application which is making use of JNI to call a native library.

I dont know any platform-neutral solution. Does appassembler already support this requirement? or how should this be handled?

user3441604
  • 582
  • 7
  • 23

3 Answers3

1

According to maven-assembly-plugin sources here and here, single setting <repositoryName>lib</repositoryName> controls both java.library.path and jar classpath dir.

Feel free to vote for feature request to have them separate:

Option to have native libraries in separate directory, not visible in classpath #62

Vadzim
  • 24,954
  • 11
  • 143
  • 151
0

I found a way of getting the desired result, but it involves duplicating quite a big part of the pom. I duplicated the execution section, and I added a platform specific extraJvmArguments value in each execution, as shown below. The build process then builds execution scripts with the correct platform specific paths.

            <executions>
                <execution>
                    <id>assemble-standalone-windows</id>
                    <phase>package</phase>
                    <goals>
                        <goal>assemble</goal>
                    </goals>
                    <configuration>
                        <extraJvmArguments>-Djava.library.path=.\..\native\lib</extraJvmArguments>
                        <programs>
                            <program>
                                <platforms>
                                    <platform>windows</platform>
                                </platforms>
                                <name>mixnet</name>
                                <mainClass>com.company.products.Application</mainClass>
                            </program>
                        </programs>
                        <repositoryLayout>flat</repositoryLayout>
                        <repositoryName>lib</repositoryName>
                        <configurationDirectory>properties</configurationDirectory>
                        <binFileExtensions>
                            <unix>.sh</unix>
                        </binFileExtensions>
                        <copyConfigurationDirectory>true</copyConfigurationDirectory>
                        <configurationSourceDirectory>src/main/resources</configurationSourceDirectory>
                    </configuration>
                </execution>
                <execution>
                    <id>assemble-standalone-unix</id>
                    <phase>package</phase>
                    <goals>
                        <goal>assemble</goal>
                    </goals>
                    <configuration>
                        <extraJvmArguments>-Djava.library.path=./../native/lib</extraJvmArguments>
                        <programs>
                            <program>
                                <platforms>
                                    <platform>unix</platform>
                                </platforms>
                                <name>mixnet</name>
                                <mainClass>com.scytl.products.ov.mixnet.Application</mainClass>
                            </program>
                        </programs>
                        <repositoryLayout>flat</repositoryLayout>
                        <repositoryName>lib</repositoryName>
                        <configurationDirectory>properties</configurationDirectory>
                        <binFileExtensions>
                            <unix>.sh</unix>
                        </binFileExtensions>
                        <copyConfigurationDirectory>true</copyConfigurationDirectory>
                        <configurationSourceDirectory>src/main/resources</configurationSourceDirectory>
                    </configuration>
                </execution>
            </executions>

Please share if you know a better way of solving the problem.

user3441604
  • 582
  • 7
  • 23
0

Here is the example from the official site: https://maven.apache.org/plugins/maven-assembly-plugin/usage.html

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>your main class</mainClass>
                    </manifest>
                </archive>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id> <!-- this is used for inheritance merges -->
                    <phase>package</phase> <!-- bind to the packaging phase -->
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
andrewchan2022
  • 4,953
  • 45
  • 48