From 5ac4ef031e5b554aaf27f8e8edb744389c88c960 Mon Sep 17 00:00:00 2001 From: Axel RICHARD Date: Mon, 15 Jan 2024 13:53:35 +0100 Subject: [PATCH] [2926] Introduce IEditingContextProcessor Bug: https://github.com/eclipse-sirius/sirius-web/issues/2926 Signed-off-by: Axel RICHARD --- CHANGELOG.adoc | 3 + .../core/api/IEditingContextProcessor.java | 40 ++++++++++ .../EditingContextSearchService.java | 47 ++++------- .../ViewEditingContextProcessor.java | 69 ++++++++++++++++ .../EditingContextSearchServiceTests.java | 78 ++++++++++++++++++- 5 files changed, 203 insertions(+), 34 deletions(-) create mode 100644 packages/core/backend/sirius-components-core/src/main/java/org/eclipse/sirius/components/core/api/IEditingContextProcessor.java create mode 100644 packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/editingcontext/ViewEditingContextProcessor.java diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 96977e2255..3d1df8cb3d 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -82,6 +82,8 @@ The default implementation of the editing context for Sirius Web, which had Siri This default implementation will now also contain all the view models properly loaded which should be considered during the lifecycle of the editing context. - https://github.com/eclipse-sirius/sirius-web/issues/2796[#2796] [sirius-web] All Flow related configurations have been moved to `sirius-components-flow-starter` module. - https://github.com/eclipse-sirius/sirius-web/issues/2883[#2883] [diagram] Add the attribute `resizedByUser` to reactflow nodes and graphql nodes. +- https://github.com/eclipse-sirius/sirius-web/issues/2926[#2926] [sirius-web] A new `IEditingContextProcessor` has been introduced. +It allows to execute operations before/after the load of an `IEditingContext` in `EditingContextSearchService`. === Dependency update @@ -124,6 +126,7 @@ Now, for a multi-valued feature, the values are properly displayed and the delet + The size of nodes that do not have been resized manually tries to fit the node default size. - https://github.com/eclipse-sirius/sirius-web/issues/2792[#2792] [diagram] Add a first version for arrange all support. +- https://github.com/eclipse-sirius/sirius-web/issues/2926[#2926] [sirius-web] Add a first version of the support fro libraries. === Improvements diff --git a/packages/core/backend/sirius-components-core/src/main/java/org/eclipse/sirius/components/core/api/IEditingContextProcessor.java b/packages/core/backend/sirius-components-core/src/main/java/org/eclipse/sirius/components/core/api/IEditingContextProcessor.java new file mode 100644 index 0000000000..1509accdb5 --- /dev/null +++ b/packages/core/backend/sirius-components-core/src/main/java/org/eclipse/sirius/components/core/api/IEditingContextProcessor.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2024 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.components.core.api; + +/** + * Processor for {@link IEditingContext}. + * + * @author arichard + */ +public interface IEditingContextProcessor { + + void preProcess(IEditingContext editingContext); + void postProcess(IEditingContext editingContext); + + /** + * Implementation which does nothing, used for mocks in unit tests. + * + * @author arichard + */ + class NoOp implements IEditingContextProcessor { + + @Override + public void preProcess(IEditingContext editingContext) { + } + + @Override + public void postProcess(IEditingContext editingContext) { + } + } +} diff --git a/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/editingcontext/EditingContextSearchService.java b/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/editingcontext/EditingContextSearchService.java index 3f70e4eb87..34220e13a0 100644 --- a/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/editingcontext/EditingContextSearchService.java +++ b/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/editingcontext/EditingContextSearchService.java @@ -14,6 +14,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -21,21 +23,18 @@ import java.util.Optional; import java.util.concurrent.TimeUnit; -import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.BasicExtendedMetaData; import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; -import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IEditingContextProcessor; import org.eclipse.sirius.components.core.api.IEditingContextSearchService; import org.eclipse.sirius.components.core.configuration.IRepresentationDescriptionRegistryConfigurer; import org.eclipse.sirius.components.emf.ResourceMetadataAdapter; import org.eclipse.sirius.components.emf.services.EditingContextCrossReferenceAdapter; import org.eclipse.sirius.components.emf.services.JSONResourceFactory; import org.eclipse.sirius.components.representations.IRepresentationDescription; -import org.eclipse.sirius.components.view.View; -import org.eclipse.sirius.components.view.emf.IViewConverter; import org.eclipse.sirius.components.view.util.services.ColorPaletteService; import org.eclipse.sirius.emfjson.resource.JsonResource; import org.eclipse.sirius.web.persistence.entities.DocumentEntity; @@ -43,7 +42,6 @@ import org.eclipse.sirius.web.persistence.repositories.IProjectRepository; import org.eclipse.sirius.web.services.api.id.IDParser; import org.eclipse.sirius.web.services.editingcontext.api.IEditingDomainFactoryService; -import org.eclipse.sirius.web.services.editingcontext.api.IViewLoader; import org.eclipse.sirius.web.services.representations.RepresentationDescriptionRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,21 +70,17 @@ public class EditingContextSearchService implements IEditingContextSearchService private final List configurers; - private final IViewLoader viewLoader; - - private final IViewConverter viewConverter; + private final List editingContextProcessors; private final Timer timer; public EditingContextSearchService(IProjectRepository projectRepository, IDocumentRepository documentRepository, IEditingDomainFactoryService editingDomainFactoryService, - List configurers, IViewLoader viewLoader, IViewConverter viewConverter, MeterRegistry meterRegistry) { + List configurers, List editingContextProcessors, MeterRegistry meterRegistry) { this.projectRepository = Objects.requireNonNull(projectRepository); this.documentRepository = Objects.requireNonNull(documentRepository); this.editingDomainFactoryService = Objects.requireNonNull(editingDomainFactoryService); this.configurers = Objects.requireNonNull(configurers); - this.viewLoader = Objects.requireNonNull(viewLoader); - this.viewConverter = Objects.requireNonNull(viewConverter); - + this.editingContextProcessors = Objects.requireNonNull(editingContextProcessors); this.timer = Timer.builder(TIMER_NAME).register(meterRegistry); } @@ -106,6 +100,12 @@ public Optional findById(String editingContextId) { resourceSet.getLoadOptions().put(JsonResource.OPTION_EXTENDED_META_DATA, new BasicExtendedMetaData(resourceSet.getPackageRegistry())); resourceSet.getLoadOptions().put(JsonResource.OPTION_SCHEMA_LOCATION, true); + Map representationDescriptions = new HashMap<>(); + + EditingContext editingContext = new EditingContext(editingContextId, editingDomain, representationDescriptions, new ArrayList<>()); + this.editingContextProcessors.forEach(processor -> processor.preProcess(editingContext)); + + List documentEntities = new IDParser().parse(editingContextId) .map(this.documentRepository::findAllByProjectId) .orElseGet(List::of) @@ -132,36 +132,23 @@ public Optional findById(String editingContextId) { this.logger.debug("{} documents loaded for the editing context {}", resourceSet.getResources().size(), editingContextId); - var views = this.viewLoader.load(); - Map representationDescriptions = this.getRepresentationDescriptions(editingDomain, views); + representationDescriptions = this.getRepresentationDescriptions(); + + this.editingContextProcessors.forEach(processor -> processor.postProcess(editingContext)); long end = System.currentTimeMillis(); this.timer.record(end - start, TimeUnit.MILLISECONDS); - return Optional.of(new EditingContext(editingContextId, editingDomain, representationDescriptions, views)); + return Optional.of(editingContext); } - private Map getRepresentationDescriptions(EditingDomain editingDomain, List views) { + private Map getRepresentationDescriptions() { Map representationDescriptions = new LinkedHashMap<>(); var registry = new RepresentationDescriptionRegistry(); this.configurers.forEach(configurer -> configurer.addRepresentationDescriptions(registry)); registry.getRepresentationDescriptions().forEach(representationDescription -> representationDescriptions.put(representationDescription.getId(), representationDescription)); - List accessibleEPackages = this.getAccessibleEPackages(editingDomain); - this.viewConverter.convert(views, accessibleEPackages).stream() - .filter(Objects::nonNull) - .forEach(representationDescription -> representationDescriptions.put(representationDescription.getId(), representationDescription)); - return representationDescriptions; } - private List getAccessibleEPackages(EditingDomain editingDomain) { - var packageRegistry = editingDomain.getResourceSet().getPackageRegistry(); - - return packageRegistry.values().stream() - .filter(EPackage.class::isInstance) - .map(EPackage.class::cast) - .toList(); - } - } diff --git a/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/editingcontext/ViewEditingContextProcessor.java b/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/editingcontext/ViewEditingContextProcessor.java new file mode 100644 index 0000000000..8a8e1a4741 --- /dev/null +++ b/packages/sirius-web/backend/sirius-web-services/src/main/java/org/eclipse/sirius/web/services/editingcontext/ViewEditingContextProcessor.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2024 Obeo. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.web.services.editingcontext; + +import java.util.List; +import java.util.Objects; + +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IEditingContextProcessor; +import org.eclipse.sirius.components.view.emf.IViewConverter; +import org.eclipse.sirius.web.services.editingcontext.api.IViewLoader; +import org.springframework.stereotype.Service; + +/** + * Editing context processor allowing to convert all views. + * + * @author arichard + */ +@Service +public class ViewEditingContextProcessor implements IEditingContextProcessor { + + private final IViewLoader viewLoader; + + private final IViewConverter viewConverter; + + public ViewEditingContextProcessor(IViewLoader viewLoader, IViewConverter viewConverter) { + this.viewLoader = viewLoader; + this.viewConverter = viewConverter; + + } + @Override + public void preProcess(IEditingContext editingContext) { + if (editingContext instanceof EditingContext siriusWebEditingContext) { + siriusWebEditingContext.getViews().addAll(this.viewLoader.load()); + } + + } + + @Override + public void postProcess(IEditingContext editingContext) { + if (editingContext instanceof EditingContext siriusWebEditingContext) { + List accessibleEPackages = this.getAccessibleEPackages(siriusWebEditingContext.getDomain()); + this.viewConverter.convert(siriusWebEditingContext.getViews(), accessibleEPackages).stream() + .filter(Objects::nonNull) + .forEach(representationDescription -> siriusWebEditingContext.getRepresentationDescriptions().put(representationDescription.getId(), representationDescription)); + } + } + + private List getAccessibleEPackages(EditingDomain editingDomain) { + var packageRegistry = editingDomain.getResourceSet().getPackageRegistry(); + + return packageRegistry.values().stream() + .filter(EPackage.class::isInstance) + .map(EPackage.class::cast) + .toList(); + } +} diff --git a/packages/sirius-web/backend/sirius-web-services/src/test/java/org/eclipse/sirius/web/services/editingcontext/EditingContextSearchServiceTests.java b/packages/sirius-web/backend/sirius-web-services/src/test/java/org/eclipse/sirius/web/services/editingcontext/EditingContextSearchServiceTests.java index 267b3cb538..5cd92177fc 100644 --- a/packages/sirius-web/backend/sirius-web-services/src/test/java/org/eclipse/sirius/web/services/editingcontext/EditingContextSearchServiceTests.java +++ b/packages/sirius-web/backend/sirius-web-services/src/test/java/org/eclipse/sirius/web/services/editingcontext/EditingContextSearchServiceTests.java @@ -18,25 +18,26 @@ import java.util.Optional; import java.util.UUID; +import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EcorePackage; import org.eclipse.emf.ecore.impl.EPackageRegistryImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IEditingContextProcessor; import org.eclipse.sirius.components.core.api.IEditingContextSearchService; import org.eclipse.sirius.components.emf.ResourceMetadataAdapter; import org.eclipse.sirius.components.emf.services.IEditingContextEPackageService; import org.eclipse.sirius.components.emf.services.JSONResourceFactory; -import org.eclipse.sirius.components.view.emf.IViewConverter; import org.eclipse.sirius.web.persistence.entities.DocumentEntity; import org.eclipse.sirius.web.persistence.entities.ProjectEntity; import org.eclipse.sirius.web.persistence.repositories.IDocumentRepository; import org.eclipse.sirius.web.persistence.repositories.IProjectRepository; import org.eclipse.sirius.web.services.editingcontext.api.IEditingDomainFactoryService; -import org.eclipse.sirius.web.services.editingcontext.api.IViewLoader; import org.eclipse.sirius.web.services.projects.api.EditingContextMetadata; import org.eclipse.sirius.web.services.projects.api.IEditingContextMetadataProvider; import org.junit.jupiter.api.Test; @@ -100,7 +101,7 @@ public void testEditingContextWithNoDocuments() { IEditingDomainFactoryService editingDomainFactoryService = new EditingDomainFactoryService(editingContextEPackageService, editingContextMetadataProvider, composedAdapterFactory, ePackageRegistry, Optional.empty()); IEditingContextSearchService editingContextSearchService = new EditingContextSearchService(projectRepository, documentRepository, editingDomainFactoryService, List.of(), - new IViewLoader.NoOp(), new IViewConverter.NoOp(), new SimpleMeterRegistry()); + List.of(new IEditingContextProcessor.NoOp()), new SimpleMeterRegistry()); IEditingContext editingContext = editingContextSearchService.findById(projectId).get(); assertThat(editingContext).isInstanceOf(EditingContext.class); @@ -148,7 +149,7 @@ public List findAllByProjectId(UUID projectId) { IEditingDomainFactoryService editingDomainFactoryService = new EditingDomainFactoryService(editingContextEPackageService, editingContextMetadataProvider, composedAdapterFactory, ePackageRegistry, Optional.empty()); IEditingContextSearchService editingContextSearchService = new EditingContextSearchService(projectRepository, documentRepository, editingDomainFactoryService, List.of(), - new IViewLoader.NoOp(), new IViewConverter.NoOp(), new SimpleMeterRegistry()); + List.of(new IEditingContextProcessor.NoOp()), new SimpleMeterRegistry()); IEditingContext editingContext = editingContextSearchService.findById(projectId.toString()).get(); assertThat(editingContext).isInstanceOf(EditingContext.class); @@ -162,6 +163,75 @@ public List findAllByProjectId(UUID projectId) { this.assertProperResourceLoading(secondResource, secondDocumentEntity); } + @Test + public void testEditingContextWithLibraries() { + UUID projectId = UUID.randomUUID(); + + ProjectEntity projectEntity = new ProjectEntity(); + projectEntity.setId(projectId); + projectEntity.setName(""); + + DocumentEntity firstDocumentEntity = new DocumentEntity(); + firstDocumentEntity.setId(UUID.randomUUID()); + firstDocumentEntity.setName("First Document"); + firstDocumentEntity.setProject(projectEntity); + firstDocumentEntity.setContent(CONTENT); + + DocumentEntity secondDocumentEntity = new DocumentEntity(); + secondDocumentEntity.setId(UUID.randomUUID()); + secondDocumentEntity.setName("Second Document"); + secondDocumentEntity.setProject(projectEntity); + secondDocumentEntity.setContent(CONTENT); + + IProjectRepository projectRepository = new NoOpProjectRepository(); + IDocumentRepository documentRepository = new NoOpDocumentRepository() { + @Override + public List findAllByProjectId(UUID projectId) { + return List.of(firstDocumentEntity, secondDocumentEntity); + } + }; + + ComposedAdapterFactory composedAdapterFactory = new ComposedAdapterFactory(); + EPackage.Registry ePackageRegistry = new EPackageRegistryImpl(); + ePackageRegistry.put(EcorePackage.eNS_URI, EcorePackage.eINSTANCE); + + IEditingContextEPackageService editingContextEPackageService = editingContextId -> List.of(); + + var editingContextMetadata = new EditingContextMetadata(List.of()); + IEditingContextMetadataProvider editingContextMetadataProvider = editingContextId -> editingContextMetadata; + + IEditingDomainFactoryService editingDomainFactoryService = new EditingDomainFactoryService(editingContextEPackageService, editingContextMetadataProvider, + composedAdapterFactory, ePackageRegistry, Optional.empty()); + + IEditingContextProcessor editingContextProcessor = new IEditingContextProcessor() { + + @Override + public void preProcess(IEditingContext editingContext) { + if (editingContext instanceof EditingContext siriusWebEditingContext) { + Resource resource = new XMIResourceImpl(URI.createURI("libraryPre.json")); + siriusWebEditingContext.getDomain().getResourceSet().getResources().add(resource); + } + } + + @Override + public void postProcess(IEditingContext editingContext) { + if (editingContext instanceof EditingContext siriusWebEditingContext) { + Resource resource = new XMIResourceImpl(URI.createURI("libraryPost.json")); + siriusWebEditingContext.getDomain().getResourceSet().getResources().add(resource); + } + } + }; + + IEditingContextSearchService editingContextSearchService = new EditingContextSearchService(projectRepository, documentRepository, editingDomainFactoryService, List.of(), + List.of(editingContextProcessor), new SimpleMeterRegistry()); + IEditingContext editingContext = editingContextSearchService.findById(projectId.toString()).get(); + + assertThat(editingContext).isInstanceOf(EditingContext.class); + EditingDomain editingDomain = ((EditingContext) editingContext).getDomain(); + + assertThat(editingDomain.getResourceSet().getResources()).hasSize(4); + } + private void assertProperResourceLoading(Resource resource, DocumentEntity documentEntity) { assertThat(resource).isNotNull(); assertThat(resource.eAdapters()).hasSize(2);