Skip to content

Commit

Permalink
[1301] Adapt sirius-web code to support inter-model references
Browse files Browse the repository at this point in the history
* Use a correct URI to instantiate a JSONResource. The URI should have a
scheme "sirius"
* Only resources with "sirius" scheme are persisted and displayed in the
Explorer
* This commit also ensures that, if a specific resource factory has been
registered, it will be used to instantiate the XMI resource at download
* Forbid the upload of a single document that contains proxies. The
check is not done when uploading a project.

#1301
Signed-off-by: Laurent Fasani <laurent.fasani@obeo.fr>
  • Loading branch information
lfasani committed Oct 5, 2022
1 parent f3a08e0 commit 7e1c50c
Show file tree
Hide file tree
Showing 27 changed files with 439 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2022 Obeo.
* Copyright (c) 2019, 2021 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
Expand Down Expand Up @@ -89,7 +89,7 @@ public CompletableFuture<IPayload> get(DataFetchingEnvironment environment) thro
.orElse(null);
// @formatter:on

UploadDocumentInput input = new UploadDocumentInput(id, editingContextId, file);
UploadDocumentInput input = new UploadDocumentInput(id, editingContextId, file, true);

// @formatter:off
return this.editingContextEventProcessorRegistry.dispatchEvent(input.getEditingContextId(), input)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.eclipse.emf.ecore.xmi.XMLParserPool;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.emf.ecore.xmi.impl.XMLParserPoolImpl;
import org.eclipse.sirius.components.emf.services.SiriusWebJSONResourceFactoryImpl;
import org.eclipse.sirius.components.emf.services.JSONResourceFactory;
import org.eclipse.sirius.components.emf.utils.EMFResourceUtils;
import org.eclipse.sirius.emfjson.resource.JsonResource;
import org.slf4j.Logger;
Expand All @@ -53,7 +53,7 @@ public StereotypeBuilder(String timerName, MeterRegistry meterRegistry) {
}

public String getStereotypeBody(EObject rootEObject) {
JsonResource resource = new SiriusWebJSONResourceFactoryImpl().createResource(URI.createURI("inmemory")); //$NON-NLS-1$
JsonResource resource = new JSONResourceFactory().createResourceFromPath("inmemory"); //$NON-NLS-1$
if (rootEObject != null) {
resource.getContents().add(rootEObject);
}
Expand All @@ -78,7 +78,7 @@ public String getStereotypeBody(ClassPathResource classPathResource) {

String content = ""; //$NON-NLS-1$
try (var inputStream = classPathResource.getInputStream()) {
URI uri = URI.createURI(classPathResource.getFilename());
URI uri = new JSONResourceFactory().createResourceURI(classPathResource.getFilename());
Resource inputResource = this.loadFromXMI(uri, inputStream);
content = this.saveAsJSON(uri, inputResource);
} catch (IOException exception) {
Expand All @@ -100,7 +100,7 @@ private Resource loadFromXMI(URI uri, InputStream inputStream) throws IOExceptio

private String saveAsJSON(URI uri, Resource inputResource) throws IOException {
String content;
JsonResource ouputResource = new SiriusWebJSONResourceFactoryImpl().createResource(uri);
JsonResource ouputResource = new JSONResourceFactory().createResource(uri);
ouputResource.getContents().addAll(inputResource.getContents());
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
Map<String, Object> jsonSaveOptions = new EMFResourceUtils().getFastJSONSaveOptions();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*******************************************************************************
* Copyright (c) 2022 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.api.document;

import java.text.MessageFormat;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

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

/**
* The input object for the operation to rewrite broken proxy URIs in documents.
*
* @author pcdavid
*/
public class RewriteProxiesInput implements IInput {
private final UUID id;

private final String editingContextId;

private final Map<String, String> oldDocumentIdToNewDocumentId;

public RewriteProxiesInput(UUID id, String editingContextId, Map<String, String> oldDocumentIdToNewDocumentId) {
this.id = Objects.requireNonNull(id);
this.editingContextId = Objects.requireNonNull(editingContextId);
this.oldDocumentIdToNewDocumentId = Objects.requireNonNull(oldDocumentIdToNewDocumentId);
}

@Override
public UUID getId() {
return this.id;
}

public String getEditingContextId() {
return this.editingContextId;
}

public Map<String, String> getOldDocumentIdToNewDocumentId() {
return this.oldDocumentIdToNewDocumentId;
}

@Override
public String toString() {
String pattern = "{0} '{'id: {1}, editingContextId: {2}, oldDocumentIdToNewDocumentId: {3}'}'"; //$NON-NLS-1$
return MessageFormat.format(pattern, this.getClass().getSimpleName(), this.id, this.editingContextId, this.oldDocumentIdToNewDocumentId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2022 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.api.document;

import java.text.MessageFormat;
import java.util.Objects;
import java.util.UUID;

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

/**
* The payload of the rewrite proxies operation.
*
* @author pcdavid
*/
public final class RewriteProxiesSuccessPayload implements IPayload {

private final UUID id;

public RewriteProxiesSuccessPayload(UUID id) {
this.id = Objects.requireNonNull(id);
}

@Override
public UUID getId() {
return this.id;
}

@Override
public String toString() {
String pattern = "{0} '{'id: {1}'}'"; //$NON-NLS-1$
return MessageFormat.format(pattern, this.getClass().getSimpleName(), this.id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,24 @@ public final class UploadDocumentInput implements IInput {

private final UploadFile file;

public UploadDocumentInput(UUID id, String editingContextId, UploadFile file) {
private final boolean checkProxies;

public UploadDocumentInput(UUID id, String editingContextId, UploadFile file, boolean checkProxies) {
this.id = Objects.requireNonNull(id);
this.editingContextId = Objects.requireNonNull(editingContextId);
this.file = Objects.requireNonNull(file);
this.checkProxies = checkProxies;
}

@Override
public UUID getId() {
return this.id;
}

public boolean isCheckProxies() {
return this.checkProxies;
}

public String getEditingContextId() {
return this.editingContextId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import java.util.Optional;
import java.util.UUID;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.sirius.components.collaborative.api.ChangeDescription;
Expand All @@ -33,7 +32,7 @@
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.core.configuration.StereotypeDescription;
import org.eclipse.sirius.components.emf.services.EditingContext;
import org.eclipse.sirius.components.emf.services.SiriusWebJSONResourceFactoryImpl;
import org.eclipse.sirius.components.emf.services.JSONResourceFactory;
import org.eclipse.sirius.emfjson.resource.JsonResource;
import org.eclipse.sirius.web.services.api.document.Document;
import org.eclipse.sirius.web.services.api.document.IDocumentService;
Expand Down Expand Up @@ -136,9 +135,8 @@ private void createDocument(One<IPayload> payloadSink, Many<ChangeDescription> c
var optionalDocument = this.documentService.createDocument(editingContextId, name, stereotypeDescription.getContent());
if (optionalDocument.isPresent()) {
Document document = optionalDocument.get();
URI uri = URI.createURI(document.getId().toString());

JsonResource resource = new SiriusWebJSONResourceFactoryImpl().createResource(uri);
JsonResource resource = new JSONResourceFactory().createResourceFromPath(document.getId().toString());
try (var inputStream = new ByteArrayInputStream(document.getContent().getBytes())) {
resource.load(inputStream, null);
} catch (IOException exception) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2022 Obeo.
* Copyright (c) 2019, 2021 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
Expand Down Expand Up @@ -32,6 +32,7 @@
import org.eclipse.sirius.components.core.api.IInput;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.emf.services.EditingContext;
import org.eclipse.sirius.components.emf.services.JSONResourceFactory;
import org.eclipse.sirius.web.services.api.document.Document;
import org.eclipse.sirius.web.services.api.document.IDocumentService;
import org.eclipse.sirius.web.services.messages.IServicesMessageService;
Expand Down Expand Up @@ -96,7 +97,7 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDesc
Document document = optionalDocument.get();

ResourceSet resourceSet = editingDomain.getResourceSet();
URI uri = URI.createURI(document.getId().toString());
URI uri = new JSONResourceFactory().createResourceURI(document.getId().toString());

// @formatter:off
List<Resource> resourcesToDelete = resourceSet.getResources().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
import org.eclipse.sirius.components.emf.services.IEditingContextEPackageService;
import org.eclipse.sirius.components.emf.services.SiriusWebJSONResourceFactoryImpl;
import org.eclipse.sirius.components.emf.services.JSONResourceFactory;
import org.eclipse.sirius.emfjson.resource.JsonResource;
import org.eclipse.sirius.web.persistence.entities.DocumentEntity;
import org.eclipse.sirius.web.persistence.repositories.IDocumentRepository;
Expand Down Expand Up @@ -152,8 +152,7 @@ public Optional<byte[]> getBytes(Document document, String resourceKind) {
ResourceSet resourceSet = new ResourceSetImpl();
resourceSet.setPackageRegistry(ePackageRegistryImpl);

URI uri = URI.createURI(document.getName());
JsonResource resource = new SiriusWebJSONResourceFactoryImpl().createResource(uri);
JsonResource resource = new JSONResourceFactory().createResourceFromPath(document.getName());
resourceSet.getResources().add(resource);
resourceSet.getResources().add(outputResource);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*******************************************************************************
* Copyright (c) 2022 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.documents;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.sirius.components.collaborative.api.ChangeDescription;
import org.eclipse.sirius.components.collaborative.api.ChangeKind;
import org.eclipse.sirius.components.collaborative.api.IEditingContextEventHandler;
import org.eclipse.sirius.components.core.api.ErrorPayload;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IInput;
import org.eclipse.sirius.components.core.api.IPayload;
import org.eclipse.sirius.components.emf.services.EditingContext;
import org.eclipse.sirius.web.services.api.document.RewriteProxiesInput;
import org.eclipse.sirius.web.services.api.document.RewriteProxiesSuccessPayload;
import org.eclipse.sirius.web.services.messages.IServicesMessageService;
import org.springframework.stereotype.Service;

import reactor.core.publisher.Sinks.Many;
import reactor.core.publisher.Sinks.One;

/**
* The event handler to rewrite broken proxy URIs in documents (typically after an upload where the newly created
* documents have different ids).
*
* @author pcdavid
*/
@Service
public class RewriteProxiesEventHandler implements IEditingContextEventHandler {
private final IServicesMessageService messageService;

public RewriteProxiesEventHandler(IServicesMessageService messageService) {
this.messageService = Objects.requireNonNull(messageService);
}

@Override
public boolean canHandle(IEditingContext editingContext, IInput input) {
return input instanceof RewriteProxiesInput;
}

@Override
public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDescriptionSink, IEditingContext editingContext, IInput input) {
IPayload payload = new ErrorPayload(input.getId(), this.messageService.unexpectedError());
ChangeDescription changeDescription = new ChangeDescription(ChangeKind.NOTHING, editingContext.getId(), input);

if (input instanceof RewriteProxiesInput && editingContext instanceof EditingContext) {
RewriteProxiesInput rewriteInput = (RewriteProxiesInput) input;
AdapterFactoryEditingDomain adapterFactoryEditingDomain = ((EditingContext) editingContext).getDomain();
int totalRewrittenCount = 0;
for (Resource resource : adapterFactoryEditingDomain.getResourceSet().getResources()) {
totalRewrittenCount += this.rewriteProxyURIs(resource, rewriteInput.getOldDocumentIdToNewDocumentId());
}
if (totalRewrittenCount > 0) {
changeDescription = new ChangeDescription(ChangeKind.SEMANTIC_CHANGE, editingContext.getId(), input);
}
payload = new RewriteProxiesSuccessPayload(input.getId());
}

payloadSink.tryEmitValue(payload);
changeDescriptionSink.tryEmitNext(changeDescription);
}

private int rewriteProxyURIs(Resource resource, Map<String, String> oldDocumentIdToNewDocumentId) {
AtomicInteger rewrittenCount = new AtomicInteger();
resource.getAllContents().forEachRemaining(eObject -> {
eObject.eCrossReferences().forEach(target -> {
InternalEObject internalEObject = (InternalEObject) target;
if (internalEObject.eIsProxy()) {
URI proxyURI = internalEObject.eProxyURI();
String oldDocumentId = proxyURI.path().substring(1);
String newDocumentId = oldDocumentIdToNewDocumentId.get(oldDocumentId);
if (newDocumentId != null) {
String prefix = EditingContext.RESOURCE_SCHEME + ":///"; //$NON-NLS-1$
URI newProxyURI = URI.createURI(proxyURI.toString().replace(prefix + oldDocumentId, prefix + newDocumentId));
internalEObject.eSetProxyURI(newProxyURI);
rewrittenCount.incrementAndGet();
}
}
});
});
return rewrittenCount.get();
}

}
Loading

0 comments on commit 7e1c50c

Please sign in to comment.