Skip to content

Commit

Permalink
feat(pandino): Add support for ActivatorResolvers
Browse files Browse the repository at this point in the history
ActivatorResolvers can be defined for different bundle types e.g.: EMS, UMD, etc. Pandino comes with support for ESM by default, while an optional UMD resolver is published as well.
  • Loading branch information
noherczeg committed Oct 6, 2022
1 parent 565309d commit c6b81e3
Show file tree
Hide file tree
Showing 15 changed files with 526 additions and 33 deletions.
22 changes: 22 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions packages/@pandino/pandino-api/src/activator-resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { BundleActivator, BundleManifestHeaders } from './bundle';

export interface ActivatorResolver {
/**
* ActivatorResolvers are responsible to return a {@code BundleActivator} for a given {@code BundleType}. E.g.:
* Resolving UMD modules are different compared to plain ESM.
*
* Resolvers can be added to Pandino's PANDINO_ACTIVATOR_RESOLVERS ConfigMap entry.
*
* @param module Any reference to a particular module.
* @param bundleHeaders Headers for the Bundle we would like to activate
*/
resolve(module: any, bundleHeaders: BundleManifestHeaders): BundleActivator;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@ import {
BUNDLE_VERSION,
REQUIRE_CAPABILITY,
PROVIDE_CAPABILITY,
BUNDLE_TYPE,
BUNDLE_UMD_NAME,
} from '../pandino-constants';
import { BundleActivator } from './bundle-activator';
import { ActivationPolicy } from './activation-policy';
import { BundleType } from './bundle-type';

export interface BundleManifestHeaders {
[BUNDLE_MANIFESTVERSION]?: string;
[BUNDLE_SYMBOLICNAME]: string;
[BUNDLE_VERSION]?: string;
[BUNDLE_TYPE]?: BundleType;
[BUNDLE_UMD_NAME]?: string;
[BUNDLE_ACTIVATOR]?: string | BundleActivator;
[BUNDLE_ACTIVATIONPOLICY]?: ActivationPolicy;
[BUNDLE_NAME]?: string;
Expand Down
1 change: 1 addition & 0 deletions packages/@pandino/pandino-api/src/bundle/bundle-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type BundleType = 'esm' | 'umd';
1 change: 1 addition & 0 deletions packages/@pandino/pandino-api/src/bundle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './bundle-reference';
export * from './bundle-state';
export * from './bundle-tracker';
export * from './bundle-tracker-customizer';
export * from './bundle-type';
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ import {
DEPLOYMENT_ROOT_PROP,
LOG_LEVEL_PROP,
LOG_LOGGER_PROP,
PANDINO_ACTIVATOR_RESOLVERS,
PANDINO_BUNDLE_IMPORTER_PROP,
PANDINO_MANIFEST_FETCHER_PROP,
} from '../pandino-constants';
import { Logger, LogLevel } from '../logger';
import { ManifestFetcher } from '../manifest-fetcher';
import { BundleImporter } from '../bundle-importer';
import { BundleType } from '../bundle';
import { ActivatorResolver } from '../activator-resolver';

export interface FrameworkConfigMap extends Record<string, any> {
[PANDINO_MANIFEST_FETCHER_PROP]: ManifestFetcher;
[PANDINO_BUNDLE_IMPORTER_PROP]: BundleImporter;
[PANDINO_ACTIVATOR_RESOLVERS]?: Record<BundleType, ActivatorResolver>;
[DEPLOYMENT_ROOT_PROP]?: string;
[LOG_LOGGER_PROP]?: Logger;
[LOG_LEVEL_PROP]?: LogLevel;
Expand Down
1 change: 1 addition & 0 deletions packages/@pandino/pandino-api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './activator-resolver';
export * from './bundle';
export * from './filter-api';
export * from './filter-parser';
Expand Down
23 changes: 23 additions & 0 deletions packages/@pandino/pandino-api/src/pandino-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const LOG_LEVEL_PROP = 'pandino.log.level';
export const LOG_LOGGER_PROP = 'pandino.log.logger';
export const PANDINO_BUNDLE_IMPORTER_PROP = 'pandino.bundle.importer';
export const PANDINO_MANIFEST_FETCHER_PROP = 'pandino.manifest.fetcher';
export const PANDINO_ACTIVATOR_RESOLVERS = 'pandino.activator.resolvers';
export const BUNDLE_NAMESPACE = 'pandino.wiring.bundle';
export const IDENTITY_NAMESPACE = 'pandino.identity';
export const TYPE_BUNDLE = 'pandino.bundle';
Expand Down Expand Up @@ -42,6 +43,28 @@ export const BUNDLE_VENDOR = 'Bundle-Vendor';
*/
export const BUNDLE_VERSION = 'Bundle-Version';

/**
* Manifest header identifying the bundle's type.
*
* Valid options are:
* - esm
* - umd
*
* Default: esm
*
* Warning! Given that UMD modules are loaded onto the `window`, Pandino cannot guarantee that they cannot be tempered
* with. Re-loading the same bundle multiple times may cause issues.
*/
export const BUNDLE_TYPE = 'Bundle-Type';

/**
* Manifest header identifying the bundle's UMD name.
*
* If the Bundle's type is `umd` then this header MUST be present, and should refer to whatever name the module has been
* exported on.
*/
export const BUNDLE_UMD_NAME = 'Bundle-UMD-Name';

/**
* If the corresponding value is a path string, then the value <b>MUST</b> be a relative path calculated from the
* {@link DEPLOYMENT_ROOT_PROP}'s value!
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ActivatorResolver, BundleActivator, BundleManifestHeaders } from '@pandino/pandino-api';

export class EsmActivatorResolver implements ActivatorResolver {
resolve(module: any, bundleHeaders: BundleManifestHeaders): BundleActivator {
return module.default;
}
}
99 changes: 66 additions & 33 deletions packages/@pandino/pandino/src/pandino.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,48 @@
import {
ActivatorResolver,
Bundle,
BundleImporter,
FrameworkEventType,
FrameworkListener,
BUNDLE_ACTIVATOR,
BUNDLE_NAME,
BUNDLE_SYMBOLICNAME,
BUNDLE_TYPE,
BUNDLE_VERSION,
BundleActivator,
BundleContext,
BundleEventType,
BundleImporter,
BundleListener,
BundleManifestHeaders,
ServiceEvent,
ServiceProperties,
BundleState,
Logger,
ManifestFetcher,
BUNDLE_ACTIVATOR,
BUNDLE_NAME,
BUNDLE_SYMBOLICNAME,
BUNDLE_VERSION,
SYSTEMBUNDLE_ACTIVATORS_PROP,
LOG_LOGGER_PROP,
BundleType,
DEPLOYMENT_ROOT_PROP,
FilterApi,
FRAMEWORK_BUNDLE_IMPORTER,
FRAMEWORK_FILTER_PARSER,
FRAMEWORK_LOGGER,
FRAMEWORK_MANIFEST_FETCHER,
FRAMEWORK_SEMVER_FACTORY,
FrameworkConfigMap,
FrameworkEventType,
FrameworkListener,
LOG_LEVEL_PROP,
LOG_LOGGER_PROP,
Logger,
LogLevel,
ServiceListener,
FilterApi,
ServiceReference,
ServiceRegistration,
ManifestFetcher,
OBJECTCLASS,
SYSTEM_BUNDLE_SYMBOLICNAME,
PANDINO_ACTIVATOR_RESOLVERS,
PANDINO_BUNDLE_IMPORTER_PROP,
PANDINO_MANIFEST_FETCHER_PROP,
FRAMEWORK_LOGGER,
DEPLOYMENT_ROOT_PROP,
FRAMEWORK_MANIFEST_FETCHER,
FRAMEWORK_BUNDLE_IMPORTER,
SYSTEM_BUNDLE_LOCATION,
FRAMEWORK_FILTER_PARSER,
FrameworkConfigMap,
ServiceFactory,
SemVer,
FRAMEWORK_SEMVER_FACTORY,
ServiceEvent,
ServiceFactory,
ServiceListener,
ServiceProperties,
ServiceReference,
ServiceRegistration,
SYSTEM_BUNDLE_LOCATION,
SYSTEM_BUNDLE_SYMBOLICNAME,
SYSTEMBUNDLE_ACTIVATORS_PROP,
} from '@pandino/pandino-api';
import { BundleImpl } from './lib/framework/bundle-impl';
import { EventDispatcher } from './lib/framework/event-dispatcher';
Expand All @@ -60,6 +64,7 @@ import { ServiceRegistryCallbacks } from './lib/framework/service-registry-callb
import { FilterParserImpl } from './lib/filter/filter-parser';
import { SemVerImpl } from './lib/utils/semver-impl';
import { SemverFactoryImpl } from './lib/utils/semver-factory';
import { EsmActivatorResolver } from './lib/framework/esm-activator-resolver';

export class Pandino extends BundleImpl implements Framework {
private readonly fetcher: ManifestFetcher;
Expand All @@ -83,6 +88,17 @@ export class Pandino extends BundleImpl implements Framework {
: new VoidImporter();
logger.setLogLevel(configMap[LOG_LEVEL_PROP] || LogLevel.LOG);

if (!configMap[PANDINO_ACTIVATOR_RESOLVERS]) {
// @ts-ignore
configMap[PANDINO_ACTIVATOR_RESOLVERS] = {
esm: new EsmActivatorResolver(),
};
}

if (!configMap[PANDINO_ACTIVATOR_RESOLVERS].esm) {
configMap[PANDINO_ACTIVATOR_RESOLVERS].esm = new EsmActivatorResolver();
}

super(
logger,
0,
Expand Down Expand Up @@ -572,18 +588,35 @@ export class Pandino extends BundleImpl implements Framework {
let activator: BundleActivator = null;
let headerMap: BundleManifestHeaders = impl.getHeaders();
let activatorDefinition = headerMap[BUNDLE_ACTIVATOR];

if (isAnyMissing(activatorDefinition)) {
throw new Error('Missing mandatory Bundle Activator!');
} else if (typeof activatorDefinition === 'string') {
this.logger.debug(`Attempting to load Activator from: ${activatorDefinition}`);

let activatorInstance: any;
try {
activatorInstance = (
await this.importer.import(activatorDefinition, impl.getLocation(), impl.getDeploymentRoot())
).default;
} catch (ex) {
throw new Error('Not found: ' + activatorDefinition + ': ' + ex);
const activatorModule = await this.importer.import(
activatorDefinition,
impl.getLocation(),
impl.getDeploymentRoot(),
);
const bundleType: BundleType = impl.getHeaders()[BUNDLE_TYPE] || 'esm';
const activatorResolver: ActivatorResolver = this.configMap.get(PANDINO_ACTIVATOR_RESOLVERS)[bundleType];

if (!activatorResolver) {
throw new Error(`No ActivatorResolver can be found in configuration for BundleType: ${bundleType}!`);
}

activatorInstance = activatorResolver.resolve(activatorModule, impl.getHeaders());

if (!activatorInstance) {
throw new Error(
`Activator for ${impl
.getCurrentRevision()
.getSymbolicName()} could not be loaded! Resolver probably returned undefined. Please check corresponding ActivatorResolver!`,
);
}

activator =
typeof activatorInstance === 'function' ? (new activatorInstance() as BundleActivator) : activatorInstance;
} else {
Expand Down
Loading

0 comments on commit c6b81e3

Please sign in to comment.