package pl.net.bluesoft.rnd.processtool.plugins.osgi;
import org.apache.felix.framework.Felix;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import pl.net.bluesoft.rnd.processtool.plugins.PluginMetadata;
import pl.net.bluesoft.rnd.processtool.plugins.ProcessToolServiceBridge;
import pl.net.bluesoft.rnd.util.i18n.impl.PropertiesBasedI18NProvider;
import pl.net.bluesoft.rnd.util.i18n.impl.PropertyLoader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import static pl.net.bluesoft.rnd.processtool.plugins.osgi.BundleInstallationHandler.*;
import static pl.net.bluesoft.rnd.processtool.plugins.osgi.OSGiBundleHelper.getBundleResourceStream;
import static pl.net.bluesoft.util.lang.StringUtil.hasText;
public class FelixServiceBridge implements ProcessToolServiceBridge {
private Felix felix;
public FelixServiceBridge(Felix felix) {
this.felix = felix;
}
private Map<String, ServiceRegistration> serviceRegistrationMap = new HashMap<String, ServiceRegistration>();
@Override
public <T> boolean registerService(Class<T> serviceClass, T instance, Properties properties) {
String serviceClassName = serviceClass.getName();
ServiceRegistration sr = serviceRegistrationMap.get(serviceClassName);
if (sr != null) {
sr.unregister();
serviceRegistrationMap.remove(serviceClassName);
}
sr = felix.getBundleContext().registerService(serviceClassName, instance, null);
if (sr != null) {
serviceRegistrationMap.put(serviceClassName, sr);
}
return sr != null;
}
@Override
public <T> T loadService(Class<T> serviceClass) {
return getServiceByReference(serviceClass, felix.getBundleContext());
}
@Override
public <T> boolean removeService(Class<T> serviceClass) {
String serviceClassName = serviceClass.getName();
ServiceRegistration sr = serviceRegistrationMap.get(serviceClassName);
if (sr != null) {
sr.unregister();
serviceRegistrationMap.remove(serviceClassName);
return true;
}
return false;
}
public static <T> T getServiceByReference(Class<T> serviceClass, BundleContext context) {
ServiceReference ref = context.getServiceReference(serviceClass.getName());
return ref != null ? (T) context.getService(ref) : null;
}
@Override
public InputStream loadResource(String bundleSymbolicName, String resourcePath) throws IOException {
for (Bundle bundle : felix.getBundleContext().getBundles()) {
if (!hasText(bundleSymbolicName) || !hasText(bundle.getSymbolicName()) || bundle.getSymbolicName().equals(bundleSymbolicName)) {
InputStream is = OSGiBundleHelper.getBundleResourceStream(bundle, resourcePath);
if (is != null) {
return is;
}
}
}
return null;
}
public synchronized List<PluginMetadata> getInstalledPlugins() throws ClassNotFoundException {
Bundle[] bundles = felix.getBundleContext().getBundles();
List<PluginMetadata> metadata = new ArrayList<PluginMetadata>();
for (final Bundle bundle : bundles) {
OSGiBundleHelper headerHelper = new OSGiBundleHelper(bundle);
BundleMetadata bm = headerHelper.getBundleMetadata();
bm.setId(bundle.getBundleId());
bm.setState(bundle.getState());
bm.setStateDescription("osgi.plugin.status." + getStatusDescription(bundle.getState()));
bm.setSymbolicName(bundle.getSymbolicName());
bm.setCanEnable(bundle.getBundleId() > 0 && bundle.getState() == Bundle.RESOLVED);
bm.setCanDisable(bundle.getBundleId() > 0 && bundle.getState() == Bundle.ACTIVE);
bm.setCanUninstall(bundle.getBundleId() > 0 && (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.INSTALLED));
bm.setVersion(bundle.getVersion().toString());
if (headerHelper.hasHeaderValues(HUMAN_NAME)) {
bm.setHumanNameKey(headerHelper.getHeaderValues(HUMAN_NAME)[0]);
}
if (headerHelper.hasHeaderValues(DESCRIPTION_KEY)) {
bm.setDescriptionKey(headerHelper.getHeaderValues(DESCRIPTION_KEY)[0]);
}
if (headerHelper.hasHeaderValues(IMPLEMENTATION_BUILD)) {
bm.setImplementationBuild(headerHelper.getHeaderValues(IMPLEMENTATION_BUILD)[0]);
}
if (headerHelper.hasHeaderValues(DESCRIPTION)) {
bm.setDescription(headerHelper.getHeaderValues(DESCRIPTION)[0]);
}
if (headerHelper.hasHeaderValues(DOCUMENTATION_URL)) {
bm.setDocumentationUrl(headerHelper.getHeaderValues(DOCUMENTATION_URL)[0]);
}
if (headerHelper.hasHeaderValues(HOMEPAGE_URL)) {
bm.setHomepageUrl(headerHelper.getHeaderValues(HOMEPAGE_URL)[0]);
}
if (bundle.getState() == Bundle.ACTIVE) {
if (headerHelper.hasHeaderValues(WIDGET_ENHANCEMENT)) {
for (String className : headerHelper.getHeaderValues(WIDGET_ENHANCEMENT)) {
bm.addWidgetClass(bundle.loadClass(className));
}
}
if (headerHelper.hasHeaderValues(STEP_ENHANCEMENT)) {
for (String className : headerHelper.getHeaderValues(STEP_ENHANCEMENT)) {
bm.addStepClass(bundle.loadClass(className));
}
}
if (headerHelper.hasHeaderValues(I18N_PROPERTY)) {
for (String property : headerHelper.getHeaderValues(I18N_PROPERTY)) {
PropertiesBasedI18NProvider provider = new PropertiesBasedI18NProvider(new PropertyLoader() {
@Override
public InputStream loadProperty(String path) throws IOException {
return getBundleResourceStream(bundle, path);
}
}, property);
bm.addI18NProvider(provider);
}
}
if (headerHelper.hasHeaderValues(ICON_RESOURCES)) {
String[] resources = headerHelper.getHeaderValues(ICON_RESOURCES);
for (String pack : resources) {
String basePath = File.separator + pack.replace(".", File.separator);
if (!basePath.endsWith(File.separator)) {
basePath += File.separator;
}
Enumeration<URL> urls = bundle.findEntries(basePath, null, true);
if (urls != null) {
while (urls.hasMoreElements()) {
bm.addIconResource(urls.nextElement());// .substring(basePath.length()));
}
}
}
}
}
metadata.add(bm);
}
return metadata;
}
private String getStatusDescription(int state) {
switch (state) {
case Bundle.ACTIVE:
return "active";
case Bundle.INSTALLED:
return "installed";
case Bundle.RESOLVED:
return "resolved";
case Bundle.STARTING:
return "starting";
case Bundle.STOPPING:
return "stopping";
case Bundle.UNINSTALLED:
return "uninstalled";
default:
return String.valueOf(state);
}
}
}