I am writing a karaf bundle which depends on an external jar library. I understand I may import this bundle in my features.xml using wrap but this means it gets loaded into its own classloader.
What I want is for my bundle's classloader to load whatever I access in this jar file and I want to make direct method calls to the classes in this jar file. How can I do this?
I don't want a new bundle - just a library that I can link my application to.
Thanks,
You can try to embed the external jar when building your bundle as follow:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>
...,
root_package_in_external_jar*,
...
</Export-Package>
<Import-Package>
...
</Import-Package>
<Embed-Dependency>your_external_jar</Embed-Dependency>
</instructions>
</configuration>
</plugin>
I'm suceeded with adding OSGi specific meta-data to the MANIFEST of the flying-saucer-pdf Maven artifact. However, I do not succeed with embedding the dependencies and transitive dependencies of that artifact into the created JAR file.
I was using the original sources from flying-saucer-pdf taken from GitHub [1] and added the following statements to the pom.xml file:
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Embed-Dependency>itext</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
</instructions>
</configuration>
</execution>
</executions>
</plugin>
The artifact has a dependency declared to itext version 2.1.7 in its original pom.xml which I did not touch. I also did not mess with the original packaging type of the artifact which is jar.
Unfortunately, this does only part of the work. The MANIFEST.MF seems correct and contains the expected OSGi tags:
Manifest-Version: 1.0
Bundle-Description: Flying Saucer is a CSS 2.1 renderer written in Jav
a. This artifact supports PDF output.
Bundle-License: http://www.gnu.org/licenses/lgpl.html
Bundle-SymbolicName: org.xhtmlrenderer.flying-saucer-pdf
Archiver-Version: Plexus Archiver
Built-By: u0400072
Bnd-LastModified: 1478168053263
Bundle-ManifestVersion: 2
Embed-Dependency: itext
Import-Package: com.apple.mrj,com.lowagie.toolbox,javax.crypto,javax.i
mageio,javax.imageio.metadata,javax.imageio.plugins.jpeg,javax.imagei
o.stream,javax.swing,javax.xml.parsers,javax.xml.transform,javax.xml.
transform.dom,javax.xml.transform.sax,javax.xml.transform.stream,org.
bouncycastle.asn1,org.bouncycastle.asn1.cmp,org.bouncycastle.asn1.cms
,org.bouncycastle.asn1.ocsp,org.bouncycastle.asn1.pkcs,org.bouncycast
le.asn1.tsp,org.bouncycastle.asn1.x509,org.bouncycastle.cms,org.bounc
ycastle.crypto,org.bouncycastle.crypto.engines,org.bouncycastle.crypt
o.modes,org.bouncycastle.crypto.paddings,org.bouncycastle.crypto.para
ms,org.bouncycastle.jce.provider,org.bouncycastle.ocsp,org.bouncycast
le.tsp,org.w3c.dom,org.xhtmlrenderer.context,org.xhtmlrenderer.css.co
nstants,org.xhtmlrenderer.css.extend,org.xhtmlrenderer.css.parser,org
.xhtmlrenderer.css.sheet,org.xhtmlrenderer.css.style,org.xhtmlrendere
r.css.style.derived,org.xhtmlrenderer.css.value,org.xhtmlrenderer.ext
end,org.xhtmlrenderer.layout,org.xhtmlrenderer.render,org.xhtmlrender
er.resource,org.xhtmlrenderer.simple.extend,org.xhtmlrenderer.swing,o
rg.xhtmlrenderer.util,org.xml.sax,org.xml.sax.helpers
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))"
Tool: Bnd-3.2.0.201605172007
Embedded-Artifacts: itext-2.1.7.jar;g="com.lowagie";a="itext";v="2.1.7
"
Export-Package: org.xhtmlrenderer.pdf;uses:="org.w3c.dom,org.xhtmlrend
erer.css.constants,org.xhtmlrenderer.css.parser,org.xhtmlrenderer.css
.style,org.xhtmlrenderer.css.value,org.xhtmlrenderer.extend,org.xhtml
renderer.layout,org.xhtmlrenderer.render,org.xhtmlrenderer.resource,o
rg.xhtmlrenderer.simple.extend,org.xhtmlrenderer.swing,org.xml.sax";v
ersion="9.0.10",org.xhtmlrenderer.pdf.util;uses:="org.w3c.dom,org.xht
mlrenderer.pdf";version="9.0.10",org.xhtmlrenderer.simple;uses:="java
x.swing,org.w3c.dom,org.xhtmlrenderer.css.extend,org.xhtmlrenderer.cs
s.sheet,org.xhtmlrenderer.extend,org.xhtmlrenderer.layout,org.xhtmlre
nderer.swing,org.xhtmlrenderer.util";version="9.0.10"
Bundle-Name: Flying Saucer PDF Rendering
Bundle-Version: 9.0.10.SNAPSHOT
Bundle-ClassPath: .,itext-2.1.7.jar
Embed-Transitive: true
Created-By: Apache Maven Bundle Plugin
Build-Jdk: 1.8.0_102
But the itext library is not put into the resulting JAR, i.e. the Bundle-ClassPath entry of the MANIFEST points to a missing content.
In addition I tried to create an entirely new artifact which declares a dependency to the original flying-saucer-pdf artifact and re-bundles it as an OSGi bundle flowing this answer [2] here on StackOverflow and this worked.
The only real difference that I can see is the packaging type 'bundle' vs. 'jar'. But I cannot change that packaging type in the original flying-saucer-pdf artifact since everything needs to stay as is for non-OSGi-usages in order to get that change accepted as a Push Request.
Do you guys know if this embedding dependencies with the maven-bundle-plugin can actually work with the packaging type 'jar'? Or does it need the packaging type 'bundle'?
I appreciate any response and hint of what I could try to get that re-bundling done directly within the original artifact.
Thank you very much.
Regards
Timo Rohrberg
There are two ways to use the maven bundle plugin.
The first way is to use
<extensions>true</extensions> and <packaging>bundle</packaging>
In this case the maven bundle plugin is in charge of all build steps and can influence the jar file contents.
The second way is to use the manifest goal and add the manifest in the jar plugin. In this case maven bundle plugin can only influence the jar. It can not embed any other library or copy over external private classes.
So if you need embedding then the only way is to change the packaging.
So I think there are two solutions that do not influence the original jar too much.
Do not embed and install the dependencies as bundles
Create a spearate module in the build to create a bundle that is then available additionally to the original jar
ServiceMix's documentation on creating a custom distribution merely states the steps to creating a custom karaf distribution. I understand that Karaf is the backbone of ServiceMix and ServiceMix is a custom distribution of Karaf.
Has anyone actually built a custom esb on top of servicemix rather than on top of karaf? If so how did you do it?
How did you stage the project with servicemix's src?
Here are some steps that I wish I had when trying to figure this out...
Download the sources for the version of service mix you want to build on: https://github.com/apache/servicemix/releases
Unpack the sources zip into any folder.
Create a project with the following layout:
MyESB
pom.xml
src
main
java
Copy the contents from the pom.xml located in apache-service-mix-x.x.x-src/assembly to your pom.xml
In that pom.xml, replace the artifactId, and name to look something like this:
<parent>
<groupId>org.apache.servicemix</groupId>
<artifactId>parent</artifactId>
<version>5.4.0</version>
</parent>
<groupId>com.mycompany.esb</groupId>
<artifactId>mycustom-esb</artifactId>
<packaging>pom</packaging>
<name>Custom :: ESB</name>
Copy the resource directories of apache-service-mix-x.x.x-src/assembly/src/main to MyESB/src/main.
Make whatever customizations you want to the org.apache.karaf.tooling:features-maven-plugin or the configuratoin files in the resource directories you just copied over.
For example, If you wanted to add a particular feature you could do the following edits to your pom.xml:
Add a features.xml to add-features-to-repo configuration descriptors
Add myfeature to the add-features-to-repo features list
To have that feature started by default, add the feature to the featuresBoot property located here: MyESB\src\main\filtered-resources\etc\org.apache.karaf.features.cfg
Run the maven install target! This will build a zip file into the MyESB/target folder. Now you can unplack that and run servicemix.bat
After starting your ESB, verify that your feature is installed by entering the following command into the Karaf console:
features:list | grep myfeature
Well, just do it like servicemix itself it does. And tbh it's just the way it's described in the Karaf documentation.
For an example you might want to look here
In short define it in your custom assembly POM, take a look at the following snippet:
<plugins>
<plugin>
<groupId>org.apache.karaf.tooling</groupId>
<artifactId>karaf-maven-plugin</artifactId>
<version>${karaf.version}</version>
<executions>
<execution>
<id>add-features-to-repo</id>
<phase>compile</phase>
<goals>
<goal>features-add-to-repository</goal>
</goals>
<configuration>
<descriptors>
<descriptor>mvn:org.apache.karaf.features/standard/${karaf.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.karaf.features/enterprise/${karaf.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.karaf.features/spring/${karaf.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.activemq/activemq-karaf/${activemq.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.camel.karaf/apache-camel/${camel.version}/xml/features</descriptor>
<descriptor>mvn:org.apache.cxf.karaf/apache-cxf/${cxf.version}/xml/features</descriptor>
<descriptor>file:${basedir}/target/classes/internal.xml</descriptor>
<descriptor>file:${basedir}/target/classes/features.xml</descriptor>
<descriptor>file:${basedir}/target/classes/examples.xml</descriptor>
</descriptors>
<features>
<feature>cxf</feature>
<feature>obr</feature>
<feature>config</feature>
<feature>standard</feature>
<feature>package</feature>
<feature>kar</feature>
<feature>ssh</feature>
<feature>management</feature>
<feature>eventadmin</feature>
<feature>activemq-broker-noweb</feature>
<feature>activemq-service</feature>
<feature>camel</feature>
<feature>camel-cxf</feature>
<feature>activemq-camel</feature>
<feature>camel-blueprint</feature>
<feature>war</feature>
<feature>jaxrs-api</feature>
</features>
<includeMvnBasedDescriptors>true</includeMvnBasedDescriptors>
<repository>target/features-repo</repository>
</configuration>
<inherited>false</inherited>
</execution>
</executions>
</plugin>
If you need your own custom bundles/features make sure you
a) have a feature descriptor for your own bundles
b) define the feature descriptor
c) tell the plugin to use the corresponding feature
I am currently working on a project that includes using JNotify to monitor when a directory/file has been created, renamed/modified, and deleted. The project is being built in Java 6, not Java 7. JNotify uses JNI to hook into the native OS to monitor the directory/file. My problem is that I need to get JNotify into our repo but I want it to be built so that the java.library.path (DLL) is packaged with the JNI JAR. How would I go about doing that in Maven?
I was able to find the solution I needed using the following maven plugin: http://code.google.com/p/mavennatives/
You must probably upload the jar manually to your archiva instance.
The repository format is fixed, so you will need to perform the rename after retrieving the artifact. That depends how you intend to use it after it is retrieved.
This is a common pattern is something like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<stripVersion>true</stripVersion>
</configuration>
<executions>
<execution>
<id>copy-jnotify</id>
<configuration>
<includeArtifactIds>JNotify</includeArtifactIds>
<outputDirectory>${project.build.directory}/my-app</outputDirectory>
</configuration>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
You can use this with the appropriate list of artifacts that will all be copied into the target/my-app directory
We're using maven to build a flex project using flex-mojo's, which is great. The problem is I can't add the swc dependencies specified in the pom to the flex build path. As far as I can see Flex Builder only lets you use an absolute path, so it can't see the maven dependencies even when using the m2eclipse plugin to add maven support.
Has anyone found a way to build with both maven and Flex Builder without duplicating the dependencies?
Flex-mojos now supports doing this using the flexmojos:flexbuilder goal. It's not perfect for nested projects but seems to work well in all other cases.
This is not a particularly elegant answer, but it may serve your purposes.
You can use the maven-dependency-plugin to output the classpath to a file. The build-classpath is the relevant goal. the configuration below will output Maven's classpath to [project directory]/target/.mavenClasspath
You could write a small script or ant task to read the .mavenClasspath file contents and append the entries to the Eclipse .classpath. If you make the script a bit smarter and remove previous entries, then set it up as an external builder, you have a nearly integrated solution.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>output-classpath</id>
<phase>package</phase>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<outputFile>${project.build.directory}.mavenClasspath</outputFile>
</configuration>
</execution>
</executions>
</plugin>
Flex Builder can now handle relative paths (see bug report); you can add them to your .actionScriptProperties as follows:
<libraryPathEntry kind="3" linkType="1" path="${M2_HOME}/repository/flexlib/flexlib/2.4/flexunit-2.4.swc" useDefaultLinkType="false"/>