Skip to content

Commit b0fd5b6

Browse files
committed
Merge branch 'main' into 2.9.x
2 parents 81e9f58 + 7492acb commit b0fd5b6

File tree

14 files changed

+386
-9
lines changed

14 files changed

+386
-9
lines changed

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoader.java

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515

1616
import static java.util.stream.Collectors.toSet;
1717

18+
import java.io.ByteArrayInputStream;
19+
import java.io.ByteArrayOutputStream;
1820
import java.io.File;
21+
import java.io.FileInputStream;
22+
import java.io.FileNotFoundException;
23+
import java.io.IOException;
1924
import java.io.InputStream;
2025
import java.nio.file.Path;
2126
import java.util.ArrayDeque;
@@ -30,6 +35,8 @@
3035
import java.util.function.Function;
3136
import java.util.function.Supplier;
3237
import java.util.stream.Stream;
38+
import java.util.zip.ZipEntry;
39+
import java.util.zip.ZipInputStream;
3340

3441
import org.eclipse.esmf.aspectmodel.AspectModelFile;
3542
import org.eclipse.esmf.aspectmodel.resolver.AspectModelFileLoader;
@@ -66,6 +73,7 @@
6673
*/
6774
public class AspectModelLoader implements ResolutionStrategySupport {
6875
private static final Logger LOG = LoggerFactory.getLogger( AspectModelLoader.class );
76+
private static final String ASPECT_MODELS_FOLDER = "aspect-models";
6977

7078
public static final Supplier<ResolutionStrategy> DEFAULT_STRATEGY = () -> {
7179
final Path currentDirectory = Path.of( System.getProperty( "user.dir" ) );
@@ -173,6 +181,90 @@ public AspectModel load( final InputStream inputStream ) {
173181
return buildAspectModel( loaderContext.loadedFiles() );
174182
}
175183

184+
@FunctionalInterface
185+
public interface InputStreamProvider {
186+
InputStream get() throws IOException;
187+
}
188+
189+
/**
190+
* Load Namespace Package (Archive) an Aspect Model from a File
191+
*
192+
* @param namespacePackage the archive file
193+
* @return the Aspect Model
194+
*/
195+
public AspectModel loadNamespacePackage( final File namespacePackage ) {
196+
if ( !namespacePackage.exists() || !namespacePackage.isFile() ) {
197+
throw new RuntimeException( new FileNotFoundException( "The specified file does not exist or is not a file." ) );
198+
}
199+
200+
try ( InputStream inputStream = new FileInputStream( namespacePackage ) ) {
201+
return loadNamespacePackage( inputStream );
202+
} catch ( IOException e ) {
203+
LOG.error( "Error reading the file: {}", namespacePackage.getAbsolutePath(), e );
204+
throw new RuntimeException( "Error reading the file: " + namespacePackage.getAbsolutePath(), e );
205+
}
206+
}
207+
208+
/**
209+
* Load Namespace Package (Archive) an Aspect Model from an InputStream
210+
*
211+
* @param inputStream the input stream
212+
* @return the Aspect Model
213+
*/
214+
public AspectModel loadNamespacePackage( final InputStream inputStream ) {
215+
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
216+
try {
217+
inputStream.transferTo( baos );
218+
} catch ( IOException e ) {
219+
throw new RuntimeException( e );
220+
}
221+
final boolean hasAspectModelsFolder = containsFolderInNamespacePackage( new ByteArrayInputStream( baos.toByteArray() ) );
222+
return loadNamespacePackageFromStream( new ByteArrayInputStream( baos.toByteArray() ), hasAspectModelsFolder );
223+
}
224+
225+
private AspectModel loadNamespacePackageFromStream( final InputStream inputStream, final boolean hasAspectModelsFolder ) {
226+
List<AspectModelFile> aspectModelFiles = new ArrayList<>();
227+
228+
try ( ZipInputStream zis = new ZipInputStream( inputStream ) ) {
229+
ZipEntry entry;
230+
231+
while ( (entry = zis.getNextEntry()) != null ) {
232+
boolean isRelevantEntry =
233+
(hasAspectModelsFolder && entry.getName().contains( String.format( "%s/", ASPECT_MODELS_FOLDER ) ) && entry.getName()
234+
.endsWith( ".ttl" ))
235+
|| (!hasAspectModelsFolder && entry.getName().endsWith( ".ttl" ));
236+
237+
if ( isRelevantEntry ) {
238+
AspectModelFile aspectModelFile = migrate( AspectModelFileLoader.load( zis ) );
239+
aspectModelFiles.add( aspectModelFile );
240+
}
241+
}
242+
243+
zis.closeEntry();
244+
} catch ( IOException e ) {
245+
LOG.error( "Error reading the Archive input stream", e );
246+
throw new RuntimeException( "Error reading the Archive input stream", e );
247+
}
248+
249+
LoaderContext loaderContext = new LoaderContext();
250+
resolve( aspectModelFiles, loaderContext );
251+
return buildAspectModel( loaderContext.loadedFiles() );
252+
}
253+
254+
private boolean containsFolderInNamespacePackage( final InputStream inputStream ) {
255+
try ( ZipInputStream zis = new ZipInputStream( inputStream ) ) {
256+
ZipEntry entry;
257+
while ( (entry = zis.getNextEntry()) != null ) {
258+
if ( entry.isDirectory() && entry.getName().contains( String.format( "%s/", ASPECT_MODELS_FOLDER ) ) ) {
259+
return true;
260+
}
261+
}
262+
} catch ( IOException e ) {
263+
throw new RuntimeException( e );
264+
}
265+
return false;
266+
}
267+
176268
private AspectModelFile migrate( final AspectModelFile file ) {
177269
return MetaModelVersionMigrator.INSTANCE.apply( file );
178270
}

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/metamodel/impl/DefaultNamespace.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public DefaultNamespace( final String packagePart, final VersionNumber versionNu
4444
* @param elements the list of elements in the namspace
4545
*/
4646
public DefaultNamespace( final String uri, final List<ModelElement> elements, final Optional<AspectModelFile> source ) {
47-
this( uri.split( ":" )[2], VersionNumber.parse( uri.split( ":" )[3] ), elements, source );
47+
this( uri.split( ":" )[2], VersionNumber.parse( uri.split( ":" )[3].replace( "#", "" ) ), elements, source );
4848
}
4949

5050
// /**

core/esmf-aspect-meta-model-java/src/test/java/org/eclipse/esmf/aspectmodel/loader/AspectModelLoaderTest.java

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,32 @@
1515

1616
import static org.assertj.core.api.Assertions.assertThat;
1717

18+
import java.io.File;
19+
import java.io.FileInputStream;
20+
import java.io.FileNotFoundException;
21+
import java.net.URISyntaxException;
22+
import java.nio.file.Path;
23+
import java.nio.file.Paths;
24+
import java.util.List;
1825
import java.util.Map;
1926
import java.util.Optional;
2027
import java.util.function.Function;
2128
import java.util.stream.Collectors;
2229

30+
import org.eclipse.esmf.aspectmodel.resolver.FileSystemStrategy;
31+
import org.eclipse.esmf.aspectmodel.resolver.ResolutionStrategy;
2332
import org.eclipse.esmf.metamodel.AbstractEntity;
33+
import org.eclipse.esmf.metamodel.AspectModel;
2434
import org.eclipse.esmf.metamodel.ComplexType;
35+
import org.eclipse.esmf.samm.KnownVersion;
2536
import org.eclipse.esmf.test.TestAspect;
2637
import org.eclipse.esmf.test.TestResources;
2738

2839
import org.junit.jupiter.api.Test;
2940

3041
class AspectModelLoaderTest {
3142
@Test
32-
public void testOfAbstractEntityCyclomaticCreation() {
43+
void testOfAbstractEntityCyclomaticCreation() {
3344
final Map<String, ComplexType> entities =
3445
TestResources.load( TestAspect.ASPECT_WITH_MULTIPLE_ENTITIES_SAME_EXTEND ).elements().stream()
3546
.filter( ComplexType.class::isInstance )
@@ -43,4 +54,134 @@ public void testOfAbstractEntityCyclomaticCreation() {
4354
assertThat( entities ).extracting( "testEntityTwo" ).isInstanceOfSatisfying( ComplexType.class, type ->
4455
assertThat( type ).extracting( ComplexType::getExtends ).extracting( Optional::get ).isSameAs( abstractEntity ) );
4556
}
57+
58+
@Test
59+
void testLoadAspectModelFromZipArchiveFile() {
60+
final Path archivePath = getPackage( "namespaces.zip" );
61+
final AspectModel aspectModel = new AspectModelLoader().loadNamespacePackage( new File( archivePath.toString() ) );
62+
63+
assertThat( aspectModel.namespaces() ).hasSize( 2 );
64+
assertThat( aspectModel.namespaces().get( 0 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.1.0" );
65+
assertThat( aspectModel.namespaces().get( 1 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.0.0" );
66+
67+
final List<String> aspectsNames = List.of( "Movement2", "Movement3", "Movement", "SimpleAspect" );
68+
69+
assertThat( aspectModel.files() ).hasSize( 4 );
70+
assertThat( aspectModel.files() )
71+
.anySatisfy( aspectModelFile -> {
72+
assertThat( aspectsNames ).contains( aspectModelFile.aspect().getName() );
73+
} );
74+
}
75+
76+
@Test
77+
void testLoadAspectModelFromZipArchiveInputStream() throws FileNotFoundException {
78+
final Path archivePath = getPackage( "namespaces.zip" );
79+
final AspectModel aspectModel = new AspectModelLoader().loadNamespacePackage( new FileInputStream( archivePath.toString() ) );
80+
81+
assertThat( aspectModel.namespaces() ).hasSize( 2 );
82+
assertThat( aspectModel.namespaces().get( 0 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.1.0" );
83+
assertThat( aspectModel.namespaces().get( 1 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.0.0" );
84+
85+
final List<String> aspectsNames = List.of( "Movement2", "Movement3", "Movement", "SimpleAspect" );
86+
87+
assertThat( aspectModel.files() ).hasSize( 4 );
88+
assertThat( aspectModel.files() )
89+
.anySatisfy( aspectModelFile -> {
90+
assertThat( aspectsNames ).contains( aspectModelFile.aspect().getName() );
91+
} );
92+
}
93+
94+
/**
95+
* Test migration to the latest version of Aspect Model in Archive
96+
*/
97+
@Test
98+
void testLoadAspectModelFromZipArchive2_0_0() throws FileNotFoundException {
99+
final Path archivePath = getPackage( "namespaces_with_old_version.zip" );
100+
final AspectModel aspectModel = new AspectModelLoader().loadNamespacePackage( new FileInputStream( archivePath.toString() ) );
101+
102+
assertThat( aspectModel.namespaces() ).hasSize( 2 );
103+
assertThat( aspectModel.namespaces().get( 0 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.1.0" );
104+
assertThat( aspectModel.namespaces().get( 1 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.0.0" );
105+
106+
final List<String> aspectsNames = List.of( "Movement2", "Movement3", "Movement4", "Movement", "SimpleAspect" );
107+
108+
assertThat( aspectModel.files() ).hasSize( 5 );
109+
assertThat( aspectModel.files() )
110+
.anySatisfy( aspectModelFile -> {
111+
assertThat( aspectsNames ).contains( aspectModelFile.aspect().getName() );
112+
} );
113+
}
114+
115+
@Test
116+
void testLoadAspectModelFromZipArchiveAspectModelsRoot() throws FileNotFoundException {
117+
final Path archivePath = getPackage( "namespaces-aspect-models-root.zip" );
118+
final AspectModel aspectModel = new AspectModelLoader().loadNamespacePackage( new FileInputStream( archivePath.toString() ) );
119+
120+
assertThat( aspectModel.namespaces() ).hasSize( 2 );
121+
assertThat( aspectModel.namespaces().get( 0 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.1.0" );
122+
assertThat( aspectModel.namespaces().get( 1 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.0.0" );
123+
124+
final List<String> aspectsNames = List.of( "Movement2", "Movement3", "Movement", "SimpleAspect" );
125+
126+
assertThat( aspectModel.files() ).hasSize( 4 );
127+
assertThat( aspectModel.files() )
128+
.anySatisfy( aspectModelFile -> {
129+
assertThat( aspectsNames ).contains( aspectModelFile.aspect().getName() );
130+
} );
131+
}
132+
133+
@Test
134+
void testLoadAspectModelFromZipArchiveAspectModelsSubfolder() throws FileNotFoundException {
135+
final Path archivePath = getPackage( "namespaces-aspect-models-subfolder.zip" );
136+
final AspectModel aspectModel = new AspectModelLoader().loadNamespacePackage( new FileInputStream( archivePath.toString() ) );
137+
138+
assertThat( aspectModel.namespaces() ).hasSize( 2 );
139+
assertThat( aspectModel.namespaces().get( 0 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.1.0" );
140+
assertThat( aspectModel.namespaces().get( 1 ).getName() ).contains( "urn:samm:org.eclipse.examples:1.0.0" );
141+
142+
final List<String> aspectsNames = List.of( "Movement2", "Movement3", "Movement", "SimpleAspect" );
143+
144+
assertThat( aspectModel.files() ).hasSize( 4 );
145+
assertThat( aspectModel.files() )
146+
.anySatisfy( aspectModelFile -> {
147+
assertThat( aspectsNames ).contains( aspectModelFile.aspect().getName() );
148+
} );
149+
}
150+
151+
@Test
152+
void testLoadAspectModelFromZipArchiveWithSharedProperty() throws FileNotFoundException, URISyntaxException {
153+
final Path archivePath = getPackage( "namespace-with-shared-property.zip" );
154+
155+
final File aspectModelsRootDirectory = new File(
156+
AspectModelLoaderTest.class.getClassLoader()
157+
.getResource( KnownVersion.getLatest().toString().toLowerCase() )
158+
.toURI().getPath() );
159+
160+
final ResolutionStrategy urnStrategy = new FileSystemStrategy( aspectModelsRootDirectory.toPath() );
161+
162+
final AspectModel aspectModel = new AspectModelLoader( urnStrategy ).loadNamespacePackage(
163+
new FileInputStream( archivePath.toString() ) );
164+
165+
assertThat( aspectModel.namespaces() ).hasSize( 1 );
166+
assertThat( aspectModel.namespaces().get( 0 ).getName() ).contains( "urn:samm:org.eclipse.esmf.test:1.0.0" );
167+
168+
final List<String> aspectsNames = List.of( "Movement" );
169+
170+
assertThat( aspectModel.files() ).hasSize( 2 );
171+
assertThat( aspectModel.files() )
172+
.anySatisfy( aspectModelFile -> {
173+
if ( !aspectModelFile.aspects().isEmpty() ) {
174+
assertThat( aspectsNames ).contains( aspectModelFile.aspect().getName() );
175+
}
176+
} );
177+
}
178+
179+
/**
180+
* Returns the File object for a test model file
181+
*/
182+
private Path getPackage( final String packageName ) {
183+
return Paths.get( String.format(
184+
"%s/../../core/esmf-test-aspect-models/src/main/resources/packages/%s",
185+
System.getProperty( "user.dir" ), packageName ) );
186+
}
46187
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH
2+
#
3+
# See the AUTHORS file(s) distributed with this work for additional
4+
# information regarding authorship.
5+
#
6+
# This Source Code Form is subject to the terms of the Mozilla Public
7+
# License, v. 2.0. If a copy of the MPL was not distributed with this
8+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
9+
#
10+
# SPDX-License-Identifier: MPL-2.0
11+
12+
@prefix : <urn:samm:org.eclipse.esmf.test:1.0.0#> .
13+
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
14+
@prefix samm-c: <urn:samm:org.eclipse.esmf.samm:characteristic:2.1.0#> .
15+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
16+
17+
:propertyWithExampleValue a samm:Property ;
18+
samm:characteristic samm-c:Text ;
19+
samm:exampleValue "test" .

core/esmf-aspect-model-aas-generator/src/test/java/org/eclipse/esmf/aspectmodel/aas/AspectModelAasGeneratorTest.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ void generateAasxWithAspectDataForCollectionProperty() throws DeserializationExc
142142

143143
@Test
144144
void generateAasxWithAspectDataForCollectionPropertyWithCustomMapper() throws DeserializationException {
145-
AspectModelAasGenerator customGenerator = new AspectModelAasGenerator( List.of( new IntegerCollectionMapper() ) );
145+
final AspectModelAasGenerator customGenerator = new AspectModelAasGenerator( List.of( new IntegerCollectionMapper() ) );
146146
final Environment env = getAssetAdministrationShellFromAspectWithData( TestAspect.ASPECT_WITH_COLLECTION_OF_SIMPLE_TYPE,
147147
customGenerator );
148148
assertThat( env.getSubmodels() )
@@ -357,17 +357,17 @@ void testGenerateAasxFromAspectModelWithEnumeration() throws DeserializationExce
357357
// anonymous enumeration in test has no urn for enum values but is required for Concept
358358
// Description referencing
359359
public void testGeneration( final TestAspect testAspect ) throws DeserializationException {
360-
final String aspectAsString = aspectToString( testAspect );
361-
final byte[] xmlFile = aspectAsString.getBytes();
360+
final String aasXmlString = aspectToAasXml( testAspect );
361+
final byte[] aasXmlInput = aasXmlString.getBytes();
362362

363-
final String aasXml = new String( xmlFile );
363+
final String aasXml = new String( aasXmlInput );
364364
assertThat( aasXml ).doesNotContain( "DefaultScalarValue[" );
365365
assertThat( aasXml ).doesNotContain( "DefaultEntity[" );
366366
assertThat( aasXml ).doesNotContain( "Optional[" );
367367

368-
final Environment env = loadAasx( new ByteArrayInputStream( xmlFile ) );
368+
final Environment env = loadAasx( new ByteArrayInputStream( aasXmlInput ) );
369369
assertThat( env.getSubmodels() ).isNotEmpty();
370-
validate( new ByteArrayInputStream( xmlFile ) );
370+
validate( new ByteArrayInputStream( aasXmlInput ) );
371371
}
372372

373373
@Test
@@ -455,7 +455,7 @@ private Environment getAssetAdministrationShellFromAspectWithData( final TestAsp
455455
return loadAasx( generator.generateAsByteArray( AasFileFormat.XML, aspect, aspectData ) );
456456
}
457457

458-
private String aspectToString( final TestAspect testAspect ) {
458+
private String aspectToAasXml( final TestAspect testAspect ) {
459459
final Aspect aspect = TestResources.load( testAspect ).aspect();
460460
return new String( generator.generateAsByteArray( AasFileFormat.XML, aspect ), StandardCharsets.UTF_8 );
461461
}

core/esmf-aspect-model-document-generators/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@
160160
<artifactId>logback-core</artifactId>
161161
<scope>test</scope>
162162
</dependency>
163+
<dependency>
164+
<groupId>org.eclipse.esmf</groupId>
165+
<artifactId>esmf-aspect-model-serializer</artifactId>
166+
</dependency>
163167
</dependencies>
164168

165169
<build>

0 commit comments

Comments
 (0)