Skip to content

Commit 86449e5

Browse files
authored
Merge branch 'main' into 538-llow-customizing-the-class-name-generating-POJO
2 parents 0d1f312 + 797c7d1 commit 86449e5

File tree

52 files changed

+1520
-375
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1520
-375
lines changed

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.apache.jena.rdf.model.ModelFactory;
3737
import org.apache.jena.rdf.model.Property;
3838
import org.apache.jena.rdf.model.RDFNode;
39+
import org.apache.jena.rdf.model.ResIterator;
3940
import org.apache.jena.rdf.model.Resource;
4041
import org.apache.jena.rdf.model.Statement;
4142
import org.apache.jena.vocabulary.RDF;
@@ -165,4 +166,32 @@ public static List<Resource> getNamedElementsReferringTo( final RDFNode node ) {
165166
} ).toList();
166167
}
167168
}
169+
170+
/**
171+
* Merges an RDF-model into another on a per-element basis instead of a per-statement basis. This means only those model element
172+
* definitions from the model to merge are merged into the target model that are not already present in the target model.
173+
* This prevents duplicate assertions of statements where the object is a blank node.
174+
*
175+
* @param target the model to merge into
176+
* @param modelToMerge the source model of model element definitions to merge
177+
*/
178+
public static void mergeModel( final Model target, final Model modelToMerge ) {
179+
final Set<String> targetSubjects = Streams.stream( target.listSubjects() )
180+
.filter( Resource::isURIResource )
181+
.map( Resource::getURI )
182+
.collect( toSet() );
183+
for ( final ResIterator it = modelToMerge.listSubjects(); it.hasNext(); ) {
184+
final Resource resource = it.next();
185+
if ( resource.isAnon() ) {
186+
continue;
187+
}
188+
if ( !targetSubjects.contains( resource.getURI() ) ) {
189+
final Model modelElementDefinition = getModelElementDefinition( resource );
190+
target.add( modelElementDefinition );
191+
}
192+
}
193+
for ( final Map.Entry<String, String> prefixEntry : modelToMerge.getNsPrefixMap().entrySet() ) {
194+
target.setNsPrefix( prefixEntry.getKey(), prefixEntry.getValue() );
195+
}
196+
}
168197
}

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,20 @@
4343
import org.eclipse.esmf.aspectmodel.resolver.AspectModelFileLoader;
4444
import org.eclipse.esmf.aspectmodel.resolver.EitherStrategy;
4545
import org.eclipse.esmf.aspectmodel.resolver.FileSystemStrategy;
46-
import org.eclipse.esmf.aspectmodel.resolver.ModelResolutionException;
4746
import org.eclipse.esmf.aspectmodel.resolver.ModelSource;
4847
import org.eclipse.esmf.aspectmodel.resolver.ResolutionStrategy;
4948
import org.eclipse.esmf.aspectmodel.resolver.ResolutionStrategySupport;
49+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
5050
import org.eclipse.esmf.aspectmodel.resolver.fs.FlatModelsRoot;
5151
import org.eclipse.esmf.aspectmodel.resolver.modelfile.DefaultAspectModelFile;
5252
import org.eclipse.esmf.aspectmodel.resolver.modelfile.MetaModelFile;
5353
import org.eclipse.esmf.aspectmodel.resolver.modelfile.RawAspectModelFile;
54+
import org.eclipse.esmf.aspectmodel.resolver.services.TurtleLoader;
5455
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
5556
import org.eclipse.esmf.aspectmodel.urn.ElementType;
5657
import org.eclipse.esmf.aspectmodel.urn.UrnSyntaxException;
5758
import org.eclipse.esmf.aspectmodel.versionupdate.MetaModelVersionMigrator;
59+
import org.eclipse.esmf.metamodel.Aspect;
5860
import org.eclipse.esmf.metamodel.AspectModel;
5961
import org.eclipse.esmf.metamodel.ModelElement;
6062
import org.eclipse.esmf.metamodel.Namespace;
@@ -113,6 +115,7 @@ public AspectModelLoader( final ResolutionStrategy resolutionStrategy ) {
113115
* @param resolutionStrategies the strategies
114116
*/
115117
public AspectModelLoader( final List<ResolutionStrategy> resolutionStrategies ) {
118+
TurtleLoader.init();
116119
if ( resolutionStrategies.size() == 1 ) {
117120
resolutionStrategy = resolutionStrategies.get( 0 );
118121
} else if ( resolutionStrategies.isEmpty() ) {
@@ -434,10 +437,10 @@ public AspectModel emptyModel() {
434437
*/
435438
public AspectModel loadAspectModelFiles( final Collection<AspectModelFile> inputFiles ) {
436439
final Model mergedModel = ModelFactory.createDefaultModel();
437-
mergedModel.add( MetaModelFile.metaModelDefinitions() );
438440
for ( final AspectModelFile file : inputFiles ) {
439-
mergedModel.add( file.sourceModel() );
441+
RdfUtil.mergeModel( mergedModel, file.sourceModel() );
440442
}
443+
mergedModel.add( MetaModelFile.metaModelDefinitions() );
441444

442445
final List<ModelElement> elements = new ArrayList<>();
443446
final List<AspectModelFile> files = new ArrayList<>();
@@ -460,6 +463,10 @@ public AspectModel loadAspectModelFiles( final Collection<AspectModelFile> input
460463
}
461464

462465
setNamespaces( files, elements );
466+
elements.stream()
467+
.filter( modelElement -> modelElement.is( Aspect.class ) )
468+
.findFirst()
469+
.ifPresent( aspect -> mergedModel.setNsPrefix( "", aspect.urn().getUrnPrefix() ) );
463470
return new DefaultAspectModel( files, mergedModel, elements );
464471
}
465472

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/AspectModelFileLoader.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import static org.apache.commons.lang3.StringUtils.isBlank;
1717

1818
import java.io.BufferedReader;
19+
import java.io.ByteArrayInputStream;
1920
import java.io.File;
2021
import java.io.FileInputStream;
2122
import java.io.FileNotFoundException;
@@ -34,6 +35,7 @@
3435

3536
import org.eclipse.esmf.aspectmodel.AspectModelFile;
3637
import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader;
38+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
3739
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ParserException;
3840
import org.eclipse.esmf.aspectmodel.resolver.modelfile.RawAspectModelFile;
3941
import org.eclipse.esmf.aspectmodel.resolver.services.TurtleLoader;
@@ -96,15 +98,24 @@ public static RawAspectModelFile load( final Model model ) {
9698
return new RawAspectModelFile( model, List.of(), Optional.empty() );
9799
}
98100

101+
public static RawAspectModelFile load( final byte[] content ) {
102+
return load( new ByteArrayInputStream( content ) );
103+
}
104+
99105
public static RawAspectModelFile load( final URL url ) {
100106
if ( url.getProtocol().equals( "file" ) ) {
101107
try {
102108
return load( Paths.get( url.toURI() ).toFile() );
103109
} catch ( final URISyntaxException exception ) {
104110
throw new ModelResolutionException( "Can not load model from file URL", exception );
105111
}
112+
} else if ( url.getProtocol().equals( "http" ) || url.getProtocol().equals( "https" ) ) {
113+
// Downloading from http(s) should take proxy settings into consideration, so we don't just .openStream() here
114+
final byte[] fileContent = new Download().downloadFile( url );
115+
return load( fileContent );
106116
}
107117
try {
118+
// Other URLs (e.g. resource://) we just load using openStream()
108119
return load( url.openStream(), Optional.of( url.toURI() ) );
109120
} catch ( final IOException | URISyntaxException exception ) {
110121
throw new ModelResolutionException( "Can not load model from URL", exception );

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/ClasspathStrategy.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.stream.Stream;
3434

3535
import org.eclipse.esmf.aspectmodel.AspectModelFile;
36+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
3637
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
3738

3839
import org.apache.commons.io.IOUtils;

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/CommandExecutor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.util.Scanner;
1919
import java.util.StringTokenizer;
2020

21+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
22+
2123
/**
2224
* Executes an external resolver via the underlying OS command and returns the stdout from the command as result.
2325
*/
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
3+
*
4+
* See the AUTHORS file(s) distributed with this work for additional
5+
* information regarding authorship.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
10+
*
11+
* SPDX-License-Identifier: MPL-2.0
12+
*/
13+
14+
package org.eclipse.esmf.aspectmodel.resolver;
15+
16+
import java.io.File;
17+
import java.io.FileOutputStream;
18+
import java.io.IOException;
19+
import java.net.URISyntaxException;
20+
import java.net.URL;
21+
import java.net.http.HttpClient;
22+
import java.net.http.HttpRequest;
23+
import java.net.http.HttpResponse;
24+
import java.time.Duration;
25+
import java.util.Optional;
26+
27+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
28+
29+
import org.slf4j.Logger;
30+
import org.slf4j.LoggerFactory;
31+
32+
/**
33+
* Convenience class to download a file via HTTP, which the ability to auto-detect and use proxy settings
34+
*/
35+
public class Download {
36+
private static final Logger LOG = LoggerFactory.getLogger( Download.class );
37+
private final ProxyConfig proxyConfig;
38+
39+
public Download( final ProxyConfig proxyConfig ) {
40+
this.proxyConfig = proxyConfig;
41+
}
42+
43+
public Download() {
44+
this( ProxyConfig.detectProxySettings() );
45+
}
46+
47+
/**
48+
* Download the file and return the contents as byte array
49+
*
50+
* @param fileUrl the URL
51+
* @return the file contents
52+
*/
53+
public byte[] downloadFile( final URL fileUrl ) {
54+
try {
55+
final HttpClient.Builder clientBuilder = HttpClient.newBuilder()
56+
.version( HttpClient.Version.HTTP_1_1 )
57+
.followRedirects( HttpClient.Redirect.ALWAYS )
58+
.connectTimeout( Duration.ofSeconds( 10 ) );
59+
Optional.ofNullable( proxyConfig.proxy() ).ifPresent( clientBuilder::proxy );
60+
Optional.ofNullable( proxyConfig.authenticator() ).ifPresent( clientBuilder::authenticator );
61+
final HttpClient client = clientBuilder.build();
62+
final HttpRequest request = HttpRequest.newBuilder().uri( fileUrl.toURI() ).build();
63+
final HttpResponse<byte[]> response = client.send( request, HttpResponse.BodyHandlers.ofByteArray() );
64+
return response.body();
65+
} catch ( final InterruptedException | URISyntaxException | IOException exception ) {
66+
throw new ModelResolutionException( "Could not retrieve " + fileUrl, exception );
67+
}
68+
}
69+
70+
/**
71+
* Download the file and write it to the file system
72+
*
73+
* @param fileUrl the URL
74+
* @param outputFile the output file to write
75+
* @return the file written
76+
*/
77+
public File downloadFile( final URL fileUrl, final File outputFile ) {
78+
try ( final FileOutputStream outputStream = new FileOutputStream( outputFile ) ) {
79+
final byte[] fileContent = downloadFile( fileUrl );
80+
outputStream.write( fileContent );
81+
} catch ( final IOException exception ) {
82+
throw new ModelResolutionException( "Could not write file " + outputFile, exception );
83+
}
84+
85+
LOG.info( "Downloaded {} to local file {}", fileUrl.getPath(), outputFile );
86+
return outputFile;
87+
}
88+
}

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/EitherStrategy.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.stream.Stream;
2121

2222
import org.eclipse.esmf.aspectmodel.AspectModelFile;
23+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
2324
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
2425

2526
import io.vavr.control.Try;

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/FileSystemStrategy.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.stream.Stream;
2323

2424
import org.eclipse.esmf.aspectmodel.AspectModelFile;
25+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
2526
import org.eclipse.esmf.aspectmodel.resolver.fs.ModelsRoot;
2627
import org.eclipse.esmf.aspectmodel.resolver.fs.StructuredModelsRoot;
2728
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;

core/esmf-aspect-meta-model-java/src/main/java/org/eclipse/esmf/aspectmodel/resolver/FromLoadedFileStrategy.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.util.stream.Stream;
1818

1919
import org.eclipse.esmf.aspectmodel.AspectModelFile;
20+
import org.eclipse.esmf.aspectmodel.resolver.exceptions.ModelResolutionException;
2021
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
2122

2223
/**
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
3+
*
4+
* See the AUTHORS file(s) distributed with this work for additional
5+
* information regarding authorship.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
10+
*
11+
* SPDX-License-Identifier: MPL-2.0
12+
*/
13+
14+
package org.eclipse.esmf.aspectmodel.resolver;
15+
16+
import java.io.Serial;
17+
import java.util.Arrays;
18+
import java.util.Optional;
19+
import java.util.function.Supplier;
20+
21+
import io.vavr.control.Try;
22+
23+
public record GitHubFileLocation(
24+
GithubRepository repositoryLocation,
25+
String directory,
26+
String namespaceMainPart,
27+
String version,
28+
String filename
29+
) {
30+
public static Optional<GitHubFileLocation> parse( final String url ) {
31+
return Try.of( () -> new GitHubUrlParser( url ).get() ).toJavaOptional();
32+
}
33+
34+
private static class ParsingException extends RuntimeException {
35+
@Serial
36+
private static final long serialVersionUID = -4855068216382713797L;
37+
}
38+
39+
private static class GitHubUrlParser implements Supplier<GitHubFileLocation> {
40+
private int index = 0;
41+
private final String source;
42+
43+
private GitHubUrlParser( final String source ) {
44+
this.source = source;
45+
}
46+
47+
private String readSection() {
48+
final int oldIndex = index;
49+
while ( index < source.length() && source.charAt( index ) != '/' ) {
50+
index++;
51+
}
52+
if ( source.charAt( index ) != '/' ) {
53+
throw new ParsingException();
54+
}
55+
final String result = source.substring( oldIndex, index );
56+
index++; // eat the slash
57+
return result;
58+
}
59+
60+
private void eatToken( final String token ) {
61+
if ( source.startsWith( token, index ) ) {
62+
index += token.length();
63+
return;
64+
}
65+
throw new ParsingException();
66+
}
67+
68+
@Override
69+
public GitHubFileLocation get() {
70+
eatToken( "https://" );
71+
final String host = readSection();
72+
final String owner = readSection();
73+
final String repository = readSection();
74+
final GithubRepository.Ref ref;
75+
if ( source.substring( index ).startsWith( "blob" ) ) {
76+
eatToken( "blob/" );
77+
final String blob = readSection();
78+
ref = blob.matches( "[vV]?\\d+\\.\\d+.*" )
79+
? new GithubRepository.Tag( blob )
80+
: new GithubRepository.Branch( blob );
81+
} else {
82+
eatToken( "raw/refs/" );
83+
if ( source.substring( index ).startsWith( "heads" ) ) {
84+
eatToken( "heads/" );
85+
final String branchName = readSection();
86+
ref = new GithubRepository.Branch( branchName );
87+
} else {
88+
eatToken( "tags/" );
89+
final String tag = readSection();
90+
ref = new GithubRepository.Tag( tag );
91+
}
92+
}
93+
final String rest = source.substring( index );
94+
final String[] parts = rest.split( "/" );
95+
final String fileName = parts[parts.length - 1];
96+
final String version = parts[parts.length - 2];
97+
final String namespaceMainPart = parts[parts.length - 3];
98+
final String directory = String.join( "/", Arrays.copyOfRange( parts, 0, parts.length - 3 ) );
99+
final GithubRepository repoLocation = new GithubRepository( host, owner, repository, ref );
100+
return new GitHubFileLocation( repoLocation, directory, namespaceMainPart, version, fileName );
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)