From 9854b4c5bab2f480343454bf748bb34f9d7ec2c4 Mon Sep 17 00:00:00 2001 From: Camille Letavernier Date: Fri, 28 Oct 2022 15:45:51 +0200 Subject: [PATCH 1/2] 179: Convert all Modelserver-Node APIs to use URI instead of String - Convert all public Modelserver-Node APIs to URI. This especially includes Providers and Services refs https://github.com/eclipse-emfcloud/emfcloud/issues/179 Contributed on behalf of STMicroelectronics Signed-off-by: Camille Letavernier --- .../src/example-command.ts | 3 +- .../src/example-validator.ts | 5 +-- .../trigger-example/src/example-trigger.ts | 9 ++--- .../src/client/model-server-client.ts | 33 ++++++++----------- .../src/command-provider-registry.spec.ts | 3 +- .../src/command-provider-registry.ts | 2 +- .../modelserver-node/src/routes/models.ts | 6 ++-- .../modelserver-node/src/routes/undo-redo.ts | 8 +++-- .../modelserver-node/src/routes/validation.ts | 3 +- .../src/server-integration-test.spec.ts | 9 ++--- .../src/services/edit-service.ts | 17 +++++----- .../src/services/model-service.ts | 6 ++-- .../src/services/subscription-manager.ts | 15 +++++---- .../src/services/validation-manager.ts | 15 +++++---- .../src/trigger-provider-registry.spec.ts | 15 +++++---- .../src/trigger-provider-registry.ts | 9 ++--- .../src/validation-provider-registry.ts | 17 +++++----- .../src/command-provider.ts | 3 +- .../modelserver-plugin-ext/src/executor.ts | 2 +- .../src/model-service.ts | 2 +- .../src/trigger-provider.ts | 5 +-- .../src/validation-provider.ts | 4 +-- 22 files changed, 102 insertions(+), 89 deletions(-) diff --git a/examples/custom-command-example/src/example-command.ts b/examples/custom-command-example/src/example-command.ts index 441fe6f..85bcf96 100644 --- a/examples/custom-command-example/src/example-command.ts +++ b/examples/custom-command-example/src/example-command.ts @@ -20,6 +20,7 @@ import { Transaction } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { inject, injectable, named } from 'inversify'; +import * as URI from 'urijs'; /** * A simple example of a plug-in that provides custom commands. @@ -52,7 +53,7 @@ class IncrementDurationCommandProvider implements CommandProvider { return true; // The command type filter is all I need } - getCommands(_modelUri: string, customCommand: ModelServerCommand): Transaction { + getCommands(_modelUri: URI, customCommand: ModelServerCommand): Transaction { const [modelURI, elementID] = customCommand.owner.$ref.split('#'); return async executor => { diff --git a/examples/custom-validator-example/src/example-validator.ts b/examples/custom-validator-example/src/example-validator.ts index 89082c5..aa0b71d 100644 --- a/examples/custom-validator-example/src/example-validator.ts +++ b/examples/custom-validator-example/src/example-validator.ts @@ -19,6 +19,7 @@ import { ValidationProvider } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { inject, injectable, named } from 'inversify'; +import * as URI from 'urijs'; /** * A simple example of a plug-in that provides custom validation. @@ -47,11 +48,11 @@ export class ExampleCustomValidationPlugin implements ModelServerPlugin { class CoffeeMachineValidator implements ValidationProvider { constructor(protected readonly modelServerClient: ModelServerClientApi, protected readonly logger: Logger) {} - canValidate(model: ModelServerObjectV2, modelURI: string): boolean { + canValidate(model: ModelServerObjectV2, modelURI: URI): boolean { return true; // Nothing further to check than the pattern supplied at registration } - validate(model: ModelServerObjectV2, modelURI: string): Diagnostic { + validate(model: ModelServerObjectV2, modelURI: URI): Diagnostic { const probabilityTest = Math.random(); if (probabilityTest < 0.5) { return Diagnostic.ok(); diff --git a/examples/trigger-example/src/example-trigger.ts b/examples/trigger-example/src/example-trigger.ts index ebc83fa..4a02868 100644 --- a/examples/trigger-example/src/example-trigger.ts +++ b/examples/trigger-example/src/example-trigger.ts @@ -20,6 +20,7 @@ import { } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { AddOperation, Operation, ReplaceOperation } from 'fast-json-patch'; import { inject, injectable, named } from 'inversify'; +import * as URI from 'urijs'; /** * A simple example of a plug-in that provides triggers for automatic update of model objects. @@ -46,16 +47,16 @@ export class ExampleTriggerPlugin implements ModelServerPlugin { class IncrementDurationTriggerProvider implements TriggerProvider { constructor(protected readonly modelServerClient: ModelServerClientApi, protected readonly logger: Logger) {} - canTrigger(modelURI: string, patch: Operation[]): boolean { + canTrigger(modelURI: URI, patch: Operation[]): boolean { return patch.some(isDurationChange); } - async getTriggers(modelURI: string, modelDelta: Operation[]): Promise { + async getTriggers(modelURI: URI, modelDelta: Operation[]): Promise { // In this case, because the trigger updates the same properties previously modified, // we have all the information we need in the `modelDelta`. But in the general case, // a trigger provider will need to find other related objects in the model and generate // new changes from those, so that's how we do it here - const model = await this.modelServerClient.get(modelURI); + const model = await this.modelServerClient.get(modelURI.toString()); const result: Operation[] = []; // Take only the last change to any given duration in case of multiple (such as @@ -65,7 +66,7 @@ class IncrementDurationTriggerProvider implements TriggerProvider { // Don't update if already a multiple of ten if (element && op.value % 10 !== 0) { this.logger.debug('Rounding up duration %d of object at %s', op.value, op.path); - result.push(replace(modelURI, element, 'duration', roundUp(op.value, 10))); + result.push(replace(modelURI.toString(), element, 'duration', roundUp(op.value, 10))); } }); diff --git a/packages/modelserver-node/src/client/model-server-client.ts b/packages/modelserver-node/src/client/model-server-client.ts index 2897701..c4c3e55 100644 --- a/packages/modelserver-node/src/client/model-server-client.ts +++ b/packages/modelserver-node/src/client/model-server-client.ts @@ -38,7 +38,6 @@ import * as WebSocket from 'ws'; import { CommandProviderRegistry } from '../command-provider-registry'; import { TriggerProviderRegistry } from '../trigger-provider-registry'; import { CompletablePromise } from './promise-utils'; -import { validateModelURI } from './uri-utils'; import { WebSocketMessageAcceptor } from './web-socket-utils'; export const UpstreamConnectionConfig = Symbol('UpstreamConnectionConfig'); @@ -71,7 +70,7 @@ export interface InternalModelServerClientApi extends ModelServerClientApi { * @returns a transactional context in which to execute a chained sequence of commands, * or a rejected promise in the case that a transaction is already open on the given model */ - openTransaction(modeluri: string): Promise; + openTransaction(modeluri: URI): Promise; } /** @@ -174,22 +173,16 @@ export class InternalModelServerClient implements InternalModelServerClientApi { return this.delegate.initialize(this._baseURL.toString(), DEFAULT_FORMAT); } - async openTransaction(modelUri: string): Promise { - let uri: URI; - try { - uri = validateModelURI(modelUri); - } catch (error) { - this.logger.error(error); - return Promise.reject(); - } - if (this.transactions.has(uri.toString())) { + async openTransaction(modelUri: URI): Promise { + const uriKey = modelUri.normalize().toString(); + if (this.transactions.has(uriKey)) { // Open a nested transaction - return this.transactions.get(uri.toString()).openTransaction(); + return this.transactions.get(uriKey).openTransaction(); } const clientID = uuid(); - return axios.post(this.makeURL('transaction', { modeluri: uri.toString() }), { data: clientID }).then(response => { + return axios.post(this.makeURL('transaction', { modeluri: modelUri.toString() }), { data: clientID }).then(response => { const { uri: transactionURI } = (response.data as CreateTransactionResponseBody).data; const result = new DefaultTransactionContext( transactionURI, @@ -198,8 +191,8 @@ export class InternalModelServerClient implements InternalModelServerClientApi { this.triggerProviderRegistry, this.logger ); - this.transactions.set(uri.toString(), result); - return result.open(tc => this.closeTransaction(uri, tc)); + this.transactions.set(uriKey, result); + return result.open(tc => this.closeTransaction(modelUri, tc)); }); } @@ -370,7 +363,7 @@ class DefaultTransactionContext implements TransactionContext { constructor( protected readonly transactionURI: string, - protected readonly modelURI: string, + protected readonly modelURI: URI, protected readonly commandProviderRegistry: CommandProviderRegistry, protected readonly triggerProviderRegistry: TriggerProviderRegistry, protected readonly logger: Logger @@ -385,7 +378,7 @@ class DefaultTransactionContext implements TransactionContext { } // Doc inherited from `EditTransaction` interface - getModelURI(): string { + getModelURI(): URI { return this.modelURI; } @@ -490,7 +483,7 @@ class DefaultTransactionContext implements TransactionContext { } // Doc inherited from `Executor` interface - async execute(modelUri: string, command: ModelServerCommand): Promise { + async execute(modelUri: URI, command: ModelServerCommand): Promise { if (!this.isOpen()) { return Promise.reject('Socket is closed.'); } @@ -499,7 +492,7 @@ class DefaultTransactionContext implements TransactionContext { } /** Internal implementation of the {@link TransactionContext.execute} method. */ - async doExecute(modelUri: string, command: ModelServerCommand): Promise { + async doExecute(modelUri: URI, command: ModelServerCommand): Promise { // Hook in command-provider plug-ins if (!this.commandProviderRegistry.hasProvider(command.type)) { // Not handled. Send along to the Model Server @@ -688,7 +681,7 @@ class DefaultTransactionContext implements TransactionContext { protected message(type: MessageBody['type'], data: unknown = {}): MessageBody { return { type, - modelUri: this.modelURI, + modelUri: this.modelURI.toString(), data }; } diff --git a/packages/modelserver-node/src/command-provider-registry.spec.ts b/packages/modelserver-node/src/command-provider-registry.spec.ts index ee5b1dc..ba9f2b2 100644 --- a/packages/modelserver-node/src/command-provider-registry.spec.ts +++ b/packages/modelserver-node/src/command-provider-registry.spec.ts @@ -12,6 +12,7 @@ import { ModelServerCommand, replace } from '@eclipse-emfcloud/modelserver-clien import { CommandProvider, Logger, Transaction } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { expect } from 'chai'; import { Container } from 'inversify'; +import * as URI from 'urijs'; import { CommandProviderRegistry } from './command-provider-registry'; @@ -52,7 +53,7 @@ class TestCommandProvider implements CommandProvider { return true; } - getCommands(_modelUri: string, customCommand: ModelServerCommand): Transaction { + getCommands(_modelUri: URI, customCommand: ModelServerCommand): Transaction { if (!customCommand.owner) { console.error('custom command owner was unexpectedly undefined'); return async () => false; diff --git a/packages/modelserver-node/src/command-provider-registry.ts b/packages/modelserver-node/src/command-provider-registry.ts index 2ebd3b8..ad1eedf 100644 --- a/packages/modelserver-node/src/command-provider-registry.ts +++ b/packages/modelserver-node/src/command-provider-registry.ts @@ -93,7 +93,7 @@ export class CommandProviderRegistry { * @returns the provided command, command transaction, or the original `customCommand` standing in for itself * if no provider can handle the custom command */ - async getCommands(modelUri: string, customCommand: ModelServerCommand): Promise { + async getCommands(modelUri: URI, customCommand: ModelServerCommand): Promise { let result: ModelServerCommand | Operation[] | Transaction | undefined; const provider = this.getProvider(customCommand); if (provider) { diff --git a/packages/modelserver-node/src/routes/models.ts b/packages/modelserver-node/src/routes/models.ts index 10dcaaf..6a0634e 100644 --- a/packages/modelserver-node/src/routes/models.ts +++ b/packages/modelserver-node/src/routes/models.ts @@ -105,7 +105,7 @@ export class ModelsRoutes implements RouteProvider { ? this.modelServerClient.create(modeluri.toString(), model, format) : this.modelServerClient.update(modeluri.toString(), model, format); - delegated.then(this.performModelValidation(modeluri.toString())).then(relay(res)).catch(handleError(res)); + delegated.then(this.performModelValidation(modeluri)).then(relay(res)).catch(handleError(res)); }; } @@ -146,7 +146,7 @@ export class ModelsRoutes implements RouteProvider { patchOrCommand: Operation | Operation[] | ModelServerCommand, res: Response> ): void { - this.editService.edit(modelURI.toString(), patchOrCommand).then(relay(res)).catch(handleError(res)); + this.editService.edit(modelURI, patchOrCommand).then(relay(res)).catch(handleError(res)); } /** @@ -155,7 +155,7 @@ export class ModelsRoutes implements RouteProvider { * @param modelURI the model created or replaced * @returns the created or replacing model */ - protected performModelValidation(modelURI: string): (delegatedResult: AnyObject) => Promise { + protected performModelValidation(modelURI: URI): (delegatedResult: AnyObject) => Promise { const validator = this.validationManager; return async (delegatedResult: AnyObject) => validator.performLiveValidation(modelURI).then(() => delegatedResult); diff --git a/packages/modelserver-node/src/routes/undo-redo.ts b/packages/modelserver-node/src/routes/undo-redo.ts index 7084d3e..90debff 100644 --- a/packages/modelserver-node/src/routes/undo-redo.ts +++ b/packages/modelserver-node/src/routes/undo-redo.ts @@ -12,6 +12,7 @@ import { ModelUpdateResult } from '@eclipse-emfcloud/modelserver-client/lib'; import { Logger, RouteProvider, RouterFactory } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { Request, RequestHandler, Response } from 'express'; import { inject, injectable, named } from 'inversify'; +import * as URI from 'urijs'; import { InternalModelServerClientApi } from '../client/model-server-client'; import { ValidationManager } from '../services/validation-manager'; @@ -69,11 +70,14 @@ export class UndoRedoRoutes implements RouteProvider { ? this.modelServerClient.undo(modelURI) : this.modelServerClient.redo(modelURI); - delegated.then(this.performLiveValidation(modelURI)).then(relay(res)).catch(handleError(res)); + delegated + .then(this.performLiveValidation(new URI(modelURI))) + .then(relay(res)) + .catch(handleError(res)); }; } - protected performLiveValidation(modelURI: string): (delegatedResult: ModelUpdateResult) => Promise { + protected performLiveValidation(modelURI: URI): (delegatedResult: ModelUpdateResult) => Promise { const validator = this.validationManager; return async (delegatedResult: ModelUpdateResult) => validator.performLiveValidation(modelURI).then(() => delegatedResult); diff --git a/packages/modelserver-node/src/routes/validation.ts b/packages/modelserver-node/src/routes/validation.ts index 4391f25..854efa3 100644 --- a/packages/modelserver-node/src/routes/validation.ts +++ b/packages/modelserver-node/src/routes/validation.ts @@ -11,6 +11,7 @@ import { Logger, RouteProvider, RouterFactory } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { Request, RequestHandler, Response } from 'express'; import { inject, injectable, named } from 'inversify'; +import URI = require('urijs'); import { InternalModelServerClientApi } from '../client/model-server-client'; import { ValidationManager } from '../services/validation-manager'; @@ -67,7 +68,7 @@ export class ValidationRoutes implements RouteProvider { return; } - this.validationManager.validate(modelURI).then(relay(res)).catch(handleError(res)); + this.validationManager.validate(new URI(modelURI)).then(relay(res)).catch(handleError(res)); }; } } diff --git a/packages/modelserver-node/src/server-integration-test.spec.ts b/packages/modelserver-node/src/server-integration-test.spec.ts index 5b4336c..8c8704a 100644 --- a/packages/modelserver-node/src/server-integration-test.spec.ts +++ b/packages/modelserver-node/src/server-integration-test.spec.ts @@ -25,6 +25,7 @@ import { Operation } from 'fast-json-patch'; import { Container } from 'inversify'; import * as sinon from 'sinon'; import { assert } from 'sinon'; +import * as URI from 'urijs'; import * as WebSocket from 'ws'; import { InternalModelServerClientApi, TransactionContext } from './client/model-server-client'; @@ -262,7 +263,7 @@ describe('Server Integration Tests', () => { }); beforeEach(async () => { - transaction = await client.openTransaction('SuperBrewer3000.coffee'); + transaction = await client.openTransaction(new URI('SuperBrewer3000.coffee')); }); afterEach(async () => { @@ -281,7 +282,7 @@ describe('Server Integration Tests', () => { it('transaction already open', async () => { try { - const duplicate = await client.openTransaction('SuperBrewer3000.coffee'); + const duplicate = await client.openTransaction(new URI('SuperBrewer3000.coffee')); await duplicate.rollback('Should not have been opened.'); expect.fail('Should not have been able to open duplicate transaction.'); } catch (error) { @@ -371,7 +372,7 @@ describe('Server Integration Tests', () => { it('Transaction rolled back by failure', async () => { const patch: Operation = { op: 'replace', path: '/workflows/0/name', value: 'New Name' }; - const transaction1 = await client.openTransaction('SuperBrewer3000.coffee'); + const transaction1 = await client.openTransaction(new URI('SuperBrewer3000.coffee')); try { await transaction1.applyPatch(patch); @@ -386,7 +387,7 @@ describe('Server Integration Tests', () => { expect(transaction1.isOpen()).to.be.false; // Should be able to open a new transaction - const transaction2 = await client.openTransaction('SuperBrewer3000.coffee'); + const transaction2 = await client.openTransaction(new URI('SuperBrewer3000.coffee')); expect(transaction2.isOpen()).to.be.true; try { diff --git a/packages/modelserver-node/src/services/edit-service.ts b/packages/modelserver-node/src/services/edit-service.ts index d93b727..0173d73 100644 --- a/packages/modelserver-node/src/services/edit-service.ts +++ b/packages/modelserver-node/src/services/edit-service.ts @@ -12,6 +12,7 @@ import { AddCommand, ModelServerCommand, ModelUpdateResult, RemoveCommand, SetCo import { Executor, Logger, Transaction } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { Operation } from 'fast-json-patch'; import { inject, injectable, named } from 'inversify'; +import * as URI from 'urijs'; import { InternalModelServerClientApi, isModelServerCommand, TransactionContext } from '../client/model-server-client'; import { CommandProviderRegistry } from '../command-provider-registry'; @@ -39,7 +40,7 @@ export class EditService { @inject(ValidationManager) protected readonly validationManager: ValidationManager; - async edit(modelURI: string, patchOrCommand: Operation | Operation[] | ModelServerCommand): Promise { + async edit(modelURI: URI, patchOrCommand: Operation | Operation[] | ModelServerCommand): Promise { if (isModelServerCommand(patchOrCommand)) { // Case of executing a command const command = patchOrCommand; @@ -51,7 +52,7 @@ export class EditService { return this.forwardEdit(modelURI, patch); } - protected async handleCommand(modelURI: string, command: ModelServerCommand): Promise { + protected async handleCommand(modelURI: URI, command: ModelServerCommand): Promise { this.logger.debug(`Getting commands provided for ${command.type}`); const provided = await this.commandProviderRegistry.getCommands(modelURI, command); @@ -59,7 +60,7 @@ export class EditService { } protected forwardEdit( - modelURI: string, + modelURI: URI, providedEdit: ModelServerCommand | Operation | Operation[] | Transaction ): Promise { if (this.triggerProviderRegistry.hasProviders()) { @@ -69,7 +70,7 @@ export class EditService { } private async forwardEditSimple( - modelURI: string, + modelURI: URI, providedEdit: ModelServerCommand | Operation | Operation[] | Transaction ): Promise { if (typeof providedEdit === 'function') { @@ -86,10 +87,10 @@ export class EditService { if (isModelServerCommand(providedEdit)) { // Command case - result = this.modelServerClient.edit(modelURI, providedEdit); + result = this.modelServerClient.edit(modelURI.toString(), providedEdit); } else { // JSON Patch case - result = this.modelServerClient.edit(modelURI, providedEdit); + result = this.modelServerClient.edit(modelURI.toString(), providedEdit); } return result.then(this.performPatchValidation(modelURI)); @@ -97,7 +98,7 @@ export class EditService { } private async forwardEditWithTriggers( - modelURI: string, + modelURI: URI, providedEdit: ModelServerCommand | Operation | Operation[] | Transaction ): Promise { let result = true; @@ -135,7 +136,7 @@ export class EditService { * @param modelURI the model patched * @returns a function that performs live validation on a model update result if it was successful */ - protected performPatchValidation(modelURI: string): (validate: ModelUpdateResult) => Promise { + protected performPatchValidation(modelURI: URI): (validate: ModelUpdateResult) => Promise { const validator = this.validationManager; return async (validate: ModelUpdateResult) => { diff --git a/packages/modelserver-node/src/services/model-service.ts b/packages/modelserver-node/src/services/model-service.ts index 943ff17..821325a 100644 --- a/packages/modelserver-node/src/services/model-service.ts +++ b/packages/modelserver-node/src/services/model-service.ts @@ -69,7 +69,7 @@ export class DefaultModelService implements ModelService { edit(patch: Operation | Operation[]): Promise; edit(command: ModelServerCommand): Promise; edit(patchOrCommand: Operation | Operation[] | ModelServerCommand): Promise { - return this.editService.edit(this.getModelURI().toString(), patchOrCommand); + return this.editService.edit(this.getModelURI(), patchOrCommand); } undo(): Promise { @@ -81,11 +81,11 @@ export class DefaultModelService implements ModelService { } openTransaction(): Promise { - return this.client.openTransaction(this.getModelURI().toString()); + return this.client.openTransaction(this.getModelURI()); } validate(): Promise { - return this.validator.validate(this.getModelURI().toString()); + return this.validator.validate(this.getModelURI()); } async create(content: M, format?: string): Promise { diff --git a/packages/modelserver-node/src/services/subscription-manager.ts b/packages/modelserver-node/src/services/subscription-manager.ts index bc1ec4e..069c40c 100644 --- a/packages/modelserver-node/src/services/subscription-manager.ts +++ b/packages/modelserver-node/src/services/subscription-manager.ts @@ -14,6 +14,7 @@ import { Logger } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { EventEmitter } from 'events'; import { inject, injectable, named } from 'inversify'; import { stringify as unparseQuery } from 'qs'; +import * as URI from 'urijs'; import * as WebSocket from 'ws'; import { UpstreamConnectionConfig } from '../client/model-server-client'; @@ -129,9 +130,9 @@ export class SubscriptionManager { * @param filter an optional subscriber filter, by options property or a generic predicate * @returns the matching subscriber sockets */ - protected getSubscribers(modelURI: string, filter?: keyof SubscriptionQuery | ((options: SubscriptionQuery) => boolean)): JSONSocket[] { + protected getSubscribers(modelURI: URI, filter?: keyof SubscriptionQuery | ((options: SubscriptionQuery) => boolean)): JSONSocket[] { return Array.from(this.subscriptions.keys()) - .filter(client => client.options.modeluri === modelURI) + .filter(client => modelURI.equals(client.options.modeluri)) .filter(subscriberFilter(filter)); } @@ -145,21 +146,21 @@ export class SubscriptionManager { * @param filter an optional subscriber filter, by options property or a generic predicate * @returns whether any matching subscriptions exist */ - protected hasSubscribers(modelURI: string, filter?: keyof SubscriptionQuery | ((options: SubscriptionQuery) => boolean)): boolean { + protected hasSubscribers(modelURI: URI, filter?: keyof SubscriptionQuery | ((options: SubscriptionQuery) => boolean)): boolean { return Array.from(this.subscriptions.keys()) - .filter(client => client.options.modeluri === modelURI) + .filter(client => modelURI.equals(client.options.modeluri)) .some(subscriberFilter(filter)); } - hasValidationSubscribers(modelURI: string): boolean { + hasValidationSubscribers(modelURI: URI): boolean { return this.hasSubscribers(modelURI, 'livevalidation'); } - protected getValidationSubscribers(modelURI: string): JSONSocket[] { + protected getValidationSubscribers(modelURI: URI): JSONSocket[] { return this.getSubscribers(modelURI, 'livevalidation'); } - async broadcastValidation(modelURI: string, results: Diagnostic): Promise { + async broadcastValidation(modelURI: URI, results: Diagnostic): Promise { const message = { type: MessageType.validationResult, data: results diff --git a/packages/modelserver-node/src/services/validation-manager.ts b/packages/modelserver-node/src/services/validation-manager.ts index 750846a..488b729 100644 --- a/packages/modelserver-node/src/services/validation-manager.ts +++ b/packages/modelserver-node/src/services/validation-manager.ts @@ -12,6 +12,9 @@ import { Diagnostic, encode, ModelServerObjectV2 } from '@eclipse-emfcloud/model import { Logger } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { inject, injectable, named, postConstruct } from 'inversify'; +import { validateModelURI } from '../client/uri-utils'; +import URI = require('urijs'); + import { InternalModelServerClientApi } from '../client/model-server-client'; import { JSONSocket } from '../client/web-socket-utils'; import { ValidationProviderRegistry } from '../validation-provider-registry'; @@ -41,15 +44,15 @@ export class ValidationManager { initialize(): void { this.subscriptionManager.addSubscribedListener((client, params) => { if (params.livevalidation) { - this.initializeLiveValidation(client, params.modeluri); + this.initializeLiveValidation(client, validateModelURI(params.modeluri)); } }); } - async validate(modelURI: string): Promise { + async validate(modelURI: URI): Promise { let model: ModelServerObjectV2; try { - model = await this.modelServerClient.get(modelURI).then(asModelServerObject); + model = await this.modelServerClient.get(modelURI.toString()).then(asModelServerObject); if (!model) { throw new Error(`Could not retrieve model '${modelURI}' to validate.`); } @@ -59,7 +62,7 @@ export class ValidationManager { } this.logger.debug(`Performing core validation of ${modelURI}`); - const defaultDiagnostic = await this.modelServerClient.validate(modelURI); + const defaultDiagnostic = await this.modelServerClient.validate(modelURI.toString()); this.logger.debug(`Performing custom validation of ${modelURI}`); const providedDiagnostic = await this.validationProviderRegistry.validate(model, modelURI); @@ -75,7 +78,7 @@ export class ValidationManager { * @param modelURI the model URI to validate * @returns whether validation was successfully performed and broadcast (not whether it found no problems) */ - async performLiveValidation(modelURI: string): Promise { + async performLiveValidation(modelURI: URI): Promise { // Short-circuit if there are no live validation subscribers if (!this.subscriptionManager.hasValidationSubscribers(modelURI)) { this.logger.debug(`No subscribers to live validation for ${modelURI}.`); @@ -91,7 +94,7 @@ export class ValidationManager { }); } - protected async initializeLiveValidation(client: JSONSocket, modelURI: string): Promise { + protected async initializeLiveValidation(client: JSONSocket, modelURI: URI): Promise { return this.validate(modelURI) .then(diagnostics => this.subscriptionManager.sendValidation(client, diagnostics)) .catch(error => this.logger.error(`Failed to initialize live validation in subscription to ${modelURI}: ${error}`)); diff --git a/packages/modelserver-node/src/trigger-provider-registry.spec.ts b/packages/modelserver-node/src/trigger-provider-registry.spec.ts index a5ab1e2..0151de8 100644 --- a/packages/modelserver-node/src/trigger-provider-registry.spec.ts +++ b/packages/modelserver-node/src/trigger-provider-registry.spec.ts @@ -15,6 +15,7 @@ import { expect } from 'chai'; import { Operation } from 'fast-json-patch'; import { Container } from 'inversify'; import * as sinon from 'sinon'; +import * as URI from 'urijs'; import { TriggerProviderRegistry } from './trigger-provider-registry'; @@ -53,11 +54,11 @@ describe('TriggerProviderRegistry', () => { describe('provider aggregation in #getProvider', () => { const provider1 = { - canTrigger: (modelURI: string) => modelURI === 'test:a', + canTrigger: (modelURI: URI) => modelURI.equals('test:a'), getTriggers: (): Operation[] => [{ op: 'replace', path: '/foo/bar/name', value: 'Provider 1' }] }; const provider2 = { - canTrigger: (modelURI: string) => modelURI.startsWith('test:'), + canTrigger: (modelURI: URI) => modelURI.protocol() === 'test', getTriggers: (): Operation[] => [{ op: 'remove', path: '/foo/bar/things/2' }] }; @@ -69,25 +70,25 @@ describe('TriggerProviderRegistry', () => { afterEach(() => registrations()); it('no provider matches', () => { - const provider = registry.getProvider('none:a', [{ op: 'replace', path: '/foo/bar/size', value: 42 }]); + const provider = registry.getProvider(new URI('none:a'), [{ op: 'replace', path: '/foo/bar/size', value: 42 }]); expect(provider).to.be.undefined; }); it('one provider matches', () => { - const provider = registry.getProvider('test:b', [{ op: 'replace', path: '/foo/bar/size', value: 42 }]); + const provider = registry.getProvider(new URI('test:b'), [{ op: 'replace', path: '/foo/bar/size', value: 42 }]); expect(provider).to.be.equal(provider2); }); it('multiple providers match', async () => { - const provider = registry.getProvider('test:a', [{ op: 'replace', path: '/foo/bar/size', value: 42 }]); + const provider = registry.getProvider(new URI('test:a'), [{ op: 'replace', path: '/foo/bar/size', value: 42 }]); expect(provider).to.exist; - const trigger = await provider.getTriggers('test:a', [{ op: 'replace', path: '/foo/bar/size', value: 42 }]); + const trigger = await provider.getTriggers(new URI('test:a'), [{ op: 'replace', path: '/foo/bar/size', value: 42 }]); expect(trigger).to.be.a('function'); const transaction = trigger as Transaction; const counter = new AsyncCounter(); const executor = sinon.spy({ - execute: async (modelUri: string, command: ModelServerCommand) => counter.tick({ success: true }), + execute: async (modelUri: URI, command: ModelServerCommand) => counter.tick({ success: true }), applyPatch: async (patch: Operation | Operation[]) => counter.tick({ success: true }) }); diff --git a/packages/modelserver-node/src/trigger-provider-registry.ts b/packages/modelserver-node/src/trigger-provider-registry.ts index 4cd4e28..75e07b1 100644 --- a/packages/modelserver-node/src/trigger-provider-registry.ts +++ b/packages/modelserver-node/src/trigger-provider-registry.ts @@ -12,6 +12,7 @@ import { Executor, Logger, Transaction, TriggerProvider } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { Operation } from 'fast-json-patch'; import { inject, injectable, named } from 'inversify'; +import * as URI from 'urijs'; import { v4 as uuid } from 'uuid'; /** @@ -62,7 +63,7 @@ export class TriggerProviderRegistry { return this.providers.size > 0; } - getProviders(modelURI: string, patch: Operation[]): TriggerProvider[] { + getProviders(modelURI: URI, patch: Operation[]): TriggerProvider[] { this.logger.debug('Looking up trigger providers for JSON Patch'); const result: TriggerProvider[] = []; for (const provider of this.providers.values()) { @@ -81,7 +82,7 @@ export class TriggerProviderRegistry { * @returns an aggregate trigger provider, or `undefined` if no registered providers * respond to the `patch` */ - getProvider(modelURI: string, patch: Operation[]): TriggerProvider | undefined { + getProvider(modelURI: URI, patch: Operation[]): TriggerProvider | undefined { const providers = this.getProviders(modelURI, patch); switch (providers.length) { case 0: @@ -100,7 +101,7 @@ export class TriggerProviderRegistry { * @param patch the JSON Patch on which to trigger further changes * @returns the provided trigger patch or transaction, if any */ - async getTriggers(modelURI: string, patch: Operation[]): Promise { + async getTriggers(modelURI: URI, patch: Operation[]): Promise { let result: Operation[] | Transaction | undefined; const provider = this.getProvider(modelURI, patch); if (provider) { @@ -124,7 +125,7 @@ export class TriggerProviderRegistry { function multiTriggerProvider(triggerProviders: TriggerProvider[]): TriggerProvider { return { canTrigger: () => true, - getTriggers: (modelURI: string, modelDelta: Operation[]) => async (executor: Executor) => { + getTriggers: (modelURI: URI, modelDelta: Operation[]) => async (executor: Executor) => { let result = true; for (const provider of triggerProviders) { diff --git a/packages/modelserver-node/src/validation-provider-registry.ts b/packages/modelserver-node/src/validation-provider-registry.ts index 41288b1..4ae5e65 100644 --- a/packages/modelserver-node/src/validation-provider-registry.ts +++ b/packages/modelserver-node/src/validation-provider-registry.ts @@ -12,11 +12,12 @@ import { Diagnostic, ModelServerObjectV2, OK } from '@eclipse-emfcloud/modelserver-client'; import { Logger, ValidationProvider, ValidationProviderRegistrationOptions } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { inject, injectable, named } from 'inversify'; +import URI = require('urijs'); import { v4 as uuid } from 'uuid'; type ValidationProviderFilter = (model: ModelServerObjectV2, modelURI: string) => boolean; -export type Validator = (model: ModelServerObjectV2, modelURI: string) => Promise; +export type Validator = (model: ModelServerObjectV2, modelURI: URI) => Promise; /** * A registry of validation providers from _Model Server_ plug-ins. @@ -75,17 +76,17 @@ export class ValidationProviderRegistry { return false; } - getProviders(model: ModelServerObjectV2, modelURI: string): ValidationProvider[] { + getProviders(model: ModelServerObjectV2, modelURI: URI): ValidationProvider[] { const result: ValidationProvider[] = []; this.providers.forEach(next => { - if (next.filter(model, modelURI)) { + if (next.filter(model, modelURI.toString())) { result.push(next.provider); } }); return result; } - getValidator(model: ModelServerObjectV2, modelURI: string): Validator | undefined { + getValidator(model: ModelServerObjectV2, modelURI: URI): Validator | undefined { this.logger.debug(`Looking up provider for validation of ${modelURI}`); const providers = this.getProviders(model, modelURI); switch (providers.length) { @@ -105,7 +106,7 @@ export class ValidationProviderRegistry { * @param modelURI its resource URI * @returns the validation result */ - async validate(model: ModelServerObjectV2, modelURI: string): Promise { + async validate(model: ModelServerObjectV2, modelURI: URI): Promise { const validator = this.getValidator(model, modelURI); return validator(model, modelURI); } @@ -124,16 +125,16 @@ function createModelURIFilter(filter?: string | RegExp): (modelURI: string) => b } function multiValidator(providers: ValidationProvider[]): Validator { - return async (model: ModelServerObjectV2, modelURI: string) => { + return async (model: ModelServerObjectV2, modelURI: URI) => { const diagnostics = await Promise.all(providers.map(v => v.validate(model, modelURI))); return summarize(model, modelURI, diagnostics); }; } -function summarize(model: ModelServerObjectV2, modelURI: string, diagnostics: Diagnostic[]): Diagnostic { +function summarize(model: ModelServerObjectV2, modelURI: URI, diagnostics: Diagnostic[]): Diagnostic { const result = Diagnostic.merge(...diagnostics); if (result.severity > OK) { - result.message = `Diagnosis of ${modelURI}`; + result.message = `Diagnosis of ${modelURI.toString()}`; result.id = '/'; } return result; diff --git a/packages/modelserver-plugin-ext/src/command-provider.ts b/packages/modelserver-plugin-ext/src/command-provider.ts index 0e85a90..d9cb9b7 100644 --- a/packages/modelserver-plugin-ext/src/command-provider.ts +++ b/packages/modelserver-plugin-ext/src/command-provider.ts @@ -10,6 +10,7 @@ *******************************************************************************/ import { ModelServerCommand } from '@eclipse-emfcloud/modelserver-client'; +import * as URI from 'urijs'; import { Transaction } from './executor'; import { MaybePromise } from './util'; @@ -39,5 +40,5 @@ export interface CommandProvider { * @returns either a command to substitute for the custom command (perhaps a compound command) or a * transaction that should be run in the context of a transactional compound command {@link Executor} */ - getCommands(modelUri: string, customCommand: ModelServerCommand): MaybePromise; + getCommands(modelUri: URI, customCommand: ModelServerCommand): MaybePromise; } diff --git a/packages/modelserver-plugin-ext/src/executor.ts b/packages/modelserver-plugin-ext/src/executor.ts index 4ff776d..6e9bb1d 100644 --- a/packages/modelserver-plugin-ext/src/executor.ts +++ b/packages/modelserver-plugin-ext/src/executor.ts @@ -27,7 +27,7 @@ export interface Executor { * @param command a command to be executed on the model * @return the result of the command's execution */ - execute(modelUri: string, command: ModelServerCommand): Promise; + execute(modelUri: URI, command: ModelServerCommand): Promise; /** * Apply a JSON patch to the model. diff --git a/packages/modelserver-plugin-ext/src/model-service.ts b/packages/modelserver-plugin-ext/src/model-service.ts index 42ded02..5136dda 100644 --- a/packages/modelserver-plugin-ext/src/model-service.ts +++ b/packages/modelserver-plugin-ext/src/model-service.ts @@ -159,7 +159,7 @@ export interface EditTransaction { /** * Query the URI of the model that this transaction edits. */ - getModelURI(): string; + getModelURI(): URI; /** * Query whether the transaction is currently open. diff --git a/packages/modelserver-plugin-ext/src/trigger-provider.ts b/packages/modelserver-plugin-ext/src/trigger-provider.ts index bba49e3..00cc1f2 100644 --- a/packages/modelserver-plugin-ext/src/trigger-provider.ts +++ b/packages/modelserver-plugin-ext/src/trigger-provider.ts @@ -10,6 +10,7 @@ *******************************************************************************/ import { Operation } from 'fast-json-patch'; +import * as URI from 'urijs'; import { Transaction } from './executor'; import { MaybePromise } from './util'; @@ -35,7 +36,7 @@ export interface TriggerProvider { * @param patch a JSON Patch describing model changes performed by a triggering edit * @returns whether the provider has any edits to add to the given `patch` */ - canTrigger(modelURI: string, patch: Operation[]): boolean; + canTrigger(modelURI: URI, patch: Operation[]): boolean; /** * Obtain follow-up edits triggered by the given `patch`. These may either be @@ -48,5 +49,5 @@ export interface TriggerProvider { * or a transaction that should be run in the context of a transactional * compound command {@link Executor} */ - getTriggers(modelURI: string, modelDelta: Operation[]): MaybePromise; + getTriggers(modelURI: URI, modelDelta: Operation[]): MaybePromise; } diff --git a/packages/modelserver-plugin-ext/src/validation-provider.ts b/packages/modelserver-plugin-ext/src/validation-provider.ts index e8ddf07..41404a5 100644 --- a/packages/modelserver-plugin-ext/src/validation-provider.ts +++ b/packages/modelserver-plugin-ext/src/validation-provider.ts @@ -26,7 +26,7 @@ export interface ValidationProvider { * @param modelURI the URI of the model resource * @returns whether the provider can and will validate the given `model` */ - canValidate(model: ModelServerObjectV2, modelURI: string): boolean; + canValidate(model: ModelServerObjectV2, modelURI: URI): boolean; /** * Validate the given `model`. @@ -35,5 +35,5 @@ export interface ValidationProvider { * @param modelURI the URI of the model resource * @returns the result of validation of the `model` */ - validate(model: ModelServerObjectV2, modelURI: string): MaybePromise; + validate(model: ModelServerObjectV2, modelURI: URI): MaybePromise; } From 953abf188f0f66762c4ab106845a4873028028b8 Mon Sep 17 00:00:00 2001 From: Camille Letavernier Date: Thu, 3 Nov 2022 09:48:26 +0100 Subject: [PATCH 2/2] 179: Convert all Modelserver-Node APIs to use URI instead of String - Use consistent import statements Contributed on behalf of STMicroelectronics Signed-off-by: Camille Letavernier --- packages/modelserver-node/src/command-provider-registry.ts | 1 + packages/modelserver-node/src/routes/validation.ts | 2 +- packages/modelserver-node/src/services/validation-manager.ts | 5 ++--- .../modelserver-node/src/validation-provider-registry.ts | 2 +- packages/modelserver-plugin-ext/src/executor.ts | 1 + packages/modelserver-plugin-ext/src/validation-provider.ts | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/modelserver-node/src/command-provider-registry.ts b/packages/modelserver-node/src/command-provider-registry.ts index ad1eedf..a273e47 100644 --- a/packages/modelserver-node/src/command-provider-registry.ts +++ b/packages/modelserver-node/src/command-provider-registry.ts @@ -13,6 +13,7 @@ import { AddCommand, ModelServerCommand, RemoveCommand, SetCommand } from '@ecli import { CommandProvider, Logger, Transaction } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { Operation } from 'fast-json-patch'; import { inject, injectable, named } from 'inversify'; +import * as URI from 'urijs'; /** * A registry of command providers from _Model Server_ plug-ins. diff --git a/packages/modelserver-node/src/routes/validation.ts b/packages/modelserver-node/src/routes/validation.ts index 854efa3..77f7efe 100644 --- a/packages/modelserver-node/src/routes/validation.ts +++ b/packages/modelserver-node/src/routes/validation.ts @@ -11,7 +11,7 @@ import { Logger, RouteProvider, RouterFactory } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { Request, RequestHandler, Response } from 'express'; import { inject, injectable, named } from 'inversify'; -import URI = require('urijs'); +import * as URI from 'urijs'; import { InternalModelServerClientApi } from '../client/model-server-client'; import { ValidationManager } from '../services/validation-manager'; diff --git a/packages/modelserver-node/src/services/validation-manager.ts b/packages/modelserver-node/src/services/validation-manager.ts index 488b729..adb7cb6 100644 --- a/packages/modelserver-node/src/services/validation-manager.ts +++ b/packages/modelserver-node/src/services/validation-manager.ts @@ -11,11 +11,10 @@ import { Diagnostic, encode, ModelServerObjectV2 } from '@eclipse-emfcloud/modelserver-client'; import { Logger } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { inject, injectable, named, postConstruct } from 'inversify'; - -import { validateModelURI } from '../client/uri-utils'; -import URI = require('urijs'); +import * as URI from 'urijs'; import { InternalModelServerClientApi } from '../client/model-server-client'; +import { validateModelURI } from '../client/uri-utils'; import { JSONSocket } from '../client/web-socket-utils'; import { ValidationProviderRegistry } from '../validation-provider-registry'; import { SubscriptionManager } from './subscription-manager'; diff --git a/packages/modelserver-node/src/validation-provider-registry.ts b/packages/modelserver-node/src/validation-provider-registry.ts index 4ae5e65..f161691 100644 --- a/packages/modelserver-node/src/validation-provider-registry.ts +++ b/packages/modelserver-node/src/validation-provider-registry.ts @@ -12,7 +12,7 @@ import { Diagnostic, ModelServerObjectV2, OK } from '@eclipse-emfcloud/modelserver-client'; import { Logger, ValidationProvider, ValidationProviderRegistrationOptions } from '@eclipse-emfcloud/modelserver-plugin-ext'; import { inject, injectable, named } from 'inversify'; -import URI = require('urijs'); +import * as URI from 'urijs'; import { v4 as uuid } from 'uuid'; type ValidationProviderFilter = (model: ModelServerObjectV2, modelURI: string) => boolean; diff --git a/packages/modelserver-plugin-ext/src/executor.ts b/packages/modelserver-plugin-ext/src/executor.ts index 6e9bb1d..12681c3 100644 --- a/packages/modelserver-plugin-ext/src/executor.ts +++ b/packages/modelserver-plugin-ext/src/executor.ts @@ -11,6 +11,7 @@ import { ModelServerCommand, ModelUpdateResult } from '@eclipse-emfcloud/modelserver-client'; import { Operation } from 'fast-json-patch'; +import * as URI from 'urijs'; /** * Protocol of a context in which commands may be executed and JSON patches applied. diff --git a/packages/modelserver-plugin-ext/src/validation-provider.ts b/packages/modelserver-plugin-ext/src/validation-provider.ts index 41404a5..b474955 100644 --- a/packages/modelserver-plugin-ext/src/validation-provider.ts +++ b/packages/modelserver-plugin-ext/src/validation-provider.ts @@ -10,9 +10,9 @@ *******************************************************************************/ import { Diagnostic, ModelServerObjectV2 } from '@eclipse-emfcloud/modelserver-client'; +import * as URI from 'urijs'; import { MaybePromise } from './util'; - /** * Protocol for a provider of custom validation rules that may be registered by a _Model Server_ plug-in. */