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: eclipse-sirius#4652
Signed-off-by: Gwendal Daniel <[email protected]>
  • Loading branch information
gdaniel committed Mar 6, 2025
1 parent 51a1cf0 commit 29ee5af
Show file tree
Hide file tree
Showing 19 changed files with 540 additions and 14 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ 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.
This predicate is used in Sirius Web's explorer to prevent users from deleting or renaming elements from dependencies.


=== Improvements
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*******************************************************************************
* 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.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.services.api.ISemanticDataSearchService;
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 = new UUIDParser().parse(siriusWebEditingContext.getId())
.map(this.semanticDataSearchService::findAllTransitiveSemanticDataById)
.orElse(Set.of());
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);
});
}
});
}
}
}
}
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);

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.eclipse.sirius.components.emf.services.JSONResourceFactory;
import org.eclipse.sirius.components.emf.services.api.IEMFEditingContext;
import org.eclipse.sirius.web.application.UUIDParser;
import org.eclipse.sirius.web.application.object.services.api.IReadOnlyObjectPredicate;
import org.eclipse.sirius.web.application.views.explorer.services.api.IExplorerServices;
import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.RepresentationIconURL;
import org.eclipse.sirius.web.domain.boundedcontexts.representationdata.RepresentationMetadata;
Expand All @@ -56,11 +57,14 @@ public class ExplorerServices implements IExplorerServices {

private final IRepresentationMetadataSearchService representationMetadataSearchService;

public ExplorerServices(IObjectService objectService, IURLParser urlParser, List<IRepresentationImageProvider> representationImageProviders, IRepresentationMetadataSearchService representationMetadataSearchService) {
private final IReadOnlyObjectPredicate readOnlyObjectPredicate;

public ExplorerServices(IObjectService objectService, IURLParser urlParser, List<IRepresentationImageProvider> representationImageProviders, IRepresentationMetadataSearchService representationMetadataSearchService, IReadOnlyObjectPredicate readOnlyObjectPredicate) {
this.objectService = Objects.requireNonNull(objectService);
this.urlParser = Objects.requireNonNull(urlParser);
this.representationImageProviders = Objects.requireNonNull(representationImageProviders);
this.representationMetadataSearchService = Objects.requireNonNull(representationMetadataSearchService);
this.readOnlyObjectPredicate = Objects.requireNonNull(readOnlyObjectPredicate);
}

@Override
Expand Down Expand Up @@ -114,19 +118,21 @@ private String getResourceLabel(Resource resource) {
@Override
public boolean isEditable(Object self) {
boolean editable = false;
if (self instanceof RepresentationMetadata) {
editable = true;
} else if (self instanceof Resource) {
editable = true;
} else if (self instanceof EObject) {
editable = this.objectService.isLabelEditable(self);
if (!this.readOnlyObjectPredicate.test(self)) {
if (self instanceof RepresentationMetadata) {
editable = true;
} else if (self instanceof Resource) {
editable = true;
} else if (self instanceof EObject) {
editable = this.objectService.isLabelEditable(self);
}
}
return editable;
}

@Override
public boolean isDeletable(Object self) {
return true;
return !this.readOnlyObjectPredicate.test(self);
}

@Override
Expand Down
Loading

0 comments on commit 29ee5af

Please sign in to comment.