Programmatically reactive/reload the OSGi service | Community
Skip to main content
June 26, 2023
Solved

Programmatically reactive/reload the OSGi service

  • June 26, 2023
  • 2 replies
  • 1862 views

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.

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by aanchal-sikka

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();
}
}

 

 

2 replies

aanchal-sikka
Community Advisor
Community Advisor
June 26, 2023

Hello @webdev91 

 

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

A better visibility, will help us guide you better

Aanchal Sikka
aanchal-sikka
Community Advisor
aanchal-sikkaCommunity AdvisorAccepted solution
Community Advisor
June 26, 2023

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
Nupur_Jain
Adobe Employee
Adobe Employee
June 26, 2023

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

October 8, 2024

Thanks for reply!