Refresh Package Bundles - osgi

I've stumbled upon a problem, that can be summarized as follows:
I have an application which is embedded with OSGI. In this OSGI container, I have installed a bundle A of version v1 which registers that service object. This service object is used by the host application. while the service object is in use, I uninstalled the bundle A and installed a new version(v2) of the bundle A. Here are my findings.
Old service object works fine even if we uninstall the bundle A(v1).
The new service object gives the new functionality of bundle A(v2).
My question here is when we refresh the bundle packages by using
List<Bundle> refreshbundles = new ArrayList<Bundle>();
Bundle local; // points to the bundle
refreshbundles.add(local);
m_felix.adapt(FrameworkWiring.class).refreshBundles(refreshbundles)
and when we try to get the service object registered by the new version of the bundle A, it is returning null. I tried looking at the source code but it didn't help. can you please help me with this?
EDIT:
HostApplication
public Felix m_felix = null;
m_felix = new Felix(config); //sending some config to felix.
m_felix.start();
//installing bundle
Bundle bundle = m_felix.getBundleContext().installBundle("file:/bundleA-1.0.jar")
bundle.start()
//getting the service object registered by bundle A.
ServiceReference sr = m_felix.getBundleContext()
.getServiceReference(SampleInterface.class.getName()))
(SampleInterface) m_felix.getBundleContext(sr).getService().sayHI();
//now uninstalling the bundle installing the new version of it say version 1.1
bundle.uninstall()
bundle = m_felix.getBundleContext().installBundle("file:/bundleA-1.1.jar")
bundle.start()
//getting the service object registered by bundleA1.1
ServiceReference sr = m_felix.getBundleContext()
.getServiceReference(SampleInterface.class.getName()))
(SampleInterface) m_felix.getBundleContext(sr).getService().sayHI();
//the above line is working fine but after refreshing the packages, Service object is returned as null
List<Bundle> refreshbundles = new ArrayList<Bundle>();
Bundle bundle; // points to the bundle
refreshbundles.add(bundle);
m_felix.adapt(FrameworkWiring.class).refreshBundles(refreshbundles)
//refresh done
ServiceReference sr = m_felix.getBundleContext()
.getServiceReference(SampleInterface.class.getName()))
(SampleInterface) m_felix.getBundleContext(sr).getService().sayHI();
//throwing null pointer exception because getService() is returning null.
what exactly is happening when we refresh the bundles?
BundleA_Activator.java
public class BundleA_Activator extends BundleActivator{
public class BundleActivatorInterfaces implements BundleActivator{
ServiceRegistration SR;
#Override
public void start(BundleContext bundleContext) {
SR = bundleContext.registerService(SampleInterface.class.getName(), new ExposedClass(), null);
}
#Override
public void stop(BundleContext bundleContext) {
SR.unregister();
}
}

Related

Accessing LoginContext from an OSGi bundle in IBM Liberty

I'm trying to perform a user authentication from within an OSGi bundle deployed inside the IBM WebSphere Liberty server.
If I try
ctx = new LoginContext("system.DEFAULT", handler);
ctx.login();
I get the exception:
javax.security.auth.login.LoginException: unable to find LoginModule class: com.ibm.ws.kernel.boot.security.LoginModuleProxy cannot be found by ...
The same happens if I use
ctx = new LoginContext("WSLogin", handler);
ctx.login();
How can I properly use the LoginContext within an OSGi bundle ?
The correct way to achieve the result is quite similar:
final LoginContext ctx = new LoginContext("WSLogin",WSCallbackHandlerFactory.getInstance().getCallbackHandler(username, password));
ctx.login();
In the previous implementation the error was due to changing the calls loader before creating the login context.
The faulty code was:
final LoginContext ctx;
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
ctx = new LoginContext("RealmUsersRoles", handler);
} finally {
Thread.currentThread().setContextClassLoader(oldClassLoader);
}

Cannot start bundle programmatically

Note: In my case, I'm using Apache Felix implementation if that's matters.
I have written bundle which I'm using as test. It's very simple "Hello World" bundle that do nothing more than print message to stdout when started/stopped:
public class Activator implements BundleActivator {
#Override
public void start(BundleContext context) throws Exception {
System.out.println("Hello, World.");
}
#Override
public void stop(BundleContext context) throws Exception {
System.out.println("Goodbye, World.");
}
}
There is also MANIFEST file which rather pointless to post since when I deploy above bundle through Apache Felix console from standard distribution (which can be downloaded here) bundle starts and print out message.
Next step I'm trying to do is deploy the very same bundle using programmatic approach. Unfortunately this is not working for me. My code looks as follow:
public static void main(String[] args) throws Exception {
FrameworkFactory frameworkFactory = getFrameworkFactory();
Framework framework = frameworkFactory.newFramework(null);
System.out.println("BundleID = " + framework.getBundleId());
System.out.println("State = " + getState(framework.getState()));
framework.init();
System.out.println("BundleID = " + framework.getBundleId());
System.out.println("State = " + getState(framework.getState()));
BundleContext bundleContext = framework.getBundleContext();
bundleContext.addBundleListener((event) -> {
System.out.println("Bundle Changed Event");
});
bundleContext.addFrameworkListener((event) -> {
System.out.println("Framework Event");
});
bundleContext.addServiceListener((event) -> {
System.out.println("Service Changed Event");
});
Bundle bundle = bundleContext.installBundle("file://<absolute-path-to-bundle-jar-same-as-above");
System.out.println("BundleID = " + bundle.getBundleId());
System.out.println("State = " + getState(bundle.getState()));
bundle.start();
System.out.println("BundleID = " + bundle.getBundleId());
System.out.println("State = " + getState(bundle.getState()));
}
private static FrameworkFactory getFrameworkFactory() throws IllegalStateException {
ServiceLoader<FrameworkFactory> loader = ServiceLoader.load(FrameworkFactory.class);
FrameworkFactory factory = null;
for (FrameworkFactory iterator : loader) {
if (factory != null) {
throw new IllegalStateException("Ambiguous SPI implementations.");
}
factory = iterator;
}
return factory;
}
private static String getState(int state) {
switch (state) {
case Bundle.UNINSTALLED:
return "UNINSTALLED";
case Bundle.INSTALLED:
return "INSTALLED";
case Bundle.RESOLVED:
return "RESOLVED";
case Bundle.STARTING:
return "STARTING";
case Bundle.STOPPING:
return "STOPPING";
case Bundle.ACTIVE:
return "ACTIVE";
default:
throw new IllegalStateException("Unknown state");
}
}
The output looks like follow:
BundleID = 0
State = INSTALLED
BundleID = 0
State = STARTING
Bundle Changed Event
BundleID = 1
State = INSTALLED
BundleID = 1
State = INSTALLED
So as far as I understand bundle got installed but last 4 lines indicate that bundle.start() got ignored for some reason.
Could you point out me what am I missing to make this work?
After hour of debugging and reading through javadoc more carefully this is happening because framework was only initialized instead of being started. To make example work you have to simply add framework.start() after framework.init() (or just call framwork.start() which calls framework.init() if found it necessary).
I'm leaving this information as there are few confusing things:
Official documentation to Apache Felix have information about embedding framework into host application. Unfortunately there is only example that use Apache Felix custom mechanisms that make it not portable to other implementations. What is confusing is warning note which if you want to create portable solution you should use init() and getBundleContext(). Whole note cited bellow:
WARNING The felix.systembundle.activators configuration property is specific to the Felix framework implementation. If you want your code to work with other framework implementations, you should call init() on the framework instance and use getBundleContext() directly. Otherwise, the approach would be very similar.
JavaDoc for parameterless version of init() method do not mention about initialization is not same as starting the framework, although init(FrameworkListener...) have such information.
This Framework will not actually be started until start is called.

Karaf PaxExam getting java.lang.IllegalStateException: Invalid BundleContext

Hi i am loading some features and bundles in runtime using FeaturesService and BundleContext. All these things are loaded successfully. After that if i do an operation on bundlecontext object i am getting
java.lang.IllegalStateException: Invalid BundleContext.
#Inject
FeaturesService service;
#Before
public void init() throws Exception{
service.installFeature("hibernate");
service.installFeature("hibernate-validator");
service.installFeature("transaction");
service.installFeature("jpa");
service.installFeature("hibernate-envers");
service.installFeature("hibernate-envers");
bc.installBundle("wrap:mvn:com.oracle/ojdbc6/11.2.0").start();
service.installFeature("DBHandler");
bc.getBundle(); // Fails
}
After a lot of browsing i understood you need to refresh the bundles. How to do it programatically and get a refeshed bundleContext object
You have this exception when you are using a bundle which is not valid : it has been stopped, or refreshed (a refresh stop the bundle and start a new instance)
When you install a feature, by default, Karaf try to define a list of bundles to refresh because of the new capabilities. For example, if a bundle have an optional dependency on a package, and the new feature add this package, then this bundle will be refreshed, in order to update his wires. This is transitive : all dependent bundles are refreshed too.
Moreover, when you use the "wrap" protocol, it create a bundle from a jar by importing all used packaged with a resolution 'optional'
In your case, I suppose the feature 'DBHandler' add a package which is used by your bundle.
You can :
After installing the features, look up your bundle by SymbolicName, with the BundleContext.getBundles() : You will have an instance of a valid bundle
Use the option NoAutoRefreshBundles to disable the refresh when installing a feature (featureService.installFeature("..", EnumSet.of(FeatureService.NoAutoRefreshBundles))). But it's not a good idea as some bundle will not see the new package
This code fixed my problem
public void refreshBundles() {
Bundle currentBundle = FrameworkUtil.getBundle(MyTest.class);
if (currentBundle == null) {
return;
}
BundleContext bundleContext = currentBundle.getBundleContext();
if (bundleContext == null) {
return;
}
Bundle systemBundle = bundleContext.getBundle(0);
if (systemBundle == null) {
return;
}
FrameworkWiring frameworkWiring = systemBundle.adapt(FrameworkWiring.class);
frameworkWiring.refreshBundles(null);
bc = frameworkWiring.getBundle().getBundleContext();
}

Activator.updated() method is not called in osgi

I am using Apache Felix for osgi. Other bundles are running just fine. I've add new bundle to the reactor. The Activator.init() method is called. But I will never get into the updated() method. Any ideas?
public class Activator extends DependencyActivatorBase implements ManagedServiceFactory {
private static final Logger logger = LoggerFactory.getLogger(Activator.class);
public static final String PID = "my.unique.pid";
private final Map<String, Component> components = new HashMap<>();
private volatile DependencyManager dependencyManager; /* injected by dependency manager */
#Override
public void init(BundleContext bc, DependencyManager dm) throws Exception {
Properties props = new Properties();
props.put(Constants.SERVICE_PID, PID);
dm.add(createComponent()
.setInterface(ManagedServiceFactory.class.getName(), props)
.setImplementation(this)
.add(createConfigurationDependency().setPid(PID))
);
dm.add(createComponent()
.setInterface(SessionRegister.class.getName(), null)
.setImplementation(SessionRegisterImpl.class)
);
dm.add(createComponent()
.setInterface(Plugin.class.getName(), null)
.setImplementation(PriorityActionHandler.class)
.add(createServiceDependency().setRequired(true).setService(PluginManager.class))
);
}
#Override
public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
logger.debug("This method should be called and run!");
if (properties == null) {
logger.warn("Configuration is empty!");
return;
}
.
.
.
}
The init method is likely not what you intended. You create a component that is a ManagedServiceFactory, with a PID, and you also make that same component have a service dependency (which translates to making it a ManagedService, with the same PID, which is not allowed and definitely confusing). I am assuming you meant either of these two.
The updated method you have right now assumes you wanted to be a ManagedServiceFactory and there updated will be invoked for each configuration (one or more) that you provide. From your code I cannot see if you have an implementation of Configuration Admin installed and if you actually somehow provide one or more configurations for this PID.
Please provide more information to further pinpoint this issue if this answer does not help you yet.

org.osgi.service.event.EventHandler fails to listen the events posted by the EventAdmin service

I am trying to run a demo application for OSGi EventAdmin service, but the EventHandler I implemented fails to listen the events posted by the EventAdmin publisher:
Below is the code for Event Publisher, followed by the code for Listener(EventHandler):
public class Publisher implements BundleActivator{
static EventAdmin eventAdmin;
ServiceReference ref;
static HashMap properties= null;
#Override
public void start(BundleContext context) throws Exception {
ref=context.getServiceReference(EventAdmin.class.getName());
if(ref==null){
System.err.println("Unable to aquire EventAdmin Ser Ref.");
}
eventAdmin=(EventAdmin) context.getService(ref);
if(eventAdmin==null){
System.err.println("unable to get service:EventAdmin");
}
properties=new HashMap();
properties.put("XYZ", "Test");
Event event = new Event("lnu/test/event/Demo", properties);
eventAdmin.postEvent(event);
System.out.println("event posted");
}
#Override
public void stop(BundleContext context) throws Exception {
// TODO Auto-generated method stub
}
}
Code for Listener:
public class Listener implements BundleActivator, EventHandler {
public void start(BundleContext context) {
Dictionary d = new Hashtable();
d.put(EventConstants.EVENT_TOPIC, "lnu/test/event/Demo" );
context.registerService( EventHandler.class.getName(),
this, d );
System.out.println("event handler is registered now");
}
public void stop( BundleContext context) {}
public void handleEvent(Event event ) {
System.err.println("Event has been captured");
System.out.println("getTopic: "+event.getTopic());
System.out.println("getproperty: "+event.getProperty("XYZ"));
}
}
The print statements in the code show that the event has been posted by the publisher and the Listener is registered with the EventHandler service but still it does not invokes handleEvent method on the listener side, I don't know why? and can't understand what is happening behind the scene. There are no runtime exceptions/errors.
The IDE used is Eclipse Juno Build id: 20120614-1722 with Equinox.
Following Target Platform bundles are included in the run configuration:
org.eclipse.osgi
org.eclipse.equinox.event
org.eclipse.equinox.util
org.eclipse.osgi.services
Can some one point me what I am missing or doing wrong? Or if you have some link to working example of OSGi EventAdmin service?
I would guess that your listener bundle is being registered after the publisher bundle has already posted the Event.
Testing this in the start methods of the bundles is error prone for this reason unless you control the start order of the bundles. I would suggest for this simple test that you start a separate thread in your publisher to post an event every few seconds. The listener should start getting them once it is registered.
Confirm that your listener bundle is importing the same org.osgi.service.event package as the EventAdmin bundle. It is possible that your listener bundle includes the org.osgi.service.event package and is thus not using the same org.osgi.service.event package as the EventAdmin bundle. This could be why the EventAdmin bundle does not call your EventHandler service. It may be something else, but this is something to check.

Resources