OSGi (Karaf) Resolution vs Maven dependencies - java

In my example below there seems to be a discrepancy / duplication in the required steps in OSGi resolution and Maven dependency support.
I have a jar which is dependent on a external 3rd party jar, in this case time4j.
<dependency>
<groupId>net.time4j</groupId>
<artifactId>time4j-core</artifactId>
<version>4.16</version>
</dependency>
I can then run my simple jar locally by importing the packages and running etc.
When importing into OSGi I have to ensure that this jar is imported first, often using the PAX Wrap Url.
This is ok for 1 jar dependency but what about when there are multiple dependencies. I could use a features.xml file to collect these jars but why? I've already specified them in my pom.xml.
It seems there should be a way for OSGi / Karaf to read the pom.xml dependencies and import these into the container using the PAX Wrap url when needed.
Have I missed something here?

Sorry but your expectations are not in sync with reality.
First of all Maven dependencies are build-time dependencies. That's why you declare dependencies you know to be available in the runtime as provided
<scope>provided</scope>
Neither OSGi nor Karaf can do anything about your build time dependencies.
BUT with OSGi you can make sure your build dependencies are also available in your runtime and don't interfere with other libraries that might be available.
That's why you need to declare your imports and exports etc.
Karaf does help you with some of the dependencies for example with feature files.
If you have a feature definition maven project, all of your compile scope dependencies can be included in one feature file.
BUT, the OSGi resolver only looks at the currently available bundles and nothing more, no connection what so ever to maven, if you want to have some sort of automagic resolving of external dependencies you need to make sure that you have
a) an OBR resolver enabled (this depends on the karaf version you are using, with 4.x it's already included) and
b) an OBR repository at hand, Karaf Cave would be the project to look for in that case, cause it can reside like a proxy on top of a maven repository.

Related

Understanding Maven dependencies and assembly

I am not very much experienced with Maven and it's compilation and packaging logic gets me confused.
I have some dependencies declares as :
<dependency>
<groupId>com.dependency_group</groupId>
<artifactId>dependency_1</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.dependency_group</groupId>
<artifactId>dependency_2</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
So as far as I understand, dependency_1 will be added to the classpath of my program as something that comes along with my jar, and dependency_2 on the other hand, will be added to the classpath as something that the system runtime will provide upon deployment.
Then I run the package goal of Maven and none of my dependencies are packed with my code (I am using the shade plugin, but even without it nothing changes).
I expected that when some dependency is set as compile scope, it will be exported with my compiled code, since AFAICS, there's no point in setting the classpath saying a dependency will come along with my code, and Maven just don't package that dependency with it. It looks to me as if Maven is not obeying it's contract.
So:
1 - What's the logic behind this?
2 - Do I have to always use the Assembly plugin?
3 - Are there cases where people will define a dependency as compile and will not want it packaged within a jar?
Let me shed some light on the main point here. There are fundamentally two kinds of java artifacts:
Applications, i.e. ears, wars, executable jars
Libraries, i.e. jars that are meant to be used as dependencies for other artifacts.
For Applications your reasoning makes perfectly sense. Wars and Ears automatically package all their compile dependencies and you need no assembly plugin for that. For libraries, you do not pack the dependencies into the library. Maven handles transitive dependency resolution and would be confused if you put a fat jar on the classpath.
The thing is that packaging jar can be both a libary or an application. If you want a standalone application, you need to tell Maven to package everything, e.g. by using the assembly plugin or shade plugin.
You use compile scope when you want some dependencies to come along with your code. For example you want Jackson to be a part of your application if you are using it for json serialization.
You use provided scope, if you want dependency to be on the classpath during the compilation but wont be included within your application. It must be provided by running environment. For example you want Lombok as it is compile only library, or you want to have Servlet Api dependency as provided when you are writing servlet application because such app will be ran on servlet container thus there is no need to pack it within your application (it will be available in container runtime)
Do I have to always use the Assembly plugin
Nobody forces you to do so.

Create common class, has dependency, how do I formally share this dependency?

I've extended an abstract class and implemented a method that I will use with Mule over and over. I want to add it to a library that I will repo on Maven central. It depends on a JAR that's provided in the Mule connector devkit (sdk for Mule connectors). How do I formally publish or tell others publicly that my common library will not work without the earlier dependency too? The dependencies org.json and fasterXML...Jackson..etc.
My code module is an HttpProcessMessage and the over-used method returns a String of formatted JSON. The message POJO gets loaded and then ultimately my method is like a toString() method but more sophisticated.
I would like for this class to be part of a common library that would become part of the community. I wish that my code here would be the foundation and have no dependencies. Now, I'm looking for an answer to address the dependencies and inform the public.
That's one of the main benefits of Maven and other dependency management tools, when your dependency is added to their Maven project, Maven will automatically fetch transitive dependencies. So there is no need to let people know what dependencies you rely on. It will automatically be handled and they can use Maven command if they wish or inspect the maven artefact to determine what transitive dependencies you rely on.
You will need to add the com.faster.xml dependencies and org.json dependencies to your Maven pom.xml and all this information is packaged alongside your Maven artefact and will be stored in a Maven repo.
More info on Maven dependencies here: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
If they are manually installing the jar outside of Maven/Gradle etc. then theres not much you can do except provide them a detailed README on installation instructions.

How is a maven artifactid connected to a file?

I experimented with webservices and jboss4 for the last couple of days, and I stumbled over the following problem:
I included this dependency in my pom.xml:
<dependency>
<groupId>org.jboss</groupId>
<artifactId>jboss-jaxws</artifactId>
<version>4.2.2</version>
</dependency>
As it turned out, this caused JBoss4 to fail with the error message
java.lang.IllegalStateException: Cannot find endpoint meta data
Until I added the tiny little line
<scope>provided</scope>
to the dependency. I now understand that this problem was caused by the fact, that JBoss4 brings this library himself, and that it is the double inclusion of the same library (probably 2 different versions) that caused this. But now, when I look into the JBoss lib folder I see the following files:
commons-codec.jar
commons-httpclient.jar
commons-logging.jar
concurrent.jar
endorsed
getopt.jar
jboss-common.jar
jboss-jmx.jar
jboss-system.jar
jboss-xml-binding.jar
log4j-boot.jar
How do I know which jars correspond to which maven artifact? How do I know for any of the million files in my .m2/repository folder which groupid, artifactid and version number they belong to?
All the jar files in provided/included by Jboss are not related to maven. They are there just for the sake for jboss it self to run. Other application who wants to run in the container need to provide they own sets of library. BUT, some time, some of the library provided by JBoss is enough for the application (since they will live on the same VM), so you dont need to provide your own. You use those provided library for your development purpose, and later, when you deploy, you dont include them in your deployment.
So, there are no telling which Jar, provided by JBOSS should relate to which artifactId or groupId or version in the maven repositories, unless for some hint on their names.
For example, if you see that Jboss brings "commons-codec.jar" with it. There are no telling that the jar comes from which artifactId or groupId or version in Maven. You may guess that "commons-codec" should be a name of some artifact. Sites like http://mvnrepository.com/ helps you to find what related maven artifact that may relate to the jar you are investigating.
The artefact name is always ${artifactId}-${version}.${type}
in your case : jboss-jaxws-4.2.2.jar.
You're just looking for it in the bad place, the lib folder you're talking about must be the one of the unified classloader, the library you're looking for must be loaded by the server classloader i.e. it must reside in JBOSS_HOME/modules
[edit]
Ferdinand Neman is right when he says that jboss is not related to maven. Dependencies declaration in pom just allows maven to build and package your project. The runtime behavior depends on your targeted environment, the only things to ensure is that your dependencies must be resolved during classloading whether because they are packaged with your project or provided by the runtime environment.
Anyway the jar jboss-jaxws-4.2.2.jar will necessary be present on your workstation (in the local maven repository) to allow class linkage during maven compilation, as the jar is marked as provided it will not be included in the resulting build artefact.
Maybe you find useful this maven command
mvn dependency:tree -Dverbose
It shows you jar dependencies, classified by group-artifact and it also represents dependencies between them as a tree.

IntelliJ Idea: how to expose classes, interfaces, annotations in developed plugins

I have created a plugin for IntelliJ Idea. In the plugin I have defined an annotation I want to use in my projects, but it doesn't seem to be accessible.
How should I specify in the plugin.xml file the packages I want to expose?
When you install a plugin, it will be on a certain place - e.g. C:\Users\xxx\.IdeaIC14\config\plugins\...
Now that you know where your jar file is, you can add it as a dependency to your project. If you use Maven, you can add something like this to your pom:
<dependency>
<groupId>yourplugin</groupId>
<artifactId>yourplugin</artifactId>
<version>1</version>
<systemPath>C:\Users\xxx\.IdeaIC14\config\plugins\yourplugin.jar</systemPath>
<scope>system</scope>
</dependency>
Or you can install the jar into your local repository and then use it as normal maven dependency.
If not, then add the dependency directly in the project settings as it was any other jar.
plugin.xml has nothing to do with any of this, this is all about jars and classpath. What you could do in your plugin is some user friendly inspections and actions, which would add the dependency for you.
By default, plugins can automatically read and access public members of any other plugin installed on the same IDE (ie. your plugin can read public variables, call public functions - everything goes on the same classpath). If you depend on another plugin, you must first add it as an explicit dependency within the plugin configuration file, so that the end user's IDE will know to download and install your plugin's required plugin dependencies if they are missing.
During development, you should now be using Gradle. In your project's build.gradle (or build.gradle.kts) file, the intellij.plugins property of the gradle-intellij-plugin will let you specify the the id and version of the plugin dependency. The values for these attributes can be found on the Plugin Repository, cf. Plugin XML ID). Subsequently, the gradle-intellij-plugin will add the desired IntelliJ Platform Plugin to your project as an External Library, thereby allowing you to get code completion, static analysis and test your plugin alongside its dependencies inside the plugin sandbox (via ./gradlew runIde).
Plugins should avoid using other plugins' internal classes for stability reasons. If you wish to enable other plugins to use your plugin programmatically (ie. suppose you want to provide an API), then the IntelliJ Platform has the concept of so-called, Extension Points. These will allow you to define a concrete interface, or contract for other plugins to access the functionality of your plugin, without needing to know much about its source code. Using extension points has the added benefit of decoupling those plugins from any internal plugin refactoring.

Gradle unable to find downloaded dependency packaged as OSGi bundle (non-OSGi app)

(Edited for clarification)
My (non-OSGi) application build is in Gradle, and I am trying to upgrade from very old version of Jersey (1.1.4.1) to something much newer (1.12?). I do not pretend to know anything about using OSGi. But when I point my Gradle dependencies (with $JERSEY_VERSION set to "1.12") to:
[group: 'com.sun.jersey', name: 'jersey-server', version: "$JERSEY_VERSION"]
it downloads the jersey-server-1.12.jar into my Gradle dependencies cache under a "bundles" directory instead of the normal "jars" directory, and then Gradle seems to not include this jar in its classpath like it would if it were under a "jars" subdirectory instead.
I discovered it went under "bundles" because the POM has it labeled as an OSGi enabled jar. I do not think we are going to want to OSGi-ify our project. Am I stuck with older versions of Jersey, or is there anything else I can do to get Gradle to see the Jersey jar? I would prefer to not manually copy the file to a local repo if possible, but rather somehow depend on the dependency management capabilities of Gradle if it is up to the task.
OSGi bundles are normal jars with extra manifest entries. You should be able to use them in a non OSGi project as you would any other dependency. Is it a problem that they end up in the cache's bundles directory?
'Twas a silly oversight: moving from 1.1.4.1 to 1.12, the POM dependencies changed, so that jersey-core.jar was no longer being brought in implicitly. I had to add jersey-core.jar explicitly. I had assumed the problem was the fact that jersey-server.jar was being imported as a bundle, but I was really just getting a ClassNotFoundException for a class that was in jersey-core.jar.

Categories