Expand my Community achievements bar.

SOLVED

Programmatically reactive/reload the OSGi service

Avatar

Level 4

Hello Everyone!

We have a requirement to reactivate/reload the specific OSGi service programmatically based on changes on certain nodes (especially, content fragment data). Is it possible to programmatically reactive/reload the specific OSGi service? If so, sharing any example or sample code snippet would be appreciated.

We are thinking of writing Listener to listen to changes in content fragments data and in that listener, we are going to programmatically restart/reactivate/reload the specific OSGi service. I am open to any other suggestions as well.

Just FYI, we have OSGi service registered with "immediate=true" so it's already active after the bundle is installed.

Thank you in advance.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hello @webdev91 

 

Please find the snipper below to refresh ABCService. Please replace ABC with the desired class name

 

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.runtime.ServiceComponentRuntime;
import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
import org.osgi.util.promise.Deferred;
import org.osgi.util.promise.Promise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;

@Component(immediate = true, service = BundleInfo.class)
public class BundleInfoImpl implements BundleInfo {
private static final Logger LOG = LoggerFactory.getLogger(BundleInfoImpl.class);
private static BundleContext bundleContext;

public static Promise<Void> enable(ComponentDescriptionDTO dto, ServiceComponentRuntime scr){
return Optional.ofNullable(dto)
.map(scr::enableComponent)
.orElse(getFailedPromise());
}
public static Promise<Void> disable(ComponentDescriptionDTO dto, ServiceComponentRuntime scr) {
return Optional.ofNullable(dto)
.map(scr::disableComponent)
.orElse(getFailedPromise());
}

public static Promise<Void> getFailedPromise(){
Deferred deferred = new Deferred<Void>();
deferred.fail( new Exception());
return deferred.getPromise();
}

private void refreshABCService(BundleContext bundleContext){
ServiceComponentRuntime scr = getServiceComponentRuntime(bundleContext);
ComponentDescriptionDTO dto = getABCServiceDTO(bundleContext, scr);
disable(dto, scr)
.then(p -> enable(dto, scr));
}
private ServiceComponentRuntime getServiceComponentRuntime(BundleContext bundleContext){
ServiceReference reference = bundleContext.getServiceReference(ServiceComponentRuntime.class.getName());
return (ServiceComponentRuntime) bundleContext.getService(reference);
}
private ComponentDescriptionDTO getABCServiceDTO(BundleContext bundleContext, ServiceComponentRuntime scr){
return getDTO(bundleContext, scr, ABC.class.getName());
}

public static ComponentDescriptionDTO getDTO(BundleContext bundleContext, ServiceComponentRuntime scr, String componentName){
for (Bundle bundle : bundleContext.getBundles()) {
ComponentDescriptionDTO dto = scr.getComponentDescriptionDTO(bundle, componentName);
if (dto != null) {
return dto;
}
}
return null;
}

@Activate
@Modified
protected void activate(ComponentContext cc) {
bundleContext = cc.getBundleContext();
}
}

 

 


Aanchal Sikka

View solution in original post

3 Replies

Avatar

Community Advisor

Hello @webdev91 

 

Why would you reload an OSGi service based on a CF? 

A better visibility, will help us guide you better


Aanchal Sikka

Avatar

Correct answer by
Community Advisor

Hello @webdev91 

 

Please find the snipper below to refresh ABCService. Please replace ABC with the desired class name

 

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.runtime.ServiceComponentRuntime;
import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
import org.osgi.util.promise.Deferred;
import org.osgi.util.promise.Promise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;

@Component(immediate = true, service = BundleInfo.class)
public class BundleInfoImpl implements BundleInfo {
private static final Logger LOG = LoggerFactory.getLogger(BundleInfoImpl.class);
private static BundleContext bundleContext;

public static Promise<Void> enable(ComponentDescriptionDTO dto, ServiceComponentRuntime scr){
return Optional.ofNullable(dto)
.map(scr::enableComponent)
.orElse(getFailedPromise());
}
public static Promise<Void> disable(ComponentDescriptionDTO dto, ServiceComponentRuntime scr) {
return Optional.ofNullable(dto)
.map(scr::disableComponent)
.orElse(getFailedPromise());
}

public static Promise<Void> getFailedPromise(){
Deferred deferred = new Deferred<Void>();
deferred.fail( new Exception());
return deferred.getPromise();
}

private void refreshABCService(BundleContext bundleContext){
ServiceComponentRuntime scr = getServiceComponentRuntime(bundleContext);
ComponentDescriptionDTO dto = getABCServiceDTO(bundleContext, scr);
disable(dto, scr)
.then(p -> enable(dto, scr));
}
private ServiceComponentRuntime getServiceComponentRuntime(BundleContext bundleContext){
ServiceReference reference = bundleContext.getServiceReference(ServiceComponentRuntime.class.getName());
return (ServiceComponentRuntime) bundleContext.getService(reference);
}
private ComponentDescriptionDTO getABCServiceDTO(BundleContext bundleContext, ServiceComponentRuntime scr){
return getDTO(bundleContext, scr, ABC.class.getName());
}

public static ComponentDescriptionDTO getDTO(BundleContext bundleContext, ServiceComponentRuntime scr, String componentName){
for (Bundle bundle : bundleContext.getBundles()) {
ComponentDescriptionDTO dto = scr.getComponentDescriptionDTO(bundle, componentName);
if (dto != null) {
return dto;
}
}
return null;
}

@Activate
@Modified
protected void activate(ComponentContext cc) {
bundleContext = cc.getBundleContext();
}
}

 

 


Aanchal Sikka

Avatar

Community Advisor

Hi @webdev91 

 

You can use Bundle Activator to refresh the service. Find below the sample code:

 

 

public Promise<Void> enable(ComponentDescriptionDTO dto, ServiceComponentRuntime scr){
    return Optional.ofNullable(dto)
        .map(scr::enableComponent)
        .orElse(getFailedPromise());
  }

private void refreshMyService(BundleContext bundleContext){
    ServiceReference reference = bundleContext.getServiceReference(ServiceComponentRuntime.class.getName());
    ServiceComponentRuntime scr = (ServiceComponentRuntime) bundleContext.getService(reference);
    ComponentDescriptionDTO dto = OSGIComponentUtil.getDTO(bundleContext, scr, MyService.class.getName()).then(p -> OSGIComponentUtil.enable(dto, scr));
  }

 

 

 

Here, we are first checking if the service is enabled and if not enabling it. You can skip then statement and directly call enable if you always has to refresh it on node change.

 

Hope it helps!

Thanks,

Nupur