diff --git a/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasVisitor.java b/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasVisitor.java index caa7d2498..8fa491619 100644 --- a/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasVisitor.java +++ b/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasVisitor.java @@ -13,6 +13,8 @@ package org.eclipse.esmf.aspectmodel.aas; import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -105,6 +107,7 @@ public class AspectModelAasVisitor implements AspectVisitor Environment visitCollectionProperty( final T coll .displayName( LangStringMapper.NAME.map( property.getPreferredNames() ) ) .description( LangStringMapper.TEXT.map( property.getDescriptions() ) ) .value( List.of( decideOnMapping( property, context ) ) ) - .typeValueListElement( AasSubmodelElements.SUBMODEL_ELEMENT ) - .supplementalSemanticIds( buildGlobalReferenceForSeeReferences( collection ) ); + .typeValueListElement( AasSubmodelElements.SUBMODEL_ELEMENT_COLLECTION ) + .supplementalSemanticIds( buildGlobalReferenceForSeeReferences( collection ) ) + .orderRelevant( false ); if ( !collection.isAnonymous() ) { submodelBuilder.semanticId( buildReferenceForCollection( collection.urn().getUrn().toString() ) ); @@ -574,7 +584,7 @@ private Environment visitCollectionProperty( final T coll context.getRawPropertyValue() .filter( ArrayNode.class::isInstance ) .map( ArrayNode.class::cast ) - .map( arrayNode -> ( Property property ) -> { + .map( arrayNode -> ( final Property property ) -> { final List values = getValues( collection, property, context, arrayNode ); return new DefaultSubmodelElementList.Builder() .idShort( property.getName() ) @@ -582,6 +592,7 @@ private Environment visitCollectionProperty( final T coll .description( LangStringMapper.TEXT.map( property.getDescriptions() ) ) .value( values ) .typeValueListElement( AasSubmodelElements.SUBMODEL_ELEMENT ) + .orderRelevant( false ) .build(); } ) ) .orElse( defaultBuilder ); @@ -734,6 +745,32 @@ public Environment visitEnumeration( final Enumeration enumeration, final Contex return context.environment; } + /** + * Transforms a given enumValue string to a specific format. + * The transformation is done by removing spaces and special characters + * from the input string, then appending the first 8 characters of the + * sha256 hash of the cleaned string to the provided prefix. + * + * @param enumValue the input string to be transformed + * @return the transformed string in the format "_role[8_characters_of_hash]" + * @throws NoSuchAlgorithmException if the SHA-256 algorithm is not available + */ + private String transformEnumerationValue( final String enumValue ) throws NoSuchAlgorithmException { + final String cleanedEnumValue = enumValue.replaceAll( ALLOWS_ENUMERATION_VALUE_REGEX, "" ); + + final MessageDigest digest = MessageDigest.getInstance( "SHA-256" ); + final byte[] hashBytes = digest.digest( cleanedEnumValue.getBytes( StandardCharsets.UTF_8 ) ); + + final StringBuilder hexString = new StringBuilder(); + for ( final byte b : hashBytes ) { + hexString.append( String.format( "%02x", b ) ); + } + + final String hashPrefix = hexString.substring( 0, 8 ); + + return "_" + cleanedEnumValue + hashPrefix; + } + @Override public Environment visitState( final State state, final Context context ) { // Same handling as with enumerations diff --git a/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/DefaultPropertyMapper.java b/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/DefaultPropertyMapper.java index ef00bcbb5..545f32040 100644 --- a/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/DefaultPropertyMapper.java +++ b/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/DefaultPropertyMapper.java @@ -23,13 +23,17 @@ public class DefaultPropertyMapper implements PropertyMapper { @Override public Property mapToAasProperty( final Type type, final org.eclipse.esmf.metamodel.Property property, final Context context ) { - return new DefaultProperty.Builder() - .idShort( context.getPropertyShortId() ) - .valueType( AasDataTypeMapper.mapAspectTypeToAasXsdDataType( mapType( type ) ) ) - .displayName( LangStringMapper.NAME.map( property.getPreferredNames() ) ) - .value( context.getPropertyValue( UNKNOWN_EXAMPLE ) ) - .semanticId( buildReferenceToGlobalReference( property ) ) - .build(); + final DefaultProperty defaultProperty = new DefaultProperty(); + defaultProperty.setIdShort( context.getPropertyShortId() ); + defaultProperty.setValueType( AasDataTypeMapper.mapAspectTypeToAasXsdDataType( mapType( type ) ) ); + defaultProperty.setDisplayName( LangStringMapper.NAME.map( property.getPreferredNames() ) ); + defaultProperty.setSemanticId( buildPropertyReferenceToGlobalReference( property ) ); + + if ( !context.getPropertyValue( UNKNOWN_EXAMPLE ).equals( UNKNOWN_EXAMPLE ) ) { + defaultProperty.setValue( context.getPropertyValue( UNKNOWN_EXAMPLE ) ); + } + + return defaultProperty; } private String mapType( final Type type ) { diff --git a/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/LangStringPropertyMapper.java b/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/LangStringPropertyMapper.java index 5c8663017..52ccf1504 100644 --- a/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/LangStringPropertyMapper.java +++ b/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/LangStringPropertyMapper.java @@ -46,7 +46,7 @@ public MultiLanguageProperty mapToAasProperty( final Type type, final Property p return new DefaultMultiLanguageProperty.Builder().idShort( context.getPropertyShortId() ) .description( LangStringMapper.TEXT.map( property.getDescriptions() ) ) .displayName( LangStringMapper.NAME.map( property.getPreferredNames() ) ) - .semanticId( buildReferenceToGlobalReference( property ) ) + .semanticId( buildPropertyReferenceToGlobalReference( property ) ) .value( extractLangStrings( property, context ) ) .build(); } diff --git a/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/PropertyMapper.java b/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/PropertyMapper.java index 9d61aa6a1..257df749c 100644 --- a/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/PropertyMapper.java +++ b/core/esmf-aspect-model-aas-generator/src/main/java/org/eclipse/esmf/aspectmodel/aas/PropertyMapper.java @@ -80,7 +80,7 @@ default int compareTo( PropertyMapper otherPropertyMapper ) { * @param property the property to build the reference for * @return the newly created reference */ - default Reference buildReferenceToGlobalReference( final Property property ) { + default Reference buildPropertyReferenceToGlobalReference( final Property property ) { final Key key = new DefaultKey.Builder() .type( KeyTypes.GLOBAL_REFERENCE ) .value( determineIdentifierFor( property ) ) diff --git a/core/esmf-aspect-model-aas-generator/src/test/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasGeneratorTest.java b/core/esmf-aspect-model-aas-generator/src/test/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasGeneratorTest.java index fc4321dd1..1af2d95f5 100644 --- a/core/esmf-aspect-model-aas-generator/src/test/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasGeneratorTest.java +++ b/core/esmf-aspect-model-aas-generator/src/test/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasGeneratorTest.java @@ -12,6 +12,7 @@ */ package org.eclipse.esmf.aspectmodel.aas; +import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.InstanceOfAssertFactories.type; import static org.junit.jupiter.api.Assertions.fail; @@ -109,18 +110,21 @@ void generateAasxWithAspectDataForNestedEntityLists() throws DeserializationExce assertThat( env.getSubmodels() ) .singleElement() .satisfies( subModel -> assertThat( subModel.getSubmodelElements() ) - .anySatisfy( sme -> - assertThat( sme ).asInstanceOf( type( SubmodelElementList.class ) ) - .extracting( SubmodelElementList::getValue ) - .asInstanceOf( InstanceOfAssertFactories.LIST ) - .anySatisfy( entity -> - assertThat( entity ).asInstanceOf( type( SubmodelElementCollection.class ) ) - .extracting( SubmodelElementCollection::getValue ) - .asInstanceOf( InstanceOfAssertFactories.LIST ) - .anySatisfy( property -> - assertThat( property ).asInstanceOf( type( Property.class ) ) - .extracting( Property::getValue ) - .isEqualTo( "2.25" ) ) ) ) ); + .anySatisfy( sme -> { + assertThat( sme ).asInstanceOf( type( SubmodelElementList.class ) ) + .extracting( SubmodelElementList::getValue ) + .asInstanceOf( InstanceOfAssertFactories.LIST ) + .anySatisfy( entity -> + assertThat( entity ).asInstanceOf( type( SubmodelElementCollection.class ) ) + .extracting( SubmodelElementCollection::getValue ) + .asInstanceOf( InstanceOfAssertFactories.LIST ) + .anySatisfy( property -> + assertThat( property ).asInstanceOf( type( Property.class ) ) + .extracting( Property::getValue ) + .isEqualTo( "2.25" ) ) ); + assertThat( ( ( SubmodelElementList ) sme ).getOrderRelevant() ).isFalse(); + } + ) ); } @Test @@ -203,7 +207,8 @@ void testGenerateAasxFromAspectModelWithCollection() throws DeserializationExcep assertThat( submodelElement ).asInstanceOf( type( SubmodelElementList.class ) ) .satisfies( submodelElementList -> { assertThat( submodelElementList.getIdShort() ).isEqualTo( "testProperty" ); - assertThat( submodelElementList.getTypeValueListElement() ).isEqualTo( AasSubmodelElements.SUBMODEL_ELEMENT ); + assertThat( submodelElementList.getTypeValueListElement() ).isEqualTo( AasSubmodelElements.SUBMODEL_ELEMENT_COLLECTION ); + assertThat( ( submodelElementList ).getOrderRelevant() ).isFalse(); } ); assertThat( submodelElement.getSemanticId().getKeys().get( 0 ).getType() ).isEqualTo( KeyTypes.GLOBAL_REFERENCE ); @@ -220,7 +225,8 @@ void testGenerateAasxFromAspectModelWithList() throws DeserializationException { assertThat( submodelElement ).asInstanceOf( type( SubmodelElementList.class ) ) .satisfies( submodelElementList -> { assertThat( submodelElementList.getIdShort() ).isEqualTo( "testProperty" ); - assertThat( submodelElementList.getTypeValueListElement() ).isEqualTo( AasSubmodelElements.SUBMODEL_ELEMENT ); + assertThat( submodelElementList.getTypeValueListElement() ).isEqualTo( AasSubmodelElements.SUBMODEL_ELEMENT_COLLECTION ); + assertThat( ( submodelElementList ).getOrderRelevant() ).isFalse(); } ); assertThat( submodelElement.getSemanticId().getKeys().get( 0 ).getType() ).isEqualTo( KeyTypes.GLOBAL_REFERENCE ); @@ -237,7 +243,8 @@ void testGenerateAasxFromAspectModelWithSet() throws DeserializationException { assertThat( submodelElement ).asInstanceOf( type( SubmodelElementList.class ) ) .satisfies( submodelElementList -> { assertThat( submodelElementList.getIdShort() ).isEqualTo( "testProperty" ); - assertThat( submodelElementList.getTypeValueListElement() ).isEqualTo( AasSubmodelElements.SUBMODEL_ELEMENT ); + assertThat( submodelElementList.getTypeValueListElement() ).isEqualTo( AasSubmodelElements.SUBMODEL_ELEMENT_COLLECTION ); + assertThat( ( submodelElementList ).getOrderRelevant() ).isFalse(); } ); assertThat( submodelElement.getSemanticId().getKeys().get( 0 ).getType() ).isEqualTo( KeyTypes.GLOBAL_REFERENCE ); @@ -251,6 +258,7 @@ void testGenerateAasxFromAspectModelWithSortedSet() throws DeserializationExcept assertThat( env.getSubmodels().get( 0 ).getSubmodelElements() ).hasSize( 1 ); final SubmodelElement submodelElement = env.getSubmodels().get( 0 ).getSubmodelElements().get( 0 ); assertThat( submodelElement ).as( "SubmodelElement is not a SubmodelElementList" ).isInstanceOf( SubmodelElementList.class ); + assertThat( ( ( ( SubmodelElementList ) submodelElement ) ).getOrderRelevant() ).isFalse(); assertThat( submodelElement.getIdShort() ).isEqualTo( "testProperty" ); assertThat( submodelElement.getSemanticId().getKeys().get( 0 ).getType() ).isEqualTo( KeyTypes.GLOBAL_REFERENCE ); @@ -413,6 +421,7 @@ void testGeneratedAasxFromAspectModelSemanticIdsAreGlobalReferences() throws Des final Property property = (Property) environment.getSubmodels().get( 0 ).getSubmodelElements().get( 0 ); assertThat( environment.getSubmodels().get( 0 ).getSubmodelElements() ).hasSize( 1 ); + assertThat( environment.getSubmodels().get( 0 ).getSemanticId().getKeys().get( 0 ).getType() ).isEqualTo( KeyTypes.GLOBAL_REFERENCE ); assertThat( environment.getConceptDescriptions() ).hasSize( 2 ); assertThat( environment.getConceptDescriptions().get( 1 ).getEmbeddedDataSpecifications() ).hasSize( 1 ); assertThat( property.getDescription() ).isEmpty();