Avoid duplicating OSGi imports in maven dependancies? - java

Currently when I am writting a bundle in that depends on a package, I have to "import" or "depend" on a whole other bundle in Maven that contains that package.
This seems like it is counter-productive to what OSGi gives me.
For example let's say I have two bundles: BundleAPI and BundleImpl.
BundleAPI provides the API interfaces:
// BundleAPI's manifest
export-package: com.service.api
BundleImpl provides the implementation:
//BundleImpl's manifest
import-package com.service.api
However, when I am coding BundleImpl in Eclipse, I am forced to "depend" in maven POM on BundleAPI itself - so that eclipse does not complain.
//BundleImpl's POM
<dependency>
<groupId>com.service</groupId>
<artifactId>com.service.api</artifactId>
[...]
</dependency>
So - on one hand, I am depending only on the package com.service.api, while on the other - I need to have the whole bundle - BundleAPI.
Is there a way to make maven or eclipse smart enough to just find the packages somewhere, instead of whole bundles?
I am very much confused as to how this works - any type of clarity here would be great. Maybe I am missing something fundamentally simple?

The key is to distinguish between build-time dependencies and runtime dependencies.
At build time you have to depend on a whole artifact, i.e. a JAR file or bundle. That's pretty much unavoidable because of the way Java compilers work. However at runtime you depend only on the packages you use in your bundle, and this is how OSGi manages runtime substitution. This is the Import-Package statement in your final bundle.
Of course as a developer you don't want to list two parallel sets of dependencies, that would be crazy. Fortunately maven-bundle-plugin is based on a tool called bnd that calculates the Import-Package statement for you based on analysing your code and discovering the actual packages used. Other tools such as bndtools (an Eclipse-based IDE for OSGi development) also use bnd in this way. Incidentally bnd is much more reliable and accurate than any human at doing this job!
So, you define only the module-level dependencies that you need at build time, and the tool generates the runtime package-level dependencies.
I would recommend against using Tycho because it forces you to use Eclipse PDE, which in turn forces you to manually manage imported packages (for the sake of full disclosure, I am the author of bndtools which competes against PDE).

You cannot develop bundles like regular Java projects with Maven and eclipse. You basically have 2 options.
Apache Felix Bundle Plugin: Basically you develop the project as a regular Java project and use Maven as you normally would. This plugin will be used to add all the OSGi specifics to the jar manifest at deployment time to OSGi enable it. The disadvantage of this aproach is that you are using a Java project in your workspace instead of a bundle, which makes running your project in the OSGi container a little extra work since Eclipse doesn't recognize it as a plugin project. Thus you have to add the jar from the Maven build as part of the target platform manually.
Tycho: This is another Maven plugin that attempts to actually bring theses two environments together and does a pretty good job of it. In this scenario, you actually create an Eclipse bundle/plugin project, which obviously makes for seamless integration in Eclipse. The pom then marks the project as being an eclipse-plugin type, which effectively makes Maven resolve the project dependencies (defined in the manifest) via the target platform instead of Maven itself.
I would take the Tycho approach as it gives a much more integrated approach with Eclipse.

Having the whole jar as a dependency shouldn't be a problem, that's how you have to do it with Maven anyway.

Related

How to manage dependencies when developing OSGI bundle in Netbeans and Karaf?

I'm struggling to wrap my head around developing OSGI bundles to publish to Karaf. I'm using Netbeans 7.4 and the Create Maven OSGI bundle when creating a new project. I think what I'm wrestling with is dealing with dependencies between different projects and working with them in Netbeans and then publishing to Karaf.
What I'm trying to do is set up a REST web service; I found this tutorial to be a good starting point in getting something basic up and running. So I started setting up a parent project with sub projects (all of these are from the Maven OSGI Bundle template). But after I started deploying bundles to my Karaf instance I started wrestling with the "missing requirement" errors within Karaf. I'd start trying to list each dependency in <Export-Package> or <Embed-Dependency> but it seems like I just keep going farther down and always getting new "missing requirement" messages listing yet another dependency. I then started trying the maven copy-dependencies plugin to export whatever dependencies are used in my project and copying whatever comes out into the Karaf deploy folder, too. That worked for the most part but I'm wrestling with what I think are downstream dependencies of a 3rd party jar, but that's probably a separate question anyway.
So, what I'd like to know is how should I be developing a coherent "application" with this setup? I understand I should separate everything into standalone bundles; i.e., I'll have my REST interface as one, the implementation as another, business logic as another. As a maven project, if I have a dependency for datetime handling or string utilities, maven will handle resolving all of those. But these dependencies won't automatically be included in my OSGI bundle, is that the case? What is the workflow to make sure that everything my project depends on is available to the bundles in Karaf? What about my projects that have other projects as dependencies, i.e., an interface implementation? I would include that project as a dependency so it will compile, but how do I make sure that that dependency is met after it is published?
The mismatch between dependencies at compile time and at deployment time is indeed a problem when working with OSGi.
What you need to know is how these relate to each other. At compile time you have the maven dependencies. When you build your project the maven bundle plugin creates the necessary Import-Package and Export-Package statements for you. Most of the time this simply works and you should avoid tuning too much there by hand.
So after the build the Manifest specifies what the resulting bundle needs but this does not automatically make sure the dependencies are met. So when you deploy the bundle to karaf you get the errors about missing dependencies. This is normal.
Now you need to install other bundles that fulfil these dependencies. Often you can simply install the jars of your maven dependencies (if they are bundles). This does not always work though. So basically you install the bundles and check if the requirements are met now.
The nice thing with karaf is that many bigger dependencies like cxf are already available as features. So it is a good idea to first try to get the dependencies by installing available features before you try to install them bundle by bundle.
So this helps you in getting your dependencies right. Then for "production" use the best solution is to create your own feature file where you refer to the bundles you found.
While installing bundles using the deploy dir seems nice at first it is not a good solution. Better install the bundles directly from maven using the mvn: url syntax karaf provides.
Regarding embedding dependencies. Sometimes it is a good solution but often it only makes things worse as it can lead to package use conflicts which are hard to solve. So better do not embed anything if it is possible.

Build multiple java projects with dynamic dependencies

I have multiple java projects in a folder. Also there is a second folder with libraries, that might be used as build dependencies from the projects. The projects may also have dependencies to other Projects. What's the best approach to build all projects ?
In other words I want to build the projects without explicit telling their dependencies.I think the biggest problem is the dependecy between the projects.
There are multiple build systems that are available that you may use. Maven has a complete dependency system built into it. Almost all third party open source jars are directly accessible via the World Wide Maven repository system. Basically, you describe the jar you need (groupId, artifactId, and version) and Maven will automatically fetch it for you. Not only that, but Maven also will build your project without having to create a build file. Instead, you have to describe your project in a project object model (a pom.xml file) and Maven will download everything you need, including all compilers, etc.
Almost all new projects use Maven, but Maven has a few downsides:
Since you don't control a build process, it can sometimes feel like poking a prodding a black box to get the build to work the way you want.
Documentation can be scant -- especially if you're moving beyond basic Java compiles.
You usually have to arrange your project in a specific layout. For example, source files should go under src/main/java while JUnit tests are under src/test/java. You don't have to follow the recommended layout, but then you'd have to modify the pom.xml file this way and that to get your build to work. That defeats the whole purpose of the pom.xml in the first place.
If you already have another build system setup (like Ant), you lose everything. There's no easy way to move from Ant to Maven.
The other is called Ant with Ivy. Ivy uses Ant for building, but can access Maven's world wide repository system for third party dependencies. It's a great compromise if you already are heavily invested in Ant. I also find Ant with Ivy to be better documented than Maven (although that's not too difficult). There's an excellent chapter going over the basics of Ivy in Manning Publication's Ant in Action.
With either process, I would recommend that you build a company wide Maven repository using either Nexus or Artifactory. This way, any proprietary third party jars (like Oracle jars) can also be stored in your company wide Maven repository since they won't be in the standard World Wide Maven repository.
By the way, if this is a company wide effort, and you are moving multiple Ant projects into Ivy, I have an Ivy project I use in Github that makes things easier.
Oh, there's a third possibility called Gradle which I know nothing about. I also believe it can use the World Wide Maven repository. It's based on Groovy which is based on Java syntax, and that's about all I can say. Maybe others can fill you in on the details. The Gradle group contends it solves a lot of problems of both Ant/Ivy and Maven.
Whatever tool you use, if you have various projects interdependent, you need to be clear on the independent ones which will be built first before building the dependent projects. You need to have a clear dependency structure for your projects.
You can do this with Apache Ivy. You can lay out the locations for you common libraries, define published artifacts and inter-dependencies in an ivy.xml document in each project, and let a top-level Ant build with the Ivy tasks figure out what the build order should be based on those dependencies.

Working with Maven

I downloaded Java source code of some project that works with Maven. After checking out
the code to Eclipse, and then building it from the command line, I followed the instructions
and imported it from Eclipse as: File > Import > Maven Projects. Now I have the core source code and many additional sub projects that seem to have the same thing like the core, just separated.
Could anyone please explain me what are these sub projects? why I need them? and on which code I need to work now if I want to make changes, the core or the new imported Maven ones?
I don't know nothing about Maven besides the fact that it's a tool for building code and managing releases.
Thanks!
In Maven land, these are called modules. There a nice way to further divide a project into very distinct pieces.
People handle Maven differently. I've seen projects where there was the actual project module, then 10 or so implementation modules. Most people use them for the above mentioned separation.
Most likely, your going to need all of the modules in order to work correctly.
To modify the project, your going to need Maven. I don't know if Eclipse has an embedded maven, but at least NetBeans does. With this you can modify anything that you want, then build it with Maven, which should be just a simple click.
In addition to what #Quackstar said:
Eclipse has embedded Maven support provided by the m2eclipse plugin. When you import a Maven project consisting of multiple modules, the default behavior is to map each Maven module as a separate Eclipse project. This allows the Eclipse build paths to be constructed in a way that matches the declared Maven module dependencies.
There is also a way to map a multi-module Maven project into a single Eclipse project that entails enabling m2eclipse's "Nested Module" support. This results in an Eclipse project with a build path that is an amalgam of all of the Maven module dependencies ... and not exactly correct. This approach is not recommended by the m2eclipse developers, and I've heard they are intending to remove the nested module feature entirely in a future release.

Using eclipse plugin independent from eclipse

Can I programmatically use an Eclipse plugin in my java code (so that it is independent from eclipse)?
Yes you can if:
The plugin you want to use doesn't have any external dependencies => it's just a library plugin
The plugin you want to use and ALL it's dependencies are in your classpath
No in all other cases. Because many plugins use at least the core concepts of OSGI/Equinox (have an activator) it will be quite hard to use them in a standalone java app.
For example, SWT can be used outside eclipse.
You should take a look in your eclipse directory. In the plugins folder you'll find a lot of .jar files. Sure, you could use these as dependencies in your project.
Yes, sure, you just need to care deploy plugin's jar files with you project properly.
Eclipse plugins are OSGi bundles.
OSGi bundles are JAR files that have extra info in META-INF that declares exports and imports. They sometimes make calls to OSGi APIs.
Many Eclipse plugins depend on other Eclipse-specific plugins.
If you use OSGi in your environment, you can easily reuse those plugins that have no Eclipse dependencies. If your application is not OSGi, you can only easily reuse those that avoid the direct use of OSGi APIs.
Well designed plugins are split into UI and "core" parts. You would probably want to grab just the core component. And you may well need to provide an OSGi framework to properly load and activate the plugin too - depending on how complex it is.
As others have also mentioned, don't forget the dependencies.

What is the most elegant solution to managing various Java external libraries?

Perhaps the reason I stalled learning Java until now is because I HATE how Java handles external libraries. I'm stuck keeping them in one place, adding them individually, fixing problems with versioning and every time I move/rename them, and copying and writing the classpath over and over each time I release a Java application.
There has to be an elegant solution to all of this. I keep all of my libraries (regardless of task, platform, or other) in their own little folder inside a "lib" folder in my development folder, kind of like this:
Dev
-lib
+JS-jQuery
+Flex-Degrafa
-Java-Xerces
+Xerces-1.2.3
+More libraries
I can use either Netbeans or Eclipse for Java dev, but none of them provide a very streamlined (and not to mention idiot-proof) way of managing all of these.
A nudge in the right direction or an online article/tutorial on this would be greatly appreciated.
You can either use Ant + Ivy or Maven to manage your library dependencies.
If it is only dependency management you're after and you're happy with the rest of your build process, I would use Ivy, as it can unobtrusively manage your dependencies, leaving your existing build process intact. There is a plugin for Eclipse called IvyIDE that contributes your dependencies via a classpath container.
Maven 2 has a steeper learning curve but provides a much richer set of functionality for building your projects and Eclipse integration through m2eclipse or IAM.
Personally I use Maven as I have a large number of projects to work with and Maven is particularly suited to efficient development across lots of projects.
Have a look at the introductory documentation to see what works for you.
Ivy Tutorial
Maven Getting Started Guide
Netbeans 6.7.1's Maven support is quite good and comes out of the box with the IDE.
The Eclipse addon was frustrating enough that I gave Netbeans another try.
A third choice besides ChssPly76's options is to use Ant with the Maven Ant Tasks. I don't know if I'd call any of these solutions particularly "elegant," but they do spare you the need to manage your own lib/ directory and classpath variables.
If you're working on Linux you can install Java libraries with APT or RPM.
Otherwise, I normally check precompiled JARs into a lib directory in my project's version control repository and make sure the names of the JAR files include full version information. E.g. lib/foo-1.5.6.jar, not lib/foo.jar.
To avoid having to manually set the classpath before running your app, you can set the classpath in the Manifests of the JARs themselves to define the dependencies of each JAR file. The JVM will follow all the dependencies when loading classes.
Maven is often more trouble than it's worth, but the ability to open a maven project directly into IDEs such as IntelliJ is excellent. For example, IntelliJ will download all dependencies and have them available without having to run a build first, or an mvn command and then a project refresh. It also isn't necessary to re-generate the project every time a dependency is added. I work with a number of Eclipse developers who switched to IntelliJ for this alone.
However, one shortfall of Maven is that many libraries (or versions of libraries) are not available on public repositories. Therefore it is often necessary to set up a local repository such as archiva. In ant, it would just be a matter of adding it to the lib directory in the repository.
Maven can also attack when you need to do something that maven doesn't directly support via a plugin. What would normally be a few lines of ant can often turn into a morning's worth of work.
Finally, buildr is an excellent way of using Maven's dependency management and plugins, while also supporting ad-hoc tasks.

Categories

Resources