How to find who needs unresolved Imported Packages? - osgi

I'm striving to make work an osgi solution where it wasn't followed the "bundle approach", so any dependencies was embedded, some "random" packages was imported, and it was used:
<DynamicImport-Package>*</DynamicImport-Package>
So there is a bit of confusion...
Now, I removed that DynamicImport, and I'm importing all:
<Import-Package>*</Import-Package>
I'm using felix maven-bundle-plugin, when I check felix console I can see many unresolved packages, so first quite obvious question is:
1) Is it normal that import-package * creates transitive dependencies import too? e.g. My bundle A depends from B which depends from C, so in the manifest I see import C too ? I believe yes it is normal.
Now, I have some unresolved packages which I'm not able to understand which other direct dependencies are using them, so second question is:
do you know a way to do that?
I would like to know it to evaluate if I can get rid of some dependencies
Thanks in advance

Related

NoClassDefFoundError on com.sun.org.apache.xalan.internal.xsltc.trax package in my OSGi maven plugin

I'm trying to parse WSDL files using the EasyWSDL library on my (atlassian) maven plugin project. I keep getting this error when I try to parse the file and it fails when the project tries to reach the TransformerFactoryImpl class from said "xalan" package. The package is located inside the JDK, so it's supposed to be available to runtime, yet for some reason it can't reach it.
I've tried importing the package through
<import-package>com.sun.org.apache.xalan.internal.*,</import-package>
section of the pom.xml, but that gives me the following error:
Unresolved requirements: [[my.plugin.package [304](R 304.0)] osgi.wiring.package; (osgi.wiring.package=com.sun.org.apache.xalan.internal.xsltc.trax)]
Which makes it seem like the other packages of xalan are found, except for the xsltc.trax one.
I've tried creating a bundle extension for OSGi that exports this one package and exposes it to the classpath but due to lack of experience and pretty poor documentation on that matter I can't get that working either. Adding Xalan as a dependency and using <scope>provided</scope> does nothing as well.
I need to find a way to put this specific package on the classpath when the program is running. When I run unit-tests on my implementations they work just fine, so it seems to purely be a runtime classpath problem.
Is there anyone with experience on this matter? I've little experience with OSGi, and my experience with maven isn't huge either. So I'm hoping it's something I did wrong myself instead of this being an impossible problem to solve.

JHipster Spring Boot modularization split package

I am trying to modularize a JHipster 5 (Spring Boot 2) application and I ran into a split package problem.
In module-info.java I have the following conflicting automatic modules:
requires problem.spring.web;
requires problem;
requires jackson.datatype.problem;
When I build the project with Maven, I get several errors due to conflicting package name org.zalando.problem like this:
error: the unnamed module reads package org.zalando.problem from both problem and jackson.datatype.problem
error: module problem.spring.web reads package org.zalando.problem from both jackson.datatype.problem and problem
I would like to know how can I solve this issue. Would I have to wait for the third party library to be modularized too? What would be a nice way to solve this conflict?
This article explains a bit on how to solve Split Packages problems. I applied it to solve the split package between jsr305 and java.xml.ws.annotation by using --patch-module argument when building, as explained here. However the project did not compile when I tried the same for these packages.
The source for this project is available on GitHub
If you want to use JARs that split a package as modules, --patch-module is the only way, but it's an arduous one. Beyond patching, you also need to craft the rest of the module graph. Say you're patching module megacorp with the content of start.up, then:
you have to make megacorp read all of start.up's dependencies with --add-reads
you have to make all modules that use start.up read megacorp with --add-reads
you have to ensure that start.up is not on the module path
This can be quite complicated, particularly if you're fighting Maven along the way. Are you sure, there is no way to simply merge the two artifacts?
If not, I'd say this project might not be ready for modularization.

How to OSGIfy a library

I'm working on a project, it's integration project, we are using Apache Camel and Apache Karaf.
In the project, I need to use the Jira REST Java client library.
So I've read quite a lot of various articles and threads about how to wrap non-OSGI library to OSGI bundle, but I'm really not sure if I got it right.
So, I've created a POM file with a dependency to the needed library. Made a package and tried to deploy it to Karaf, of course, Karaf complained for missing packages.
So, I've found corresponding maven dependency, added it, package goes into <Import-Package> and dependency into <Embed-Dependency>.
Another round, deploy, find dependency, add, ... and again, and again, until Karaf is fine with the bundle.
Is that really correct? It seems to me like quite crazy, so I guess I don't got it as usualy :)
Finally, the package get to stable that was on my work computer, I checked it quickly and went home, there I continued but, strange, the same POM / package, compiled on my personal computer is not working, again complaining about missing package, but this time, this package is for sure in the POMĀ file and for sure it is embeded in the package, I can see it there.
This missing package is this time org.apache.commons.codec.
org.osgi.framework.BundleException: Unresolved constraint in bundle jiraclient.bundle [134]: Unable to resolve 134.0: missing requirement [134.0] osgi.wiring.package; (osgi.wiring.package=org.apache.commons.codec)
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:3826)[org.apache.felix.framework-4.0.3.jar:]
at org.apache.felix.framework.Felix.startBundle(Felix.java:1868)[org.apache.felix.framework-4.0.3.jar:]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:944)[org.apache.felix.framework-4.0.3.jar:]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1247)[6:org.apache.felix.fileinstall:3.2.6]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1219)[6:org.apache.felix.fileinstall:3.2.6]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:1208)[6:org.apache.felix.fileinstall:3.2.6]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:503)[6:org.apache.felix.fileinstall:3.2.6]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:291)[6:org.apache.felix.fileinstall:3.2.6]
So, now I'm totally confused, what is wrong :(
Pretty please, guys, help me. Thanks!
The POM file is long, so I guess link is better: http://pastebin.com/j5cmWveG
Yes OSGi is IMHO "far from easy to use" in terms of its deployment model, requiring 100% bundles with osgi metadata in MANIFEST.MF files. And you need a PhD in mathematics to understand the BND tool. And unfortunately many JARs are not OSGi bundles.
Looking at your pom.xml file with all the imports|exports, and that "not easy to understand" syntax, would just take 5-sec for any average engineer to understand that this "something is wrotten in the state of Denmark" ; eg OSGi != the world we live in. This must and should be easier IMHO.
You can install a plain JAR in Karaf using the wrap url handler:
http://karaf.apache.org/manual/latest/developers-guide/creating-bundles.html
Another trick is to create an uber JAR, eg to put it all in a single JAR file and then you can deploy that.
There is also FAB (Fuse Bundles) which makes OSGi deployment easier, as it handles much of this craziness for you at deploy time, instead of you having to deal with the OSGi MANIFEST.MF madness: http://www.davsclaus.com/2012/08/osgi-deployment-made-easy-with-fab.html

OSGi classloader issues

I am very new to OSGi.
I am developing a plugin A (osgi bundle), suppose A which depends on libraries, suppose B-1.0 and C-1.0. Now If the library C-1.0 depends on library B-2.0 (Note: the different version of library B). So my plugin has two different versions of the library B in its classpath. Now, How can I handle this situation ?
As I am studying from last 4-5 days about OSGi that it creates a classloader for each plugin in the JIRA application, so that dependency version mismatch do not occur between plugins. But What would a developer do If a plugin itself needs two different versions of a library jar ?
Can I create two different classloaders in a single osgi bundle through OSGi, say one for package X and another one for package Y ?
Please help me in any of the above scenarios or point me to the right direction.
Thanks in advance.
Remember that bundles do not depend on other bundles!!
Bundles import packages that are exported by other bundles. (unless you have used Require-Bundle, but you should not). So to rephrase the scenario from your example:
Bundle A imports package org.foo. Bundle C exports package org.foo, and OSGi wires the import to the export. So far so good.
Bundle C also imports package org.bar. Bundle B 1.0 exports package org.bar. Therefore OSGi wires these together and everything is still fine.
Now... bundle A also imports package org.wibble. Bundle B 2.0 exports package org.wibble. This is fine as well! Bundles B 1.0 and B 2.0 are simply different bundles as far as OSGi is concerned, they can both be installed at the same time.
So when you look at the dependencies the way they actually work, you find that it's perfectly possible for A to import code that comes from two different versions of B. However there is a limitation. Consider the following:
Bundle D imports packages org.foo and org.bar v1.0 (yes, packages are versioned).
Bundle E exports package org.foo, which satisfies the import in D. Bundle E also imports package org.bar v2.0.
Some other bundles (say F v1 and F v2) export the 2 versions of the org.bar packages.
Actually this scenario can still work. D can import version 1.0 of package org.bar from somewhere, and E can import version 2.0 of package org.bar from somewhere else, at the same time as D is importing package org.foo from E. I personally find this pretty incredible! But it does not work if org.foo "uses" org.bar, where "uses" means that some types in org.bar are visible in the API of org.foo. In this case, bundle D would be exposed to 2 different copies org.bar, which is not allowed, so OSGi will prevent bundle D from running by not allowing it to enter RESOLVED or ACTIVE states.
In osgi bundle or plugin you'll have meta-inf flie which will define which classes you import if you pass extra agrument being the version=2.0 then it will use the class from B-2.0 if you don't specify anything then it'll resolve to one that is loaded by classloader first.
i.e.
import-package(C 1.0):
b.some.package; version="2.0" or b.some.package; version="[2.0,4.0)"
import-package(A 1.0):
b.some.package; version="1.0" or b.some.package; version="1.0"
Hope this helps
Anup
Since each OSGi bundle has its own classloader, there will be 4 bundles in the runtime, and also 4 classloaders (A, B-1.0, B-2.0, C-1.0).
You may have two copies of the same class included in B (one from 1.0 and another from 2.0). If you run this, you may simply run into a ClassCastException in the A code because two versions of B classes are not the same.
OSGi provides a "uses" clause to detect this type of situations early. For example, C may have a uses clauses like the following:
Export-Package: c.some.package;uses="b.some.package";version="1.0"
Import-Package: b.some.package;version="2.0"
In this case, you will have an earlier failure (while resolving A), known as a uses conflict, because C places a constraint for its consumer on an acceptable version of B.
Conceptually, the only way to fix this problem is to have consumers of B (A and C in this case) agree on the version of B.

Equinox Bundle import conflict

1) Bundle A reexports package com.X, which it gets from bundle C
2) Bundle B exports package com.X
3) Now bunlde D has dependency on both A and B.
From where will the bundle D get the package com.X from?
The first question is why you have 2 bundles defining the same package - this is called split packages and isn't recommended because you can have problems with shadowing.
With Import-Package the runtime will pick either bundle A or B to resolve the package dependency and you can't control this directly (you can do various tricks like the Eclipse guys do by setting mandatory properties on the exports).
With Require-Bundle you'll end up with a merged com.X package, so you'll see the superset of types, but I'm not sure what happens if you have overlapping types.
The simplest thing is to avoid split packages in the first place.

Resources