I am trying to convert my project into an OSGI application. I have few doubts. Suppose ModuleA in my application is dependent on external jars jarA and jarB. Now to make ModeuleA run, I am embedding both the jars using embed-dependency property of maven-bundle-plugin.
Now suppose I have another module ModuleB which is also dependent on jarA. So this module also embeds the jarA. My project ends up having jarA being embedded 2 times which will unnecessarily bloat the size of project.
Is there any way to tell OSGI to load jarA only once and provide it to both the modules.
If converting these jars to OSGI bundles is the only solution, I have few more questions:
What is the easiest way to convert jar to a bundle. BND tool looks like a good solution but I am not able to find proper documentation about it.
jarA will also have some dependent jars. So do I need to convert all the dependent jars to bundles also. My project has more than 100 jars. How can I automate this process.
Thanks in advance :)
There are actually to solutions to this, both a little bit different from what you are doing right now:
Build one "third party dependencies" bundle, which will embed all of the non OSGi dependencies your project has.
Convert every non OSGi dependency to a OSGi bundle.
Option 1 is easier to handle so I think most projects do this. I, personally, prefer option 2. We have a Maven "pom.xml" template that we use to convert those dependencies.
The "pom.xml" looks like this:
<?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>
<properties>
<library.groupId></library.groupId>
<library.artifactId></library.artifactId>
<library.version></library.version>
</properties>
<artifactId></artifactId>
<packaging>bundle</packaging>
<name></name>
<description>${library.groupId}:${library.artifactId}:${library.version}</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>*;resolution:=optional</Import-Package>
<Export-Package>*</Export-Package>
<Embed-Dependency>*;scope=compile|runtime;inline=true</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>${library.groupId}</groupId>
<artifactId>${library.artifactId}</artifactId>
<version>${library.version}</version>
</dependency>
</dependencies>
</project>
This does:
Add the non OSGi library as dependency
Tell maven-bundle-plugin to embed this dependency (transitive)
Tell maven-bundle-plugin to export all of the dependencies packages
I left some things blank that you have to set like library.groupId, library.artifactId and library.version. And somethings we need to tweak the configuration of the maven-bundle-plugin. But this is our starting point. Somethings for example, you do not want to export all packages etc.
If you really have 100+ dependencies that you need to convert you might be better of using this template and just adding all of your 100 dependencies as dependency and build one big bundle with all of them inside.
You can find the documentation for the maven-bundle-plugin here:
https://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html
At this point I also want to mention that there is a new bundle plugin that you might want to consider for this: bnd-maven-plugin.
See: https://github.com/bndtools/bnd/tree/master/maven/bnd-maven-plugin
Related
Is there a way to translate this human language in an xml codeblock that Maven will happily understand?
Hey Maven, look you are a great dependency management system. I am working on a JavaEE project which is intended to be deployed on Wildfly 10.1.0. Please put all Libraries that are specified in Wildflys parent BOM http://repo1.maven.org/maven2/org/wildfly/wildfly-parent/10.1.0.Final/wildfly-parent-10.1.0.Final.pom on the compiletime classpath and consider them as provided by Wildfly at runtime. And please dont bother me to list every single referenced artifact in the dependencies section of the projects pom file. Thank you Maven, you are so cool.
To clarify:
As far as I understand, importing the bom file in the dependencyManagement section of my pom file will only spare me to specify the Version Number of every single artifact, but I will still have to declare every artifactID and groupID.
This is indeed discussed here How to use BOM file with Maven
But in this answer is also stated:
Then you do not have to specify the version attribute of a dependency.
I would prefer to declare only that I am using wildfly and then be able to use all client libraries without declaring any other dependencies.
But I must admit, I have the feeling to miss something obvious. There should be an easy way to do this.
If you want everything in a another pom to be set as a dependency and as provided you can specify that in your pom. A minimal pom for wildfly 10.1.0.Final that includes everything seems to be 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>wft</groupId>
<artifactId>wft</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>wft</name>
<description>wft</description>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-spec-api</artifactId>
<version>10.1.0.Final</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
But I would still recommend doing it the way that wildfly does it themselves, which is to put the BOM in the depencency management section and declare artifacts as you need them. Why? I don't know other than it's cleaner to read and maybe easier for maven/java to compile and build.
There are lots of tutorials, which shows how to cope with dependencies of the OSGi project and how should they be converted to the bundle. After more than one day research, I have still not found how to deal with the dependencies with provided scope.
Let me give an example. I am currently using Dropbox (dropbox-core-sdk 3.0) and it has two dependencies (com.google.android and javax.servlet) with provided scope. When I use the techniques such as maven-bundle-plugin or bnd, it only downloads the artifacts and its transitive dependencies. However, I need also provided dependencies in order to be able to import my project to the OSGi container.
I am using maven-bundle-plugin and my pom.xml looks like:
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId};singleton:=true</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Export-Package>*</Export-Package>
<Embed-Transitive>true</Embed-Transitive>
<Embed-Dependency>*</Embed-Dependency>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
even if Embed-Dependency says include everything, only the dependencies + transitive dependencies are in the jar. However, I want the provided-scoped jars are also in the jar.
Is there any way to download dependencies with provided scope. If not, how to deal with this situation?
I would have to defer to the Maven BND experts out there, but I don't think you can include provided dependencies through a Maven build. Since it is unlikely you will be using the Android components outside of your bundle, couldn't you just manually download the needed Jars and place them in your bundle (Bundle-Classpath)?
I think you can specify the scopes of the dependencies you want to embed. Be careful though that some dependencies like the OSGi spec jars should never be deployed.
In general you may only embed dependencies that are hidden inside the bundle. Any packages that are needed to talk to other bundles should better not deployed.
For example the servlet api is typically provided by the httpservice bundle you use.
Try this option:
<Embed-Dependency>*;scope=compile|provided</Embed-Dependency>
I have a pom.xml file, and I have commented one dependency and one plugin. After this I refreshed and made reimport, but the plugin works anyway. I can't understand why, because it is absent in the pom.xml.
Actually I try to change output directory for the Surefire Plugin, but it is always target/surefire.
<?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>
<groupId>TEST</groupId>
<artifactId>TEST</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<!--<org.apache.maven.surefire.version>2.19.1</org.apache.maven.surefire.version>-->
</properties>
<!--<reporting>-->
<!--<plugins>-->
<!--<plugin>-->
<!--<groupId>org.apache.maven.plugins</groupId>-->
<!--<artifactId>maven-surefire-report-plugin</artifactId>-->
<!--<version>2.19.1</version>-->
<!--</plugin>-->
<!--</plugins>-->
<!--</reporting>-->
<dependencies>
<!--<dependency>-->
<!--<groupId>org.apache.maven.surefire</groupId>-->
<!--<artifactId>surefire</artifactId>-->
<!--<version>${org.apache.maven.surefire.version}</version>-->
<!--<type>pom</type>-->
<!--</dependency>-->
</dependencies>
</project>
There are several misconceptions with the question. Let's go through them.
Why is a plugin being invoked when I commented a dependency?
Because a <dependency> has no effect at all on the execution of plugins. This is used to declare what your project depends on in order to compile it and run it. It is separate from the actual build process of your project, which is launched by Maven and invokes several plugins to do some tasks, like performing the actual compilation or copying files, etc.
Why is a plugin being invoked when I commented it out?!
The explanation relies on the existence of build lifecycles. To put it simply, a lifecycle consists of several phases, which consists themselves of plugin goals. There are multiple lifecycles possible but the default one is the central one and typically governs the packaging and deployment of the project. The phases are, for example, compile which represents the phase in which the project's sources are being compiled, or package which represents the phase where the project is being packaged into a deliverable, or test which represents the unit-testing of your project.
And, also by default, there are several plugins already bound to phases of the default lifecycle (depending on the packaging). You will notice that there is:
test: surefire:test
which means that, in the test phase of the default lifecycle (for certain packaging), the goal surefire:test is going to be invoked (see also the documentation). This is what you're seeing here: maven-surefire-plugin, whose prefix is surefire and was used above, has a goal called test, whose purpose is to run the test classes of your project.
There's a second consideration. The explanation above refers to build plugins, declared in the <build><plugins><plugin> element of your POM. What you commented out was actually the <reporting> section, which contains the reporting plugins invoked when generating a website for your project.
The actual question
Actually I try to change output directory for surefire plugin
You can do so by configuring the reportsDirectory of the maven-surefire-plugin, which is by default target/surefire-reports. This would look like in your case:
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<build>
...
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<reportsDirectory>target/someDirectory</reportsDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
Notice how this is placed inside <build> to configure the build plugins. And you can omit the <groupId>org.apache.maven.plugins</groupId>, it is the default.
Best practice is that all generated files during the build (like Surefire reports) are placed inside target, or more generally, the build directory (which can be obtained with the ${project.build.directory} property in a generic manner).
Here I have two projects those are project(1) and project(2).
I am going to generate a .war file for the project(1) but it depends on project(2).
I built the project(2) as a .jar file and added it to the project(1)'s build path but while runnig mvn install it results in compilation errors like:
package com.disha.db.dao.orm.gen does not exist` the package is in the project(2).
Can any one please help to me.
You have to delegate dependency management to Maven and that's actually where it comes in hand, otherwise you can move on packaging and resolving inter-projects dependencies by hand and let the Maven alternative be dropped.
You should make sure you have provided the correct Project Object Module description for your projects (pom.xm) along with tha packaging type.
Then since you want the project(2) to be availble for project(1) at compilation time, you have to declare, project(2) as a dependency of project(1).
project(2) pom.xml (I will refer to it as project-2 since 'project(2)' does not match a valid id pattern.):
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>project2.group.id</groupId>
<artifactId>project-2</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
</project>
Now the project(1) will refer to the project-2 artifact as a dependency with scope compile:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>project1.group.id</groupId>
<artifactId>project-1</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>project2.group.id</groupId>
<artifactId>project-2</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
Note: Update the group and artifact IDs with ones you are using.
I came across this question when trying to share the Struts packages among multiple bundles inside an OSGi container. I wanted to avoid both duplicating dependencies inside the bundles and introducing a new dependency between them (by having one bundle export its internal dependencies for the other to share).
It turns out the answer is very easy if you happen to use Maven, and if you aren't, you can still use the Maven solution to learn how to create the same result with some other mechanism.
I found this approach useful multiple times during my project, so I'll post an example here.
An additional path for those not so keen on maven, unable to port, or perfectly happy with ant/ivy
I've found the that easiest way to accomplish the stated task is to turn the non-OSGi library into an OSGi library by letting the manifest export every package and add on some approriate symbolic names / versions. I've been able to do this VERY easily with bnd via ant tasks (or even direct command line invocation). There are also repositories which contain "osgi-ified" version of many popular libraries. Some libraries (joda-time) are already shipping with correct OSGi manifests.
Using Maven, it is very easy to create an OSGi bundle from any library. However, I think the same result can be created with other mechanisms, too. The Maven solution helped me understand how it works.
Creating the bundle is done by creating a project which has the library as a dependency and then packaging the project using the maven-bundle-plugin from the Apache Felix project and specifying the library packages with the Export-Package instruction. I used this to share Google Protocol Buffers between bundles inside an OSGi container:
<?xml version="1.0" encoding="UTF-8" ?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.lib</groupId>
<artifactId>protobuf-dist</artifactId>
<version>2.1.0</version>
<name>Google Protocol Buffers OSGi Distribution</name>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>com.google.protobuf</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
If you want all transitive dependencies rolled into the bundle, too, use the bundleall goal of the plugin.
The plugin recognizes and honours existing OSGi manifests in the dependency.
You can also use the bundle plugin to just create the manifest and tell the jar packaging plugin (or the jar-with-dependencies builtin assembly) to use that manifest via the archive section. The plugin's page linked above shows how to do that.