Skip to content

feat:filtering shells based on timestamp #506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 28 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
34de88e
feat: filtering Shells based on timestamp
shijinrajbosch Mar 27, 2025
57d1616
feat: filtering Shells based on timestamp
shijinrajbosch Mar 27, 2025
313f80b
feat: filtering Shells based on timestamp
shijinrajbosch Mar 27, 2025
3693ca8
feat: filtering Shells based on timestamp
shijinrajbosch Mar 27, 2025
8185079
feat: filtering Shells based on timestamp
shijinrajbosch Mar 27, 2025
4abc410
Updated AssetAdministrationShellApiDelegate.java with filtering logic…
shijinrajbosch Mar 27, 2025
7b113f7
Updated AssetAdministrationShellApiDelegate.java with filtering logic…
shijinrajbosch Mar 27, 2025
cb436c0
Updated AssetAdministrationShellApiDelegate.java with filtering logic…
shijinrajbosch Mar 27, 2025
a4be965
Updated AssetAdministrationShellApiDelegate.java with filtering logic…
shijinrajbosch Mar 27, 2025
7b4a811
Updated AssetAdministrationShellApiDelegate.java with filtering logic…
shijinrajbosch Mar 27, 2025
d7e2fb5
Updated AssetAdministrationShellApiDelegate.java with filtering logic…
shijinrajbosch Mar 27, 2025
ebe8da6
Corrected the formatting
shijinrajbosch Mar 27, 2025
69c6c96
Corrected the formatting
shijinrajbosch Mar 27, 2025
f98bf0a
Corrected the formatting
shijinrajbosch Mar 27, 2025
53d682d
Corrected the formatting
shijinrajbosch Mar 27, 2025
4cf04f4
Corrected the formatting
shijinrajbosch Mar 27, 2025
e33c0d4
Corrected the formatting
shijinrajbosch Mar 27, 2025
c44ffb1
Corrected the formatting
shijinrajbosch Mar 28, 2025
9540477
Corrected the formatting
shijinrajbosch Mar 28, 2025
06864ce
Corrected the formatting
shijinrajbosch Mar 28, 2025
d0c95bb
fix: Granular access handler logic correction
shijinrajbosch Apr 29, 2025
e811239
doc: Added Search by created after functionality details
shijinrajbosch May 14, 2025
39209c4
doc: Added Search by created after functionality details
shijinrajbosch May 14, 2025
120729c
doc: Added Search by created after functionality details
shijinrajbosch May 14, 2025
c3f6612
doc: Added Search by created after functionality details
shijinrajbosch May 14, 2025
56068da
doc: Added Search by created after functionality details
shijinrajbosch May 14, 2025
5df3cc0
doc: Added Search by created after functionality details
shijinrajbosch May 14, 2025
523def1
refactor: Renamed createdDate field to createdAt
shijinrajbosch May 20, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## 0.7.1
### Added
- Filtering shells based on timestamp
## fixed
- Bugfix: removed uniqueness check for idShort validation while shell creation

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,27 @@

package org.eclipse.tractusx.semantics.registry.mapper;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.eclipse.tractusx.semantics.aas.registry.model.*;

import org.eclipse.tractusx.semantics.aas.registry.model.AssetAdministrationShellDescriptor;
import org.eclipse.tractusx.semantics.aas.registry.model.AssetLink;
import org.eclipse.tractusx.semantics.aas.registry.model.GetAssetAdministrationShellDescriptorsResult;
import org.eclipse.tractusx.semantics.aas.registry.model.LangStringTextType;
import org.eclipse.tractusx.semantics.aas.registry.model.Reference;
import org.eclipse.tractusx.semantics.aas.registry.model.SpecificAssetId;
import org.eclipse.tractusx.semantics.registry.dto.ShellCollectionDto;
import org.eclipse.tractusx.semantics.registry.model.*;
import org.eclipse.tractusx.semantics.registry.model.Shell;
import org.eclipse.tractusx.semantics.registry.model.ShellDescription;
import org.eclipse.tractusx.semantics.registry.model.ShellDisplayName;
import org.eclipse.tractusx.semantics.registry.model.ShellIdentifier;
import org.eclipse.tractusx.semantics.registry.model.ShellIdentifierExternalSubjectReference;
import org.eclipse.tractusx.semantics.registry.model.ShellIdentifierSemanticReference;
import org.eclipse.tractusx.semantics.registry.model.ShellIdentifierSupplemSemanticReference;
import org.mapstruct.AfterMapping;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.InjectionStrategy;
Expand All @@ -34,87 +50,95 @@
import org.mapstruct.Mappings;
import org.mapstruct.NullValuePropertyMappingStrategy;


@Mapper(uses = {SubmodelMapper.class}, componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR ,nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE )
@Mapper( uses = {
SubmodelMapper.class }, componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE )
public interface ShellMapper {
@Mappings({
@Mapping(target = "idExternal", source = "id"),
@Mapping(target = "identifiers", source = "specificAssetIds"),
@Mapping(target = "descriptions", source = "description"),
@Mapping(target = "submodels", source = "submodelDescriptors"),
@Mapping(target = "shellType", source = "assetType"),
@Mapping(target = "shellKind", source = "assetKind"),
@Mapping(target = "id", ignore = true),
@Mapping(target = "displayNames", source = "displayName"),
})
Shell fromApiDto(AssetAdministrationShellDescriptor apiDto);

ShellDescription mapShellDescription (LangStringTextType description);

ShellDisplayName mapShellDisplayName (LangStringTextType displayName);

@Mappings({
@Mapping(target = "key", source = "name"),
@Mapping(target = "supplementalSemanticIds", source = "supplementalSemanticIds"),
@Mapping(target = "semanticId", source = "semanticId"),
@Mapping(target = "externalSubjectId", source = "externalSubjectId"),
})
ShellIdentifier fromApiDto(SpecificAssetId apiDto);

@Mappings({
@Mapping(target = "key", source = "name"),
})
ShellIdentifier fromApiDto(AssetLink apiDto);

Set<ShellIdentifier> fromAssetLinkApiDto(List<AssetLink> apiDto);

ShellIdentifierSupplemSemanticReference maptoShellIdentifierSupplemSemanticReference ( Reference supplementalSemanticId );

ShellIdentifierSemanticReference maptoShellIdentifierSemanticReference ( Reference semanticId );

ShellIdentifierExternalSubjectReference maptoShellIdentifierExternalSubjectReference ( Reference externalSubjectId );

Set<ShellIdentifier> fromApiDto(List<SpecificAssetId> apiDto);

@Mappings({
@Mapping(target = "name", source = "key"),
})
SpecificAssetId fromDtoApi(ShellIdentifier apiDto);

@Mappings({
@Mapping(source = "idExternal", target = "id"),
@Mapping(source = "identifiers", target = "specificAssetIds"),
@Mapping(source = "descriptions", target = "description"),
@Mapping(source = "submodels", target = "submodelDescriptors"),
@Mapping(source = "displayNames", target = "displayName"),
})
@InheritInverseConfiguration
AssetAdministrationShellDescriptor toApiDto(Shell shell);

LangStringTextType mapAssetDescription (ShellDescription description);

LangStringTextType mapAssetDisplayName (ShellDisplayName shellDisplayName);

@Mappings({
@Mapping(source = "items", target = "result"),
@Mapping(source = "cursor", target = "pagingMetadata.cursor"),
})
GetAssetAdministrationShellDescriptorsResult toApiDto( ShellCollectionDto shell);

List<SpecificAssetId> toApiDto(Set<ShellIdentifier> shell);

@AfterMapping
default Shell convertGlobalAssetIdToShellIdentifier(AssetAdministrationShellDescriptor apiDto, @MappingTarget Shell shell){
return ShellMapperCustomization.globalAssetIdToShellIdentifier(apiDto, shell);
}

@AfterMapping
default void convertShellIdentifierToGlobalAssetId(Shell shell, @MappingTarget AssetAdministrationShellDescriptor apiDto){
ShellMapperCustomization.shellIdentifierToGlobalAssetId(shell, apiDto);
}
@Mappings( {
@Mapping( target = "idExternal", source = "id" ),
@Mapping( target = "identifiers", source = "specificAssetIds" ),
@Mapping( target = "descriptions", source = "description" ),
@Mapping( target = "submodels", source = "submodelDescriptors" ),
@Mapping( target = "shellType", source = "assetType" ),
@Mapping( target = "shellKind", source = "assetKind" ),
@Mapping( target = "id", ignore = true ),
@Mapping( target = "displayNames", source = "displayName" ),
} )
Shell fromApiDto( AssetAdministrationShellDescriptor apiDto );

default Instant map( final OffsetDateTime value ) {
return Optional.ofNullable( value ).map( OffsetDateTime::toInstant ).orElse( null );
}

default OffsetDateTime map( final Instant value ) {
return Optional.ofNullable( value ).map( instant -> instant.atOffset( ZoneId.systemDefault().getRules().getOffset( instant ) ) ).orElse( null );
}

ShellDescription mapShellDescription( LangStringTextType description );

ShellDisplayName mapShellDisplayName( LangStringTextType displayName );

@Mappings( {
@Mapping( target = "key", source = "name" ),
@Mapping( target = "supplementalSemanticIds", source = "supplementalSemanticIds" ),
@Mapping( target = "semanticId", source = "semanticId" ),
@Mapping( target = "externalSubjectId", source = "externalSubjectId" ),
} )
ShellIdentifier fromApiDto( SpecificAssetId apiDto );

@Mappings( {
@Mapping( target = "key", source = "name" ),
} )
ShellIdentifier fromApiDto( AssetLink apiDto );

Set<ShellIdentifier> fromAssetLinkApiDto( List<AssetLink> apiDto );

ShellIdentifierSupplemSemanticReference maptoShellIdentifierSupplemSemanticReference( Reference supplementalSemanticId );

ShellIdentifierSemanticReference maptoShellIdentifierSemanticReference( Reference semanticId );

ShellIdentifierExternalSubjectReference maptoShellIdentifierExternalSubjectReference( Reference externalSubjectId );

Set<ShellIdentifier> fromApiDto( List<SpecificAssetId> apiDto );

@Mappings( {
@Mapping( target = "name", source = "key" ),
} )
SpecificAssetId fromDtoApi( ShellIdentifier apiDto );

@Mappings( {
@Mapping( source = "idExternal", target = "id" ),
@Mapping( source = "identifiers", target = "specificAssetIds" ),
@Mapping( source = "descriptions", target = "description" ),
@Mapping( source = "submodels", target = "submodelDescriptors" ),
@Mapping( source = "displayNames", target = "displayName" ),
} )
@InheritInverseConfiguration
AssetAdministrationShellDescriptor toApiDto( Shell shell );

LangStringTextType mapAssetDescription( ShellDescription description );

LangStringTextType mapAssetDisplayName( ShellDisplayName shellDisplayName );

@Mappings( {
@Mapping( source = "items", target = "result" ),
@Mapping( source = "cursor", target = "pagingMetadata.cursor" ),
} )
GetAssetAdministrationShellDescriptorsResult toApiDto( ShellCollectionDto shell );

List<SpecificAssetId> toApiDto( Set<ShellIdentifier> shell );

@AfterMapping
default Shell convertGlobalAssetIdToShellIdentifier( final AssetAdministrationShellDescriptor apiDto, @MappingTarget final Shell shell ) {
return ShellMapperCustomization.globalAssetIdToShellIdentifier( apiDto, shell );
}

@AfterMapping
default void convertShellIdentifierToGlobalAssetId( final Shell shell, @MappingTarget final AssetAdministrationShellDescriptor apiDto ) {
ShellMapperCustomization.shellIdentifierToGlobalAssetId( shell, apiDto );
}

@AfterMapping
default void removeGlobalAssetIdFromIdentifiers(@MappingTarget List<SpecificAssetId> apiDto){
ShellMapperCustomization.removeGlobalAssetIdIdentifier(apiDto);
default void removeGlobalAssetIdFromIdentifiers( @MappingTarget final List<SpecificAssetId> apiDto ) {
ShellMapperCustomization.removeGlobalAssetIdIdentifier( apiDto );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

package org.eclipse.tractusx.semantics.registry.service;

import java.time.OffsetDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
Expand All @@ -42,16 +43,17 @@ public class DefaultShellAccessHandler implements ShellAccessHandler {
private final String externalSubjectIdWildcardPrefix;
private final List<String> externalSubjectIdWildcardAllowedTypes;

public DefaultShellAccessHandler( RegistryProperties registryProperties ) {
this.owningTenantId = registryProperties.getIdm().getOwningTenantId();
this.externalSubjectIdWildcardPrefix = registryProperties.getExternalSubjectIdWildcardPrefix();
this.externalSubjectIdWildcardAllowedTypes = registryProperties.getExternalSubjectIdWildcardAllowedTypes();
public DefaultShellAccessHandler( final RegistryProperties registryProperties ) {
owningTenantId = registryProperties.getIdm().getOwningTenantId();
externalSubjectIdWildcardPrefix = registryProperties.getExternalSubjectIdWildcardPrefix();
externalSubjectIdWildcardAllowedTypes = registryProperties.getExternalSubjectIdWildcardAllowedTypes();
}

@Override
public Specification<Shell> shellFilterSpecification( String sortFieldName, ShellCursor cursor, String externalSubjectId ) {
public Specification<Shell> shellFilterSpecification( final String sortFieldName, final ShellCursor cursor, final String externalSubjectId,
final OffsetDateTime createdAfter ) {
return new ShellSpecification<>( sortFieldName, cursor, externalSubjectId, owningTenantId, externalSubjectIdWildcardPrefix,
externalSubjectIdWildcardAllowedTypes );
externalSubjectIdWildcardAllowedTypes, createdAfter );
}

/**
Expand All @@ -67,13 +69,13 @@ public Specification<Shell> shellFilterSpecification( String sortFieldName, Shel
//Could map to null if the shell should not be visible at all
@Override
@Nullable
public Shell filterShellProperties( Shell shell, String externalSubjectId ) {
public Shell filterShellProperties( final Shell shell, final String externalSubjectId ) {
if ( externalSubjectId.equals( owningTenantId ) ) {
return shell;
}

Set<ShellIdentifier> filteredIdentifiers = filterSpecificAssetIdsByTenantId( shell.getIdentifiers(), externalSubjectId );
boolean hasOnlyPublicAccess = filteredIdentifiers.stream().noneMatch( shellIdentifier -> {
final Set<ShellIdentifier> filteredIdentifiers = filterSpecificAssetIdsByTenantId( shell.getIdentifiers(), externalSubjectId );
final boolean hasOnlyPublicAccess = filteredIdentifiers.stream().noneMatch( shellIdentifier -> {
if ( shellIdentifier.getExternalSubjectId() == null ) {
return false;
}
Expand All @@ -84,7 +86,7 @@ public Shell filterShellProperties( Shell shell, String externalSubjectId ) {
if ( hasOnlyPublicAccess ) {
// Filter out globalAssetId from specificAssetId. TODO: implement to save globalAssetId in separate database column
// GlobalAssetId is set via mapper. In case of only read access, no globalAssetId should be shown.
Set<ShellIdentifier> filteredIdentifiersWithNoGlobalAssetId = filteredIdentifiers.stream().filter(
final Set<ShellIdentifier> filteredIdentifiersWithNoGlobalAssetId = filteredIdentifiers.stream().filter(
shellIdentifier -> !shellIdentifier.getKey().equals( ShellIdentifier.GLOBAL_ASSET_ID_KEY ) )
.collect( Collectors.toSet() );
return new Shell()
Expand All @@ -98,32 +100,32 @@ public Shell filterShellProperties( Shell shell, String externalSubjectId ) {
}

@Override
public List<Shell> filterListOfShellProperties( List<Shell> shells, String externalSubjectId ) {
public List<Shell> filterListOfShellProperties( final List<Shell> shells, final String externalSubjectId ) {
return shells.stream()
.map( shell -> filterShellProperties( shell, externalSubjectId ) )
.toList();
}

private Set<ShellIdentifier> filterSpecificAssetIdsByTenantId( Set<ShellIdentifier> shellIdentifiers, String tenantId ) {
private Set<ShellIdentifier> filterSpecificAssetIdsByTenantId( final Set<ShellIdentifier> shellIdentifiers, final String tenantId ) {
// the owning tenant should always see all identifiers
if ( tenantId.equals( owningTenantId ) ) {
return shellIdentifiers;
}

Set<ShellIdentifier> externalSubjectIdSet = new HashSet<>();
for ( ShellIdentifier identifier : shellIdentifiers ) {
final Set<ShellIdentifier> externalSubjectIdSet = new HashSet<>();
for ( final ShellIdentifier identifier : shellIdentifiers ) {
// Check if specificAssetId is globalAssetId -> TODO: implement to save globalAssetId in separate database column
if ( identifier.getKey().equals( ShellIdentifier.GLOBAL_ASSET_ID_KEY ) ) {
externalSubjectIdSet.add( identifier );
}
if ( identifier.getExternalSubjectId() != null ) {
Set<ShellIdentifierExternalSubjectReferenceKey> optionalReferenceKey =
final Set<ShellIdentifierExternalSubjectReferenceKey> optionalReferenceKey =
identifier.getExternalSubjectId().getKeys().stream().filter( shellIdentifierExternalSubjectReferenceKey ->
// Match if externalSubjectId = tenantId
// Match if externalSubjectId = tenantId
shellIdentifierExternalSubjectReferenceKey.getValue().equals( tenantId )
// or match if externalSubjectId = externalSubjectIdWildcardPrefix and key of identifier (for example manufacturerPartId) is allowing wildcard.
|| (shellIdentifierExternalSubjectReferenceKey.getValue().equals( externalSubjectIdWildcardPrefix )
&& externalSubjectIdWildcardAllowedTypes.contains( identifier.getKey() )) )
// or match if externalSubjectId = externalSubjectIdWildcardPrefix and key of identifier (for example manufacturerPartId) is allowing wildcard.
|| (shellIdentifierExternalSubjectReferenceKey.getValue().equals( externalSubjectIdWildcardPrefix )
&& externalSubjectIdWildcardAllowedTypes.contains( identifier.getKey() )) )
.collect( Collectors.toSet() );
if ( !optionalReferenceKey.isEmpty() ) {
identifier.getExternalSubjectId().setKeys( optionalReferenceKey );
Expand Down
Loading
Loading