Handling split packages: Require-Bundle with maven-bundle-plugin - java

I'm adapting an existing collection of libraries, building them as OSGi bundles. It's a multi-module Maven project, with several layers of POM inheritance and aggregation. Ideally, plugin configuration would be placed in parent POMs only.
The project is composed of more than 100 jars. There's already a mega bundle that encompasses the entire library and export all packages. My effort aims at making the library more modular, which is the main reason of having them as OSGi bundles in the first place.
The main issue is this library has a split package nightmare, and I cannot change the package structure. I'm trying to solve the issue using Require-Bundle, as recommended in the book OSGi in Action, even though the book mentions it's not a good practice. I tried the recommendation of using an arbitrary attribute named "split" in Import-Package to separate parts of a bundle and only import certain packages. But due to the number of bundles providing the same package, that turned out to be too complicated to configure.
My question is how to configure the maven-bundle-plugin <Require-Bundle> directive, if at all possible, to use wildcards (e.g. *) as a form of telling it to use all Maven dependencies, instead of having to manually list all bundles names and versions; i.e. is there an alternative to this:
<Require-Bundle>lib-api; version=${project.version}</Require-Bundle>
that uses some kind of wildcard matching and that could be put in a parent POM?

In short, no. bnd has no support for Require-Bundle, it treats it as a normal header.

Related

Java 9 modules and uber-jar

When developing Java libraries we're currently using the Apache Maven Shade Plugin to hide internal dependencies on other libraries (jars) by renaming their package names.
Is it possible to hide these internal library-dependencies by using the Java 9 module system and not exporting the name of the internally used libraries?
I.e:
Both module A and B include, but does not export, class org.codehaus.jackson.map.ObjectMapper (included using e.g. Maven Shade plugin) with different versions for the class
Module A uses module B
Will each module still use its implementation org.codehaus.jackson.map.ObjectMapper?
I believe it should by so, but I have found no documentation explicitely confirming this, nor any texts / examples recommending this approach for this quite usual versioning issue.
This issue is described as http://openjdk.java.net/projects/jigsaw/spec/issues/#MultiModuleExecutableJARs and there's no support for it yet. In case all dependencies are modules, it would make sense to use jlink to solve this. But as long as there is at least one non-module, there's no solution available yet. This is something that needs to be solved within the JDK/JRE.
It is still a valid case, so I would suggest to ask this question the at jigsaw-dev mailinglist and refer to #MultiModuleExecutableJARs

Maven Multi Module Project Structuring Issues

Well here is an interesting experience i had since last couple of weeks structuring my maven multi module project.
When i decided to use maven for my build life cycle management i had couple of reason that i wished to choose maven.
a. Mostly development teams are divided so that each team can work on separate Module within the project like Team-A to work on User Management System, Team-B to work on Authorization System, Team-C to work on Document Management System...and so on. Each team has java developers, testers, UI experts etc.
So the maven Project structure should be such that each team can independently work on their respective modules. They must be able to code, compile, build, test, deploy their module without having to compile, test modules belonging to other teams.
And thus i came to conclusion that each development module of the maven multi-module project must represent a Functional Module
After some discussions on forums i found people suggesting me to follow layered approach were child modules must be layers like controller-layer,service-layer,dao-layer etc. I did not pay heed to this advice because this not solving my purpose of teams working on individual module. This way for large project the build and deployment time for each team during development increases which does impact the project time-lines. sometimes the build and deploy time is upto 30 minutes say if there are 10 to 11 modules in the project.
But i did pay heed to a suggestion that keeping DAO layer separate for each module is not a good idea as DAO is highly granular and reused by other modules. and so the dependency of one module on other would would any how become greater.
I found a solution to this problem by creating a common module and moving DAOs and DOMAIN to the common module which will be inherited as a dependency by each module. And this seems to be a more viable option. Now the Project Structure looks like this.
Now when i build the project and run the webapp on server, It complains 404, Resource Not Found. I found that this is because the WEB-INF/classes folder is missing, src/main/java is missing in web-app module. I searched and found couple of links that suggested it is Deployment Assembly issue in Eclipse. So i need to manually create these folders and add in the deployment assembly because maven does not do it.
But the bigger questions are
do i need to move the Controller classes like com.mycompany.usermgmtsys.controller.UserMgmtController etc.. to src/main/java Or maven should find the controllers from the module jars included as dependency in WEB-INF/lib.
I dont want to do this i.e. putting java file in web-app. i want all the controllers should be available to the web-app as dependency for example WEB-INF/lib/usermgmtsystem.jar. But then wouldnt the Tomcat be looking for controllers in classes folder.
I dont know what should i do ? Any suggestions would be appreciated.
Its the way the eclipse render maven based project. It generally creates two structure. One based on master pom (parent project) and others based on individual module pom. however doing changes in any structure will reflect in the other one. As a practice I do changes in individual module folder structures and is more easy to read too.
Personally I try to avoid multi-module projects as, if you're using the Maven Release Plugin, you are locked into releasing all your modules together.
While this may sound like a convenience the problem arises when you need to do bug fix release to one of the modules - you end up releasing all the modules, not just the module with the bug fix, incrementing their version even though they haven't changed.
You also take a hit if you're running CI with multi-module projects - you're build typically runs over all modules from you root pom but if you're working in a particular module, you end up taking the hit of building those that haven't changed, in effect losing some of the benefits that the modularization was meant to provide.
So, go with independent modules but, and this is the important bit, create a common 'dependency' pom used by each.
A 'dependency' pom is a pom that standardizes all the dependencies across your projects and is different in that those dependencies are specified in the dependencyManagement section rather than the dependencies section (it also sets up standard plugin config, etc). This allows your project poms to specify the dependency pom as their parent and then declare the dependencies they need minus the versions, which are picked up from the 'dependency' pom and thus standardized across your projects.
If you are still concerned about being able to built everything, this can be achieved with a simple batch-file.
This is a good question. There are many aspects that must be considered for a useful project layout. I'd like to try to answer one which you didn't mention. Is your app extensible by users? If it is, then consider creating a separate module for your public API layer (service interfaces, DTOs used by those services, and Exceptions thrown by the services).
In our app, we have several maven modules per functional area. The idea is that a group worked on a feature within just one functional area and this isolation kept them messing with sources being modified by another group. Each functional area is broken down further in maven sub-modules we call "api", "domain", and "service" - we don't lump services/controllers, domain, and exceptions into a single module. The api module contains those classes we want to expose to customers for their customizations. Our service layer is the implementation of those interfaces. Further, we do not allow one module's service to call another module's service as this would bypass our service orchestration layer where customer can attach extensions to our services. Using separate maven modules per functional area helps enforce this.
We have other modules (internal-api, web, adapter) but they don't really add to this topic.
I figured out the issue. Controllers are presentation-layer components. The dispatcher expects the presentation layer components in the WEB-INF/classes folder in the target rather than looking for it in the lib. I am not sure if this is valid only for maven based structuring in eclipse. So finally these are the changes i have made
a. Created a src/main/java source folder in web-app. It is not generated by default in web-app module.
b. Add packages and respective controllers in the src/main/java folder.
So the final structure that i have (i am not pasting exact eclipse snapshot, this is generalized view)

Classloader to isolate a jar (class identity crisis)

I'm using jarX that has embedded dependencies that conflict with my own dependencies, so I'm creating a classloader to isolate jarX's dependencies from my main classloader.
jarX is outside my app's classpath, but my classes that use jarX's classes are in my classpath, so when I instantiate my classes loaded via the custom classloader, I run into the class identity crisis in the form of ClassCastException as the JVM's version of my classes are considered different from those loaded by my custom classloader.
I found this blog post where they solved a similar problem by only interacting with the custom classloader loaded classes via reflection, which seems to solve this problem.
It just feels like it should be easier than this. Does anyone know a better way to handle this problem?
The easiest way is to open jarX, remove the offending classes, and done. It is a bad practice to embed dependencies in a JAR unless that is JAR is meant to be used only as a standalone runnable fat-jar. JARs that are meant to be used as libraries should not embed dependencies.
When you notice that people package third-party classes in their JARs, I'd recommend pointing out to them that this is generally not a good idea and to encourage them to refrain from doing so. If a project provides a runnable fat-jar including all dependencies, that is fine. But, it should not be the only JAR they provide. A plain JAR or set of JARs without any third-party code should also be offered. In the rare cases that third-party code was modified and must be included, it should be done under the package namespace of the provider, not of the original third-party.
Finally, for real solutions to building modular Java applications and handling classloader isolation, check out one of the several OSGi implementations or project Jigsaw.
Can you post which jar is it and what are the classes that it overlaps, with the full stacktrace? Have a look at this tool I wrote to generate a list of duplicate classes in the WAR, there is an option to exclude duplicates of the same size.
These are some measures that can be done to solve this:
Try to reduce the number of duplicates by doing a case by case analysis of why the overlap exists. Add maven exclusions for jars that are complete duplicates.
Check if there is a version of the same jar without the dependencies that you could use, which jar is it, xerces, etc?
If there is no jar without dependencies, you can you exclude the other jar that overlaps jarX and see if the application still works. This means all components that need the jar have a compatible version of the jarX library
Separate the application into two WARs each with the version of the library you need. This will reduce the number of libraries in which
These where measures that are likelly to be more maintainable long-term
If the previous measures do not work:
open the jar, delete the duplicate classes and publish in the maven repository with a different name jarX-patched
you can configure nexus to serve a patched jar instead of an unpatched jar transparently
If your container supports OSGI that would be even better, but if you don't use a OSGI container for development as well, then the application would not work in development.

Why make my project an OSGI bundle as opposed to a standard JAR package?

For what reasons would I want to make my project an OSGI bundle as opposed to just a standard JAR package? Does it only make sense if it is going to be used by an application that uses an OSGI framework (eg: Equinox/Eclipse)? Or is it also useful from a development point of view, ie: being able to easily reuse my OSGI bundle by other projects during Eclipse development?
OSGi provides support for modules, you could control the dependencies. Each module may include and exclude packages from other bundles. You can also replace bundles during runtime. Making a whole project a single bundle has none of these benefits. I would only wrap a jar like a jdbc driver as bundle if it is not available as an OSGi bundle.
First check whether your project would have a benefit. Then identify which modules should be a bundle.
If your project is a public or open source library, then please do make it an OSGi bundle. This will be of great help to OSGi developers who may want to use your library.
On the other hand if your library is private then the benefits of OSGifying it are limited. Mostly it will be an advantage if you decide to adopt OSGi strategically later. You may also derive some benefit from the explicit dependencies, i.e. you can look into the bundle to work out exactly what it depends on.
There is no runtime cost of doing this. The OSGi data in the manifest is simply ignored by non-OSGi runtimes.
You will have to generate the OSGi manifest though as part of your build step. The best tool to use for this is Bnd, which can be easily integrated into any ANT build -- use it as a replacement for the "JAR" task. If you are building with Maven, then use the Maven Bundle Plugin (which uses Bnd internally).
This is useful only if it's going to be used from within an OSGi container as you mentioned.
If you are searching an answer on why it is useful in general is something you can find a lot just by googling - start from Wikipedia:
http://en.wikipedia.org/wiki/OSGi
In general, I'd say OSGi's main benefits are encapsulation/versioning, solving JAR hell and management provided by the framework, which may or may not be interesting to you depending on your project.
I definitively suggest reading about OSGi if you haven't already - it's very interesting technology. I would suggest reading Neil Bartlett's articles on EclipseZone - this is the first one:
http://www.eclipsezone.com/eclipse/forums/t90365.html
There are a bunch of them, so google them - very interesting read, which will also give you an idea whether this is something you should consider.
SpringSource is a big proponent of OSGi, so it's worth taking a look there, too:
http://www.springsource.org/osgi
If you ever plan on using it in an OSGi context then you might as well make it a bundle. I don't know that there are any negative affects to making it a bundle, whereas if you don't make it a bundle and find out later on that you need it to be then you may have to go back and fix it. Aside from that I personally don't know of anything other than OSGi which uses the manifest meta information - but like I said; I don't think it will hurt.
OSGIfying a project will allow OSGI to be used for dependency management in Eclipse instead of the standard Eclipse project build mechanism, or an external dependency management tool such as Ivy or Maven. Making a project into an OSGI bundle allows you to express that project's package dependencies as bundle dependencies (if a bundle exists for the package dependency) which will be handled by the OSGI framework instead of those other mechanisms (standard Eclipse project build/Ivy/Maven).
Standard Eclipse project dependencies are established by specifying other projects and libraries on your project's build path. Converting to OSGI would replace your build path references with MANIFEST.MF import-package or required-bundles declarations.
Advantages of using OSGI for dependency management over the standard eclipse mechanism are:
re-export dependences: your bundle can re-export their dependent packages which means code relying on your bundle doesn't also have to rely on your bundle's dependants if it also uses them
version management: so you can specify the minimum and maximum expected version of a dependency.
See also Should I use Eclipse plug-ins (or OSGi Bundles) as a plain dependency management tool?

OSGI - handling 3rd party JARs required by a bundle

I'm just getting started with OSGI development and am struggling to understand how best to handle dependant JARs.
i.e. if I'm creating a bundle the likelyhood is that I will need to use a few 3rd party JARs. When I create my bundle JAR to deploy to OSGI, obviously these 3rd party JARs are not included and thus the bundle will not run.
I understand that one option is to turn these JARs into bundles and also deploy them to the OSGI container. However if they only need to be used by the one bundle this doesn't seem ideal.
What is the best solution to this? Can the JARs be embedded within the bundle JAR and if so is this a reasonable approach?
You can include a third party jar inside your bundle by adding the third party jar to the root directory of the bundle jar file and then adding a bundle classpath header to the bundle's manifest, e.g.:
Bundle-ClassPath: .,my3rdparty.jar
If you want to place third party jar to subdirectory, specify the path without using heading ./, e.g
Bundle-ClassPath: .,lib/my3rdparty.jar # (not ./lib/my3rdparty.jar)
I would almost always bundle each jar separately. OSGi itself is meant for modularization and you take the whole system ad absurdum by not doing this.
If you want to convert JARs into bundles you might want to use the BND Tool written by Peter Kriens. But first I would suggest you look for the bundle in the SpringSource Enterprise Bundle Repository if they haven't already done the work for you.
It is possible to embed non-OSGi dependencies into the bundle.
An easy way to do this is to use Maven to manage your dependencies and Maven Bundle Plugin to build your bundle. Take a look at the <Embed-Dependency> and <Embed-Transitive> instructions of the Maven Bundle Plugin described in the section Embedding dependencies of the plug-in documentation page.
As Roland pointed out this is not an ideal solution with respect to the intentions of OSGi, i.e. modularization and reuse of individual modules. However it might be pragmatic solution for time being until the 3rd-party dependencies can be converted into OSGi bundles.
This thread is a bit old, but I wanted to point out one of the limitations of embedding dependencies. Recall that dependencies are at the jar level, but when you export packages some may need to come from the embedded dependencies. If this happens, you will end up with duplicate classes, one set inline in the top level bundle and another in the embedded jar. Of course, you can inline the entire embedded jar, but before you know it this propagates across your entire dependency chain. This is just one of the problems that Roland and others refer to.
Here is an example if you are using the Maven Bundle Plugin.
Note: This plugin automatically imports packages that your dependencies need. This may or may not be a problem for you. Thankfully, you can suppress the packages you don't really need to import (see below).
<Import-Package>
<!-- this was imported by one of the dependencies; I don't really need it -->
!org.apache.jackrabbit.test,
*
</Import-Package>
<Include-Resource>
lib/concurrent-1.3.4.jar,
lib/jackrabbit-core-2.6.5.jar,
lib/jackrabbit-spi-2.6.5.jar,
lib/jackrabbit-spi-commons-2.6.5.jar,
lib/lucene-core-3.6.0.jar,
lib/tika-core-1.3.jar
</Include-Resource>
<Bundle-ClassPath>
.,
concurrent-1.3.4.jar,
jackrabbit-core-2.6.5.jar,
jackrabbit-spi-2.6.5.jar,
jackrabbit-spi-commons-2.6.5.jar,
lucene-core-3.6.0.jar,
tika-core-1.3.jar
</Bundle-ClassPath>
Can we use OSGI to override the bootstrap classloader jars loaded during runtime, like if we wanted to override JAXP1.4.5 available with Java7 to JAXP1.6, there is -Dendorese feature to override the default API to upgraded API. Can we able to do this thing with the help of OSGI.

Categories