UNPKG

openhab

Version:
137 lines (120 loc) 4.12 kB
/** * OSGi module. * This module provides access to OSGi services. * * @namespace osgi */ const log = require('./log')('osgi'); const bundleContext = require('@runtime/osgi').bundleContext; const lifecycleTracker = require('@runtime').lifecycleTracker; const Hashtable = Java.type('java.util.Hashtable'); /** * Map of interface names to sets of services registered (by this module) * * @private */ const registeredServices = {}; function _jsObjectToHashtable (obj) { if (obj === null) { return null; } const rv = new Hashtable(); for (const k in obj) { rv.put(k, obj[k]); } return rv; } /** * Gets a service registered with OSGi. * * @private * @param {string|JavaClass} classOrName the class of the service to get * @returns {*|null} an instance of the service, or `null` if it cannot be found */ function _lookupService (classOrName) { let bc = bundleContext; if (bundleContext === undefined) { log.warn('bundleContext is undefined'); const FrameworkUtil = Java.type('org.osgi.framework.FrameworkUtil'); const _bundle = FrameworkUtil.getBundle(scriptExtension.getClass()); // eslint-disable-line no-undef bc = (_bundle !== null) ? _bundle.getBundleContext() : null; } if (bc !== null) { const classname = (typeof classOrName === 'object') ? classOrName.getName() : classOrName; const ref = bc.getServiceReference(classname); return (ref !== null) ? bc.getService(ref) : null; } } /** * Gets a service registered with OSGi. * Allows providing multiple classes/names to try for lookup. * * @memberof osgi * @param {...(string|JavaClass)} classOrNames the class of the service to get * * @returns {*|null} an instance of the service, or `null` if it cannot be found * @throws {Error} if no services of the requested type(s) can be found */ function getService (...classOrNames) { let rv = null; for (const classOrName of classOrNames) { try { rv = _lookupService(classOrName); } catch (e) { log.warn(`Failed to get service ${classOrName}: {}`, e); } if (typeof rv !== 'undefined' && rv !== null) { return rv; } } throw Error(`Failed to get any services of type(s): ${classOrNames}`); } /** * Finds services registered with OSGi. * * @memberof osgi * @param {string} className the class of the service to get * @param {*} [filter] an optional filter used to filter the returned services * @returns {Array<*>} any instances of the service that can be found */ function findServices (className, filter) { if (bundleContext !== null) { const refs = bundleContext.getAllServiceReferences(className, filter); return refs != null ? [...refs].map(ref => bundleContext.getService(ref)) : []; } } function registerService (service, ...interfaceNames) { lifecycleTracker.addDisposeHook(() => unregisterService(service)); registerPermanentService(service, interfaceNames, null); } function registerPermanentService (service, interfaceNames, properties = null) { const registration = bundleContext.registerService(interfaceNames, service, _jsObjectToHashtable(properties)); for (const interfaceName of interfaceNames) { if (typeof registeredServices[interfaceName] === 'undefined') { registeredServices[interfaceName] = new Set(); } registeredServices[interfaceName].add({ service, registration }); log.debug('Registered service {} of as {}', service, interfaceName); } return registration; } function unregisterService (serviceToUnregister) { log.debug('Unregistering service {}', serviceToUnregister); for (const interfaceName in registeredServices) { const servicesForInterface = registeredServices[interfaceName]; servicesForInterface.forEach(({ service, registration }) => { if (service === serviceToUnregister) { servicesForInterface.delete({ service, registration }); registration.unregister(); log.debug('Unregistered service: {}', service); } }); } } module.exports = { getService, findServices, registerService, registerPermanentService, unregisterService };