Skip to content
Draft
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
25 changes: 23 additions & 2 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
= Changelog

== v2026.1.0 (work in progress)
== v2026.3.0 (work in progress)

=== Shapes

=== Breaking changes

=== Dependency update

=== Bug fixes

- https://github.com/eclipse-syson/syson/issues/1847[#1847] [export] Textual export duplicates "abstract" keyword for `OccurrenceUsage`.

=== Improvements

- https://github.com/eclipse-syson/syson/issues/1694[#1694] [syson] Customize Elasticsearch indices to work with SysML.
SysON now uses its own indexing logic instead of the default one provided by Sirius Web.
This allows to limit the size of the indices, and ensure information stored in the indices are useful to perform cross-project search.
You can find more information on how to setup Elasticsearch, how elements are mapped to index documents, and how to query them in the documentation.

=== New features


== v2026.1.0

=== Shapes

Expand Down Expand Up @@ -51,7 +73,6 @@ This fix ensure that imported models containing, for example, a top-level `Libra
- https://github.com/eclipse-syson/syson/issues/1825[#1825] `LiteralRational` value wrongly rounded during textual export.
- https://github.com/eclipse-syson/syson/issues/1784[#1784] Error while exporting `FeatureValue` using enumeration literals.


=== Improvements

- https://github.com/eclipse-syson/syson/issues/1666[#1666] [export] Export `SatisfyRequirementUsage` in textual format.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*******************************************************************************
* 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.index;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import org.eclipse.sirius.web.application.index.services.api.IIndexEntry;

/**
* A sub index entry contained in an {@link IIndexEntry}.
*
* <p>
* Nested index entries are used inside regular {@link IIndexEntry} POJOs to represent elements connected to the elements represented by the {@link IIndexEntry}. In most cases,
* {@link INestedIndexEntry} should not contain other {@link INestedIndexEntry}, in order to avoid infinite nesting depth, which cannot be stored in the index. This constraint may be relaxed for
* {@link INestedIndexEntry} representing relationships, which can themselves contain an {@link INestedIndexEntry} representing the other end of the relationship.
* </p>
* <p>
* For example, an {@link IIndexEntry} representing a SysML element can contain {@link INestedIndexEntry} representing its owned elements, but these nested entries should not contain information
* related to their own nested elements. The same {@link IIndexEntry} can contain {@link INestedIndexEntry} representing its relationships, which themselves can contain {@link INestedIndexEntry}
* representing the other end of the relationship, but this second level of nested entries cannot contain another level of {@link INestedIndexEntry}.
* </p>
* <p>
* The fields {@code id}, {@code type}, and {@code label} should match the identifier of the semantic element, the name of its SysML type, and the label used to present it to the end user. Note that
* these fields are serialized with a {@code @} prefix because they represent technical information, and shouldn't clash with potential fields computed from attributes in the SysML metamodel.
* An extra field {@code @nestedIndexEntryType} is also produced during the serialization to store the concrete type of the POJO. This lets Sirius Web find the actual type to use when deserializing
* query results.
* {@link INestedIndexEntry} does not provide {@code iconURLs} nor {@code editingContextId}, because they are not directly manipulated by Sirius Web (their containing {@link IIndexEntry} are).
* </p>
*
* @author gdaniel
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@nestedIndexEntryType")
public interface INestedIndexEntry {

String NESTED_INDEX_ENTRY_TYPE_FIELD = "@nestedIndexEntryType";

@JsonProperty(IIndexEntry.ID_FIELD)
String id();

@JsonProperty(IIndexEntry.TYPE_FIELD)
String type();

@JsonProperty(IIndexEntry.LABEL_FIELD)
String label();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*******************************************************************************
* 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.index;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.sirius.components.core.api.IEditingContext;
import org.eclipse.sirius.components.core.api.IIdentityService;
import org.eclipse.sirius.components.core.api.ILabelService;
import org.eclipse.sirius.web.application.index.services.api.IIndexEntry;
import org.eclipse.syson.sysml.Namespace;
import org.eclipse.syson.sysml.SysmlPackage;
import org.eclipse.syson.sysml.Type;
import org.eclipse.syson.sysml.util.SysmlSwitch;

/**
* Provides {@link IIndexEntry} for SysML elements.
*
* <p>
* {@link IIndexEntry} are top-level POJOs representing SysML elements that are stored in Elasticsearch indices. They can contain {@link INestedIndexEntry} to represent elements connected to the
* element they represent.
* </p>
* <p>
* SysON serializes SysML elements into entries that can contain nested entries with a maximum depth of:
* <ul>
* <li>1 for nested elements: for example, a package containing a part will define fields such as {@code name} (the name of the package), but also {@code ownedElement.name} (the name of the part)</li>
* <li>2 for nested specializations: for example, a part typed by a part definition will define fields such as {@code name} (the name of the part}, but also {@code ownedSpecialization.general.name}
* (the name of the part definition typing the part)</li>
* </ul>
* </p>
*
* @author gdaniel
*/
public class IndexEntrySwitch extends SysmlSwitch<Optional<IIndexEntry>> {

private final IIdentityService identityService;

private final ILabelService labelService;

private final IEditingContext editingContext;

private final NestedIndexEntrySwitch nestedIndexEntrySwitch;

public IndexEntrySwitch(IIdentityService identityService, ILabelService labelService, IEditingContext editingContext) {
this.identityService = Objects.requireNonNull(identityService);
this.labelService = Objects.requireNonNull(labelService);
this.editingContext = Objects.requireNonNull(editingContext);
this.nestedIndexEntrySwitch = new NestedIndexEntrySwitch(identityService, labelService);
}

@Override
public Optional<IIndexEntry> doSwitch(EObject eObject) {
Optional<IIndexEntry> result = Optional.empty();
if (eObject != null) {
result = super.doSwitch(eObject);
}
return result;
}

@Override
public Optional<IIndexEntry> defaultCase(EObject object) {
return Optional.empty();
}

@Override
public Optional<IIndexEntry> caseNamespace(Namespace namespace) {
String objectId = this.identityService.getId(namespace);
String type = this.getEClassifierName(namespace.eClass());
String label = this.labelService.getStyledLabel(namespace).toString();
List<String> iconURLs = this.labelService.getImagePaths(namespace);

String name = namespace.getName();
String shortName = namespace.getShortName();
String qualifiedName = namespace.getQualifiedName();

Optional<INestedIndexEntry> ownerNestedIndexEntry = this.nestedIndexEntrySwitch.doSwitch(namespace.getOwner());
List<INestedIndexEntry> ownedElementNestedIndexEntries = namespace.getOwnedElement().stream()
.map(this.nestedIndexEntrySwitch::doSwitch)
.filter(Optional::isPresent)
.map(Optional::get)
.toList();

return Optional.of(new NamespaceIndexEntry(this.editingContext.getId(), objectId, type, label, iconURLs, name, shortName, qualifiedName, ownerNestedIndexEntry.orElse(null),
ownedElementNestedIndexEntries));
}

@Override
public Optional<IIndexEntry> caseType(Type type) {
String objectId = this.identityService.getId(type);
String objectType = this.getEClassifierName(type.eClass());
String label = this.labelService.getStyledLabel(type).toString();
List<String> iconURLs = this.labelService.getImagePaths(type);

String name = type.getName();
String shortName = type.getShortName();
String qualifiedName = type.getQualifiedName();

Optional<INestedIndexEntry> ownerNestedIndexEntry = this.nestedIndexEntrySwitch.doSwitch(type.getOwner());
List<INestedIndexEntry> ownedElementNestedIndexEntries = type.getOwnedElement().stream()
.map(this.nestedIndexEntrySwitch::doSwitch)
.filter(Optional::isPresent)
.map(Optional::get)
.toList();
List<NestedSpecializationIndexEntry> ownedSpecializationNestedIndexEntries = type.getOwnedSpecialization().stream()
.map(this.nestedIndexEntrySwitch::doSwitch)
.filter(Optional::isPresent)
.map(Optional::get)
.filter(NestedSpecializationIndexEntry.class::isInstance)
.map(NestedSpecializationIndexEntry.class::cast)
.toList();

return Optional.of(new TypeIndexEntry(this.editingContext.getId(), objectId, objectType, label, iconURLs, name, shortName, qualifiedName, ownerNestedIndexEntry.orElse(null),
ownedSpecializationNestedIndexEntries, ownedElementNestedIndexEntries));
}

private String getEClassifierName(EClassifier eClassifier) {
String name = eClassifier.getName();
if (eClassifier instanceof EClass eClass) {
if (SysmlPackage.eINSTANCE.getUsage().isSuperTypeOf(eClass)
&& !SysmlPackage.eINSTANCE.getConnectorAsUsage().equals(eClass)
&& !SysmlPackage.eINSTANCE.getBindingConnectorAsUsage().equals(eClass)
&& !SysmlPackage.eINSTANCE.getSuccessionAsUsage().equals(eClass)) {
if (eClass.getName().endsWith("Usage")) {
name = eClass.getName().substring(0, eClass.getName().length() - 5);
}
}
}
return name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*******************************************************************************
* 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.index;

import java.util.List;

import org.eclipse.sirius.web.application.index.services.api.IIndexEntry;

/**
* An index entry representing a {@link org.eclipse.syson.sysml.Namespace}.
*
* <p>
* This record contains relevant data related to a SysML Namespace (e.g. name, short name, qualified name), as well as technical information used by Sirius Web to present index entries to the end user
* (label, icons, type).
* </p>
* <p>
* This class contains {@link INestedIndexEntry}, which are additional objects serialized as sub-fields of this index entry, which allows to access information related to elements connected to the
* namespace (e.g. {@code owner.name} to access the name of the owner, or {@code ownedElement.name} to access the name of the owned elements).
* </p>
*
* @param editingContextId the identifier of the editing context containing the namespace
* @param id the identifier of the namespace
* @param type the name of the concrete SysML type of the namespace
* @param label the label of the namespace
* @param iconURLs the URLs of the icons of the namespace
* @param name the name of the namespace
* @param shortName the short name of the namespace
* @param qualifiedName the qualified name of the namespace
* @param owner the nested entry holding information related to the namespace's owner
* @param ownedElement the nested entries holding information related to the namespace owned elements
*
* @author gdaniel
*/
public record NamespaceIndexEntry(
String editingContextId,
String id,
String type,
String label,
List<String> iconURLs,
String name,
String shortName,
String qualifiedName,
INestedIndexEntry owner,
List<INestedIndexEntry> ownedElement
) implements IIndexEntry {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*******************************************************************************
* 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.index;

/**
* An index entry representing a nested {@link org.eclipse.syson.sysml.Element}.
*
* <p>
* This record does not contain recursive {@link INestedIndexEntry} in order to avoid infinite entry nesting when converting elements into index entries.
* See {@link INestedIndexEntry} for more information.
* </p>
*
* @param id the identifier of the element
* @param type the name of the concrete SysML type of the element
* @param label the label of the element
* @param name the name of the element
* @param shortName the short name of the element
* @param qualifiedName the qualified name of the element
*
* @author gdaniel
*/
public record NestedElementIndexEntry(
String id,
String type,
String label,
String name,
String shortName,
String qualifiedName
) implements INestedIndexEntry {
}
Loading
Loading