Skip to content

Commit

Permalink
[2926] Introduce IEditingContextProcessor
Browse files Browse the repository at this point in the history
Bug: #2926
Signed-off-by: Axel RICHARD <axel.richard@obeo.fr>
  • Loading branch information
AxelRICHARD committed Jan 15, 2024
1 parent 241377b commit 5ac4ef0
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 34 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.adoc
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
@@ -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) {
}
}
}
Expand Up @@ -14,36 +14,34 @@

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;
import java.util.Objects;
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;
import org.eclipse.sirius.web.persistence.repositories.IDocumentRepository;
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;
Expand Down Expand Up @@ -72,21 +70,17 @@ public class EditingContextSearchService implements IEditingContextSearchService

private final List<IRepresentationDescriptionRegistryConfigurer> configurers;

private final IViewLoader viewLoader;

private final IViewConverter viewConverter;
private final List<IEditingContextProcessor> editingContextProcessors;

private final Timer timer;

public EditingContextSearchService(IProjectRepository projectRepository, IDocumentRepository documentRepository, IEditingDomainFactoryService editingDomainFactoryService,
List<IRepresentationDescriptionRegistryConfigurer> configurers, IViewLoader viewLoader, IViewConverter viewConverter, MeterRegistry meterRegistry) {
List<IRepresentationDescriptionRegistryConfigurer> configurers, List<IEditingContextProcessor> 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);
}

Expand All @@ -106,6 +100,12 @@ public Optional<IEditingContext> findById(String editingContextId) {
resourceSet.getLoadOptions().put(JsonResource.OPTION_EXTENDED_META_DATA, new BasicExtendedMetaData(resourceSet.getPackageRegistry()));
resourceSet.getLoadOptions().put(JsonResource.OPTION_SCHEMA_LOCATION, true);

Map<String, IRepresentationDescription> representationDescriptions = new HashMap<>();

EditingContext editingContext = new EditingContext(editingContextId, editingDomain, representationDescriptions, new ArrayList<>());
this.editingContextProcessors.forEach(processor -> processor.preProcess(editingContext));


List<DocumentEntity> documentEntities = new IDParser().parse(editingContextId)
.map(this.documentRepository::findAllByProjectId)
.orElseGet(List::of)
Expand All @@ -132,36 +132,23 @@ public Optional<IEditingContext> findById(String editingContextId) {

this.logger.debug("{} documents loaded for the editing context {}", resourceSet.getResources().size(), editingContextId);

var views = this.viewLoader.load();
Map<String, IRepresentationDescription> 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<String, IRepresentationDescription> getRepresentationDescriptions(EditingDomain editingDomain, List<View> views) {
private Map<String, IRepresentationDescription> getRepresentationDescriptions() {
Map<String, IRepresentationDescription> representationDescriptions = new LinkedHashMap<>();
var registry = new RepresentationDescriptionRegistry();
this.configurers.forEach(configurer -> configurer.addRepresentationDescriptions(registry));
registry.getRepresentationDescriptions().forEach(representationDescription -> representationDescriptions.put(representationDescription.getId(), representationDescription));

List<EPackage> accessibleEPackages = this.getAccessibleEPackages(editingDomain);
this.viewConverter.convert(views, accessibleEPackages).stream()
.filter(Objects::nonNull)
.forEach(representationDescription -> representationDescriptions.put(representationDescription.getId(), representationDescription));

return representationDescriptions;
}

private List<EPackage> getAccessibleEPackages(EditingDomain editingDomain) {
var packageRegistry = editingDomain.getResourceSet().getPackageRegistry();

return packageRegistry.values().stream()
.filter(EPackage.class::isInstance)
.map(EPackage.class::cast)
.toList();
}

}
@@ -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<EPackage> 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<EPackage> getAccessibleEPackages(EditingDomain editingDomain) {
var packageRegistry = editingDomain.getResourceSet().getPackageRegistry();

return packageRegistry.values().stream()
.filter(EPackage.class::isInstance)
.map(EPackage.class::cast)
.toList();
}
}
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -148,7 +149,7 @@ public List<DocumentEntity> 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);
Expand All @@ -162,6 +163,75 @@ public List<DocumentEntity> 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<DocumentEntity> 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);
Expand Down

0 comments on commit 5ac4ef0

Please sign in to comment.