Skip to content

Commit

Permalink
[4652] Add support for loading editing contexts with dependencies
Browse files Browse the repository at this point in the history
Bug: #4652
Signed-off-by: Gwendal Daniel <[email protected]>
  • Loading branch information
gdaniel committed Mar 6, 2025
1 parent 51a1cf0 commit de3ea8f
Show file tree
Hide file tree
Showing 21 changed files with 564 additions and 14 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ See the new interface `org.eclipse.sirius.components.emf.services.api.IRepresent
- https://github.com/eclipse-sirius/sirius-web/issues/4597[#4597] [sirius-web] Add a command to publish libraries from studios
The command creates a library for each _RepresentationDescription_ and _Domain_ in the studio, and creates the dependencies between them.
A _shared components_ library can be created in the process to store elements that are needed by other libraries but are not stored in libraries themselves.
- https://github.com/eclipse-sirius/sirius-web/issues/4652[#4652] [sirius-web] Add support for loading projects with dependencies
Semantic data can have dependencies between them, which are transitively loaded when an editing context is created.
A new predicate `IReadOnlyObjectPredicate` has been added with a default implementation that returns `true` if the object belongs to semantic data loaded as a dependency.


=== Improvements
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*******************************************************************************
* Copyright (c) 2025 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.application.editingcontext.services;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.web.application.UUIDParser;
import org.eclipse.sirius.web.application.editingcontext.EditingContext;
import org.eclipse.sirius.web.application.editingcontext.services.api.IEditingContextDependencyLoader;
import org.eclipse.sirius.web.application.editingcontext.services.api.IEditingContextMigrationParticipantPredicate;
import org.eclipse.sirius.web.application.editingcontext.services.api.IResourceLoader;
import org.eclipse.sirius.web.domain.boundedcontexts.semanticdata.SemanticData;
import org.eclipse.sirius.web.domain.boundedcontexts.semanticdata.SemanticDataDependency;
import org.eclipse.sirius.web.domain.boundedcontexts.semanticdata.services.api.ISemanticDataSearchService;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.stereotype.Service;

/**
* Loads dependencies into the editing context.
*
* @author gdaniel
*/
@Service
public class EditingContextDependencyLoader implements IEditingContextDependencyLoader {

private final ISemanticDataSearchService semanticDataSearchService;

private final IResourceLoader resourceLoader;

private final List<IEditingContextMigrationParticipantPredicate> migrationParticipantPredicates;

public EditingContextDependencyLoader(ISemanticDataSearchService semanticDataSearchService, IResourceLoader resourceLoader, List<IEditingContextMigrationParticipantPredicate> migrationParticipantPredicates) {
this.semanticDataSearchService = Objects.requireNonNull(semanticDataSearchService);
this.resourceLoader = Objects.requireNonNull(resourceLoader);
this.migrationParticipantPredicates = Objects.requireNonNull(migrationParticipantPredicates);
}

@Override
public void loadDependencies(IEditingContext editingContext) {
if (editingContext instanceof EditingContext siriusWebEditingContext) {
Set<SemanticData> dependenciesSemanticData = this.getDependenciesSemanticData(siriusWebEditingContext);
for (SemanticData semanticData : dependenciesSemanticData) {
semanticData.getDocuments().forEach(document -> {
URI dependencyResourceURI = URI.createURI(DEPENDENCY_SCHEME + ":///" + document.getId().toString());
if (siriusWebEditingContext.getDomain().getResourceSet().getResource(dependencyResourceURI, false) == null) {
Optional<Resource> resource = this.resourceLoader.toResource(siriusWebEditingContext.getDomain().getResourceSet(), document.getId().toString(), document.getName(), document.getContent(),
this.migrationParticipantPredicates.stream().anyMatch(predicate -> predicate.test(editingContext.getId())));
resource.ifPresent(r -> {
siriusWebEditingContext.getDomain().getResourceSet().getURIConverter().getURIMap().put(r.getURI(), dependencyResourceURI);
r.setURI(dependencyResourceURI);
});
}
});
}
}
}

private Set<SemanticData> getDependenciesSemanticData(EditingContext editingContext) {
Set<SemanticData> semanticDataToLoad = new LinkedHashSet<>();
List<SemanticData> editingContextDependencies = new UUIDParser().parse(editingContext.getId())
.flatMap(this.semanticDataSearchService::findById)
.map(SemanticData::getDependencies)
.orElse(List.of())
.stream()
.map(SemanticDataDependency::dependencySemanticDataId)
.map(AggregateReference::getId)
.map(this.semanticDataSearchService::findById)
.filter(Optional::isPresent)
.map(Optional::get)
.toList();

for (SemanticData editingContextDependency : editingContextDependencies) {
semanticDataToLoad.add(editingContextDependency);
semanticDataToLoad.addAll(this.semanticDataSearchService.findAllTransitiveSemanticDataById(editingContextDependency.getId()));
}
return semanticDataToLoad;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.eclipse.sirius.components.emf.services.EditingContextCrossReferenceAdapter;
import org.eclipse.sirius.emfjson.resource.JsonResource;
import org.eclipse.sirius.web.application.editingcontext.EditingContext;
import org.eclipse.sirius.web.application.editingcontext.services.api.IEditingContextDependencyLoader;
import org.eclipse.sirius.web.application.editingcontext.services.api.IEditingContextLoader;
import org.eclipse.sirius.web.application.editingcontext.services.api.IEditingContextMigrationParticipantPredicate;
import org.eclipse.sirius.web.application.editingcontext.services.api.IResourceLoader;
Expand All @@ -41,22 +42,27 @@ public class EditingContextLoader implements IEditingContextLoader {

private final IResourceLoader resourceLoader;

private final IEditingContextDependencyLoader editingContextLibraryLoader;

private final List<IEditingContextRepresentationDescriptionProvider> representationDescriptionProviders;

private final List<IEditingContextProcessor> editingContextProcessors;

private final List<IEditingContextMigrationParticipantPredicate> migrationParticipantPredicates;

public EditingContextLoader(IResourceLoader resourceLoader, List<IEditingContextRepresentationDescriptionProvider> representationDescriptionProviders, List<IEditingContextProcessor> editingContextProcessors, List<IEditingContextMigrationParticipantPredicate> migrationParticipantPredicates) {
public EditingContextLoader(IResourceLoader resourceLoader, IEditingContextDependencyLoader editingContextLibraryLoader, List<IEditingContextRepresentationDescriptionProvider> representationDescriptionProviders, List<IEditingContextProcessor> editingContextProcessors, List<IEditingContextMigrationParticipantPredicate> migrationParticipantPredicates) {
this.resourceLoader = Objects.requireNonNull(resourceLoader);
this.editingContextLibraryLoader = Objects.requireNonNull(editingContextLibraryLoader);
this.representationDescriptionProviders = Objects.requireNonNull(representationDescriptionProviders);
this.editingContextProcessors = Objects.requireNonNull(editingContextProcessors);
this.migrationParticipantPredicates = Objects.requireNonNull(migrationParticipantPredicates);
}

@Override
public void load(EditingContext editingContext, SemanticData semanticData) {
this.editingContextProcessors.forEach(processor -> processor.preProcess(editingContext));

this.editingContextLibraryLoader.loadDependencies(editingContext);
this.loadSemanticData(editingContext, semanticData);

this.representationDescriptionProviders.forEach(representationDescriptionProvider -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2025 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.application.editingcontext.services.api;

import org.eclipse.sirius.components.core.api.IEditingContext;

/**
* Loads dependencies into the editing context.
*
* @author gdaniel
*/
public interface IEditingContextDependencyLoader {

String DEPENDENCY_SCHEME = "dependency";

void loadDependencies(IEditingContext editingContext);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*******************************************************************************
* Copyright (c) 2025 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.application.object.services;

import java.util.List;
import java.util.Objects;

import org.eclipse.sirius.web.application.object.services.api.IDefaultReadOnlyObjectPredicate;
import org.eclipse.sirius.web.application.object.services.api.IReadOnlyObjectPredicate;
import org.eclipse.sirius.web.application.object.services.api.IReadOnlyObjectPredicateDelegate;
import org.springframework.stereotype.Service;

/**
* Implementation of {@link IReadOnlyObjectPredicate} which delegates to {@link IReadOnlyObjectPredicateDelegate} or fallback to
* {@link IDefaultReadOnlyObjectPredicate}.
*
* @author gdaniel
*/
@Service
public class ComposedReadOnlyObjectPredicate implements IReadOnlyObjectPredicate {

private final List<IReadOnlyObjectPredicateDelegate> readOnlyObjectPredicateDelegate;

private final IDefaultReadOnlyObjectPredicate defaultReadOnlyObjectPredicate;

public ComposedReadOnlyObjectPredicate(List<IReadOnlyObjectPredicateDelegate> readOnlyObjectPredicateDelegate, IDefaultReadOnlyObjectPredicate defaultReadOnlyObjectPredicate) {
this.readOnlyObjectPredicateDelegate = Objects.requireNonNull(readOnlyObjectPredicateDelegate);
this.defaultReadOnlyObjectPredicate = Objects.requireNonNull(defaultReadOnlyObjectPredicate);
}

@Override
public boolean test(Object object) {
var optionalDelegate = this.readOnlyObjectPredicateDelegate.stream()
.filter(delegate -> delegate.canHandle(object))
.findFirst();
if (optionalDelegate.isPresent()) {
return optionalDelegate.get().test(object);
}
return this.defaultReadOnlyObjectPredicate.test(object);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*******************************************************************************
* Copyright (c) 2025 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.application.object.services;

import java.util.Objects;
import java.util.Optional;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.sirius.web.application.editingcontext.services.api.IEditingContextDependencyLoader;
import org.eclipse.sirius.web.application.object.services.api.IDefaultReadOnlyObjectPredicate;
import org.springframework.stereotype.Service;

/**
* The default service used to test if an object is read-only.
*
* @author gdaniel
*/
@Service
public class DefaultReadOnlyObjectPredicate implements IDefaultReadOnlyObjectPredicate {

@Override
public boolean test(Object object) {
boolean result = false;
if (object instanceof EObject eObject) {
result = Optional.ofNullable(eObject.eResource())
.map(Resource::getURI)
.map(URI::scheme)
.filter(scheme -> Objects.equals(scheme, IEditingContextDependencyLoader.DEPENDENCY_SCHEME))
.isPresent();
} else if (object instanceof Resource resource) {
result = Objects.equals(resource.getURI().scheme(), IEditingContextDependencyLoader.DEPENDENCY_SCHEME);
}
return result;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2025 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.application.object.services.api;

import java.util.function.Predicate;

/**
* The default service used to test if an object is read-only.
*
* @author gdaniel
*/
public interface IDefaultReadOnlyObjectPredicate extends Predicate<Object> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*******************************************************************************
* Copyright (c) 2025 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.application.object.services.api;

import java.util.function.Predicate;

/**
* Used to test if an object is read-only.
*
* @author gdaniel
*/
public interface IReadOnlyObjectPredicate extends Predicate<Object> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2025 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.application.object.services.api;

import java.util.function.Predicate;

/**
* Used to test if an object is read-only.
*
* @author gdaniel
*/
public interface IReadOnlyObjectPredicateDelegate extends Predicate<Object> {

boolean canHandle(Object object);

}
Loading

0 comments on commit de3ea8f

Please sign in to comment.