Skip to content

Commit

Permalink
Merge branch 'main' into 2.9.x
Browse files Browse the repository at this point in the history
  • Loading branch information
atextor committed Nov 21, 2024
2 parents 754df89 + 76417ce commit a31752d
Show file tree
Hide file tree
Showing 202 changed files with 3,499 additions and 1,712 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Model (SAMM) and supports its use.
# Contributing Source Code (using GitHub)

* We use this GitHub repository to track issues and feature requests.
* For general discussions of the ESMF, modeling questions etc. we use the [community forum](https://www.eclipse.org/forums/index.php/f/617/).
* For general discussions of the ESMF, modeling questions etc. we use the [ESMF Chat](https://chat.eclipse.org/#/room/#eclipse-semantic-modeling-framework:matrix.eclipse.org).
* For discussions specific to development, the preferred way is the [developer mailing list](https://accounts.eclipse.org/mailing-list/esmf-dev).

## Architecture Decision Records
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ To build the documentation locally, please check out and follow the instructions
Are you having trouble with ESMF SDK? We want to help!

* Check the [ESMF SDK developer documentation](https://eclipse-esmf.github.io/esmf-developer-guide/index.html)
* Ask a question the [community forum](https://www.eclipse.org/forums/index.php/f/617/).
* Ask a question in the [ESMF Chat ](https://chat.eclipse.org/#/room/#eclipse-semantic-modeling-framework:matrix.eclipse.org).
* Check the SAMM [specification](https://eclipse-esmf.github.io/samm-specification/snapshot/index.html)
* Having issues with the ESMF SDK? Open a [GitHub issue](https://github.com/eclipse-esmf/esmf-sdk/issues).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,53 @@

import org.apache.jena.rdf.model.Model;

/**
* An AspectModelFile is the abstraction of one "code unit". When its source location is in a file system, the
* AspectModelFile corresponds to one file, but this does not have to be the case: An AspectModelFile could also
* exist in memory, or purely virtually (e.g., as an abstraction of a sub-graph in a triple store).
*/
public interface AspectModelFile extends ModelElementGroup {
/**
* The RDF model with the contents of this AspectModelFile
*
* @return the model
*/
Model sourceModel();

/**
* The list of Strings that are contained as a comment block at the start of the file. This is often used
* for copyright and license information.
*
* @return the header comment
*/
default List<String> headerComment() {
return List.of();
}

/**
* The URI that denominates the source location, if present. It can be a file:// or https:// URL, but it
* could for example also be an Aspect Model URN, if it refers to a file that is part of the SAMM specification.
* Generally, this should be the physical location, not a logical identifier, in other words, where was this
* AspectModelFile loaded from.
*
* @return the source location
*/
Optional<URI> sourceLocation();

/**
* Returns the {@link Namespace} this AspectModelFile is a part of
*
* @return the namespace
*/
default Namespace namespace() {
throw new UnsupportedOperationException( "Uninitialized Aspect Model" );
}

/**
* Lists the model elements that are contained in this AspectModelFile
*
* @return the model elements
*/
@Override
default List<ModelElement> elements() {
throw new UnsupportedOperationException( "Uninitialized Aspect Model" );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
Expand Down Expand Up @@ -209,14 +208,14 @@ public AspectModel load( final InputStream inputStream ) {
*/
public AspectModel loadNamespacePackage( final File namespacePackage ) {
if ( !namespacePackage.exists() || !namespacePackage.isFile() ) {
throw new RuntimeException( new FileNotFoundException( "The specified file does not exist or is not a file." ) );
throw new ModelResolutionException( "The specified file does not exist or is not a file." );
}

try ( final InputStream inputStream = new FileInputStream( namespacePackage ) ) {
return loadNamespacePackage( inputStream );
} catch ( final IOException e ) {
LOG.error( "Error reading the file: {}", namespacePackage.getAbsolutePath(), e );
throw new RuntimeException( "Error reading the file: " + namespacePackage.getAbsolutePath(), e );
} catch ( final IOException exception ) {
LOG.error( "Error reading the file: {}", namespacePackage.getAbsolutePath(), exception );
throw new ModelResolutionException( "Error reading the file: " + namespacePackage.getAbsolutePath(), exception );
}
}

Expand All @@ -228,12 +227,13 @@ public AspectModel loadNamespacePackage( final File namespacePackage ) {
*/
public AspectModel loadNamespacePackage( final InputStream inputStream ) {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final boolean hasAspectModelsFolder;
try {
inputStream.transferTo( baos );
} catch ( final IOException e ) {
throw new RuntimeException( e );
hasAspectModelsFolder = containsFolderInNamespacePackage( new ByteArrayInputStream( baos.toByteArray() ) );
} catch ( final IOException exception ) {
throw new ModelResolutionException( "Could not read from input", exception );
}
final boolean hasAspectModelsFolder = containsFolderInNamespacePackage( new ByteArrayInputStream( baos.toByteArray() ) );
return loadNamespacePackageFromStream( new ByteArrayInputStream( baos.toByteArray() ), hasAspectModelsFolder );
}

Expand All @@ -245,8 +245,8 @@ private AspectModel loadNamespacePackageFromStream( final InputStream inputStrea

while ( ( entry = zis.getNextEntry() ) != null ) {
final boolean isRelevantEntry =
( hasAspectModelsFolder && entry.getName().contains( String.format( "%s/", ASPECT_MODELS_FOLDER ) ) && entry.getName()
.endsWith( ".ttl" ) )
( hasAspectModelsFolder && entry.getName().contains( String.format( "%s/", ASPECT_MODELS_FOLDER ) )
&& entry.getName().endsWith( ".ttl" ) )
|| ( !hasAspectModelsFolder && entry.getName().endsWith( ".ttl" ) );

if ( isRelevantEntry ) {
Expand All @@ -256,26 +256,24 @@ private AspectModel loadNamespacePackageFromStream( final InputStream inputStrea
}

zis.closeEntry();
} catch ( final IOException e ) {
LOG.error( "Error reading the Archive input stream", e );
throw new RuntimeException( "Error reading the Archive input stream", e );
} catch ( final IOException exception ) {
LOG.error( "Error reading the Archive input stream", exception );
throw new ModelResolutionException( "Error reading the Archive input stream", exception );
}

final LoaderContext loaderContext = new LoaderContext();
resolve( aspectModelFiles, loaderContext );
return loadAspectModelFiles( loaderContext.loadedFiles() );
}

private boolean containsFolderInNamespacePackage( final InputStream inputStream ) {
private boolean containsFolderInNamespacePackage( final InputStream inputStream ) throws IOException {
try ( final ZipInputStream zis = new ZipInputStream( inputStream ) ) {
ZipEntry entry;
while ( ( entry = zis.getNextEntry() ) != null ) {
if ( entry.isDirectory() && entry.getName().contains( String.format( "%s/", ASPECT_MODELS_FOLDER ) ) ) {
return true;
}
}
} catch ( final IOException e ) {
throw new RuntimeException( e );
}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@
import org.apache.jena.vocabulary.RDF;
import org.apache.jena.vocabulary.RDFS;

/**
* Used as part of the loading process in the {@link AspectModelLoader}, it creates instance for the the {@link ModelElement}s
* in an AspectModel.
*/
public class ModelElementFactory extends AttributeValueRetriever {
private final Model model;
private final Map<Resource, Instantiator<?>> instantiators = new HashMap<>();
Expand Down Expand Up @@ -351,7 +355,7 @@ private static Resource getModelElementType( final Resource modelElement ) {
return getModelElementType( superElement );
}

public AspectModelFile getSourceLocation( Resource modelElement ) {
public AspectModelFile getSourceLocation( final Resource modelElement ) {
return sourceLocator.apply( modelElement );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;

Expand All @@ -48,9 +50,10 @@ public Download() {
* Download the file and return the contents as byte array
*
* @param fileUrl the URL
* @param headers list of additional headers to set
* @return the file contents
*/
public byte[] downloadFile( final URL fileUrl ) {
public byte[] downloadFile( final URL fileUrl, final Map<String, String> headers ) {
try {
final HttpClient.Builder clientBuilder = HttpClient.newBuilder()
.version( HttpClient.Version.HTTP_1_1 )
Expand All @@ -59,14 +62,31 @@ public byte[] downloadFile( final URL fileUrl ) {
Optional.ofNullable( proxyConfig.proxy() ).ifPresent( clientBuilder::proxy );
Optional.ofNullable( proxyConfig.authenticator() ).ifPresent( clientBuilder::authenticator );
final HttpClient client = clientBuilder.build();
final HttpRequest request = HttpRequest.newBuilder().uri( fileUrl.toURI() ).build();
final String[] headersArray = headers.entrySet().stream()
.flatMap( entry -> Stream.of( entry.getKey(), entry.getValue() ) )
.toList()
.toArray( new String[0] );
final HttpRequest request = HttpRequest.newBuilder()
.uri( fileUrl.toURI() )
.headers( headersArray )
.build();
final HttpResponse<byte[]> response = client.send( request, HttpResponse.BodyHandlers.ofByteArray() );
return response.body();
} catch ( final InterruptedException | URISyntaxException | IOException exception ) {
throw new ModelResolutionException( "Could not retrieve " + fileUrl, exception );
}
}

/**
* Download the file and return the contents as byte array
*
* @param fileUrl the URL
* @return the file contents
*/
public byte[] downloadFile( final URL fileUrl ) {
return downloadFile( fileUrl, Map.of() );
}

/**
* Download the file and write it to the file system
*
Expand All @@ -75,8 +95,12 @@ public byte[] downloadFile( final URL fileUrl ) {
* @return the file written
*/
public File downloadFile( final URL fileUrl, final File outputFile ) {
return downloadFile( fileUrl, Map.of(), outputFile );
}

public File downloadFile( final URL fileUrl, final Map<String, String> headers, final File outputFile ) {
try ( final FileOutputStream outputStream = new FileOutputStream( outputFile ) ) {
final byte[] fileContent = downloadFile( fileUrl );
final byte[] fileContent = downloadFile( fileUrl, headers );
outputStream.write( fileContent );
} catch ( final IOException exception ) {
throw new ModelResolutionException( "Could not write file " + outputFile, exception );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ public String refType() {
}

public URL zipLocation() {
final String url = "https://%s/%s/%s/archive/refs/%s/%s.zip".formatted(
host(), owner(), repository(), branchOrTag().refType(), branchOrTag().name() );
// See https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#download-a-repository-archive-zip
// General URL structure: https://api.github.com/repos/OWNER/REPO/zipball/REF
final String theHost = host().equals( "github.com" ) ? "api.github.com" : host();
final String url = "https://%s/repos/%s/%s/zipball/%s".formatted( theHost, owner(), repository(), branchOrTag().name() );
try {
return new URL( url );
} catch ( final MalformedURLException exception ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public record ProxyConfig(

public static final ProxyConfig NO_PROXY = new ProxyConfig( null, null );

public static ProxyConfig from( final String host, final int port ) {
return new ProxyConfig( ProxySelector.of( new InetSocketAddress( host, port ) ), null );
}

public static ProxyConfig detectProxySettings() {
final String envProxy = System.getenv( "http_proxy" );
if ( envProxy != null && System.getProperty( "http.proxyHost" ) == null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Represents the root directory of the directory hierarchy in which Aspect Models are organized.
* The directory is assumed to contain a file system hierarchy as follows: {@code N/V/X.ttl} where N is the namespace,
Expand All @@ -43,6 +46,8 @@
* </pre>
*/
public class StructuredModelsRoot extends ModelsRoot {
private static final Logger LOG = LoggerFactory.getLogger( StructuredModelsRoot.class );

public StructuredModelsRoot( final Path path ) {
super( path );
}
Expand Down Expand Up @@ -83,8 +88,11 @@ public Stream<URI> namespaceContents( final AspectModelUrn namespace ) {
.resolve( namespace.getNamespaceMainPart() )
.resolve( namespace.getVersion() )
.toFile();
return Arrays.stream( Objects.requireNonNull( namespaceDirectory.listFiles( file ->
file.getName().endsWith( ".ttl" ) ) ) )
.map( File::toURI );
final File[] files = namespaceDirectory.listFiles( file -> file.getName().endsWith( ".ttl" ) );
if ( files == null ) {
LOG.debug( "Supposed models root {} does not contain any .ttl files", namespaceDirectory );
return Stream.empty();
}
return Arrays.stream( Objects.requireNonNull( files ) ).map( File::toURI );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;

/**
* An implementation of an {@link AspectModelFile} that knows about the RDF model content and source location, but has not
* instantiated the model elements yet. Calling {@link #elements()} on this file will throw an exception. It is intended
* to represent the intermediary result of loading an Aspect Model file, possibly from a remote location.
*
* @param sourceModel the source RDF model
* @param headerComment the header comment
* @param sourceLocation the source location
*/
@SuppressWarnings( "OptionalUsedAsFieldOrParameterType" )
@RecordBuilder
public record RawAspectModelFile(
Expand Down
27 changes: 27 additions & 0 deletions core/esmf-aspect-model-aas-generator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
<groupId>org.eclipse.esmf</groupId>
<artifactId>esmf-aspect-meta-model-java</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.esmf</groupId>
<artifactId>esmf-aspect-model-generator</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.digitaltwin.aas4j</groupId>
<artifactId>aas4j-model</artifactId>
Expand All @@ -42,6 +46,11 @@
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder-processor</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.eclipse.esmf</groupId>
Expand All @@ -59,4 +68,22 @@
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder-processor</artifactId>
<version>${record-builder-version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
*
* See the AUTHORS file(s) distributed with this work for additional
* information regarding authorship.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/

package org.eclipse.esmf.aspectmodel.aas;

import org.eclipse.esmf.aspectmodel.generator.BinaryArtifact;

public class AasArtifact extends BinaryArtifact {
public AasArtifact( final String id, final byte[] content ) {
super( id, content );
}
}
Loading

0 comments on commit a31752d

Please sign in to comment.