osgi.js

  1. /**
  2. * OSGi module.
  3. * This module provides access to OSGi services.
  4. *
  5. * @namespace osgi
  6. */
  7. const log = require('./log')('osgi');
  8. const bundleContext = require('@runtime/osgi').bundleContext;
  9. const lifecycleTracker = require('@runtime').lifecycleTracker;
  10. const Hashtable = Java.type('java.util.Hashtable');
  11. /**
  12. * Map of interface names to sets of services registered (by this module)
  13. *
  14. * @private
  15. */
  16. const registeredServices = {};
  17. function _jsObjectToHashtable (obj) {
  18. if (obj === null) {
  19. return null;
  20. }
  21. const rv = new Hashtable();
  22. for (const k in obj) {
  23. rv.put(k, obj[k]);
  24. }
  25. return rv;
  26. }
  27. /**
  28. * Gets a service registered with OSGi.
  29. *
  30. * @private
  31. * @param {string|JavaClass} classOrName the class of the service to get
  32. * @returns {*|null} an instance of the service, or `null` if it cannot be found
  33. */
  34. function _lookupService (classOrName) {
  35. let bc = bundleContext;
  36. if (bundleContext === undefined) {
  37. log.warn('bundleContext is undefined');
  38. const FrameworkUtil = Java.type('org.osgi.framework.FrameworkUtil');
  39. const _bundle = FrameworkUtil.getBundle(scriptExtension.getClass()); // eslint-disable-line no-undef
  40. bc = (_bundle !== null) ? _bundle.getBundleContext() : null;
  41. }
  42. if (bc !== null) {
  43. const classname = (typeof classOrName === 'object') ? classOrName.getName() : classOrName;
  44. const ref = bc.getServiceReference(classname);
  45. return (ref !== null) ? bc.getService(ref) : null;
  46. }
  47. }
  48. /**
  49. * Gets a service registered with OSGi.
  50. * Allows providing multiple classes/names to try for lookup.
  51. *
  52. * @memberof osgi
  53. * @param {...(string|JavaClass)} classOrNames the class of the service to get
  54. *
  55. * @returns {*|null} an instance of the service, or `null` if it cannot be found
  56. * @throws {Error} if no services of the requested type(s) can be found
  57. */
  58. function getService (...classOrNames) {
  59. let rv = null;
  60. for (const classOrName of classOrNames) {
  61. try {
  62. rv = _lookupService(classOrName);
  63. } catch (e) {
  64. log.warn(`Failed to get service ${classOrName}: {}`, e);
  65. }
  66. if (typeof rv !== 'undefined' && rv !== null) {
  67. return rv;
  68. }
  69. }
  70. throw Error(`Failed to get any services of type(s): ${classOrNames}`);
  71. }
  72. /**
  73. * Finds services registered with OSGi.
  74. *
  75. * @memberof osgi
  76. * @param {string} className the class of the service to get
  77. * @param {*} [filter] an optional filter used to filter the returned services
  78. * @returns {Array<*>} any instances of the service that can be found
  79. */
  80. function findServices (className, filter) {
  81. if (bundleContext !== null) {
  82. const refs = bundleContext.getAllServiceReferences(className, filter);
  83. return refs != null ? [...refs].map(ref => bundleContext.getService(ref)) : [];
  84. }
  85. }
  86. function registerService (service, ...interfaceNames) {
  87. lifecycleTracker.addDisposeHook(() => unregisterService(service));
  88. registerPermanentService(service, interfaceNames, null);
  89. }
  90. function registerPermanentService (service, interfaceNames, properties = null) {
  91. const registration = bundleContext.registerService(interfaceNames, service, _jsObjectToHashtable(properties));
  92. for (const interfaceName of interfaceNames) {
  93. if (typeof registeredServices[interfaceName] === 'undefined') {
  94. registeredServices[interfaceName] = new Set();
  95. }
  96. registeredServices[interfaceName].add({ service, registration });
  97. log.debug('Registered service {} of as {}', service, interfaceName);
  98. }
  99. return registration;
  100. }
  101. function unregisterService (serviceToUnregister) {
  102. log.debug('Unregistering service {}', serviceToUnregister);
  103. for (const interfaceName in registeredServices) {
  104. const servicesForInterface = registeredServices[interfaceName];
  105. servicesForInterface.forEach(({ service, registration }) => {
  106. if (service === serviceToUnregister) {
  107. servicesForInterface.delete({ service, registration });
  108. registration.unregister();
  109. log.debug('Unregistered service: {}', service);
  110. }
  111. });
  112. }
  113. }
  114. module.exports = {
  115. getService,
  116. findServices,
  117. registerService,
  118. registerPermanentService,
  119. unregisterService
  120. };