Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4509] Add a command to import libraries into a studio #4655

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ 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.
- https://github.com/eclipse-sirius/sirius-web/issues/4509[#4509] [sirius-web] Add a command to import libraries into a studio
The command is only present in studio projects, but the corresponding mutation can work on any project.
Downstream applications can provide their own command to import libraries into their projects, and rely on Sirius Web's import mechanism to load libraries.
The publication of a studio that references elements from imported libraries now produces libraries with the appropriate 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 editingContextDependencyLoader;

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 editingContextDependencyLoader, List<IEditingContextRepresentationDescriptionProvider> representationDescriptionProviders, List<IEditingContextProcessor> editingContextProcessors, List<IEditingContextMigrationParticipantPredicate> migrationParticipantPredicates) {
this.resourceLoader = Objects.requireNonNull(resourceLoader);
this.editingContextDependencyLoader = Objects.requireNonNull(editingContextDependencyLoader);
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.editingContextDependencyLoader.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,55 @@
/*******************************************************************************
* 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.library.controllers;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Objects;
import java.util.concurrent.CompletableFuture;

import org.eclipse.sirius.components.annotations.spring.graphql.QueryDataFetcher;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;
import org.eclipse.sirius.components.graphql.api.IEditingContextDispatcher;
import org.eclipse.sirius.web.application.library.dto.ImportLibrariesInput;

import graphql.schema.DataFetchingEnvironment;

/**
* Data fetcher for the field Mutation#importLibraries.
*
* @author gdaniel
*/
@QueryDataFetcher(type = "Mutation", field = "importLibraries")
public class MutationImportLibrariesDataFetcher implements IDataFetcherWithFieldCoordinates<CompletableFuture<IPayload>> {

private static final String INPUT_ARGUMENT = "input";

private final ObjectMapper objectMapper;

private final IEditingContextDispatcher editingContextDispatcher;

public MutationImportLibrariesDataFetcher(ObjectMapper objectMapper, IEditingContextDispatcher editingContextDispatcher) {
this.objectMapper = Objects.requireNonNull(objectMapper);
this.editingContextDispatcher = Objects.requireNonNull(editingContextDispatcher);
}

@Override
public CompletableFuture<IPayload> get(DataFetchingEnvironment environment) throws Exception {
Object argument = environment.getArgument(INPUT_ARGUMENT);
var input = this.objectMapper.convertValue(argument, ImportLibrariesInput.class);

return this.editingContextDispatcher.dispatchMutation(input.editingContextId(), input)
.toFuture();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*******************************************************************************
* 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.library.dto;

import java.util.List;
import java.util.UUID;

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

import jakarta.validation.constraints.NotNull;

/**
* Input used to import libraries.
*
* @author gdaniel
*/
public record ImportLibrariesInput(@NotNull UUID id, @NotNull String editingContextId, @NotNull String type, @NotNull List<String> libraryIds) implements IInput {

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.eclipse.sirius.web.application.library.dto;

import java.time.Instant;
import java.util.UUID;

import jakarta.validation.constraints.NotNull;

Expand All @@ -22,6 +23,7 @@
* @author gdaniel
*/
public record LibraryDTO(
@NotNull UUID id,
@NotNull String namespace,
@NotNull String name,
@NotNull String version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class LibraryMapper implements ILibraryMapper {
@Override
public LibraryDTO toDTO(Library library) {
return new LibraryDTO(
library.getId(),
library.getNamespace(),
library.getName(),
library.getVersion(),
Expand Down
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> {

}
Loading