BND puts the same package to both export and import sections of manifest.mf - maven

I have a Vaadin application, which I'm trying to build as a set of OSGI bundles using Maven + BND.
I can't deploy the bundles To Apache Felix because some dependencies can't be resolved.
Apache Felix complains that can't find package XYZ required by bundle "A", although this package is defined in this same bundle!!
I looked at the MANIFEST.MF file generated by Maven + BND and saw that the package (XYZ) from this bundle is added to both "import" and "export" sections. I understand why "export", but why "import"?? Why is the bundle trying to import its own package?
my MANIFEST.MF
Manifest-Version: 1.0
Export-Package: myexample.admin;uses:="com.vaadin.ui,myexample.webshared,
com.vaadin.terminal,myexample.mvc.view.impl,
myexample.mvc.model,myexample.mvc.renderer.map.impl,
myexample.mvc.renderer,myexample.mvc.model.impl,myexample.util"
Built-By: ask
Tool: Bnd-0.0.384
Bundle-Name: admin
Created-By: 1.6.0_21 (Sun Microsystems Inc.)
Bundle-Version: 0
Build-Jdk: 1.6.0_26
Bnd-LastModified: 1315674240833
Bundle-ManifestVersion: 2
Import-Package: myexample.admin;version="1.0",myexample.mvc.model,
myexample.mvc.model.impl,myexample.mvc.renderer,
myexample.mvc.renderer.map.impl,myexample.mvc.view.impl,
myexample.util,myexample.webshared,com.vaadin.terminal,com.vaadin.ui
Bundle-SymbolicName: admin
Include-Resource: ..\classes
Originally-Created-By: Apache Maven Bundle Plugin

This is correct behaviour. The explanation is in section 3.5.6 of the OSGi core specification.
Regarding the unresolved error from Felix... this must be related to something else. Please post the actual error message.

Niel is, of course correct. To be honest though, I've been very successful with using the noimports:=true to get around this. In my applications, I usually have the following in my maven-bundle-plugin section:
<Export-package>*;noimports:=true</export-package>
This results in all of your packages being exported into OSGi, and none of them will appear in your import-package section. If you only need a couple of your exported packages to not appear in your import-package section, you can set the noimports flag for each individual package. Lastly, this syntax is from BND, so it should also work in your .bnd files.

Related

OSGi bundle export versioning

I'm pretty new in osgi world, and probably missing something, and i'm having troubles exposing different versions of the same sevice for liferay.
Here is what i am trying to do (and sorry for my english):
I wrote a service, wrapped it in a bundle and successfully deployed it on osgi. My bnd.bnd file looks like this
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices
and, once packaged, the manifest file is like this
Manifest-Version: 1.0
Bnd-LastModified: 1542646653910
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServic
esActivator
Bundle-ClassPath: .,lib/pn--logger-7.1.0.jar,lib/pn--services-base-7.1
.0.jar,lib/pn--prop-files-7.1.0.jar,lib/gson-2.8.5.jar,lib/pn--expand
o-values-7.1.0.jar
Bundle-ManifestVersion: 2
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.0
Created-By: 1.8.0_191 (Oracle Corporation)
Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.0"
Import-Package: com.liferay.expando.kernel.exception;version="[1.0,2)"
,com.liferay.expando.kernel.model;version="[1.1,2)",com.liferay.expan
do.kernel.service;version="[1.1,2)",com.liferay.portal.kernel.excepti
on;version="[7.2,8)",com.liferay.portal.kernel.model;version="[2.0,3)
",it.peernetwork.lr.pilot.testservices,org.osgi.framework;version="[1
.8,2)"
Javac-Debug: on
Javac-Deprecation: off
Javac-Encoding: UTF-8
Private-Package: it.peernetwork.lr.pilot.test.services.impl,it.peernet
work.lr.pilot.testservices.impl,it.peernetwork.lr.pilot.testservices.
x,lib,it.peernetwork.lr.logger,it.peernetwork.lr.servicesbase,it.peer
network.lr.propfiles,it.peernetwork.lr.propfiles.utils,com.google.gso
n,com.google.gson.annotations,com.google.gson.internal,com.google.gso
n.internal.bind,com.google.gson.internal.bind.util,com.google.gson.in
ternal.reflect,com.google.gson.reflect,com.google.gson.stream,it.peer
network.lr.expandovalues
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Tool: Bnd-3.2.0.201605172007
This manifest file declares
Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.0"
and i think this is correct.
Once deployed (successfully) i check the bundle state with the command bundle __BUNDLE_ID__ that gives me
pilot--test-services_7.1.0 [1014]
Id=1014, Status=ACTIVE Data Root=/home/ltrioschi/development/liferay-osgi/liferay-ce-portal-7.1.0-ga1/osgi/state/org.eclipse.osgi/1014/data
"Registered Services"
{it.peernetwork.lr.pilot.testservices.UselessService}={service.id=1607, service.bundleid=1014, service.scope=singleton}
No services in use.
Exported packages
it.peernetwork.lr.pilot.testservices; version="7.1.0"[exported]
Imported packages
com.liferay.expando.kernel.exception; version="1.0.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
com.liferay.expando.kernel.model; version="1.1.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
com.liferay.expando.kernel.service; version="1.1.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
com.liferay.portal.kernel.exception; version="7.2.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
com.liferay.portal.kernel.model; version="2.0.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
org.osgi.framework; version="1.8.0" <org.eclipse.osgi_3.10.200.v20150831-0856 [0]>
No fragment bundles
No required bundles
Then i wrote a portlet that requires this service. The bnd.dnd file is
Bundle-Name: it.peernetwork.lr.pilot.test-portlet
Bundle-SymbolicName: pilot--test-portlet
Bundle-Version: 7.1.0
Import-Package: \
it.peernetwork.lr.pilot.testservices;version=[7.1.0],\
*
-metatype: *
And once deployed it loads correctly the service and uses it with no issues.
Now...my problem is i need a new version of the service, but i do not want to undeploy the current version.
So i wrote the new version of the service and the new bnd.bnd file is
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.1.1
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices
(the only difference is the Bundle-Version)
Once packaged the only difference in manifest file is the Export-Package line
Export-Package: it.peernetwork.lr.pilot.testservices;version="7.1.1"
and looks like it smoothly deploys on osgi
g! lb pilot
START LEVEL 20
ID|State |Level|Name
1014|Active | 10|it.peernetwork.lr.pilot.test-services (7.1.0)
1015|Active | 10|it.peernetwork.lr.pilot.test-services (7.1.1)
but with the command bundle ___NEW_BUNDLE_ID___ i get
No exported packages
instead of
Exported packages
it.peernetwork.lr.pilot.testservices; version="7.1.1"[exported]
(that i expected). It means (to me) that the bundle is deployed, but none of its services are exposed.
Then i updated my portlets bundle (bnd.bnd) this way
Bundle-Name: it.peernetwork.lr.pilot.test-portlet
Bundle-SymbolicName: pilot--test-portlet
Bundle-Version: 7.1.0
Import-Package: \
it.peernetwork.lr.pilot.testservices;version=[7.1.1],\
*
-metatype: *
(changed version in Import-Package) and deployed on osgi. Deploy was correct, but it still uses the old version of the services bundle (7.1.0) even if Import-Package declares version 7.1.1. It does not give error because of the "missing" requested service version.
Can someone give me some tips about what i am doing wrong?
Thanks in advance.
UPDATE 1
Dependencies in build.gradle file have been updated accordingly with the version specified in bnd.bnd.
UPDATE 2
#quatax
The updated portlet bundle's manifest file has Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.1.1]" (followed by all other required imports)...seems correct to me...
UPDATE 3
#Neil Bartlett (Service version updated to 8.0.0)
I updated pilot--test-services bnd.bnd file setting Bundle-Version: 8.0.0.
The whole bnd.bnd file is
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 8.0.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices
Manifest file is
Manifest-Version: 1.0
Bnd-LastModified: 1543316524201
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServic
esActivator
Bundle-ClassPath: .,lib/pn--logger-7.1.0.jar,lib/pn--services-base-7.1
.0.jar,lib/pn--prop-files-7.1.0.jar,lib/gson-2.8.5.jar,lib/pn--expand
o-values-7.1.0.jar
Bundle-ManifestVersion: 2
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 8.0.0
Created-By: 1.8.0_191 (Oracle Corporation)
Export-Package: it.peernetwork.lr.pilot.testservices;version="8.0.0"
Import-Package: com.liferay.expando.kernel.exception;version="[1.0,2)"
,com.liferay.expando.kernel.model;version="[1.1,2)",com.liferay.expan
do.kernel.service;version="[1.1,2)",com.liferay.portal.kernel.excepti
on;version="[7.2,8)",com.liferay.portal.kernel.model;version="[2.0,3)
",it.peernetwork.lr.pilot.testservices,org.osgi.framework;version="[1
.8,2)"
Javac-Debug: on
Javac-Deprecation: off
Javac-Encoding: UTF-8
Private-Package: it.peernetwork.lr.pilot.test.services.impl,it.peernet
work.lr.pilot.testservices.impl,it.peernetwork.lr.pilot.testservices.
x,lib,it.peernetwork.lr.logger,it.peernetwork.lr.servicesbase,it.peer
network.lr.propfiles,it.peernetwork.lr.propfiles.utils,com.google.gso
n,com.google.gson.annotations,com.google.gson.internal,com.google.gso
n.internal.bind,com.google.gson.internal.bind.util,com.google.gson.in
ternal.reflect,com.google.gson.reflect,com.google.gson.stream,it.peer
network.lr.expandovalues
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Tool: Bnd-3.2.0.201605172007
. When i deploy it it seems ok (starts and status is "Active"), but bundle ___ID___ says No exported packages
Then i updated pilot--test-portlet's build.gradle setting the correct version of the dependency (8.0.0). It's manifes file says Import-Package: it.peernetwork.lr.pilot.testservices;version="[8.0,9). When i deploy this package it does not start (status "Installed" and error Unresolved requirement: Import-Package: it.peernetwork.lr.pilot.testservices; version="[8.0.0,9.0.0)")
UPDATE 4 -- -- RESOLVED
Thank you very much #Neil. Thanks to your tips i solved my issue. The right advice was this.
Explicitally declaring
Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.2,8)",\
*
in the pilot--test-services's bnd.bnd file (self import, with the opportune version range) makes osgi export correctly the package and loads the correct class instances when required.
The complete bnd.bnd file is
Bundle-Name: it.peernetwork.lr.pilot.test-services
Bundle-SymbolicName: pilot--test-services
Bundle-Version: 7.2.0
Bundle-Activator: it.peernetwork.lr.pilot.testservices.impl.TestServicesActivator
Export-Package: it.peernetwork.lr.pilot.testservices
Import-Package: it.peernetwork.lr.pilot.testservices;version="[7.2,8)",\
*
In pilot--test-portlet's build.gradle file i only had to update the dependency version
compileOnly group: "it.peernetwork.lr", name: "pilot--test-services", version: "7.2.0"
I tried with version 7.1.0, 7.2.0 and 8.0.0 and works smoothly. All "services" bundles are deployed on osgi. Deploying the portlet bundle with different dependency versions always takes the right service.
Thank you again.
I recommend deleting the Import-Package instruction from your bnd.bnd file for the pilot--test-portlet bundle. It is not necessary: bnd will generate all the imports you need based on the actual requirements in your code.
Your original bundle pilot--test-services both exports and imports the package it.peernetwork.lr.pilot.testservices. This is correct when your bundle makes use of the package itself in addition to exporting it. Therefore when you install both v7.1.0 and v7.1.1, the v7.1.0 bundle will import the package from the other version instead of exporting the older version. The pilot--test-portlet correctly imports from version 7.1.1.
In other words, everything here is working the way it should.

How does OSGi bundle get started without Bundle-Activator

How can an OSGi bundle become active without Bundle-Activator in the MANIFEST-MF file? For example, Google guava can run as a bundle and become active in Karaf container but the MANIFEST-MF file doesn't include Bundle-Activator property.
Manifest-Version: 1.0
Bnd-LastModified: 1408992499326
Build-Jdk: 1.7.0-google-v6
Built-By: cgdecker
Bundle-Description: Guava is a suite of core and expanded libraries that
include utility classes, google's collections, io classes, and much
much more. Guava has only one code dependency - javax.annotation
, per the JSR-305 spec.
Bundle-DocURL: https://guava-libraries.googlecode.com/
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-ManifestVersion: 2
Bundle-Name: Guava: Google Core Libraries for Java
Bundle-SymbolicName: com.google.guava
Bundle-Version: 18.0.0
Created-By: Apache Maven Bundle Plugin
Export-Package: com.google.common.net;uses:="javax.annotation,com.google
.common.base,com.google.common.hash,com.google.common.io,com.google.com
mon.primitives,com.google.common.collect,com.google.common.escape";vers
ion="18.0.0",com.google.common.html;uses:="com.google.common.escape,jav
ax.annotation";version="18.0.0",com.google.common.collect;uses:="com.go
ogle.common.base,javax.annotation,com.google.common.primitives,com.goog
le.common.math";version="18.0.0",com.google.common.primitives;uses:="co
m.google.common.base,javax.annotation,sun.misc";version="18.0.0",com.go
ogle.common.base;uses:="javax.annotation";version="18.0.0",com.google.c
ommon.escape;uses:="com.google.common.base,javax.annotation";version="1
8.0.0",com.google.common.cache;uses:="com.google.common.collect,com.goo
gle.common.util.concurrent,javax.annotation,com.google.common.base,com.
google.common.primitives,sun.misc";version="18.0.0",com.google.common.e
ventbus;uses:="com.google.common.collect,com.google.common.cache,javax.
annotation,com.google.common.base,com.google.common.util.concurrent,com
.google.common.reflect";version="18.0.0",com.google.common.util.concurr
ent;uses:="com.google.common.base,javax.annotation,com.google.common.co
llect,com.google.common.primitives,com.google.common.math";version="18.
0.0",com.google.common.hash;uses:="com.google.common.primitives,com.goo
gle.common.base,javax.annotation,com.google.common.math";version="18.0.
0",com.google.common.io;uses:="javax.annotation,com.google.common.base,
com.google.common.math,com.google.common.hash,com.google.common.collect
,com.google.common.primitives";version="18.0.0",com.google.common.xml;u
ses:="com.google.common.escape,javax.annotation";version="18.0.0",com.g
oogle.common.reflect;uses:="javax.annotation,com.google.common.base,com
.google.common.collect,com.google.common.primitives";version="18.0.0",c
om.google.common.math;uses:="com.google.common.base,com.google.common.p
rimitives,javax.annotation";version="18.0.0",com.google.common.annotati
ons;version="18.0.0"
Import-Package: javax.annotation;resolution:=optional,sun.misc;resolutio
n:=optional
Tool: Bnd-1.50.0
For one, there are also other means of starting a logic in a bundle, for example it could be Blueprint, or Declarative Services. But I doubt guava does have that,
so what you see here is a typical case.
An OSGi bundle usually follows the following steps:
a) installed
b) resolved
c) starting
d) active
e) stopping
f) uninstalled
This is for all bundles, only fragments will stay in the resolved state as a fragment bundle itself can't be started/activated.
If your bundle (or guava in this case) doesn't have an explicit Activator class which will be called in the active stage, the bundle still can be active.

How to add cglib to a OSGI manifest of RCP client?

I want to use cglib in an RCP client. The RCP client is build using maven and the tycho plugin. We are useing a manifest first strategy.
This is my MANIFEST.MF:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: INFO+ RCP Common UI Plug-in
Bundle-SymbolicName: a.company.prj.rcp.common.ui
Bundle-Version: 8.0.14.qualifier
Bundle-Vendor: Schweizerische Bundesbahnen SBB
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-Activator: a.company.prj.rcp.common.ui.CommonUIPlugin
Bundle-ActivationPolicy: lazy
Export-Package:
a.company.prj.rcp.common.ui,
...
a.company.prj.rcp.common.ui.wizards.page
Import-Package:
org.apache.log4j;version="1.2.17"
Require-Bundle:
org.eclipse.ui;bundle-version="3.7.0",
org.eclipse.ui.forms;bundle-version="3.5.101",
com.ibm.ws.jpa.thinclient;bundle-version="8.0.6",
...
a.company.prj.rcp.core;bundle-version="8.0.14",
...
To add cglib I changed the Import-Package section to:
Import-Package:
net.sf.cglib;version="3.2.0",
org.apache.log4j;version="1.2.17"
Now Eclipse complains with:
No available bundle exports package 'net.sf.cglib'
Ayn ideas how to include cglib with this environment?
You will need to add the cglib bundle to your target platform, i.e., the set of all bundles Tycho will consider when resolving dependencies. You have three options to do so (taken from the Tycho wiki page on this topic):
You can simply add an entire p2 repository to your target platform.
You can use a .target file and reference the cglib bundle therein (as already suggested by stempler).
You can declare a Maven <dependency> on cglib and make Tycho “consider” it.
As you already have a working Tycho build, I suggest you use whatever option you or your colleagues have used in the build before.
One more note: Options 1 and 2 require that the cglib bundle is available in a p2 repository, whereas option 3 works even if the bundle comes from a “normal” Maven repository like the Central Repository. But in all three cases the cglib JAR must be a valid OSGi bundle, i.e., include an OSGi MANIFEST.MF with Bundle-SymbolicName etc.
You should build the cglib jar file to a plugin and install it in Eclipse before you can use it. You can refer to this link: How can I add the external jar to the eclipse rcp application?

Apache felix osgi unable to export package

I have below set up in manifest.mf file,
Manifest-Version: 1.0
Bnd-LastModified: 1359719312904
Bundle-Activator: org.amdatu.mongo.impl.Activator
Bundle-ManifestVersion: 2
Bundle-Name: org.amdatu.mongo
Bundle-SymbolicName: org.amdatu.mongo
Bundle-Version: 1.0.4
Created-By: 1.7.0_09 (Oracle Corporation)
Export-Package: org.amdatu.mongo;uses:="com.mongodb";version="1.0"
Import-Package: com.mongodb,org.amdatu.mongo;version="[1.0,2)",org.apach
e.felix.dm;version="[3.0,4)",org.osgi.framework;version="[1.5,2)",org.o
sgi.service.cm;version="[1.3,2)",org.osgi.service.log;version="[1.3,2)"
Private-Package: org.amdatu.mongo.impl
Tool: Bnd-1.51.0
When I install this bundle I am not getting org.amdatu.mongo package in export list in apache felix?
Please check the image below ...my bundle is in active plus running state.Still I am not able to see export package??
I have no package with ID 508 from which this bundle importing the org.amdatu.mongo
I have search in web console and I got only one bundle.Please check the image below,
The problem is not that Felix is unable to export the package. It just doesn't need to.
You have listed the package org.amdatu.mongo as both an export and an import. This gives the OSGi Framework a choice: import it if there is an another bundle already exporting it; otherwise, export it.
So in other words you are seeing normal, correct behaviour.

Not able to access classes in javamail in OSGi

I have an OSGi bundle and I'm using java mail api in it to add mail functionality.
The problem I'm facing is, the bundle class loader is not adding the entries for mail-1.4.jar and activation.jar in classpath variable which it creates while loading the local or global classes.
I've added the mail-1.4.jar and activation.jar in the bundle classpath in manifest and these jar are simple jars(not the OSGi bundles). And these are in lib directory in my bundle.
Now while loading javax.mail.Address class ClassNotFoundException is thrown.
And this is when I'm running my application using command line.
It works completely fine when I run it in Eclipse.
I'm using equinox as my container.
Any suggestions?
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Workexp
Bundle-SymbolicName: com.gslab.workexp
Bundle-Version: 1.0.0
Bundle-Activator: com.gslab.workexp.Activator
Bundle-Vendor: GSLAB
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: org.osgi.framework
Bundle-ClassPath: .,
lib/mysql-connector-java-5.1.20-bin.jar,
lib/commons-beanutils-1.8.0.jar,
lib/commons-collections-2.1.1.jar,
lib/commons-digester-2.1.jar,
lib/commons-javaflow-20060411.jar,
lib/commons-logging-1.1.1.jar,
lib/iText-2.1.7.jar,
lib/jasperreports-4.6.0.jar,
lib/jdt-compiler-3.1.1.jar,
lib/log4j-1.2.9.jar,
lib/mail-1.4.jar,
lib/activation.jar
Your use of the bundle classpath is unusual. You should use Import-Package (best practice) or Require-Bundle for dependencies. Bundle classpath is saying all those jars are packaged inside a lib folder inside your bundle archive. I suspect this isn't the case, and even if it was, you'd be totally bypassing all the modularity Eclipse gives you.
Try adding the 'javax.mail' package to your Import-Package header. For an explanation of why this isn't needed in Eclipse, see i/Why_does_Eclipse_find_javax.swing_but_not_Felix%3F.
Make sure you have included your lib folder inside the bin.includes (Build Tab in the Manifest editor) or they won't get exported in the final jar.
This is a very annoying 'bug' that it works in eclipse (because the files are accessible in the file system) but the builder will ignore not included files.

Resources