UNPKG

@eclipse-emfcloud/model-service-theia

Version:
224 lines 10.1 kB
"use strict"; // ***************************************************************************** // Copyright (C) 2023-2024 STMicroelectronics. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: MIT License which is // available at https://opensource.org/licenses/MIT. // // SPDX-License-Identifier: EPL-2.0 OR MIT // ***************************************************************************** var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultModelHubManager = exports.ModelServiceContributionFactory = exports.ModelHubManager = void 0; const model_accessor_bus_1 = require("@eclipse-emfcloud/model-accessor-bus"); const model_service_1 = require("@eclipse-emfcloud/model-service"); const model_validation_1 = require("@eclipse-emfcloud/model-validation"); const core_1 = require("@theia/core"); const inversify_1 = require("@theia/core/shared/inversify"); const common_1 = require("../common"); const model_hub_lifecycle_contribution_1 = require("./model-hub-lifecycle-contribution"); /** Service identifier for the Model Hub manager. */ exports.ModelHubManager = Symbol('ModelHubManager'); /** * Dependency injection symbol for ModelServiceContributionFactory. */ exports.ModelServiceContributionFactory = Symbol('ModelServiceContributionFactory'); let DefaultModelHubManager = class DefaultModelHubManager { constructor() { this.initializationTimeoutMs = 30_000; this.modelHubs = new Map(); this.trackingSubscriptions = []; /* Model hub lifecycle to use when there are no applicable contributions. */ this.defaultModelHubLifecycle = { createModelHub: (...args) => new model_service_1.ModelHubImpl(...args), }; } getModelHub(context) { let result = this.modelHubs.get(context)?.modelHub; if (!result) { result = this.createModelHub(context); } return result; } async provideModelHub(context) { const result = this.getModelHub(context); try { await this.initializeContext(context); } catch (error) { // Forget this record. The next attempt to provide the model hub will start over try { result.dispose(); } finally { this.modelHubs.delete(context); } throw error; } return result; } disposeContext(context) { const record = this.modelHubs.get(context); this.modelHubs.delete(context); if (record) { if (record.lifecycle.disposeModelHub) { record.lifecycle.disposeModelHub(record.modelHub); } else { record.modelHub.dispose(); } } } /** * Creates and initializes a new model hub for a given `context`. * * @param context the model hub context that defines, in some application-specific way, the scope of the models managed in the hub * @returns the `context`'s model hub */ createModelHub(context) { const modelManager = (0, model_service_1.createModelServiceModelManager)(); const validationService = new model_validation_1.ModelValidationServiceImpl(); const modelAccessorBus = new model_accessor_bus_1.ModelAccessorBusImpl(); // Get the lifecycle contribution to use to create the Model Hub const [_, lifecycle] = this.modelHubLifecycleContributions .getContributions() .reduce(([prevPrio, prev], curr) => { const currPrio = curr.getPriority?.(context) ?? 0; return !isNaN(currPrio) && currPrio > prevPrio ? [currPrio, curr] : [prevPrio, prev]; }, [-Infinity, this.defaultModelHubLifecycle]); // Create the Model Hub const result = lifecycle.createModelHub(context, modelManager, validationService, modelAccessorBus); const contribute = (contribution) => result.addModelServiceContribution(contribution); const configure = (contribution) => contribution.setModelHub(result); const contributions = this.modelServiceContributionFactory(); // Add all contributions to the Model Hub contributions.forEach(contribute); // All contributions are added, so make it known to model services contributions.forEach(configure); this.modelHubs.set(context, { modelHub: result, lifecycle, initialized: false, }); return result; } async initializeContext(context) { const record = this.modelHubs.get(context); if (!record) { throw new Error(`No model hub exists for context ${context}.`); } if (record.pendingInitialization === undefined) { if (!record.lifecycle.initializeModelHub) { // Nothing to initialize, so just toggle it record.initialized = true; record.pendingInitialization = Promise.resolve(record.modelHub); this.notifyModelHubCreated(context); } else { const measurement = this.stopwatch?.start(`initialize model hub`, { thresholdMillis: 500, context: `model hub '${context}`, }); const initializeModelHub = record.lifecycle.initializeModelHub; record.pendingInitialization = (0, common_1.retryUntilFulfilled)(() => { const initializedModelHub = initializeModelHub .call(record.lifecycle, record.modelHub) .then(() => record.modelHub); return (0, common_1.timeout)(initializedModelHub, this.initializationTimeoutMs, (outcome) => { if (outcome === 'timeout') { measurement?.error('timed out'); return ('Model Hub initialization timed out for context: ' + context); } else if (outcome instanceof Error) { measurement?.error('failed', outcome); } else { record.initialized = true; this.notifyModelHubCreated(context); measurement?.log('complete'); } return undefined; }); }); } } const result = await record.pendingInitialization; const disposeSub = result.subscribe(); disposeSub.onModelHubDisposed = () => this.notifyModelHubDestroyed(context); return result; } // // Model hub tracking // notifyModelHubCreated(context) { this.trackingSubscriptions.forEach((sub) => sub.onModelHubCreated?.(context)); } notifyModelHubDestroyed(context) { this.trackingSubscriptions.forEach((sub) => sub.onModelHubDestroyed?.(context)); } trackModelHubs() { let _onModelHubCreated; const modelHubs = this.modelHubs; const result = { close: () => { const index = this.trackingSubscriptions.indexOf(result); if (index >= 0) { this.trackingSubscriptions.splice(index, 1); } }, get onModelHubCreated() { return _onModelHubCreated; }, set onModelHubCreated(onModelHubCreated) { _onModelHubCreated = onModelHubCreated; if (onModelHubCreated) { modelHubs.forEach((record, context) => { if (record.initialized) { onModelHubCreated(context); } }); } }, }; this.trackingSubscriptions.push(result); return result; } isModelHubAvailable(context) { return this.modelHubs.get(context)?.initialized === true; } }; exports.DefaultModelHubManager = DefaultModelHubManager; __decorate([ (0, inversify_1.inject)(exports.ModelServiceContributionFactory), __metadata("design:type", Function) ], DefaultModelHubManager.prototype, "modelServiceContributionFactory", void 0); __decorate([ (0, inversify_1.inject)(core_1.ContributionProvider), (0, inversify_1.named)(model_hub_lifecycle_contribution_1.ModelHubLifecycleContribution), __metadata("design:type", Object) ], DefaultModelHubManager.prototype, "modelHubLifecycleContributions", void 0); __decorate([ (0, inversify_1.optional)(), (0, inversify_1.inject)(core_1.Stopwatch), __metadata("design:type", Object) ], DefaultModelHubManager.prototype, "stopwatch", void 0); exports.DefaultModelHubManager = DefaultModelHubManager = __decorate([ (0, inversify_1.injectable)() ], DefaultModelHubManager); //# sourceMappingURL=model-hub-manager.js.map