@eclipse-emfcloud/model-service-theia
Version:
Model service Theia
224 lines • 10.1 kB
JavaScript
;
// *****************************************************************************
// 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