osgi: import package that partially exists inside bundle - osgi

I have a package X.Y.Z that exists in 2 bundles A and B:
bundle A
package X.Y.Z
class Class1
bundle B
package X.Y.Z
class Class2
Bundle B exports package X.Y.Z.
Bundle A imports package X.Y.Z and gets an exception that his own class Class1 is not found. Should it work?
I use glassfish 3.1 with felix

No it should not work. If you import package X.Y.Z then that import will be used in preference to the bundle's own internal contents.
More generally, you have a problem known as split packages. Packages should be coherent and exported by a single bundle, not smeared across multiple bundles. You should refactor your bundle contents so that all classes belonging to package X.Y.Z are present in a single bundle.

Again, Niel is absolutely correct. But, sometimes vendors, for whatever reason will have multiple .jar files containing the same packages. This is sometimes done when they want to provide small .jar files for discreet implementations of thier product. An example of why this may be done is if they have a text-processing algorithm for an EDI document that is different than a text processing algorithm for an xml document. In this example, they may choose to create two .jar (versions 1 and 2) files containing "badlyPlannedImplementation.util" containing the different implementationing classes. Personally, I've only run into this a couple of times, but the question is how do you handle it?
When you run into the issue where you have two .jar files that export the same package and you want access to both packages classes you use a mechanism called "shading". Shading is when you take those two packages and you gather their contents together in another .jar files package. This used to be done by a maven plugin called "maven-shade-plugin" but now the functionality is part of the maven-bundle plugin.
First, create a new project, we'll call ours "badlyPlannedImplementationShaded". Then, in your project create a pom.xml file. In your dependency section, include dependencies for both of your .jar files that you're trying to shade together.
Then, add the following to your build section.
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactid>
<version>2.1.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-Version>${project.version}</Bundle-Version>
<Export-Package>
badlyPlannedImplementation.util;version="1",
badlyPlannedImplementation.util;version="2"
</Export-Package>
</instructions>
</configuration>
</plugin>
Doing this will create a new bundle that contains a util package that has all of the classes from the two .jar files you were trying to use.
I hope that helps!

Related

How to provide additional class for a package on OSGi system classpath for J2SE 1.8 profile

Inside ee.j2se-1.8 the package org.w3c.dom is included.
org.osgi.framework.system.packages = \
...
org.w3c.dom,\
...
org.osgi.framework.bootdelegation = \
...
org.w3c.*,\
org.xml.*,\
....
The bundle xml-apis_1.4.1.20140905-131237.jar contains the same package org.w3c.dom, but with one important class more ... ElementTraversal.class more.
So here my questions...
How can I provide the missing class inside my Equinox OSGi runtime?
You are suffering from the fact that people do not take packages seriously. We have a similar problem in the jta API. The version delivered by the VM is not identical to the version that is delivered as a special package.
The solution is to include the JAR with the extra packages on the class path where the framework resides. It looks like you're using bnd (good!) so this would look like:
-runpath: xml-apis__xml-apis;version="[1.4.1,2.0.0)"
If this had been a bundle with proper exports then you would have automatically gotten its exports as system packages. Looking at the packages in this bundle it seems all packages are already in the standard exports of the VM. However, if you have packages int his JAR that are not exported by the VM then you can add them as follows:
-runsystempackages: javax.xml.foo

OSGI Felix not exporting the src/main/resource files

As we know that by defaul osgi export-package only export the package from src/main/java folder,
but i need the other file form src/main/resource also to be exported to use by other projects.
Below is the example of my
ProjectA (packaging type is jar)
src/main/java
x.y.z.SomeClass.java
src/main/resource
x.y.z.config.SomeConfigFile.xml
pom.xml contains
<Export-Package>
x.y.z.*,
x.y.z.config.*,
*
</Export-Package>
ProjectB (packaging type is bundle)
src/main/java
a.b.c.AnotherClass.java
src/main/resource
a.b.c.config.AnotherConfigFile.xml
pom.xml contains
<Import-Package>
x.y.z.*,
x.y.z.config.*,
*
</Import-Package>
Here my requirement is to use SomeConfigFile.xml of ProjectA into AnotherConfigFile.xml of
projectB but i always get FileNotFoundException for the above scenario.
Please help me use the src/main/resource classpath files into another osgi project.
How i can achieve the above defined scenario.
You should probably use Include-Resource instead of Import-Package. More info on the header here (in the 'headers' section): http://www.aqute.biz/Bnd/Format.
There can be several issues (I guess it is option one but the others might be useful as well)
If there is no java class usage, you must specify the required package exactly at the Import-Package section. You cannot use asterisk.
If you want to export a package that is under META-INF, in the Export-Package section you must define it with a quote and an equality character. E.g: '=META-INF.subdir'
If you want to access a resource that is in an imported package, you cannot use the bundle.getResource() function as it searches only in the current bundle. You must use the classLoader of the bundle or the or listResources function of BundleWiring.

Replacing classes/resources with an OSGi fragment - possible without including a jar in the fragment?

We want to replace certain resources in a host OSGi bundle by adding an OSGi fragment.
As I understand it, the resources included in an OSGi fragment are merely added to the classpath of the host bundle.
There is no guarantee that if the fragment is adding a resource that already exists in the host bundle,
the resource from the fragment will be loaded: it could also still be the host version.
In order to make sure the fragment version of the resource is loaded instead of the host version,
http://wiki.osgi.org/wiki/Fragment mentions it is possible to use the Bundle-ClassPath header to specify resources as "first"(preferred).
It gives patch.jar as an example:
Bundle-ClassPath: patch.jar,.
As mentioned there: "Since patch.jar is ahead of '.' it will allow classes to be preferentially loaded from the fragment instead of the host."
I could use this technique, but this means I first have to bundle my fragment resources in a separate jar and then include this jar in the fragment bundle.
Is there a way to preferentially load classes/resources from the fragment instead of the host without having to include a jar in the fragment?
You don't have to include a jar. You can instead use a "patch" directory and then put your classes in a patch directory in the fragment.
Ok, there are a couple of ways to accomplish what you want. As I understand it, after everything is done, you want to export packages from a library bundle except for the packages located in your patch bundle.
To accomplish this, in the Manifest.MF of your library bundle, specify the explicit packages you want to export instead of '.'. You can do this with a fragment so that you won't have to modify the original bundle. Then, do the same with your patch bundle.
Another option is to use the maven-bundle-plugin to "shade" (merge) the patch bundle and the library bundle together into a new bundle. As long as the patch bundle and he library bundle have different version numbers, this will also work. Many blogs will instruct you to use the maven-shade-plugin along with the maven-bundle-plugin for this option, but they are incorrect. You can definately perform shading with the maven-bundle-plugin.
For those that are still struggling, these are the exact steps that worked for me:
Create a fragment project with the resource/class you want to replace
In the fragment's build.properties, change source.. = src/ and output.. = bin/ to source.patch/ = src/ and output.patch/ = bin/
In the fragment's manifest, add patch/ to the bundle class-path
Example:
Let's say you have com.example.ui plug-in which has a com.example.ui.MessageDialog class that you want to replace.
Create a fragment project com.example.ui.fragment
Create the MessageDialog class in the com.example.ui package (not com.example.ui.fragment);
Edit the fragment's build.properties file like this:
source.patch/ = src/
output.patch/ = bin/
In the fragment's manifest add this:
Bundle-ClassPath: patch/
In the com.example.ui manifest change the bundle class-path:
Bundle-ClassPath: patch/,.

Copying java source file from different maven project and modifying its package declaration

Suppose we have two different maven projects; project A and project B
Project B uses A and needs to dynamically (using maven pluggins ?) copy a source file "A.java" from project A, modify its package declaration and compile it (project B should have the same class from project A but with other package declaration ..)
I am trying to copy the source file from A to B before modifying the package declaration and compile all.
Is this the good approach ?
So, project A expose its java file as a resource
<build>
<resources>
<resource>
<directory>src/</directory>
<includes>
<include>**/A.java</include>
</includes>
</resource>
</resources>
</build>
But how can I copy this file to B (B is a dependency in A) ? does "maven-resources-plugin" enable to copy resources from a dependency project, and if so, how do I specify the property "directory" in "resource"
I tried by specify the location of the file in the jar dependency but it did not work
Do you have other propositions ?
Thanks
Finally I solved it by the following steps:
1 - Use "maven-dependency-plugin" to extract (unpack) what I want (the source files from the jar) of included artifacts.
2 - Use "maven-antrun-plugin" to execute ant commands, to replace the strings, create the new package and move modified sources ..
see here
3 - Use "build-helper-maven-plugin" to point the compiler to the new source package in order to include them in the compilation phase
PS: These three steps must happen in the phase "generate-sources" !
maven-resources-plugin enable you to copy java source anywhere before compiling (you can initialize phases) but the problem lies in package declaration in the java file. you need to modify it also and that is not simple in maven
But why you need to do so ? why you need to use the same code in two different packages ???

Buildr Manifest generate class-path from EAR package

I am using (and learning) Buildr to build and package my projects. I would like to auto generate the class-path attribute in an EJB projects MANIFEST file. Currently I am doing:
manifest_cp = compile.dependencies.map { |d|
"#{File.basename(d.name)}"
}.join(" ")
package(:jar).with :manifest=>manifest.merge('Class-Path'=>manifest_cp)
I am new to Ruby and Buildr so there probably is a better way to do this. However I was actually hoping to be able to generate the jars I define and package in my EAR as opposed to getting the compile dependencies in my JAR.
I package my ear project like:
package(:ear).include(ANTLR, AOP_ALLIANCE, ...
Is it possible in my EJB project build when packaging the jar and modifying the manifest I create the Class-Path attribute with all the dependencies packaged in the EAR? On top of that I would also like to exclude one or two dependencies?
thanks
UPDATE
I tried a different approach that seems better (but still probably there are much better ways than what I have). I created a constant that held all my artifacts I want to include in my EAR and then built up the classpath string:
EARLIBS = [ANTLR, AOP_ALLIANCE, ... ]
manifest_cp = Buildr.artifacts(EARLIBS).each { |artifact| artifact.invoke }.map{ |d|
"#{File.basename(d.to_s)}"
}.join(" ")
When I package the EJB I specify the manifest_cp that was created above:
package(:jar).with :manifest=>manifest.merge('Class-Path'=>manifest_cp)
When I package the EAR I reference the constant declared with all the artifacts:
package(:ear).include(EARLIBS)
Even though this works for what I want I would appreciate it if anyone has a better way of doing it
thanks,
The builds doc for the EarTask contains the solution I believe:
All specified libraries are added to the EAR archive and the Class-Path manifiest entry is modified for each EAR component.

Resources