How to run multiple inter-dependent maven modules - java

I have a multi-module maven OSGi project. I am using the maven-assembly-plugin to organise the different jars into a central folder, from which the OSGi container will be loading the various project modules:
dist pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>dist</artifactId>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>distro-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/bin.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<parent>
<groupId>rev</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
</project>
The module jars get put into the central folder as I wish to. I, however, with time, can't really keep track of how the module dependencies relate to each other. For example, a certain module might need that another module be started before it can get executed properly. How can I guarantee that before a module-B gets started, a module-A will first be started - I would like to configure this in a way that some code handles the order of execution?
This is the error I get when such order of execution is not right. I don't think the bundles get installed.
Exception in thread "main" org.osgi.framework.BundleException: Unable to resolve OSGiDmHelloWorldConsumer [2](R 2.0): missing requirement [OSGiDmHelloWorldConsumer [2](R 2.0)] osgi.wiring.package; (&(osgi.wiring.package=com.bw.osgi.provider.able)(version>=1.0.0)(!(version>=2.0.0))) Unresolved requirements: [[OSGiDmHelloWorldConsumer [2](R 2.0)] osgi.wiring.package; (&(osgi.wiring.package=com.bw.osgi.provider.able)(version>=1.0.0)(!(version>=2.0.0)))]
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4111)
at org.apache.felix.framework.Felix.startBundle(Felix.java:2117)
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998)
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:984)
at main.App.initialize(App.java:46)
at main.App.main(App.java:22)
Below is the class public class App {} that throws the error:
App
public class App {
public static void main(String[] args) throws BundleException, URISyntaxException {
App app = new App();
app.initialize();
}
private void initialize() throws BundleException, URISyntaxException {
Map<String, String> map = new HashMap<String, String>();
// make sure the cache is cleaned
map.put(Constants.FRAMEWORK_STORAGE_CLEAN, Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
map.put("ds.showtrace", "true");
map.put("ds.showerrors", "true");
FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();
Framework framework = frameworkFactory.newFramework(map);
System.out.println("Starting OSGi Framework");
framework.init();
loadScrBundle(framework);
String baseDir = "/D:/Maven-Assembly-Plugin-MM/dist/target/dist-1.0-SNAPSHOT-bin/plugins/";
framework.getBundleContext().installBundle("file:" + baseDir + "core-1.0.jar");
framework.getBundleContext().installBundle("file:" + baseDir + "clientfile-plugin-1.0-SNAPSHOT.jar");
framework.getBundleContext().installBundle("file:" + baseDir + "dist-1.0-SNAPSHOT.jar");
List<Bundle> bundles = new ArrayList<Bundle>();
for (Bundle bundle : framework.getBundleContext().getBundles()) {
bundle.start();
bundles.add(bundle);
System.out.println("Bundle Name: " + bundle.getSymbolicName());
System.out.println("Bundle ID: " + bundle.getBundleId());
if (bundle.getRegisteredServices() != null) {
for (ServiceReference<?> serviceReference : bundle.getRegisteredServices())
System.out.println("\tRegistered service: " + serviceReference);
}
}
System.out.println("Total Bundles: " + bundles.size());
}
private void loadScrBundle(Framework framework) throws URISyntaxException, BundleException {
URL url = getClass().getClassLoader().getResource("org/apache/felix/scr/ScrService.class");
if (url == null)
throw new RuntimeException("Could not find the class org.apache.felix.scr.ScrService");
String jarPath = url.toURI().getSchemeSpecificPart().replaceAll("!.*", "");
System.out.println("Found declarative services implementation: " + jarPath);
framework.getBundleContext().installBundle(jarPath).start();
}
}
How can I go about resolving this? Thank you all in advance.
UPDATE
The module jars get put into the central folder as I wish to. I, however, get the following error for all the modules except the felix modules when I try to run the project after calling mvn clean install, ie, all modules from the central maven repository, such as org.apache.felix.framework and org.apache.felix.scr are run in the OSGi container, except those I write myself.
The Problem In Greater Detail
I have published a the a very short version of the problem project in greater detail HERE, Maven-Assembly-Plugin-MM. This, OSGi - Simple Hello World with services, is the tutorial that I followed.
Eclipse:
Import > Existing Maven Projects > C:\***Path***\Maven-Assembly-Plugin-MM

Bundle loading order should not matter in OSGi applications.
But OSGi services might have dependencies to other services.
You can use a framework such as Declarative Services to easily manage dependencies (eg. using the SCR annotations).
You'll need the following plugin:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<executions>
<execution>
<id>generate-scr-scrdescriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
And the following dependencies:
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<!-- only needed at compile time, not at runtime -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr</artifactId>
<scope>runtime</scope>
</dependency>

Related

"A bean with that name has already been defined" error coming in spring boot multi module project

I am working with one spring boot multi module maven project, here i am getting below exception, every time when i run application it fails for different different files.
The bean 'evServiceCpeRepository' could not be registered. A bean with that name has already been defined
this project has three module sbill , amr and executable ,
this all classes i have in sbill module... amr module is empty it has just one controller and in amr module pom file i have added dependency for sbill module because amr module can access classes of sbill.
executable module just contain spring boot main class , apart from that no any classes this module is executable module.
#SpringBootApplication
#ComponentScan(basePackages = { "com"})
#EntityScan(basePackages = { "com"})
#EnableJpaRepositories(basePackages = { "com"})
public class MainClass {public static void main(String[] args) {
SpringApplication.run(MainClass.class, args);
}}
pom of executable module
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.sbill</groupId>
<artifactId>sbill-wrapper</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<packaging>war</packaging>
<artifactId>executable</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.sbill</groupId>
<artifactId>sbill</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sbill</groupId>
<artifactId>amr</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- Adding plugin of mavan resource to copy dist folder for war -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/classes/static/</outputDirectory>
<resources>
<resource>
<directory>../web/dist</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I am able to resolve this issue myself...
issue was related to #EnableJpaRepositories(basePackages = { "com"}) annotation. this annotation i have put in Mainclass.java file and this annotation was already there in one configuration file of module sbill.
so two times spring was trying to create beans that's why it was failing.
i removed that annotation from another configuration file and its works perfectly fine.

Share properties between maven plugin and the calling maven project pom

I have created a Maven Plugin P, which I want to use as a dependency in another Maven project A. I am providing some parameters to that the plugin P from the pom of Maven project A.
I want to set some properties in plugin P based on parameters provided by project A and want them to be referenced in pom of project A. How can I do that ?
I have tried setting properties for MavenProject in the plugin P. How can I refer them in the pom for project A?
Project A pom snippet:
<plugin>
<groupId>sample.plugin</groupId>
<artifactId>sample-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>testing</goal>
</goals>
<configuration>
<param1>value1</param1>
<param2>value2</param2>
</configuration>
</execution>
</executions>
</plugin>
Plugin P code snippet
#Mojo( name = "testing")
public class TestMojo extends AbstractMojo
{
.
.
#Parameter(property = "param1")
private String param1;
#Parameter(property = "param2")
private String param2;
#Parameter(defaultValue = "${project}")
private org.apache.maven.project.MavenProject project;
public void execute() throws MojoExecutionException
{
if(param1.equalsIgnoreCase("value1")){
project.getProperties().setProperty("PROP1","val1");
} else{
project.getProperties().setProperty("PROP1","val3");
}
if(param2.equalsIgnoreCase("value2")){
project.getProperties().setProperty("PROP2","val2");
} else{
project.getProperties().setProperty("PROP2","val3");
}
}
}
I expect the PROP1 and PROP2 to be used in project A
Found the solution, if we add ${project} A as a parameter to the plugin configuration, we can add properties to it, which can be referred in project A pom.
Ex:
<plugin>
<groupId>sample.plugin</groupId>
<artifactId>sample-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>testing</goal>
</goals>
<configuration>
<param1>value1</param1>
<param2>value2</param2>
<project>${project}</project>
</configuration>
</execution>
</executions>
</plugin>
in Plugin one can use this Maven project
project.getProperties.setProperty("projectProperty",propertyValue);
If i'm understanding this question correctly, try adding:
<dependencies>
<dependency>
<groupId>sample.plugin</groupId>
<artifactId>sample-plugin</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
at the bottom of Plugin P's pom.xml file, right before the end of </project>
I am not entirely sure this will even work as I have limited knowledge of Maven, but please let me know.
Best of luck to you.

Use ANTLR v4 runtime within eclipse plugin

Hello I am new in eclipse-plugin development and I am starting a project to incorporate a translator in an eclipse-plugin and for this purpose I started by using the eclipse plugin hello word example and the grammar file provided in this example, I am able to compile my project and run the plug in but when I try to load the parser I get an exception 'Caused by: java.lang.NoClassDefFoundError: org/antlr/v4/runtime/CharStream', I don't know what the problem could be, I have already tested the parser, but outside plug in environment and works fine.
I am also trying to incorporate maven to download the dependencies and run antlr so I added this in the pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.plugin.helloworld</groupId>
<artifactId>org.plugin.helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
<version>4.7.1</version>
</dependency>
</dependencies>
<build>
<defaultGoal>install</defaultGoal>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.7.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>4.7.1</version>
<configuration>
<sourceDirectory>src/evaluator</sourceDirectory>
<outputDirectory>src/evaluator</outputDirectory>
<visitor>true</visitor>
<listener>false</listener>
</configuration>
<executions>
<execution>
<id>antlr</id>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
I am using the lexer and the parser as follows:
public class SampleHandler extends AbstractHandler {
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
CharStream in = CharStreams.fromString("\"12*(5-6)\"");
evaluatorLexer lexer = new evaluatorLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
evaluatorParser parser = new evaluatorParser(tokens);
MessageDialog.openInformation(
window.getShell(),
"Helloworld",
parser.eval().toString());
return null;
}
}
And the referenced libraries like this:
I set the build.properties as follows
source.. = src/
output.. = bin/
bin.includes = plugin.xml,\
META-INF/,\
.,\
icons/,\
lib/antlr4-runtime-4.7.1.jar,\
lib/ST4-4.0.8.jar,\
lib/antlr4-4.7.1.jar,\
lib/antlr4-runtime-4.7.1-sources.jar
I read about adding as a bundle in the manifest but I can't find that option in the dependencies tab just the org.antlr.runtime not the v4.
You need to add the jars to the Bundle-Classpathin the MANIFEST.MF.
In the MANIFEST.MF editor do this on the 'Runtime' tab. In the 'Classpath' section click 'Add...' and add the jars, be sure to leave the '.' entry which represents your normal code.
Your Bundle-Classpath should end up looking something like:
Bundle-ClassPath: .,
lib/antlr4-runtime-4.7.1.jar,
lib/ST4-4.0.8.jar,
lib/antlr4-4.7.1.jar,
lib/antlr4-runtime-4.7.1-sources.jar

unable to satisfy dependency from com.lmax.disruptor 3.2.0 to package sun.misc 0.0.0

I am developing an eclipse plugin which needs an com.lmax.disruptor.It imports sun.misc. I have this in my p2 repository but when I maven build my plugin I am getting this error "unable to satisfy dependency from com.lmax.disruptor 3.2.0 to package sun.misc 0.0.0."
I have gone through the sites Resolve a dependency on package sun.misc with Tycho they are saying to create a plugin fragment but when I tried to create it and added export page as sun.misc, It is throwing an error like "package sun.misc doesnot exsist in the plugin".
How can solve this issue please help me with this.? Instead of creating new plugin fragment,is there is any possible way i can add in my plugin itself ?
Thanks,
As mentioned in oberlies' answer in the question you link to, you need to build a system bundle fragment, which exposes, i.e., exports, the sun.misc package. I don't know of any other way. However, this is easier than could be expected.
You do this by creating an OSGi MANIFEST.MF that exports sun.misc, and then bundle it into a fragment. This is done via Maven as follows.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>your.group</groupId>
<version>1.0.0</version>
<artifactId>your.group.fragment.sun.misc</artifactId>
<packaging>jar</packaging>
<name>System Bundle Fragment exporting sun.misc</name>
<description>This bundle extends the System Bundle export list with the sun.misc package such that OSGi bundles may refer to Sun's misc implementation without the OSGi framework itself to provide it in a non-portable way.</description>
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<forceCreation>true</forceCreation>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
<manifestEntries>
<Export-Package>sun.misc</Export-Package>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.5.4</version>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Category>your.group</Bundle-Category>
<Fragment-Host>system.bundle; extension:=framework</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
Run mvn clean install on this POM. Now you need to make the fragment consumable for Tycho, i.e., you need to make it available via a p2 Software Site.
Thankfully there is a great Maven plugin which can help with that: reficio's p2-maven-plugin. You can use it to basically wrap any mavenized JAR into an OSGi bundle and then provide it via a p2 site.
Set up the respective POM as follows.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sun-misc-p2</groupId>
<artifactId>site</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.reficio</groupId>
<artifactId>p2-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<artifacts>
<!-- specify your depencies here -->
<!-- groupId:artifactId:version -->
<artifact><id>com.lmax:disruptor:3.3.2</id></artifact>
<artifact><id>your.group:your.group.fragment.sun.misc:1.0.0</id></artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.5.v20120716</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<webAppSourceDirectory>${basedir}/target/repository/</webAppSourceDirectory>
<webApp>
<contextPath>/site</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>reficio</id>
<url>http://repo.reficio.org/maven/</url>
</pluginRepository>
</pluginRepositories>
</project>
Note that I use this plugin to provide the LMAX Disruptor (version 3.3.2, the latest one at the time of writing, is thankfully available from Maven Central).
Run mvn p2:site on the POM. This will create a p2 site containing the sun.misc fragment at {project-folder}/target/repository.
This p2 repository - and with it the sun.misc fragment - can now be added to your target platform, and hence used in your Tycho build.
This should fix it, and - to answer your question if "there is any possible way [you] can add in [your] plugin itself" - this is the only possible way to do it (I know of).
The sources are also available at https://github.com/newcodeontheblock/eclipse-rcp-with-async-logging. The whole procedure is also described in more detail in this - my - blog post about using async Log4j 2 loggers in an Eclipse RCP.

Including shared object in maven assembly

I'm currently trying to build my project with maven and sqlite4java. Which is available in the offical maven repositories.
The offical sqlite4java page on google code does have an example configuration but it's a bit outdated and does not suit my needs. I want to have a single .jar-File in the end which i can deploy elsewhere. The problem here is the shared object depedency. I am using the official build goal from their page to copy the so to the build.dir/lib but my assembly goal crashes with:
[INFO] Failed to create assembly: Error adding file-set for 'com.almworks.sqlite4java:libsqlite4java-linux-i386:so:0.282' to archive: Error adding archived file-set. PlexusIoResourceCollection not found for: /home/lhw/.m2/repository/com/almworks/sqlite4java/libsqlite4java-linux-i386/0.282/libsqlite4java-linux-i386-0.282.so
No such archiver: 'so'.
​
What am I doing wrong? Here is my current pom.xml stripped from some dependencies unrelated to this topic
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.ring0.lhw</groupId>
<artifactId>system</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.almworks.sqlite4java</groupId>
<artifactId>sqlite4java</artifactId>
<version>${sqlite4java.version}</version>
</dependency>
<dependency>
<groupId>com.almworks.sqlite4java</groupId>
<artifactId>libsqlite4java-linux-i386</artifactId>
<version>${sqlite4java.version}</version>
<type>so</type>
</dependency>
</dependencies>
<properties>
<sqlite4java.version>0.282</sqlite4java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>compile</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.almworks.sqlite4java</groupId>
<artifactId>libsqlite4java-linux-i386</artifactId>
<version>${sqlite4java.version}</version>
<type>so</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.2</version>
<configuration>
<skipTests>true</skipTests>
<systemProperties>
<property>
<name>sqlite4java.library.path</name>
<value>${project.build.directory}/lib</value>
</property>
</systemProperties>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>de.ring0.lhw.Init</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Edit :
I think that the jar-with-dependencies assembly descriptor tries to unpack the dependencies.
See the link :
http://maven.apache.org/plugins/maven-assembly-plugin/descriptor-refs.html
maven.apache.org/plugins/maven-assembly-plugin/… ...
<unpack>true</unpack>
And of course it fails to unpack the .so
So you might have to use a custom assembly to perform what you want to do
It is possible to create executable jar with stock "jar-with-dependencies" assembly descriptor and without using any startup shell/batch scripts. However, it requires dirty workarounds that doesn't involve much Maven configurations.
We need to place all native libraries (included in sqlite4java zip download) to src/main/resources directory. Also remove sqlite4java native library dependency from your Maven POM file.
Because sqlite4java's native library loader doesn't look at your classpath or inside of JAR file, you have to extract native libraries at startup, and set "sqlite4java.library.path" system property at runtime. Please see the following sample code:
/** List of native libraries you put in src/main/resources */
public static final String[] NATIVE_LIB_FILENAMES = {
"libsqlite4java-linux-amd64.so",
"libsqlite4java-linux-i386.so",
"libsqlite4java-osx.jnilib",
"libsqlite4java-osx-10.4.jnilib",
"libsqlite4java-osx-ppc.jnilib",
"sqlite4java-win32-x64.dll",
"sqlite4java-win32-x86.dll",
};
/**
* Extract native libraries to the current directory.
* This example needs Apache Commons IO (https://commons.apache.org/proper/commons-io/)
*/
public static void extractNativeResources() {
for(String filename: NATIVE_LIB_FILENAMES) {
// Change "DemoSQLite2" to your class name
final InputStream in = DemoSQLite2.class.getResourceAsStream("/"+filename);
if(in != null) {
try {
System.out.println("Extracting " + filename);
FileUtils.copyInputStreamToFile(in, new File(filename));
} catch (IOException e) {
System.err.println("Can't extract " + filename);
e.printStackTrace();
}
}
}
}
/**
* Delete native libraries in the current directory
*/
public static void removeNativeResources() {
for(String filename: NATIVE_LIB_FILENAMES) {
File file = new File(filename);
file.delete();
}
}
public static void main(String[] args) throws Exception {
boolean deleteNativesOnExit = false; // Delete natives on exit
// Extract native libraries if sqlite4java.library.path property is not set
String sqlitePath = System.getProperty("sqlite4java.library.path");
if(sqlitePath == null) {
System.setProperty("sqlite4java.library.path", "."); // Read natives from current directory
extractNativeResources();
deleteNativesOnExit = true;
}
// Do SQLite jobs here
final SQLiteConnection db = new SQLiteConnection(new File("test.db"));
try {
db.open();
db.dispose();
System.out.println("Success");
} catch (Exception e) {
e.printStackTrace();
System.err.println("FAILED");
}
// Delete the native libraries we extracted
if(deleteNativesOnExit) removeNativeResources();
}
Now your app should be buildable with standard "jar-with-dependencies" descriptor, and your app is runnable with standard "java -jar your_jar.jar" command.
Of course, if sqlite4java gets updates in future, you have to manually update the native libraries in your resource directory.
If you have a better, less dirty solution, please let me know!

Categories

Resources