Skip to content

Commit

Permalink
[3979] Add Element related REST APIs in Sirius Web
Browse files Browse the repository at this point in the history
Bug: #3979
Signed-off-by: Axel RICHARD <[email protected]>
  • Loading branch information
AxelRICHARD committed Sep 24, 2024
1 parent 0df97fb commit 35e604f
Show file tree
Hide file tree
Showing 29 changed files with 1,509 additions and 31 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ The new endpoints are:
description (optional).
** deleteProject (`POST /api/rest/projects/{projectId}`): Delete the project with the given id (projectId).
** updateProject (`PUT /projects/{projectId}`): Update the project with the given id (projectId).
Add Object related REST APIs.
The new endpoints are:
** getElements (`GET /api/rest/projects/{projectId}/commits/{commitId}/elements`): Get all the elements in a given project at the given commit. There are no commits in Sirius Web so you can use the same Id as the projectId for the commitId.
** getElementById (`GET /api/rest/projects/{projectId}/commits/{commitId}/elements/{elementId}`): Get element with the given id (elementId) in the given project at the given commit. There are no commits in Sirius Web so you can use the same Id as the projectId for the commitId.
** getRelationshipsByRelatedElement (`GET /api/rest/projects/{projectId}/commits/{commitId}/elements/{elementId}/relationships`): Get relationships that are incoming, outgoing, or both relative to the given related element. There are no commits in Sirius Web so you can use the same Id as the projectId for the commitId.
** getRootElements (`GET /api/rest/projects/{projectId}/commits/{commitId}/roots`): Get all the root elements in the given project at the given commit. There are no commits in Sirius Web so you can use the same Id as the projectId for the commitId.
A new `IObjectRestServiceDelegate` interface is available, allowing to customize the default implementation of services related to Object related REST APIs.
Specifiers can implement this new interface with a spring `Service`.
Specifiers are also encouraged to implement their own JSON serializers for their domains, as the default one may not return expected results.

=== Improvements

Expand Down
32 changes: 32 additions & 0 deletions doc/adrs/160_support_rest_apis.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
= [ADR-160] Support REST APIs

== Context

REST APIs can be useful to execute CRUD requests in Sirius Web.

=== Current behavior

There are currently no REST APIs allowing to query/modify projects/models in Sirius Web.

== Decision

The decision is to support all REST APIs described in the Systems Modeling Application Programming Interface (API) and Services section "8.1 REST/HTTP PSM" coming from https://www.omg.org/spec/SystemsModelingAPI/.

We will consider at least both the ProjectService and ElementNavigationService endpoints.

Additional resources:
- https://www.omg.org/spec/SystemsModelingAPI/20230201/OpenAPI.json
- https://www.omg.org/spec/SystemsModelingAPI/20230201/Schemas.json

Some concepts in this specification are coming from SysMLv2 (i.e. Element and Relationship).
For example, the `GET /projects/{projectId}/commits/{commitId}/elements/` will return the list of all objects contained in the given project.

Depending on the metamodel, objects could be serialized differently in JSON.
So, Sirius Web will let specifiers serialized their objects as they want.

Some default implementation of the Java services associated to the object-related REST APIs will be provided through a new interface `IDefaultObjectRestService`.
Specifiers will also be able to provide their own implementations by implementing `IObjectRestServiceDelegate` as a spring `Service`.

== Status

Work in progress
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*******************************************************************************
* 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.application.object.controllers;

import java.time.Duration;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

import org.eclipse.sirius.components.collaborative.api.IEditingContextEventProcessorRegistry;
import org.eclipse.sirius.web.application.object.dto.Direction;
import org.eclipse.sirius.web.application.object.dto.GetElementByIdRestInput;
import org.eclipse.sirius.web.application.object.dto.GetElementByIdRestSuccessPayload;
import org.eclipse.sirius.web.application.object.dto.GetElementsRestInput;
import org.eclipse.sirius.web.application.object.dto.GetElementsRestSuccessPayload;
import org.eclipse.sirius.web.application.object.dto.GetRelationshipsByRelatedElementRestInput;
import org.eclipse.sirius.web.application.object.dto.GetRelationshipsByRelatedElementRestSuccessPayload;
import org.eclipse.sirius.web.application.object.dto.GetRootElementsRestInput;
import org.eclipse.sirius.web.application.object.dto.GetRootElementsRestSuccessPayload;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* REST Controller for the Object Endpoint.
*
* @author arichard
*/
@RestController
@RequestMapping("/api/rest/projects/{projectId}/commits/{commitId}")
public class ObjectRestController {

private static final int TIMEOUT = 20;

private final IEditingContextEventProcessorRegistry editingContextEventProcessorRegistry;

public ObjectRestController(IEditingContextEventProcessorRegistry editingContextEventProcessorRegistry) {
this.editingContextEventProcessorRegistry = Objects.requireNonNull(editingContextEventProcessorRegistry);
}

@GetMapping(path = "/elements")
public ResponseEntity<List<Object>> getElements(@PathVariable UUID projectId, @PathVariable UUID commitId) {
ResponseEntity<List<Object>> responseEntity = new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
var optionalEditingContextEventProcessor = this.editingContextEventProcessorRegistry.getOrCreateEditingContextEventProcessor(projectId.toString());
if (optionalEditingContextEventProcessor.isPresent()) {
var editingContextEventProcessor = optionalEditingContextEventProcessor.get();
var payload = editingContextEventProcessor.handle(new GetElementsRestInput(UUID.randomUUID())).block(Duration.ofSeconds(TIMEOUT));
if (payload instanceof GetElementsRestSuccessPayload successPayload) {
responseEntity = new ResponseEntity<>(successPayload.elements(), HttpStatus.OK);
}
}
return responseEntity;
}

@GetMapping(path = "/elements/{elementId}")
public ResponseEntity<Object> getElementById(@PathVariable UUID projectId, @PathVariable UUID commitId, @PathVariable UUID elementId) {
ResponseEntity<Object> responseEntity = new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
var optionalEditingContextEventProcessor = this.editingContextEventProcessorRegistry.getOrCreateEditingContextEventProcessor(projectId.toString());
if (optionalEditingContextEventProcessor.isPresent()) {
var editingContextEventProcessor = optionalEditingContextEventProcessor.get();
var payload = editingContextEventProcessor.handle(new GetElementByIdRestInput(UUID.randomUUID(), elementId.toString())).block(Duration.ofSeconds(TIMEOUT));
if (payload instanceof GetElementByIdRestSuccessPayload successPayload) {
responseEntity = new ResponseEntity<>(successPayload.element(), HttpStatus.OK);
}
}
return responseEntity;
}

@GetMapping(path = "/elements/{relatedElementId}/relationships")
public ResponseEntity<List<Object>> getRelationshipsByRelatedElement(@PathVariable UUID projectId, @PathVariable UUID commitId, @PathVariable UUID relatedElementId, Optional<Direction> direction) {
ResponseEntity<List<Object>> responseEntity = new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
var optionalEditingContextEventProcessor = this.editingContextEventProcessorRegistry.getOrCreateEditingContextEventProcessor(projectId.toString());
if (optionalEditingContextEventProcessor.isPresent()) {
var editingContextEventProcessor = optionalEditingContextEventProcessor.get();
Direction directionParam;
if (direction.isPresent()) {
directionParam = direction.get();
} else {
directionParam = Direction.BOTH;
}
var payload = editingContextEventProcessor.handle(new GetRelationshipsByRelatedElementRestInput(UUID.randomUUID(), relatedElementId.toString(), directionParam)).block(Duration.ofSeconds(TIMEOUT));
if (payload instanceof GetRelationshipsByRelatedElementRestSuccessPayload successPayload) {
responseEntity = new ResponseEntity<>(successPayload.relationships(), HttpStatus.OK);
}
}
return responseEntity;
}

@GetMapping(path = "/roots")
public ResponseEntity<List<Object>> getRootElements(@PathVariable UUID projectId, @PathVariable UUID commitId) {
ResponseEntity<List<Object>> responseEntity = new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
var optionalEditingContextEventProcessor = this.editingContextEventProcessorRegistry.getOrCreateEditingContextEventProcessor(projectId.toString());
if (optionalEditingContextEventProcessor.isPresent()) {
var editingContextEventProcessor = optionalEditingContextEventProcessor.get();
var payload = editingContextEventProcessor.handle(new GetRootElementsRestInput(UUID.randomUUID())).block(Duration.ofSeconds(TIMEOUT));
if (payload instanceof GetRootElementsRestSuccessPayload successPayload) {
responseEntity = new ResponseEntity<>(successPayload.rootElements(), HttpStatus.OK);
}
}
return responseEntity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*******************************************************************************
* 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.application.object.dto;

/**
* Used to indicate the direction of the relationships to retrieve when calling "getRelationshipsByRelatedElement" REST API.
*
* @author arichard
*/
public enum Direction {
IN, OUT, BOTH
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************************
* 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.application.object.dto;

import java.util.UUID;

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

/**
* The input object of the GetElementByIdRestEventHandler.
*
* @author arichard
*/
public record GetElementByIdRestInput(UUID id, String elementId) implements IInput {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*******************************************************************************
* 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.application.object.dto;

import java.util.Objects;
import java.util.UUID;

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

/**
* The payload for the "getElementById" REST API on success.
*
* @author arichard
*/
public record GetElementByIdRestSuccessPayload(UUID id, Object element) implements IPayload {
public GetElementByIdRestSuccessPayload {
Objects.requireNonNull(id);
Objects.requireNonNull(element);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************************
* 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.application.object.dto;

import java.util.UUID;

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

/**
* The input object of the GetElementsRestEventHandler.
*
* @author arichard
*/
public record GetElementsRestInput(UUID id) implements IInput {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*******************************************************************************
* 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.application.object.dto;

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

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

/**
* The payload for the "getElements" REST API on success.
*
* @author arichard
*/
public record GetElementsRestSuccessPayload(UUID id, List<Object> elements) implements IPayload {
public GetElementsRestSuccessPayload {
Objects.requireNonNull(id);
Objects.requireNonNull(elements);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************************
* 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.application.object.dto;

import java.util.UUID;

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

/**
* The input object of the GetRelationshipsByRelatedElementRestEventHandler.
*
* @author arichard
*/
public record GetRelationshipsByRelatedElementRestInput(UUID id, String elementId, Direction direction) implements IInput {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*******************************************************************************
* 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.application.object.dto;

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

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

/**
* The payload for the "getRelationshipsByRelatedElement" REST API on success.
*
* @author arichard
*/
public record GetRelationshipsByRelatedElementRestSuccessPayload(UUID id, List<Object> relationships) implements IPayload {
public GetRelationshipsByRelatedElementRestSuccessPayload {
Objects.requireNonNull(id);
Objects.requireNonNull(relationships);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*******************************************************************************
* 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.application.object.dto;

import java.util.UUID;

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

/**
* The input object of the GetRootElementsRestEventHandler.
*
* @author arichard
*/
public record GetRootElementsRestInput(UUID id) implements IInput {
}
Loading

0 comments on commit 35e604f

Please sign in to comment.