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.
Solved! Go to Solution.
Views
Replies
Total Likes
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();
}
}
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();
}
}
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
Thanks for reply!
Views
Replies
Total Likes
Views
Likes
Replies
Views
Likes
Replies