Skip to content
Merged
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
9 changes: 6 additions & 3 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
- [cleanup] The definition of the tools specific to the requirements table has been moved to the backend.
As a result, the following GraphQL mutations have been removed `exposeRequirements` and `createRequirement`.
- [test] Reduce our call to `DiagramNavigator#nodeWithTargetObjectLabel` which has been deprecated for removal.
+ The API of `ToolTester#invokeTool` and `NodeCreationTestsService#createNode` has been updated accordingly to take a `targetObjectId` instead of a `label`.
The API of `ToolTester#invokeTool` and `NodeCreationTestsService#createNode` has been updated accordingly to take a `targetObjectId` instead of a `label`.
- https://github.com/eclipse-syson/syson/issues/2045[#2045] [diagrams] The service `ViewNodeService#revealCompartment` has been changed to reveal a compartment only when it is needed.
+ Only reveal a compartment of a node when none of the revealed compartment can display the `targetElement`.
+ If many compartment candidates exist, choose the first free form compartment.
Only reveal a compartment of a node when none of the revealed compartment can display the `targetElement`.
If many compartment candidates exist, choose the first free form compartment.
- [services] As part of the migration to the new diagram service architecture, the following methods have been moved out of `ViewNodeService` (which as been deleted):
+
** `List<Element> getExposedElements(Element self, EClass domainType, List<Object> ancestors, IEditingContext editingContext, DiagramContext diagramContext)` to `DiagramQueryAQLService.getExposedElements(Element self, EClass domainType, List<Object> ancestors, IEditingContext editingContext, DiagramContext diagramContext)`
Expand All @@ -34,6 +34,8 @@ As a result, the following GraphQL mutations have been removed `exposeRequiremen
** `org.eclipse.syson.diagram.common.view.services.RevealCompartmentSwitch` to `org.eclipse.syson.diagram.services.utils.RevealCompartmentSwitch`
+
Also, a new helper method `DiagramQueryAQLService.isNotAncestorOf(...)` has been added to support edge preconditions previously written as `aql:not graphicalEdgeSource.isAncestorOf(graphicalEdgeTarget, cache)`.
- https://github.com/eclipse-syson/syson/issues/2143[#2143] [configuration] The `relativePathToDirectoryContainingLibraryFiles` field in `SysONLibraryLoadingDefinition` now expects a `String` instead of a `java.nio.file.Path`.
This change ensures compatibility with classpath resource resolution, which requires forward slashes (`/`) as path separators.

=== Dependency update

Expand All @@ -53,6 +55,7 @@ Also, a new helper method `DiagramQueryAQLService.isNotAncestorOf(...)` has been

- https://github.com/eclipse-syson/syson/issues/2045[#2045] [diagrams] In Interconnection View diagrams, fix an issue where the `parts` compartment of a `PartDefinition` graphical node was incorrectly revealed when creating a `PartUsage` from the `PartDefinition` graphical node, even if the `interconnection` compartment was already visible.
- https://github.com/eclipse-syson/syson/issues/2094[#2094] [libraries] Ensure library documents are read-only.
- https://github.com/eclipse-syson/syson/issues/2143[#2143] [configuration] Fixed classpath resource resolution on Windows by enforcing forward slashes (`/`) in library paths.

=== Improvements

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024, 2025 Obeo.
* Copyright (c) 2024, 2026 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 All @@ -12,7 +12,6 @@
*******************************************************************************/
package org.eclipse.syson.application.configuration;

import java.nio.file.Paths;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
Expand Down Expand Up @@ -47,14 +46,14 @@ public class SysONDefaultLibrariesConfiguration {
public static final SysONLibraryLoadingDefinition KERML = new SysONLibraryLoadingDefinition(
"KerML Standard Library",
ElementUtil.KERML_LIBRARY_SCHEME,
Paths.get("kerml.libraries"),
"kerml.libraries",
Collections.singletonList(JsonResourceFactoryImpl.EXTENSION),
new JSONResourceFactory()::createResource);

public static final SysONLibraryLoadingDefinition SYSML = new SysONLibraryLoadingDefinition(
"SysML Standard Library",
ElementUtil.SYSML_LIBRARY_SCHEME,
Paths.get("sysml.libraries"),
"sysml.libraries",
Collections.singletonList(JsonResourceFactoryImpl.EXTENSION),
new JSONResourceFactory()::createResource);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2025 Obeo.
* Copyright (c) 2025, 2026 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 @@ -132,7 +132,7 @@ public List<ClassPathResource> findAllLibraryResourcesFromApplicationClasspath(f
final List<ClassPathResource> allResourcesForLibraryLoadingDefinition = new ArrayList<>();
final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
for (final String fileExtension : definition.fileExtensions()) {
final String locationPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + definition.relativePathToDirectoryContainingLibraryFiles().toString() + "/*." + fileExtension;
final String locationPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + definition.relativePathToDirectoryContainingLibraryFiles() + "/*." + fileExtension;

final List<org.springframework.core.io.Resource> resources = new ArrayList<>();
try {
Expand All @@ -141,7 +141,7 @@ public List<ClassPathResource> findAllLibraryResourcesFromApplicationClasspath(f
LOGGER.error("There was an unexpected issue while attempting to retrieve %s resources at location: %s".formatted(definition.familyName(), locationPattern), ioException);
}

resources.stream().map(resource -> new ClassPathResource(definition.relativePathToDirectoryContainingLibraryFiles().resolve(resource.getFilename()).toString()))
resources.stream().map(resource -> new ClassPathResource(definition.relativePathToDirectoryContainingLibraryFiles() + "/" + resource.getFilename()))
.forEach(allResourcesForLibraryLoadingDefinition::add);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2025 Obeo.
Comment thread
AxelRICHARD marked this conversation as resolved.
* Copyright (c) 2025, 2026 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 All @@ -12,7 +12,6 @@
*******************************************************************************/
package org.eclipse.syson.application.libraries;

import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
Expand All @@ -24,7 +23,9 @@
/**
* Defines how to identify, retrieve and load the different files constituting a SysON library.
*
* Note that the resources must be in the classpath of the application.
* The resources must be in the classpath of the application.
* The {@code relativePathToDirectoryContainingLibraryFiles} must use forward slashes ("/") as separators,
* as it is intended to be used in the classpath (e.g., JAR files or classpath directories).
*
* @author flatombe
* @see SysONDefaultLibrariesConfiguration#KERML
Expand All @@ -33,7 +34,7 @@
public record SysONLibraryLoadingDefinition(
String familyName,
String scheme,
Path relativePathToDirectoryContainingLibraryFiles,
String relativePathToDirectoryContainingLibraryFiles,
List<String> fileExtensions,
Function<URI, Resource> resourceLoadingBehavior) {

Expand All @@ -45,9 +46,7 @@ public record SysONLibraryLoadingDefinition(
* @param scheme
* the (non-{@code null}) scheme to use for the EMF {@link URI}s used to load resources of this library.
* @param relativePathToDirectoryContainingLibraryFiles
* the (non-{@code null}) relative {@link Path} to the <b>directory</b> containing the library files. If
* set to {@code foo/bar} then the library files are expected to be in directory
* {@code src/main/resources/foo/bar}.
* the (non-{@code null}) relative path (using forward slashes "/") to the <b>directory</b> containing the library files in the classpath.
* @param fileExtensions
* the (non-{@code null}) {@link List} of file extensions to look for in
* {@code relativePathToDirectoryContainingLibraryFiles}.
Expand All @@ -61,11 +60,15 @@ public record SysONLibraryLoadingDefinition(
Objects.requireNonNull(fileExtensions);
Objects.requireNonNull(resourceLoadingBehavior);

if (relativePathToDirectoryContainingLibraryFiles.isAbsolute()) {
throw new IllegalArgumentException("Path '%s' is absolute, but a relative one was expected.".formatted(relativePathToDirectoryContainingLibraryFiles.toString()));
if (relativePathToDirectoryContainingLibraryFiles.startsWith("/")) {
throw new IllegalArgumentException("Path '%s' is absolute, but a relative one was expected.".formatted(relativePathToDirectoryContainingLibraryFiles));
}
if (relativePathToDirectoryContainingLibraryFiles.toFile().exists() && !relativePathToDirectoryContainingLibraryFiles.toFile().isDirectory()) {
Comment thread
AxelRICHARD marked this conversation as resolved.
throw new IllegalArgumentException("Path '%s' exists but is not a directory.".formatted(relativePathToDirectoryContainingLibraryFiles.toString()));

// Validate that the path does not contain Windows-style separators
if (relativePathToDirectoryContainingLibraryFiles.contains("\\")) {
throw new IllegalArgumentException(
"Path '%s' contains Windows-style separators ('\\'). Only forward slashes ('/') are allowed for classpath resources.".formatted(relativePathToDirectoryContainingLibraryFiles)
);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*******************************************************************************
* Copyright (c) 2026 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.syson.application.configuration;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;

import java.util.List;
import java.util.function.Function;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.syson.application.libraries.SysONLibraryLoadingDefinition;
import org.junit.jupiter.api.Test;

/**
* Test about the library loading definition.
*
* @author frouene
*/
public class SysONLibraryLoadingDefinitionTest {

private static final String VALID_FAMILY_NAME = "TestLibrary";
private static final String VALID_SCHEME = "test";
private static final String VALID_RELATIVE_PATH = "name/library";
private static final List<String> VALID_EXTENSIONS = List.of("json", "xml");
private static final Function<URI, Resource> VALID_LOADING_BEHAVIOR = mock(Function.class);

@Test
void testValidDefinition() {
SysONLibraryLoadingDefinition definition = new SysONLibraryLoadingDefinition(
VALID_FAMILY_NAME,
VALID_SCHEME,
VALID_RELATIVE_PATH,
VALID_EXTENSIONS,
VALID_LOADING_BEHAVIOR
);

assertNotNull(definition);
assertEquals(VALID_FAMILY_NAME, definition.familyName());
assertEquals(VALID_SCHEME, definition.scheme());
assertEquals(VALID_RELATIVE_PATH, definition.relativePathToDirectoryContainingLibraryFiles());
assertEquals(VALID_EXTENSIONS, definition.fileExtensions());
assertEquals(VALID_LOADING_BEHAVIOR, definition.resourceLoadingBehavior());
}

@Test
void testAbsolutePath() {
assertThrows(IllegalArgumentException.class, () ->
new SysONLibraryLoadingDefinition(
VALID_FAMILY_NAME,
VALID_SCHEME,
"/name/library",
VALID_EXTENSIONS,
VALID_LOADING_BEHAVIOR
)
);
}

@Test
void testWindowsSeparators() {
assertThrows(IllegalArgumentException.class, () ->
new SysONLibraryLoadingDefinition(
VALID_FAMILY_NAME,
VALID_SCHEME,
"name\\library",
VALID_EXTENSIONS,
VALID_LOADING_BEHAVIOR
)
);
}

}
Loading